/* globals describe, it */ import * as bytes from '../src/bytes.js' import * as b2 from '../src/bases/base2.js' import * as b8 from '../src/bases/base8.js' import * as b10 from '../src/bases/base10.js' import * as b16 from '../src/bases/base16.js' import * as b32 from '../src/bases/base32.js' import * as b36 from '../src/bases/base36.js' import * as b58 from '../src/bases/base58.js' import * as b64 from '../src/bases/base64.js' import { assert } from 'aegir/chai' const { base16, base32, base58btc, base64 } = { ...b16, ...b32, ...b58, ...b64 } describe('multibase', () => { for (const base of [base16, base32, base58btc, base64]) { describe(`basics ${base.name}`, () => { it('encode/decode', () => { const string = base.encode(bytes.fromString('test')) assert.deepStrictEqual(string[0], base.prefix) const buffer = base.decode(string) assert.deepStrictEqual(buffer, bytes.fromString('test')) }) it('pristine backing buffer', () => { // some deepEqual() libraries go as deep as the backing buffer, make sure it's pristine const string = base.encode(bytes.fromString('test')) const buffer = base.decode(string) const expected = bytes.fromString('test') assert.deepStrictEqual(new Uint8Array(buffer).join(','), new Uint8Array(expected.buffer).join(',')) }) it('empty', () => { const str = base.encode(bytes.fromString('')) assert.deepStrictEqual(str, base.prefix) assert.deepStrictEqual(base.decode(str), bytes.fromString('')) }) it('bad chars', () => { const str = base.prefix + '#$%^&*&^%$#' const msg = `Non-${base.name} character` assert.throws(() => base.decode(str), msg) }) }) } it('encode string failure', () => { const msg = 'Unknown type, must be binary type' // @ts-expect-error - expects bytes assert.throws(() => base32.encode('asdf'), msg) // @ts-expect-error - expects bytes assert.throws(() => base32.encoder.encode('asdf'), msg) }) it('decode int failure', () => { const msg = 'Can only multibase decode strings' // @ts-expect-error - 'number' is not assignable to parameter of type 'string' assert.throws(() => base32.decode(1), msg) // @ts-expect-error - 'number' is not assignable to parameter of type 'string' assert.throws(() => base32.decoder.decode(1), msg) }) const buff = bytes.fromString('test') const nonPrintableBuff = Uint8Array.from([239, 250, 254]) /** * @param {typeof b2|b8|b10|b16|b32|b36|b58|b64} bases */ const baseTest = bases => { for (const base of Object.values(bases)) { if (base && base.name) { it(`encode/decode ${base.name}`, () => { const encoded = base.encode(buff) const decoded = base.decode(encoded) assert.deepStrictEqual(decoded, buff) assert.deepStrictEqual(encoded, base.encoder.encode(buff)) assert.deepStrictEqual(buff, base.decoder.decode(encoded)) }) it(`encode/decode ${base.name} with non-printable values`, () => { const encoded = base.encode(nonPrintableBuff) const decoded = base.decode(encoded) assert.deepStrictEqual(decoded, nonPrintableBuff) assert.deepStrictEqual(encoded, base.encoder.encode(nonPrintableBuff)) assert.deepStrictEqual(nonPrintableBuff, base.decoder.decode(encoded)) }) } } } describe('base2', () => { baseTest(b2) }) describe('base8', () => { baseTest(b8) }) describe('base10', () => { baseTest(b10) }) describe('base16', () => { baseTest(b16) }) describe('base32', () => { baseTest(b32) }) describe('base36', () => { baseTest(b36) }) describe('base58', () => { baseTest(b58) }) describe('base64', () => { baseTest(b64) }) it('multibase mismatch', () => { const b64 = base64.encode(bytes.fromString('test')) const msg = `Unable to decode multibase string "${b64}", base32 decoder only supports inputs prefixed with ${base32.prefix}` assert.throws(() => base32.decode(b64), msg) }) it('decoder composition', () => { const base = base32.decoder.or(base58btc.decoder) const b32 = base32.encode(bytes.fromString('test')) assert.deepStrictEqual(base.decode(b32), bytes.fromString('test')) const b58 = base58btc.encode(bytes.fromString('test')) assert.deepStrictEqual(base.decode(b58), bytes.fromString('test')) const b64 = base64.encode(bytes.fromString('test')) const msg = `Unable to decode multibase string "${b64}", only inputs prefixed with ${base32.prefix},${base58btc.prefix} are supported` assert.throws(() => base.decode(b64), msg) const baseExt = base.or(base64) assert.deepStrictEqual(baseExt.decode(b64), bytes.fromString('test')) // original composition stays intact assert.throws(() => base.decode(b64), msg) // non-composed combined with composed const baseExt2 = base32.decoder.or(base64.decoder.or(base16.decoder)) assert.deepStrictEqual(baseExt2.decode(b64), bytes.fromString('test')) // composed combined with composed const baseExt3 = base.or(base64.decoder.or(base16.decoder)) assert.deepStrictEqual(baseExt3.decode(b64), bytes.fromString('test')) }) it('truncated data', () => { const b64 = base64.encode(Uint8Array.from([245, 250])) assert.throws(() => base64.decode(b64.substring(0, b64.length - 1)), 'Unexpected end of data') }) it('infers prefix and name corretly', () => { /** @type {'base32'} */ const name = base32.name /** @type {'base16'} */ // @ts-expect-error - TS catches mismatch const name2 = base32.name /** @type {'b'} */ const prefix = base32.prefix assert.equal(prefix, 'b') assert.equal(name, 'base32') assert.equal(name2, name) }) })