index.test.js
1 import { test } from "node:test"; 2 import assert from "node:assert/strict"; 3 import * as fc from "fast-check"; 4 import { decode, encode } from "./index.js"; 5 6 // https://tools.ietf.org/id/draft-msporny-base58-01.html 7 const stringTestVectors = [ 8 ["", ""], 9 ["Hello World!", "2NEpo7TZRRrLZSi2U"], 10 [ 11 "The quick brown fox jumps over the lazy dog.", 12 "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z", 13 ], 14 ]; 15 16 // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_encode_decode.json 17 const hexTestVectors = [ 18 ["61", "2g"], 19 ["626262", "a3gV"], 20 ["636363", "aPEr"], 21 ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], 22 [ 23 "00eb15231dfceb60925886b67d065299925915aeb172c06647", 24 "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", 25 ], 26 ["516b6fcd0f", "ABnLTmg"], 27 ["bf4f89001e670274dd", "3SEo3LWLoPntC"], 28 ["572e4794", "3EFU7m"], 29 ["ecac89cad93923c02321", "EJDM8drfXA6uyA"], 30 ["10c8511e", "Rt5zm"], 31 // ["00000000000000000000", "1111111111"], 32 [ 33 "000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", 34 "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", 35 ], 36 [ 37 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", 38 "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY", 39 ], 40 ]; 41 42 test("base58: encode", (t) => { 43 for (const [string, expected] of stringTestVectors) { 44 const input = new TextEncoder().encode(string); 45 assert.equal(encode(input), expected, string); 46 } 47 48 for (const [hex, expected] of hexTestVectors) { 49 const input = Uint8Array.from( 50 hex.match(/[\da-fA-F]{2}/g).map((h) => parseInt(h, 16)), 51 ); 52 assert.equal(encode(input), expected, hex); 53 } 54 }); 55 56 test("base58: decode", (t) => { 57 for (const [expected, input] of stringTestVectors) { 58 const string = new TextDecoder().decode(decode(input)); 59 assert.equal(string, expected, input); 60 } 61 62 for (const [hex, input] of hexTestVectors) { 63 const expected = Uint8Array.from( 64 hex.match(/[\da-fA-F]{2}/g).map((h) => parseInt(h, 16)), 65 ); 66 assert.deepEqual(decode(input), expected, input); 67 } 68 }); 69 70 test("base58: roundtrip (decode . encode === id)", (t) => { 71 function roundtrip(bs) { 72 assert.deepEqual(new Uint8Array(bs), decode(encode(bs))); 73 } 74 75 // Input: random Uint8Array. 76 fc.assert(fc.property(fc.uint8Array(), roundtrip)); 77 78 // Input: arrays of arbitrary length filled with constant octets. 79 fc.assert(fc.property(fc.array(fc.constant(0x00)), roundtrip)); 80 fc.assert(fc.property(fc.array(fc.constant(0xff)), roundtrip)); 81 }); 82 83 test("base58: roundtrip (encode . decode === id)", (t) => { 84 const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 85 const arbInput = fc.string({ unit: fc.constantFrom(...alphabet.split("")) }); 86 87 function roundtrip(str) { 88 assert.deepEqual(str, encode(decode(str))); 89 } 90 91 // Input: random string. 92 fc.assert(fc.property(arbInput, roundtrip)); 93 94 // Input: strings of arbitrary length filled with constant characters. 95 fc.assert(fc.property(fc.string({ unit: fc.constant("1") }), roundtrip)); 96 fc.assert(fc.property(fc.string({ unit: fc.constant("z") }), roundtrip)); 97 });