diff --git a/package.json b/package.json index ddec997..1f6f13d 100644 --- a/package.json +++ b/package.json @@ -1,66 +1,66 @@ { - "name": "uint8array-tools", - "version": "0.0.7", - "description": "A library for dealing with Uint8Arrays.", - "homepage": "https://github.com/bitcoinjs/uint8array-tools#readme", - "bugs": { - "url": "https://github.com/bitcoinjs/uint8array-tools/issues" + "name": "uint8array-tools", + "version": "0.0.7", + "description": "A library for dealing with Uint8Arrays.", + "homepage": "https://github.com/bitcoinjs/uint8array-tools#readme", + "bugs": { + "url": "https://github.com/bitcoinjs/uint8array-tools/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/bitcoinjs/uint8array-tools.git" + }, + "main": "./src/cjs/index.cjs", + "exports": { + "node": { + "module": "./src/mjs/index.js", + "require": "./src/cjs/index.cjs", + "import": "./src/mjs/index.js", + "types": "./src/cjs/index.d.ts" }, - "repository": { - "type": "git", - "url": "https://github.com/bitcoinjs/uint8array-tools.git" - }, - "main": "./src/cjs/index.cjs", - "exports": { - "node": { - "module": "./src/mjs/index.js", - "require": "./src/cjs/index.cjs", - "import": "./src/mjs/index.js", - "types": "./src/cjs/index.d.ts" - }, - "browser": "./src/mjs/browser.js", - "default": "./src/mjs/browser.js", - "types": "./src/cjs/index.d.ts" - }, - "types": "src/cjs/index.d.ts", - "type": "module", - "scripts": { - "build": "npm run clean && npm run build-ts && npm run convert-cjs && rm -f ./src/cjs/browser.d.ts", - "build-ts": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json", - "clean": "rm -rf ./src/* && rm -rf ./coverage && rm -f ./package-lock.json", - "convert-cjs": "for f in ./src/cjs/*.js; do mv -- \"$f\" \"${f%.js}.cjs\"; done", - "coverage": "npm run unit -- --coverage", - "eslint": "eslint ts_src/*.ts", - "format": "npm run eslint -- --fix", - "gitdiff:ci": "npm run build && git diff --exit-code", - "lint": "npm run eslint", - "test": "npm run unit", - "unit": "jest --config=jest.json --runInBand" - }, - "keywords": [ - "uint8array", - "hex", - "tools" - ], - "files": [ - "src" - ], - "author": "Jonathan Underwood (junderwood@bitcoinbank.co.jp)", - "license": "MIT", - "devDependencies": { - "@types/jest": "27.0.2", - "@types/node": "16.11.1", - "@typescript-eslint/eslint-plugin": "5.0.0", - "@typescript-eslint/parser": "5.0.0", - "eslint": "8.0.1", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.2.5", - "prettier": "2.4.1", - "ts-jest": "27.0.7", - "typescript": "4.4.4" - }, - "engines": { - "node": ">=14.0.0" - } + "browser": "./src/mjs/browser.js", + "default": "./src/mjs/browser.js", + "types": "./src/cjs/index.d.ts" + }, + "types": "src/cjs/index.d.ts", + "type": "module", + "scripts": { + "build": "npm run clean && npm run build-ts && npm run convert-cjs && rm -f ./src/cjs/browser.d.ts", + "build-ts": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json", + "clean": "rm -rf ./src/* && rm -rf ./coverage && rm -f ./package-lock.json", + "convert-cjs": "for f in ./src/cjs/*.js; do mv -- \"$f\" \"${f%.js}.cjs\"; done", + "coverage": "npm run unit -- --coverage", + "eslint": "eslint ts_src/*.ts", + "format": "npm run eslint -- --fix", + "gitdiff:ci": "npm run build && git diff --exit-code", + "lint": "npm run eslint", + "test": "npm run unit", + "unit": "jest --config=jest.json --runInBand" + }, + "keywords": [ + "uint8array", + "hex", + "tools" + ], + "files": [ + "src" + ], + "author": "Jonathan Underwood (junderwood@bitcoinbank.co.jp)", + "license": "MIT", + "devDependencies": { + "@types/jest": "27.0.2", + "@types/node": "16.11.1", + "@typescript-eslint/eslint-plugin": "5.0.0", + "@typescript-eslint/parser": "5.0.0", + "eslint": "8.0.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "4.0.0", + "jest": "27.2.5", + "prettier": "2.4.1", + "ts-jest": "27.0.7", + "typescript": "4.4.4" + }, + "engines": { + "node": ">=14.0.0" + } } diff --git a/ts_src/index.ts b/ts_src/index.ts index a038e73..d69ffbb 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -1,189 +1,189 @@ export function toUtf8(bytes: Uint8Array): string { - return Buffer.from(bytes || []).toString(); + return Buffer.from(bytes || []).toString(); } export function fromUtf8(s: string): Uint8Array { - return Uint8Array.from(Buffer.from(s || "", "utf8")); + return Uint8Array.from(Buffer.from(s || "", "utf8")); } export function concat(arrays: Uint8Array[]): Uint8Array { - return Uint8Array.from(Buffer.concat(arrays)); + return Uint8Array.from(Buffer.concat(arrays)); } export function toHex(bytes: Uint8Array): string { - return Buffer.from(bytes || []).toString("hex"); + return Buffer.from(bytes || []).toString("hex"); } export function fromHex(hexString: string): Uint8Array { - return Uint8Array.from(Buffer.from(hexString || "", "hex")); + return Uint8Array.from(Buffer.from(hexString || "", "hex")); } export function toBase64(bytes: Uint8Array): string { - return Buffer.from(bytes).toString("base64"); + return Buffer.from(bytes).toString("base64"); } export function fromBase64(base64: string): Uint8Array { - return Uint8Array.from(Buffer.from(base64 || "", "base64")); + return Uint8Array.from(Buffer.from(base64 || "", "base64")); } export type CompareResult = -1 | 0 | 1; export function compare(v1: Uint8Array, v2: Uint8Array): CompareResult { - return Buffer.from(v1).compare(Buffer.from(v2)) as CompareResult; + return Buffer.from(v1).compare(Buffer.from(v2)) as CompareResult; } export type endian = "LE" | "BE" | "le" | "be"; export function writeUInt8( - buffer: Uint8Array, - offset: number, - value: number + buffer: Uint8Array, + offset: number, + value: number ): void { - if (offset + 1 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - const buf = Buffer.alloc(1); - buf.writeUInt8(value, 0); - buffer.set(Uint8Array.from(buf), offset); + const buf = Buffer.alloc(1); + buf.writeUInt8(value, 0); + buffer.set(Uint8Array.from(buf), offset); } export function writeUInt16( - buffer: Uint8Array, - offset: number, - value: number, - littleEndian: endian + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian ): void { - if (offset + 2 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.alloc(2); + const buf = Buffer.alloc(2); - if (littleEndian === "LE") { - buf.writeUInt16LE(value, 0); - } else { - buf.writeUInt16BE(value, 0); - } - buffer.set(Uint8Array.from(buf), offset); + if (littleEndian === "LE") { + buf.writeUInt16LE(value, 0); + } else { + buf.writeUInt16BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); } export function writeUInt32( - buffer: Uint8Array, - offset: number, - value: number, - littleEndian: endian + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian ): void { - if (offset + 4 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.alloc(4); + const buf = Buffer.alloc(4); - if (littleEndian === "LE") { - buf.writeUInt32LE(value, 0); - } else { - buf.writeUInt32BE(value, 0); - } - buffer.set(Uint8Array.from(buf), offset); + if (littleEndian === "LE") { + buf.writeUInt32LE(value, 0); + } else { + buf.writeUInt32BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); } export function writeUInt64( - buffer: Uint8Array, - offset: number, - value: bigint, - littleEndian: endian + buffer: Uint8Array, + offset: number, + value: bigint, + littleEndian: endian ): void { - if (offset + 8 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.alloc(8); + const buf = Buffer.alloc(8); - if (value > 0xffffffffffffffffn) { - throw new Error( - `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}` - ); - } + if (value > 0xffffffffffffffffn) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}` + ); + } - if (littleEndian === "LE") { - buf.writeBigUInt64LE(value, 0); - } else { - buf.writeBigUInt64BE(value, 0); - } - buffer.set(Uint8Array.from(buf), offset); + if (littleEndian === "LE") { + buf.writeBigUInt64LE(value, 0); + } else { + buf.writeBigUInt64BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); } export function readUInt8(buffer: Uint8Array, offset: number): number { - if (offset + 1 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - const buf = Buffer.from(buffer); - return buf.readUInt8(offset); + const buf = Buffer.from(buffer); + return buf.readUInt8(offset); } export function readUInt16( - buffer: Uint8Array, - offset: number, - littleEndian: endian + buffer: Uint8Array, + offset: number, + littleEndian: endian ): number { - if (offset + 2 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.from(buffer); + const buf = Buffer.from(buffer); - if (littleEndian === "LE") { - return buf.readUInt16LE(offset); - } else { - return buf.readUInt16BE(offset); - } + if (littleEndian === "LE") { + return buf.readUInt16LE(offset); + } else { + return buf.readUInt16BE(offset); + } } export function readUInt32( - buffer: Uint8Array, - offset: number, - littleEndian: endian + buffer: Uint8Array, + offset: number, + littleEndian: endian ): number { - if (offset + 4 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.from(buffer); + const buf = Buffer.from(buffer); - if (littleEndian === "LE") { - return buf.readUInt32LE(offset); - } else { - return buf.readUInt32BE(offset); - } + if (littleEndian === "LE") { + return buf.readUInt32LE(offset); + } else { + return buf.readUInt32BE(offset); + } } export function readUInt64( - buffer: Uint8Array, - offset: number, - littleEndian: endian + buffer: Uint8Array, + offset: number, + littleEndian: endian ): bigint { - if (offset + 8 > buffer.length) { - throw new Error("Offset is outside the bounds of Uint8Array"); - } + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } - littleEndian = littleEndian.toUpperCase() as endian; + littleEndian = littleEndian.toUpperCase() as endian; - const buf = Buffer.from(buffer); + const buf = Buffer.from(buffer); - if (littleEndian === "LE") { - return buf.readBigUInt64LE(offset); - } else { - return buf.readBigUInt64BE(offset); - } + if (littleEndian === "LE") { + return buf.readBigUInt64LE(offset); + } else { + return buf.readBigUInt64BE(offset); + } } diff --git a/ts_src/tests.spec.ts b/ts_src/tests.spec.ts index 4227c9a..d92aaf0 100644 --- a/ts_src/tests.spec.ts +++ b/ts_src/tests.spec.ts @@ -2,8 +2,8 @@ import * as browser from "./browser"; import * as node from "./index"; const modules = [ - ["browser", browser], - ["node", node], + ["browser", browser], + ["node", node], ] as [string, typeof browser][]; const f = (d: number[]) => Uint8Array.from(d); @@ -19,480 +19,398 @@ const utf8 = "!~"; const longBytes2 = new Uint8Array(513).fill(0x61); const longUtf8 = "a".repeat(513); const testBytes = f([ - 227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175, + 227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175, ]); const str = "こんにちは"; const brokenHexes = [ - [" ff00", f([]), "leading space"], - ["ffa bcdef", f([0xff]), "middle space"], - ["ffba34aQcdef", f([0xff, 0xba, 0x34]), "invalid char"], - ["Qfba34abcdef", f([]), "invalid char"], + [" ff00", f([]), "leading space"], + ["ffa bcdef", f([0xff]), "middle space"], + ["ffba34aQcdef", f([0xff, 0xba, 0x34]), "invalid char"], + ["Qfba34abcdef", f([]), "invalid char"], ] as [string, Uint8Array, string][]; describe(`Uint8Array tools`, () => { - for (const [name, tools] of modules) { - describe(name, () => { - it(`should parse hex with fromHex`, () => { - expect(tools.fromHex(hex)).toEqual(bytes); - expect((tools.fromHex as any)()).toEqual(f([])); - }); - for (const [bhex, result, reason] of brokenHexes) { - it(`should abort parsing hex ${bhex} because of ${reason}`, () => { - expect(tools.fromHex(bhex)).toEqual(result); - }); - } - it(`should output hex with toHex`, () => { - expect(tools.toHex(bytes)).toEqual(hex); - expect(tools.toHex(longBytes)).toEqual(longHex); - expect((tools.toHex as any)()).toEqual(""); - }); - it(`should output utf8 with toUtf8`, () => { - expect(tools.toUtf8(bytes3)).toEqual(utf8); - expect(tools.toUtf8(testBytes)).toEqual(str); - expect(tools.toUtf8(longBytes2)).toEqual(longUtf8); - expect((tools.toUtf8 as any)()).toEqual(""); - }); - it("should read utf8 with fromUtf8", () => { - expect(tools.fromUtf8(utf8)).toEqual(bytes3); - expect(tools.fromUtf8(str)).toEqual(testBytes); - expect(tools.fromUtf8(longUtf8)).toEqual(longBytes2); - expect((tools.fromUtf8 as any)()).toEqual(f([])); - }); - it(`should compare Uint8Arrays`, () => { - expect(tools.compare(bytes, bytes2)).toBe(-1); - expect(tools.compare(bytes, bytes)).toBe(0); - expect(tools.compare(bytes2, bytes)).toBe(1); - expect(tools.compare(bytes2, bytes2Larger)).toBe(-1); - expect(tools.compare(bytes2Larger, bytes2)).toBe(1); - expect(tools.compare(bytes2, bytes2LargerLeft)).toBe(1); - expect(tools.compare(bytes2LargerLeft, bytes2)).toBe(-1); - }); - it("should concat Uint8Arrays", () => { - const fixtures = [ - [new Uint8Array([]), new Uint8Array([])], - [new Uint8Array([1]), new Uint8Array([1])], - [new Uint8Array([])], - [new Uint8Array()], - [...new Array(1000)].map((_) => new Uint8Array([123])), - ]; - - for (const fixture of fixtures) { - expect(new Uint8Array(Buffer.concat(fixture))).toEqual( - tools.concat(fixture) - ); - } - }); - it("should read from base64", () => { - const fixtures = [ - Buffer.from("").toString("base64"), - Buffer.from("a").toString("base64"), - Buffer.from("ab").toString("base64"), - Buffer.from("abc").toString("base64"), - Buffer.from("abcd").toString("base64"), - Buffer.from("abcde").toString("base64"), - Buffer.from("abcdef").toString("base64"), - Buffer.from("abcdefg").toString("base64"), - Buffer.from("abcdefgh").toString("base64"), - Buffer.from("abcdefghi").toString("base64"), - Buffer.from("abcdefghij").toString("base64"), - Buffer.from("abcdefghijk").toString("base64"), - Buffer.from("abcdefghijkl").toString("base64"), - Buffer.from("abcdefghijklm").toString("base64"), - Buffer.from("abcdefghijklmn").toString("base64"), - ]; - - for (const fixture of fixtures) { - expect(tools.fromBase64(fixture)).toEqual( - Uint8Array.from(Buffer.from(fixture, "base64")) - ); - } - }); - - it("should write to base64", () => { - const fixtures = [ - Buffer.from("").toString("base64"), - Buffer.from("a").toString("base64"), - Buffer.from("ab").toString("base64"), - Buffer.from("abc").toString("base64"), - Buffer.from("abcd").toString("base64"), - Buffer.from("abcde").toString("base64"), - Buffer.from("abcdef").toString("base64"), - Buffer.from("abcdefg").toString("base64"), - Buffer.from("abcdefgh").toString("base64"), - Buffer.from("abcdefghi").toString("base64"), - Buffer.from("abcdefghij").toString("base64"), - Buffer.from("abcdefghijk").toString("base64"), - Buffer.from("abcdefghijkl").toString("base64"), - Buffer.from("abcdefghijklm").toString("base64"), - Buffer.from("abcdefghijklmn").toString("base64"), - ]; - - for (const fixture of fixtures) { - expect(tools.toBase64(tools.fromBase64(fixture))).toEqual( - fixture - ); - } - }); - - it("should writeUint8", () => { - const hexs = ["03", "fd"]; - - for (const hex of hexs) { - const actualArray = new Uint8Array(1); - const expectedArray = Buffer.alloc(1); - - tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); - expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - } - }); - - it("should writeUint16", () => { - const hexs = ["0300", "0003", "fdff", "fffd"]; - - for (const hex of hexs) { - const actualArray = new Uint8Array(2); - const expectedArray = Buffer.alloc(2); - - for (const endian of ["BE", "LE"]) { - tools.writeUInt16( - actualArray, - 0, - Number.parseInt(hex, 16), - endian as browser.endian - ); - expectedArray[ - ("writeUInt16" + endian) as - | "writeUInt16LE" - | "writeUInt16BE" - ](Number.parseInt(hex, 16), 0); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - } - } - }); - - it("should writeUint32", () => { - const hexs = ["03000000", "00000003", "fdffffff", "fffffffd"]; - - for (const hex of hexs) { - const actualArray = new Uint8Array(4); - const expectedArray = Buffer.alloc(4); - - for (const endian of ["BE", "LE"]) { - tools.writeUInt32( - actualArray, - 0, - Number.parseInt(hex, 16), - endian as browser.endian - ); - expectedArray[ - ("writeUInt32" + endian) as - | "writeUInt32LE" - | "writeUInt32BE" - ](Number.parseInt(hex, 16), 0); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - } - } - }); - - it("should writeUint64", () => { - const hexs = [ - "0300000000000000", - "0000000000000003", - "fdffffffffffffff", - "fffffffffffffffd", - ]; - - for (const hex of hexs) { - const actualArray = new Uint8Array(8); - const expectedArray = Buffer.alloc(8); - - for (const endian of ["BE", "LE"]) { - tools.writeUInt64( - actualArray, - 0, - BigInt("0x" + hex), - endian as browser.endian - ); - expectedArray[ - ("writeBigUInt64" + endian) as - | "writeBigUInt64LE" - | "writeBigUInt64BE" - ](BigInt("0x" + hex), 0); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - } - } - }); - - it("should throw an error when offset is out of bounds", () => { - const bytes = new Uint8Array(100); - - expect(() => - tools.writeUInt8(bytes, bytes.length - 1 + 1, 1) - ).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - - expect(() => - tools.writeUInt16(bytes, bytes.length - 2 + 1, 1, "LE") - ).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - - expect(() => - tools.writeUInt32(bytes, bytes.length - 4 + 1, 1, "LE") - ).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - - expect(() => - tools.writeUInt64(bytes, bytes.length - 8 + 1, 1n, "LE") - ).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - }); - - it("should write at the correct offset", () => { - const actualArray = new Uint8Array(100); - const expectedArray = Buffer.alloc(100); - let hex = "03"; - const offset = 50; - - tools.writeUInt8(actualArray, offset, Number.parseInt(hex, 16)); - expectedArray.writeUInt8(Number.parseInt(hex, 16), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - hex = "0300"; - - tools.writeUInt16( - actualArray, - offset, - Number.parseInt(hex, 16), - "LE" - ); - expectedArray.writeUInt16LE(Number.parseInt(hex, 16), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - tools.writeUInt16( - actualArray, - offset, - Number.parseInt(hex, 16), - "BE" - ); - expectedArray.writeUInt16BE(Number.parseInt(hex, 16), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - hex = "03000000"; - - tools.writeUInt32( - actualArray, - offset, - Number.parseInt(hex, 16), - "LE" - ); - expectedArray.writeUInt32LE(Number.parseInt(hex, 16), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - tools.writeUInt32( - actualArray, - offset, - Number.parseInt(hex, 16), - "BE" - ); - expectedArray.writeUInt32BE(Number.parseInt(hex, 16), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - hex = "0300000000000000"; - - tools.writeUInt64( - actualArray, - offset, - BigInt("0x" + hex), - "LE" - ); - expectedArray.writeBigUInt64LE(BigInt("0x" + hex), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - - tools.writeUInt64( - actualArray, - offset, - BigInt("0x" + hex), - "BE" - ); - expectedArray.writeBigUInt64BE(BigInt("0x" + hex), offset); - - expect(expectedArray.toString("hex")).toEqual( - tools.toHex(actualArray) - ); - }); - it("should throw an error on overflow", () => { - let bytes = new Uint8Array(1); - - let overflowVal = 0xffn + 1n; - expect(() => tools.writeUInt8(bytes, 0, 0xff + 1)).toThrowError( - `The value of "value" is out of range. It must be >= 0 and <= ${0xffn}. Received ${overflowVal}` - ); - - bytes = new Uint8Array(2); - overflowVal = 0xffffn + 1n; - - expect(() => - tools.writeUInt16(bytes, 0, 0xffff + 1, "LE") - ).toThrowError( - `The value of "value" is out of range. It must be >= 0 and <= ${0xffffn}. Received ${overflowVal}` - ); - - bytes = new Uint8Array(4); - overflowVal = 0xffffffffn + 1n; - - expect(() => - tools.writeUInt32(bytes, 0, 0xffffffff + 1, "LE") - ).toThrowError( - `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffn}. Received ${overflowVal}` - ); - - bytes = new Uint8Array(8); - overflowVal = 0xffffffffffffffffn + 1n; - - expect(() => - tools.writeUInt64(bytes, 0, 0xffffffffffffffffn + 1n, "LE") - ).toThrowError( - `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn.toString()}. Received ${overflowVal}` - ); - }); - - it("should read bytes at the correct offset", () => { - const actualArray = new Uint8Array(200); - const expectedArray = Buffer.alloc(200); - - let hex = "ff"; - tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); - expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); - - expect(expectedArray.readUInt8(0)).toEqual( - tools.readUInt8(actualArray, 0) - ); - - hex = "abcd"; - tools.writeUInt16( - actualArray, - 10, - Number.parseInt(hex, 16), - "LE" - ); - expectedArray.writeUInt16LE(Number.parseInt(hex, 16), 10); - - expect(expectedArray.readUInt16LE(10)).toEqual( - tools.readUInt16(actualArray, 10, "LE") - ); - - tools.writeUInt16( - actualArray, - 20, - Number.parseInt(hex, 16), - "BE" - ); - expectedArray.writeUInt16BE(Number.parseInt(hex, 16), 20); - - expect(expectedArray.readUInt16BE(20)).toEqual( - tools.readUInt16(actualArray, 20, "BE") - ); - - hex = "ffffabff"; - tools.writeUInt32( - actualArray, - 30, - Number.parseInt(hex, 16), - "LE" - ); - expectedArray.writeUInt32LE(Number.parseInt(hex, 16), 30); - - expect(expectedArray.readUInt32LE(30)).toEqual( - tools.readUInt32(actualArray, 30, "LE") - ); - - tools.writeUInt32( - actualArray, - 50, - Number.parseInt(hex, 16), - "BE" - ); - expectedArray.writeUInt32BE(Number.parseInt(hex, 16), 50); - - expect(expectedArray.readUInt32BE(50)).toEqual( - tools.readUInt32(actualArray, 50, "BE") - ); - - hex = "ffffffffffffabff"; - tools.writeUInt64(actualArray, 70, BigInt("0x" + hex), "LE"); - expectedArray.writeBigUInt64LE(BigInt("0x" + hex), 70); - - expect(expectedArray.readBigUInt64LE(70)).toEqual( - tools.readUInt64(actualArray, 70, "LE") - ); - - tools.writeUInt64(actualArray, 110, BigInt("0x" + hex), "BE"); - expectedArray.writeBigUInt64BE(BigInt("0x" + hex), 110); - - expect(expectedArray.readBigUInt64BE(110)).toEqual( - tools.readUInt64(actualArray, 110, "BE") - ); - }); - - it("should throw an error if the offset is out of bounds", () => { - const arr = new Uint8Array(10); - - expect(() => tools.readUInt8(arr, 10)).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - - const fns = [ - tools.readUInt16, - tools.readUInt32, - tools.readUInt64, - ]; - - for (const fn of fns) { - expect(() => fn(arr, 10, "LE")).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - - expect(() => fn(arr, 10, "BE")).toThrowError( - new Error("Offset is outside the bounds of Uint8Array") - ); - } - }); + for (const [name, tools] of modules) { + describe(name, () => { + it(`should parse hex with fromHex`, () => { + expect(tools.fromHex(hex)).toEqual(bytes); + expect((tools.fromHex as any)()).toEqual(f([])); + }); + for (const [bhex, result, reason] of brokenHexes) { + it(`should abort parsing hex ${bhex} because of ${reason}`, () => { + expect(tools.fromHex(bhex)).toEqual(result); }); - } + } + it(`should output hex with toHex`, () => { + expect(tools.toHex(bytes)).toEqual(hex); + expect(tools.toHex(longBytes)).toEqual(longHex); + expect((tools.toHex as any)()).toEqual(""); + }); + it(`should output utf8 with toUtf8`, () => { + expect(tools.toUtf8(bytes3)).toEqual(utf8); + expect(tools.toUtf8(testBytes)).toEqual(str); + expect(tools.toUtf8(longBytes2)).toEqual(longUtf8); + expect((tools.toUtf8 as any)()).toEqual(""); + }); + it("should read utf8 with fromUtf8", () => { + expect(tools.fromUtf8(utf8)).toEqual(bytes3); + expect(tools.fromUtf8(str)).toEqual(testBytes); + expect(tools.fromUtf8(longUtf8)).toEqual(longBytes2); + expect((tools.fromUtf8 as any)()).toEqual(f([])); + }); + it(`should compare Uint8Arrays`, () => { + expect(tools.compare(bytes, bytes2)).toBe(-1); + expect(tools.compare(bytes, bytes)).toBe(0); + expect(tools.compare(bytes2, bytes)).toBe(1); + expect(tools.compare(bytes2, bytes2Larger)).toBe(-1); + expect(tools.compare(bytes2Larger, bytes2)).toBe(1); + expect(tools.compare(bytes2, bytes2LargerLeft)).toBe(1); + expect(tools.compare(bytes2LargerLeft, bytes2)).toBe(-1); + }); + it("should concat Uint8Arrays", () => { + const fixtures = [ + [new Uint8Array([]), new Uint8Array([])], + [new Uint8Array([1]), new Uint8Array([1])], + [new Uint8Array([])], + [new Uint8Array()], + [...new Array(1000)].map(() => new Uint8Array([123])), + ]; + + for (const fixture of fixtures) { + expect(new Uint8Array(Buffer.concat(fixture))).toEqual( + tools.concat(fixture) + ); + } + }); + it("should read from base64", () => { + const fixtures = [ + Buffer.from("").toString("base64"), + Buffer.from("a").toString("base64"), + Buffer.from("ab").toString("base64"), + Buffer.from("abc").toString("base64"), + Buffer.from("abcd").toString("base64"), + Buffer.from("abcde").toString("base64"), + Buffer.from("abcdef").toString("base64"), + Buffer.from("abcdefg").toString("base64"), + Buffer.from("abcdefgh").toString("base64"), + Buffer.from("abcdefghi").toString("base64"), + Buffer.from("abcdefghij").toString("base64"), + Buffer.from("abcdefghijk").toString("base64"), + Buffer.from("abcdefghijkl").toString("base64"), + Buffer.from("abcdefghijklm").toString("base64"), + Buffer.from("abcdefghijklmn").toString("base64"), + ]; + + for (const fixture of fixtures) { + expect(tools.fromBase64(fixture)).toEqual( + Uint8Array.from(Buffer.from(fixture, "base64")) + ); + } + }); + + it("should write to base64", () => { + const fixtures = [ + Buffer.from("").toString("base64"), + Buffer.from("a").toString("base64"), + Buffer.from("ab").toString("base64"), + Buffer.from("abc").toString("base64"), + Buffer.from("abcd").toString("base64"), + Buffer.from("abcde").toString("base64"), + Buffer.from("abcdef").toString("base64"), + Buffer.from("abcdefg").toString("base64"), + Buffer.from("abcdefgh").toString("base64"), + Buffer.from("abcdefghi").toString("base64"), + Buffer.from("abcdefghij").toString("base64"), + Buffer.from("abcdefghijk").toString("base64"), + Buffer.from("abcdefghijkl").toString("base64"), + Buffer.from("abcdefghijklm").toString("base64"), + Buffer.from("abcdefghijklmn").toString("base64"), + ]; + + for (const fixture of fixtures) { + expect(tools.toBase64(tools.fromBase64(fixture))).toEqual(fixture); + } + }); + + it("should writeUint8", () => { + const hexs = ["03", "fd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(1); + const expectedArray = Buffer.alloc(1); + + tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + }); + + it("should writeUint16", () => { + const hexs = ["0300", "0003", "fdff", "fffd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(2); + const expectedArray = Buffer.alloc(2); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt16( + actualArray, + 0, + Number.parseInt(hex, 16), + endian as browser.endian + ); + expectedArray[ + ("writeUInt16" + endian) as "writeUInt16LE" | "writeUInt16BE" + ](Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should writeUint32", () => { + const hexs = ["03000000", "00000003", "fdffffff", "fffffffd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(4); + const expectedArray = Buffer.alloc(4); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt32( + actualArray, + 0, + Number.parseInt(hex, 16), + endian as browser.endian + ); + expectedArray[ + ("writeUInt32" + endian) as "writeUInt32LE" | "writeUInt32BE" + ](Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should writeUint64", () => { + const hexs = [ + "0300000000000000", + "0000000000000003", + "fdffffffffffffff", + "fffffffffffffffd", + ]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(8); + const expectedArray = Buffer.alloc(8); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt64( + actualArray, + 0, + BigInt("0x" + hex), + endian as browser.endian + ); + expectedArray[ + ("writeBigUInt64" + endian) as + | "writeBigUInt64LE" + | "writeBigUInt64BE" + ](BigInt("0x" + hex), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should throw an error when offset is out of bounds", () => { + const bytes = new Uint8Array(100); + + expect(() => + tools.writeUInt8(bytes, bytes.length - 1 + 1, 1) + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt16(bytes, bytes.length - 2 + 1, 1, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt32(bytes, bytes.length - 4 + 1, 1, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt64(bytes, bytes.length - 8 + 1, 1n, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + }); + + it("should write at the correct offset", () => { + const actualArray = new Uint8Array(100); + const expectedArray = Buffer.alloc(100); + let hex = "03"; + const offset = 50; + + tools.writeUInt8(actualArray, offset, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "0300"; + + tools.writeUInt16(actualArray, offset, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt16LE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt16(actualArray, offset, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt16BE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "03000000"; + + tools.writeUInt32(actualArray, offset, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt32LE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt32(actualArray, offset, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt32BE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "0300000000000000"; + + tools.writeUInt64(actualArray, offset, BigInt("0x" + hex), "LE"); + expectedArray.writeBigUInt64LE(BigInt("0x" + hex), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt64(actualArray, offset, BigInt("0x" + hex), "BE"); + expectedArray.writeBigUInt64BE(BigInt("0x" + hex), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + }); + it("should throw an error on overflow", () => { + let bytes = new Uint8Array(1); + + let overflowVal = 0xffn + 1n; + expect(() => tools.writeUInt8(bytes, 0, 0xff + 1)).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(2); + overflowVal = 0xffffn + 1n; + + expect(() => + tools.writeUInt16(bytes, 0, 0xffff + 1, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(4); + overflowVal = 0xffffffffn + 1n; + + expect(() => + tools.writeUInt32(bytes, 0, 0xffffffff + 1, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(8); + overflowVal = 0xffffffffffffffffn + 1n; + + expect(() => + tools.writeUInt64(bytes, 0, 0xffffffffffffffffn + 1n, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn.toString()}. Received ${overflowVal}` + ); + }); + + it("should read bytes at the correct offset", () => { + const actualArray = new Uint8Array(200); + const expectedArray = Buffer.alloc(200); + + let hex = "ff"; + tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); + + expect(expectedArray.readUInt8(0)).toEqual( + tools.readUInt8(actualArray, 0) + ); + + hex = "abcd"; + tools.writeUInt16(actualArray, 10, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt16LE(Number.parseInt(hex, 16), 10); + + expect(expectedArray.readUInt16LE(10)).toEqual( + tools.readUInt16(actualArray, 10, "LE") + ); + + tools.writeUInt16(actualArray, 20, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt16BE(Number.parseInt(hex, 16), 20); + + expect(expectedArray.readUInt16BE(20)).toEqual( + tools.readUInt16(actualArray, 20, "BE") + ); + + hex = "ffffabff"; + tools.writeUInt32(actualArray, 30, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt32LE(Number.parseInt(hex, 16), 30); + + expect(expectedArray.readUInt32LE(30)).toEqual( + tools.readUInt32(actualArray, 30, "LE") + ); + + tools.writeUInt32(actualArray, 50, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt32BE(Number.parseInt(hex, 16), 50); + + expect(expectedArray.readUInt32BE(50)).toEqual( + tools.readUInt32(actualArray, 50, "BE") + ); + + hex = "ffffffffffffabff"; + tools.writeUInt64(actualArray, 70, BigInt("0x" + hex), "LE"); + expectedArray.writeBigUInt64LE(BigInt("0x" + hex), 70); + + expect(expectedArray.readBigUInt64LE(70)).toEqual( + tools.readUInt64(actualArray, 70, "LE") + ); + + tools.writeUInt64(actualArray, 110, BigInt("0x" + hex), "BE"); + expectedArray.writeBigUInt64BE(BigInt("0x" + hex), 110); + + expect(expectedArray.readBigUInt64BE(110)).toEqual( + tools.readUInt64(actualArray, 110, "BE") + ); + }); + + it("should throw an error if the offset is out of bounds", () => { + const arr = new Uint8Array(10); + + expect(() => tools.readUInt8(arr, 10)).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + + const fns = [tools.readUInt16, tools.readUInt32, tools.readUInt64]; + + for (const fn of fns) { + expect(() => fn(arr, 10, "LE")).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + + expect(() => fn(arr, 10, "BE")).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + } + }); + }); + } });