X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/3d2a5e40eaf384aee6b9699bc71af015fd2cb2e9..refs/heads/current:/binary.test.js?ds=inline diff --git a/binary.test.js b/binary.test.js old mode 100755 new mode 100644 index 161f8db..98f441a --- a/binary.test.js +++ b/binary.test.js @@ -1,7 +1,7 @@ // ♓🌟 Piscēs ∷ binary.test.js // ==================================================================== // -// Copyright © 2020–2022 Lady [@ Lady’s Computer]. +// Copyright © 2020–2023 Lady [@ Lady’s Computer]. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -16,50 +16,508 @@ import { it, } from "./dev-deps.js"; import { + arrayBufferSlice, + base16Binary, + base16String, + base32Binary, + base32String, base64Binary, base64String, filenameSafeBase64Binary, filenameSafeBase64String, + get16BitSignedIntegralItem, + get16BitUnsignedIntegralItem, + get32BitFloatingPointItem, + get32BitSignedIntegralItem, + get32BitUnsignedIntegralItem, + get64BitFloatingPointItem, + get64BitSignedIntegralItem, + get64BitUnsignedIntegralItem, + get8BitSignedIntegralItem, + get8BitUnsignedIntegralItem, + isArrayBuffer, + isArrayBufferView, + isBase16, + isBase32, isBase64, isFilenameSafeBase64, + isSharedArrayBuffer, + isTypedArray, + isWRMGBase32, + set16BitIntegralItem, + set32BitFloatingPointItem, + set32BitIntegralItem, + set64BitFloatingPointItem, + set64BitIntegralItem, + set8BitIntegralItem, + toArrayBuffer, + wrmgBase32Binary, + wrmgBase32String, } from "./binary.js"; -const base64s = { - "AGIAYQBzAGUANgA0": "base64", - "R/Q=": new Uint16Array([62535]), - "S0lCSQ==": new Uint8ClampedArray([75, 73, 66, 73]).buffer, - YmFzZTY0: new DataView( - new Uint8Array([98, 97, 115, 101, 54, 52]).buffer, - ), -}; +// These tests assume a LITTLE‐ENDIAN environment. +const data = new Map([ + ["", { + base16: "", + base32: "", + base64: "", + wrmg: "", + }], + ["base64", { + base16: "006200610073006500360034", + base32: "ABRAAYIAOMAGKABWAA2A====", + base64: "AGIAYQBzAGUANgA0", + wrmg: "01H00R80EC06A01P00T0", + }], + [new Uint16Array([62535]), { + base16: "47F4", + base32: "I72A====", + base64: "R/Q=", + wrmg: "8ZT0", + }], + [new Uint8ClampedArray([75, 73, 66, 73]).buffer, { + base16: "4B494249", + base32: "JNEUESI=", + base64: "S0lCSQ==", + wrmg: "9D4M4J8", + }], + [new DataView(new Uint8Array([98, 97, 115, 101, 54, 52]).buffer), { + base16: "626173653634", + base32: "MJQXGZJWGQ======", + base64: "YmFzZTY0", + wrmg: "C9GQ6S9P6G", + }], + + // The following three examples are from RFC 3548. + [new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]), { + base16: "14FB9C03D97E", + base32: "CT5ZYA6ZPY======", + base64: "FPucA9l+", + wrmg: "2KXSR0YSFR", + }], + [new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9]), { + base16: "14FB9C03D9", + base32: "CT5ZYA6Z", + base64: "FPucA9k=", + wrmg: "2KXSR0YS", + }], + [new Uint8Array([0x14, 0xFB, 0x9C, 0x03]), { + base16: "14FB9C03", + base32: "CT5ZYAY=", + base64: "FPucAw==", + wrmg: "2KXSR0R", + }], + + // The following examples are from the Ruby base32 gem. + [new Uint8Array([0x28]), { + base16: "28", + base32: "FA======", + base64: "KA==", + wrmg: "50", + }], + [new Uint8Array([0xD6]), { + base16: "D6", + base32: "2Y======", + base64: "1g==", + wrmg: "TR", + }], + [new Uint16Array([0xF8D6]), { + base16: "D6F8", + base32: "234A====", + base64: "1vg=", + wrmg: "TVW0", + }], + [new Uint8Array([0xD6, 0xF8, 0x00]), { + base16: "D6F800", + base32: "234AA===", + base64: "1vgA", + wrmg: "TVW00", + }], + [new Uint8Array([0xD6, 0xF8, 0x10]), { + base16: "D6F810", + base32: "234BA===", + base64: "1vgQ", + wrmg: "TVW10", + }], + [new Uint32Array([0x0C11F8D6]), { + base16: "D6F8110C", + base32: "234BCDA=", + base64: "1vgRDA==", + wrmg: "TVW1230", + }], + [new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), { + base16: "D6F8110C80", + base32: "234BCDEA", + base64: "1vgRDIA=", + wrmg: "TVW12340", + }], + [new Uint16Array([0xF8D6, 0x0C11, 0x3085]), { + base16: "D6F8110C8530", + base32: "234BCDEFGA======", + base64: "1vgRDIUw", + wrmg: "TVW1234560", + }], +]); + +describe("arrayBufferSlice", () => { + it("[[Call]] slices an `ArrayBuffer`", () => { + const baseBuffer = Uint8Array.from([2, 3, 1, 9, 8, 5]).buffer; + assertEquals( + new Uint8Array(arrayBufferSlice(baseBuffer, 1, 4)), + Uint8Array.from([3, 1, 9]), + ); + }); + + it("[[Call]] slices an `SharedArrayBuffer`", () => { + const baseBuffer = new SharedArrayBuffer(6); + new Uint8Array(baseBuffer).set([2, 3, 1, 9, 8, 5], 0); + assertEquals( + new Uint8Array(arrayBufferSlice(baseBuffer, 1, 4)), + Uint8Array.from([3, 1, 9]), + ); + }); + + it("[[Call]] throws for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + new DataView(new ArrayBuffer()), + new Uint8Array(), + ].forEach((value) => + assertThrows(() => arrayBufferSlice(value, 0, 0)) + ); + }); +}); + +describe("base16Binary", () => { + it("[[Call]] returns the correct data", () => { + assertEquals( + new Uint8Array(base16Binary("")), + new Uint8Array([]), + "", + ); + assertEquals( + new Uint8Array(base16Binary("006200610073006500360034")), + Uint8Array.from( + "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", + ($) => $.charCodeAt(0), + ), + "006200610073006500360034", + ); + assertEquals( + new Uint16Array(base16Binary("47F4")), + new Uint16Array([62535]), + "47F4", + ); + assertEquals( + new Uint8ClampedArray(base16Binary("4B494249")), + new Uint8ClampedArray([75, 73, 66, 73]), + "4B494249", + ); + assertEquals( + new Uint8Array(base16Binary("626173653634")), + new Uint8Array([98, 97, 115, 101, 54, 52]), + "626173653634", + ); + assertEquals( + new Uint8Array(base16Binary("14FB9C03D97E")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]), + "14FB9C03D97E", + ); + assertEquals( + new Uint8Array(base16Binary("14FB9C03D9")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9]), + "14FB9C03D9", + ); + assertEquals( + new Uint8Array(base16Binary("14FB9C03")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03]), + "14FB9C03", + ); + assertEquals( + new Uint8Array(base16Binary("28")), + new Uint8Array([0x28]), + "28", + ); + assertEquals( + new Uint8Array(base16Binary("D6")), + new Uint8Array([0xD6]), + "D6", + ); + assertEquals( + new Uint16Array(base16Binary("D6F8")), + new Uint16Array([0xF8D6]), + "D6F8", + ); + assertEquals( + new Uint8Array(base16Binary("D6F800")), + new Uint8Array([0xD6, 0xF8, 0x00]), + "D6F800", + ); + assertEquals( + new Uint8Array(base16Binary("D6F810")), + new Uint8Array([0xD6, 0xF8, 0x10]), + "D6F810", + ); + assertEquals( + new Uint32Array(base16Binary("D6F8110C")), + new Uint32Array([0x0C11F8D6]), + "D6F8110C", + ); + assertEquals( + new Uint8Array(base16Binary("D6F8110C80")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "D6F8110C80", + ); + assertEquals( + new Uint16Array(base16Binary("D6F8110C8530")), + new Uint16Array([0xF8D6, 0x0C11, 0x3085]), + "D6F8110C8530", + ); + }); + + it("[[Call]] is case‐insensitive", () => { + assertEquals( + new Uint8Array(base16Binary("d6f8110C80")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "d6f8110C80", + ); + }); + + it("[[Call]] throws when provided with an invalid character", () => { + assertThrows(() => base16Binary("ABCG")); + }); + + it("[[Call]] throws when provided with a length with a remainder of 1 when divided by 2", () => { + assertThrows(() => base16Binary("A")); + assertThrows(() => base16Binary("ABC")); + }); +}); + +describe("base16String", () => { + it("[[Call]] returns the correct string", () => { + for (const [source, { base16 }] of data) { + assertStrictEquals(base16String(source), base16); + } + }); +}); + +describe("base32Binary", () => { + it("[[Call]] returns the correct data", () => { + assertEquals( + new Uint8Array(base32Binary("")), + new Uint8Array([]), + "", + ); + assertEquals( + new Uint8Array(base32Binary("ABRAAYIAOMAGKABWAA2A====")), + Uint8Array.from( + "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", + ($) => $.charCodeAt(0), + ), + "ABRAAYIAOMAGKABWAA2A====", + ); + assertEquals( + new Uint16Array(base32Binary("I72A====")), + new Uint16Array([62535]), + "I72A====", + ); + assertEquals( + new Uint8ClampedArray(base32Binary("JNEUESI=")), + new Uint8ClampedArray([75, 73, 66, 73]), + "JNEUESI=", + ); + assertEquals( + new Uint8Array(base32Binary("MJQXGZJWGQ======")), + new Uint8Array([98, 97, 115, 101, 54, 52]), + "MJQXGZJWGQ======", + ); + assertEquals( + new Uint8Array(base32Binary("CT5ZYA6ZPY======")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]), + "CT5ZYA6ZPY======", + ); + assertEquals( + new Uint8Array(base32Binary("CT5ZYA6Z")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9]), + "CT5ZYA6Z", + ); + assertEquals( + new Uint8Array(base32Binary("CT5ZYAY=")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03]), + "CT5ZYAY=", + ); + assertEquals( + new Uint8Array(base32Binary("FA======")), + new Uint8Array([0x28]), + "FA======", + ); + assertEquals( + new Uint8Array(base32Binary("2Y======")), + new Uint8Array([0xD6]), + "2Y======", + ); + assertEquals( + new Uint16Array(base32Binary("234A====")), + new Uint16Array([0xF8D6]), + "234A====", + ); + assertEquals( + new Uint8Array(base32Binary("234AA===")), + new Uint8Array([0xD6, 0xF8, 0x00]), + "234AA===", + ); + assertEquals( + new Uint8Array(base32Binary("234BA===")), + new Uint8Array([0xD6, 0xF8, 0x10]), + "234BA===", + ); + assertEquals( + new Uint32Array(base32Binary("234BCDA=")), + new Uint32Array([0x0C11F8D6]), + "234BCDA=", + ); + assertEquals( + new Uint8Array(base32Binary("234BCDEA")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "234BCDEA", + ); + assertEquals( + new Uint16Array(base32Binary("234BCDEFGA======")), + new Uint16Array([0xF8D6, 0x0C11, 0x3085]), + "234BCDEFGA======", + ); + }); + + it("[[Call]] is case‐insensitive", () => { + assertEquals( + new Uint8Array(base32Binary("234bcdEA")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "234bcdEA", + ); + }); + + it("[[Call]] throws when provided with an invalid character", () => { + assertThrows(() => base32Binary("ABC0")); + assertThrows(() => base32Binary("ABC1")); + assertThrows(() => base32Binary("ABC8")); + assertThrows(() => base32Binary("ABC9")); + }); + + it("[[Call]] throws when provided with an invalid equals", () => { + assertThrows(() => base32Binary("CT3ZYAY==")); + }); + + it("[[Call]] throws when provided with a length with a remainder of 1, 3 ∣ 6 when divided by 8", () => { + assertThrows(() => base32Binary("234BCDEAA")); + assertThrows(() => base32Binary("234BCDEAA=======")); + assertThrows(() => base32Binary("UHI")); + assertThrows(() => base32Binary("UHIUJD")); + }); +}); + +describe("base32String", () => { + it("[[Call]] returns the correct string", () => { + for (const [source, { base32 }] of data) { + assertStrictEquals(base32String(source), base32); + } + }); +}); describe("base64Binary", () => { it("[[Call]] returns the correct data", () => { assertEquals( - base64Binary("AGIAYQBzAGUANgA0"), - new Uint8Array( - Array.prototype.map.call( - "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", - ($) => $.charCodeAt(0), - ), - ).buffer, + new Uint8Array(base64Binary("")), + new Uint8Array([]), + "", + ); + assertEquals( + new Uint8Array(base64Binary("AGIAYQBzAGUANgA0")), + Uint8Array.from( + "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", + ($) => $.charCodeAt(0), + ), "AGIAYQBzAGUANgA0", ); assertEquals( - base64Binary("R/Q="), - new Uint16Array([62535]).buffer, + new Uint16Array(base64Binary("R/Q=")), + new Uint16Array([62535]), "R/Q=", ); assertEquals( - base64Binary("S0lCSQ=="), - new Uint8ClampedArray([75, 73, 66, 73]).buffer, + new Uint8ClampedArray(base64Binary("S0lCSQ==")), + new Uint8ClampedArray([75, 73, 66, 73]), "S0lCSQ==", ); assertEquals( - base64Binary("YmFzZTY0"), - new Uint8Array([98, 97, 115, 101, 54, 52]).buffer, + new Uint8Array(base64Binary("YmFzZTY0")), + new Uint8Array([98, 97, 115, 101, 54, 52]), "YmFzZTY0", ); + assertEquals( + new Uint8Array(base64Binary("FPucA9l+")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]), + "FPucA9l+", + ); + assertEquals( + new Uint8Array(base64Binary("FPucA9k=")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9]), + "FPucA9k=", + ); + assertEquals( + new Uint8Array(base64Binary("FPucAw==")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03]), + "FPucAw==", + ); + assertEquals( + new Uint8Array(base64Binary("KA==")), + new Uint8Array([0x28]), + "KA==", + ); + assertEquals( + new Uint8Array(base64Binary("1g==")), + new Uint8Array([0xD6]), + "1g==", + ); + assertEquals( + new Uint16Array(base64Binary("1vg")), + new Uint16Array([0xF8D6]), + "1vg", + ); + assertEquals( + new Uint8Array(base64Binary("1vgA")), + new Uint8Array([0xD6, 0xF8, 0x00]), + "1vgA", + ); + assertEquals( + new Uint8Array(base64Binary("1vgQ")), + new Uint8Array([0xD6, 0xF8, 0x10]), + "1vgQ", + ); + assertEquals( + new Uint32Array(base64Binary("1vgRDA==")), + new Uint32Array([0x0C11F8D6]), + "1vgRDA==", + ); + assertEquals( + new Uint8Array(base64Binary("1vgRDIA=")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "1vgRDIA=", + ); + assertEquals( + new Uint16Array(base64Binary("1vgRDIUw")), + new Uint16Array([0xF8D6, 0x0C11, 0x3085]), + "1vgRDIUw", + ); }); it("[[Call]] throws when provided with an invalid character", () => { @@ -78,39 +536,82 @@ describe("base64Binary", () => { describe("base64String", () => { it("[[Call]] returns the correct string", () => { - Object.entries(base64s).forEach(([key, value]) => - assertStrictEquals(base64String(value), key) - ); + for (const [source, { base64 }] of data) { + assertStrictEquals(base64String(source), base64); + } }); }); describe("filenameSafeBase64Binary", () => { it("[[Call]] returns the correct data", () => { assertEquals( - filenameSafeBase64Binary("AGIAYQBzAGUANgA0"), - new Uint8Array( - Array.prototype.map.call( - "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", - ($) => $.charCodeAt(0), - ), - ).buffer, + new Uint8Array(filenameSafeBase64Binary("")), + new Uint8Array([]), + "", + ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("AGIAYQBzAGUANgA0")), + Uint8Array.from( + "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", + ($) => $.charCodeAt(0), + ), "AGIAYQBzAGUANgA0", ); assertEquals( - filenameSafeBase64Binary("R_Q="), - new Uint16Array([62535]).buffer, + new Uint16Array(filenameSafeBase64Binary("R_Q=")), + new Uint16Array([62535]), "R/Q=", ); assertEquals( - filenameSafeBase64Binary("S0lCSQ=="), - new Uint8ClampedArray([75, 73, 66, 73]).buffer, + new Uint8ClampedArray(filenameSafeBase64Binary("S0lCSQ==")), + new Uint8ClampedArray([75, 73, 66, 73]), "S0lCSQ==", ); assertEquals( - filenameSafeBase64Binary("YmFzZTY0"), - new Uint8Array([98, 97, 115, 101, 54, 52]).buffer, + new Uint8Array(filenameSafeBase64Binary("YmFzZTY0")), + new Uint8Array([98, 97, 115, 101, 54, 52]), "YmFzZTY0", ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("KA==")), + new Uint8Array([0x28]), + "KA==", + ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("1g==")), + new Uint8Array([0xD6]), + "1g==", + ); + assertEquals( + new Uint16Array(filenameSafeBase64Binary("1vg")), + new Uint16Array([0xF8D6]), + "1vg", + ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("1vgA")), + new Uint8Array([0xD6, 0xF8, 0x00]), + "1vgA", + ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("1vgQ")), + new Uint8Array([0xD6, 0xF8, 0x10]), + "1vgQ", + ); + assertEquals( + new Uint32Array(filenameSafeBase64Binary("1vgQDA==")), + new Uint32Array([0x0C10F8D6]), + "1vgQDA==", + ); + assertEquals( + new Uint8Array(filenameSafeBase64Binary("1vgQDIA=")), + new Uint8Array([0xD6, 0xF8, 0x10, 0x0C, 0x80]), + "1vgQDIA=", + ); + assertEquals( + new Uint16Array(filenameSafeBase64Binary("1vgQDIUw")), + new Uint16Array([0xF8D6, 0x0C10, 0x3085]), + "1vgQDIUw", + ); }); it("[[Call]] throws when provided with an invalid character", () => { @@ -129,18 +630,330 @@ describe("filenameSafeBase64Binary", () => { describe("filenameSafeBase64String", () => { it("[[Call]] returns the correct string", () => { - Object.entries(base64s).forEach(([key, value]) => + for (const [source, { base64 }] of data) { assertStrictEquals( - filenameSafeBase64String(value), - key.replace("+", "-").replace("/", "_"), - ) + filenameSafeBase64String(source), + base64.replace("+", "-").replace("/", "_"), + ); + } + }); +}); + +describe("get8BitSignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from([0, -1, 0]).buffer; + assertStrictEquals(get8BitSignedIntegralItem(buffer, 1), -1n); + assertStrictEquals( + get8BitSignedIntegralItem(new DataView(buffer), 1), + -1n, + ); + assertStrictEquals( + get8BitSignedIntegralItem(new Uint8Array(buffer), 1), + -1n, + ); + }); +}); + +describe("get8BitUnsignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from([0, -1, 0]).buffer; + assertStrictEquals(get8BitUnsignedIntegralItem(buffer, 1), 255n); + assertStrictEquals( + get8BitUnsignedIntegralItem(new DataView(buffer), 1), + 255n, + ); + assertStrictEquals( + get8BitUnsignedIntegralItem(new Int8Array(buffer), 1), + 255n, + ); + }); +}); + +describe("get16BitSignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from([0, 0, -1, -1, 0, 0]).buffer; + assertStrictEquals(get16BitSignedIntegralItem(buffer, 2), -1n); + assertStrictEquals( + get16BitSignedIntegralItem(new DataView(buffer), 2), + -1n, + ); + assertStrictEquals( + get16BitSignedIntegralItem(new Uint16Array(buffer), 2), + -1n, + ); + }); +}); + +describe("get16BitUnsignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from([0, 0, -1, -1, 0, 0]).buffer; + assertStrictEquals( + get16BitUnsignedIntegralItem(buffer, 2), + (1n << 16n) - 1n, + ); + assertStrictEquals( + get16BitUnsignedIntegralItem(new DataView(buffer), 2), + (1n << 16n) - 1n, + ); + assertStrictEquals( + get16BitUnsignedIntegralItem(new Int16Array(buffer), 2), + (1n << 16n) - 1n, + ); + }); +}); + +describe("get32BitFloatingPointItem", () => { + it("[[Call]] gets the item", () => { + const buffer = new ArrayBuffer(12); + const view = new DataView(buffer); + view.setFloat32(0, NaN); + view.setFloat32(4, -Infinity); + view.setFloat32(8, -0); + assertStrictEquals(get32BitFloatingPointItem(buffer, 0), NaN); + assertStrictEquals( + get32BitFloatingPointItem(buffer, 4), + -Infinity, + ); + assertStrictEquals(get32BitFloatingPointItem(buffer, 8), -0); + assertStrictEquals( + get32BitFloatingPointItem(new DataView(buffer), 4), + -Infinity, + ); + assertStrictEquals( + get32BitFloatingPointItem(new Uint32Array(buffer), 4), + -Infinity, + ); + }); +}); + +describe("get32BitSignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from( + [0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0], + ).buffer; + assertStrictEquals(get32BitSignedIntegralItem(buffer, 4), -1n); + assertStrictEquals( + get32BitSignedIntegralItem(new DataView(buffer), 4), + -1n, + ); + assertStrictEquals( + get32BitSignedIntegralItem(new Uint32Array(buffer), 4), + -1n, + ); + }); +}); + +describe("get32BitUnsignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from( + [0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0], + ).buffer; + assertStrictEquals( + get32BitUnsignedIntegralItem(buffer, 4), + (1n << 32n) - 1n, + ); + assertStrictEquals( + get32BitUnsignedIntegralItem(new DataView(buffer), 4), + (1n << 32n) - 1n, + ); + assertStrictEquals( + get32BitUnsignedIntegralItem(new Int32Array(buffer), 4), + (1n << 32n) - 1n, + ); + }); +}); + +describe("get64BitFloatingPointItem", () => { + it("[[Call]] gets the item", () => { + const buffer = new ArrayBuffer(24); + const view = new DataView(buffer); + view.setFloat64(0, NaN); + view.setFloat64(8, -Infinity); + view.setFloat64(16, -0); + assertStrictEquals(get64BitFloatingPointItem(buffer, 0), NaN); + assertStrictEquals( + get64BitFloatingPointItem(buffer, 8), + -Infinity, + ); + assertStrictEquals(get64BitFloatingPointItem(buffer, 16), -0); + assertStrictEquals( + get64BitFloatingPointItem(new DataView(buffer), 8), + -Infinity, + ); + assertStrictEquals( + get64BitFloatingPointItem(new BigUint64Array(buffer), 8), + -Infinity, + ); + }); +}); + +describe("get64BitSignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from( + [0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1], + ).buffer; + assertStrictEquals(get64BitSignedIntegralItem(buffer, 8), -1n); + assertStrictEquals( + get64BitSignedIntegralItem(new DataView(buffer), 8), + -1n, + ); + assertStrictEquals( + get64BitSignedIntegralItem(new BigUint64Array(buffer), 8), + -1n, + ); + }); +}); + +describe("get64BitUnsignedIntegralItem", () => { + it("[[Call]] gets the item", () => { + const buffer = Int8Array.from( + [0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1], + ).buffer; + assertStrictEquals( + get64BitUnsignedIntegralItem(buffer, 8), + (1n << 64n) - 1n, + ); + assertStrictEquals( + get64BitUnsignedIntegralItem(new DataView(buffer), 8), + (1n << 64n) - 1n, + ); + assertStrictEquals( + get64BitUnsignedIntegralItem(new BigInt64Array(buffer), 8), + (1n << 64n) - 1n, + ); + }); +}); + +describe("isArrayBuffer", () => { + it("[[Call]] returns true for array buffers", () => { + assertStrictEquals( + isArrayBuffer(new ArrayBuffer()), + true, + ); + assertStrictEquals( + isArrayBuffer(new SharedArrayBuffer()), + true, + ); + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + new DataView(new ArrayBuffer()), + new Uint8Array(), + ].forEach((value) => + assertStrictEquals(isArrayBuffer(value), false) + ); + }); +}); + +describe("isArrayBufferView", () => { + it("[[Call]] returns true for data views", () => { + assertStrictEquals( + isArrayBufferView(new DataView(new ArrayBuffer())), + true, + ); + }); + + it("[[Call]] returns true for typed arrays", () => { + assertStrictEquals( + isArrayBufferView(new Uint8ClampedArray()), + true, ); + assertStrictEquals(isArrayBufferView(new BigInt64Array()), true); + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + new ArrayBuffer(), + new SharedArrayBuffer(), + ].forEach((value) => + assertStrictEquals(isArrayBufferView(value), false) + ); + }); +}); + +describe("isBase16", () => { + it("[[Call]] returns true for base64 strings", () => { + for (const { base16 } of data.values()) { + assertStrictEquals(isBase16(base16), true); + assertStrictEquals(isBase16(base16.toLowerCase()), true); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "abc_", + "a", + "abc", + "abcg", + ].forEach((value) => assertStrictEquals(isBase16(value), false)); + }); +}); + +describe("isBase32", () => { + it("[[Call]] returns true for base32 strings", () => { + for (const { base32 } of data.values()) { + assertStrictEquals(isBase32(base32), true); + assertStrictEquals(isBase32(base32.toLowerCase()), true); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "ABC1", + "A=======", + "ABCDEFGHI", + ].forEach((value) => assertStrictEquals(isBase32(value), false)); }); }); describe("isBase64", () => { it("[[Call]] returns true for base64 strings", () => { - Object.keys(base64s).forEach((key) => assert(isBase64(key))); + for (const { base64 } of data.values()) { + assertStrictEquals(isBase64(base64), true); + } }); it("[[Call]] returns false for others", () => { @@ -158,17 +971,20 @@ describe("isBase64", () => { "abc_", "a", "abc==", - ].forEach((value) => assert(!isBase64(value))); + ].forEach((value) => assertStrictEquals(isBase64(value), false)); }); }); describe("isFilenameSafeBase64", () => { it("[[Call]] returns true for filename‐safe base64 strings", () => { - Object.keys(base64s).forEach((key) => - assert( - isFilenameSafeBase64(key.replace("+", "-").replace("/", "_")), - ) - ); + for (const { base64 } of data.values()) { + assertStrictEquals( + isFilenameSafeBase64( + base64.replace("+", "-").replace("/", "_"), + ), + true, + ); + } }); it("[[Call]] returns false for others", () => { @@ -186,6 +1002,416 @@ describe("isFilenameSafeBase64", () => { "abc/", "a", "abc==", - ].forEach((value) => assert(!isFilenameSafeBase64(value))); + ].forEach((value) => + assertStrictEquals(isFilenameSafeBase64(value), false) + ); + }); +}); + +describe("isSharedArrayBuffer", () => { + it("[[Call]] returns true for shared array buffers", () => { + assertStrictEquals( + isSharedArrayBuffer(new SharedArrayBuffer()), + true, + ); + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + new ArrayBuffer(), + new DataView(new ArrayBuffer()), + new Uint8Array(), + ].forEach((value) => + assertStrictEquals(isSharedArrayBuffer(value), false) + ); + }); +}); + +describe("isTypedArray", () => { + it("[[Call]] returns true for typed arrays", () => { + assertStrictEquals( + isTypedArray(new Uint8Array()), + true, + ); + assertStrictEquals( + isTypedArray(new BigInt64Array()), + true, + ); + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + new ArrayBuffer(), + new SharedArrayBuffer(), + new DataView(new ArrayBuffer()), + ].forEach((value) => + assertStrictEquals(isTypedArray(value), false) + ); + }); +}); + +describe("isWRMGBase32", () => { + it("[[Call]] returns true for W·R·M·G base32 strings", () => { + for (const { wrmg } of data.values()) { + assertStrictEquals(isWRMGBase32(wrmg), true); + assertStrictEquals(isWRMGBase32(wrmg.toLowerCase()), true); + assertStrictEquals(isWRMGBase32(`--${wrmg}--`), true); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/1/gu, "I")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/1/gu, "L")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/0/gu, "O")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/1/gu, "i")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/1/gu, "l")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/0/gu, "o")), + true, + ); + assertStrictEquals( + isWRMGBase32(wrmg.replaceAll(/./gu, ($) => { + const rand = Math.random(); + return rand < 0.25 + ? $ + : rand < 0.5 + ? `-${$}` + : rand < 0.75 + ? `${$}-` + : `-${$}-`; + })), + true, + ); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "ABCU", + "A", + "ABCDEFGH1", + ].forEach((value) => + assertStrictEquals(isWRMGBase32(value), false) + ); + }); +}); + +describe("set8BitIntegralItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(3); + set8BitIntegralItem(buffer, 1, -1n); + set8BitIntegralItem(buffer, 2, (1 << 8) - 1); + assertEquals( + new Int8Array(buffer), + Int8Array.from([0, -1, -1]), + ); + }); +}); + +describe("set16BitIntegralItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(6); + set16BitIntegralItem(buffer, 2, -1n); + set16BitIntegralItem(buffer, 4, (1 << 16) - 1); + assertEquals( + new Int8Array(buffer), + Int8Array.from([0, 0, -1, -1, -1, -1]), + ); + }); +}); + +describe("set32BitFloatingPointItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(12); + const expected = new ArrayBuffer(12); + const view = new DataView(expected); + view.setFloat32(0, NaN); + set32BitFloatingPointItem(buffer, 0, NaN); + view.setFloat32(4, -Infinity); + set32BitFloatingPointItem(buffer, 4, -Infinity); + view.setFloat32(8, -0); + set32BitFloatingPointItem(buffer, 8, -0); + assertEquals( + new Uint8Array(buffer), + new Uint8Array(expected), + ); + }); +}); + +describe("set32BitIntegralItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(12); + set32BitIntegralItem(buffer, 4, -1n); + set32BitIntegralItem(buffer, 8, -1 >>> 0); + assertEquals( + new Int8Array(buffer), + Int8Array.from([0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1]), + ); + }); +}); + +describe("set64BitFloatingPointItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(24); + const expected = new ArrayBuffer(24); + const view = new DataView(expected); + view.setFloat64(0, NaN); + set64BitFloatingPointItem(buffer, 0, NaN); + view.setFloat64(4, -Infinity); + set64BitFloatingPointItem(buffer, 4, -Infinity); + view.setFloat64(8, -0); + set64BitFloatingPointItem(buffer, 8, -0); + assertEquals( + new Uint8Array(buffer), + new Uint8Array(expected), + ); + }); +}); + +describe("set64BitIntegralItem", () => { + it("[[Call]] sets the item", () => { + const buffer = new ArrayBuffer(12); + set64BitIntegralItem(buffer, 4, -1n); + assertEquals( + new Int8Array(buffer), + Int8Array.from([0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1]), + ); + }); +}); + +describe("toArrayBuffer", () => { + it("[[Call]] returns the argument for array buffers", () => { + const buffer = new ArrayBuffer(); + assertStrictEquals(toArrayBuffer(buffer), buffer); + }); + + it("[[Call]] returns the buffer for data views", () => { + const src = Uint8Array.from([2, 3, 1]); + const buffer = toArrayBuffer(new DataView(src.buffer)); + assert(buffer instanceof ArrayBuffer); + assertEquals(new Uint8Array(buffer), src); + }); + + it("[[Call]] returns the buffer for typed arrays", () => { + const src = Uint8Array.from([2, 3, 1]); + const buffer = toArrayBuffer(src); + assert(buffer instanceof ArrayBuffer); + assertEquals(new Uint8Array(buffer), src); + }); + + it("[[Call]] throws for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "string", + ].forEach((value) => + assertThrows(() => { + toArrayBuffer(value); + }) + ); + }); +}); + +describe("wrmgBase32Binary", () => { + it("[[Call]] returns the correct data", () => { + assertEquals( + new Uint8Array(wrmgBase32Binary("")), + new Uint8Array([]), + "", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("01H00R80EC06A01P00T0")), + Uint8Array.from( + "\u{0}b\u{0}a\u{0}s\u{0}e\u{0}6\u{0}4", + ($) => $.charCodeAt(0), + ), + "01H00R80EC06A01P00T0", + ); + assertEquals( + new Uint16Array(wrmgBase32Binary("8ZT0")), + new Uint16Array([62535]), + "8ZT0", + ); + assertEquals( + new Uint8ClampedArray(wrmgBase32Binary("9D4M4J8")), + new Uint8ClampedArray([75, 73, 66, 73]), + "9D4M4J8", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("C9GQ6S9P6G")), + new Uint8Array([98, 97, 115, 101, 54, 52]), + "C9GQ6S9P6G", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("2KXSR0YSFR")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]), + "2KXSR0YSFR", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("2KXSR0YS")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03, 0xD9]), + "2KXSR0YS", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("2KXSR0R")), + new Uint8Array([0x14, 0xFB, 0x9C, 0x03]), + "2KXSR0R", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("50")), + new Uint8Array([0x28]), + "50", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TR")), + new Uint8Array([0xD6]), + "TR", + ); + assertEquals( + new Uint16Array(wrmgBase32Binary("TVW0")), + new Uint16Array([0xF8D6]), + "TVW0", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVW00")), + new Uint8Array([0xD6, 0xF8, 0x00]), + "TVW00", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVW10")), + new Uint8Array([0xD6, 0xF8, 0x10]), + "TVW10", + ); + assertEquals( + new Uint32Array(wrmgBase32Binary("TVW1230")), + new Uint32Array([0x0C11F8D6]), + "TVW1230", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVW12340")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "TVW12340", + ); + assertEquals( + new Uint16Array(wrmgBase32Binary("TVW1234560")), + new Uint16Array([0xF8D6, 0x0C11, 0x3085]), + "TVW1234560", + ); + }); + + it("[[Call]] is case‐insensitive", () => { + assertEquals( + new Uint8Array(wrmgBase32Binary("tVw12340")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "tVw12340", + ); + }); + + it("[[Call]] casts I, L & O", () => { + assertEquals( + new Uint8Array(wrmgBase32Binary("TVWI234O")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "TVWI234O", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVWi234o")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "TVWi234o", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVWL234O")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "TVWL234O", + ); + assertEquals( + new Uint8Array(wrmgBase32Binary("TVWl234o")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "TVWl234o", + ); + }); + + it("[[Call]] ignores hyphens", () => { + assertEquals( + new Uint8Array(wrmgBase32Binary("--TVW---123-40-----")), + new Uint8Array([0xD6, 0xF8, 0x11, 0x0C, 0x80]), + "--TVW---123-40-----", + ); + }); + + it("[[Call]] throws when provided with an invalid character", () => { + assertThrows(() => wrmgBase32Binary("ABCu")); + assertThrows(() => wrmgBase32Binary("ABCU")); + assertThrows(() => wrmgBase32Binary("ABC=")); + }); + + it("[[Call]] throws when provided with a length with a remainder of 1, 3 ∣ 6 when divided by 8", () => { + assertThrows(() => base32Binary("TVW123400")); + assertThrows(() => base32Binary("TVW123400=======")); + assertThrows(() => base32Binary("M78")); + assertThrows(() => base32Binary("M78M93")); + }); + + it("[[Call]] throws when provided with a length with a remainder of 1 when divided by 4", () => { + assertThrows(() => wrmgBase32Binary("234BCDEAA")); + assertThrows(() => wrmgBase32Binary("2-34-B--CD-EA-A-")); + }); +}); + +describe("wrmgBase32String", () => { + it("[[Call]] returns the correct string", () => { + for (const [source, { wrmg }] of data) { + assertStrictEquals(wrmgBase32String(source), wrmg); + } }); });