X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/8d2beebdeea4000740fc3914f5d568f473629951..6e6d4e3261c1c943fe44fa9e381bcf8bf1441fd6:/binary.test.js?ds=sidebyside diff --git a/binary.test.js b/binary.test.js index be6c6a3..82fa4e0 100755 --- a/binary.test.js +++ b/binary.test.js @@ -16,70 +16,362 @@ import { it, } from "./dev-deps.js"; import { + base16Binary, + base16String, + base32Binary, + base32String, base64Binary, base64String, filenameSafeBase64Binary, filenameSafeBase64String, + isBase16, + isBase32, isBase64, isFilenameSafeBase64, + isWRMGBase32, + wrmgBase32Binary, + wrmgBase32String, } from "./binary.js"; // 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("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( @@ -286,6 +578,61 @@ describe("filenameSafeBase64String", () => { }); }); +describe("isBase16", () => { + it("[[Call]] returns true for base64 strings", () => { + for (const { base16 } of data.values()) { + assert(isBase16(base16)); + assert(isBase16(base16.toLowerCase())); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "abc_", + "a", + "abc", + "abcg", + ].forEach((value) => assert(!isBase16(value))); + }); +}); + +describe("isBase32", () => { + it("[[Call]] returns true for base32 strings", () => { + for (const { base32 } of data.values()) { + assert(isBase32(base32)); + assert(isBase32(base32.toLowerCase())); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "ABC1", + "A=======", + "ABCDEFGHI", + ].forEach((value) => assert(!isBase32(value))); + }); +}); + describe("isBase64", () => { it("[[Call]] returns true for base64 strings", () => { for (const { base64 } of data.values()) { @@ -341,3 +688,200 @@ describe("isFilenameSafeBase64", () => { ].forEach((value) => assert(!isFilenameSafeBase64(value))); }); }); + +describe("isWRMGBase32", () => { + it("[[Call]] returns true for W·R·M·G base32 strings", () => { + for (const { wrmg } of data.values()) { + assert(isWRMGBase32(wrmg)); + assert(isWRMGBase32(wrmg.toLowerCase())); + assert(isWRMGBase32(`--${wrmg}--`)); + assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "I"))); + assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "L"))); + assert(isWRMGBase32(wrmg.replaceAll(/0/gu, "O"))); + assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "i"))); + assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "l"))); + assert(isWRMGBase32(wrmg.replaceAll(/0/gu, "o"))); + assert(isWRMGBase32(wrmg.replaceAll(/./gu, ($) => { + const rand = Math.random(); + return rand < 0.25 + ? $ + : rand < 0.5 + ? `-${$}` + : rand < 0.75 + ? `${$}-` + : `-${$}-`; + }))); + } + }); + + it("[[Call]] returns false for others", () => { + [ + undefined, + null, + true, + Symbol(), + 27, + 98n, + {}, + [], + () => {}, + new Proxy({}, {}), + "ABCU", + "A", + "ABCDEFGH1", + ].forEach((value) => assert(!isWRMGBase32(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); + } + }); +});