Skip to content

Instantly share code, notes, and snippets.

@iso2022jp
Created November 4, 2025 00:35
Show Gist options
  • Select an option

  • Save iso2022jp/b71d82d8875d0228e3bc708277dfe505 to your computer and use it in GitHub Desktop.

Select an option

Save iso2022jp/b71d82d8875d0228e3bc708277dfe505 to your computer and use it in GitHub Desktop.
Base32
'use strict';
// @ts-check
/**
* The Base 32 Encoding and Base 32 Encoding with Extended Hex Alphabet
*
* This module provides Base32 encoding and decoding functionality similar to Uint8Array's Base64 methods
* @see https://www.rfc-editor.org/rfc/rfc4648.html#section-6
* @see https://www.rfc-editor.org/rfc/rfc4648.html#section-7
*/
/**
* Radix 32 code units to base32 characters
* 0123456789abcdefghijklmnopqrstuv => ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
* @type {Map<string, string>}
*/
const BASE32_ENCODE_MAPPING = new Map([
['0', 'A'], ['1', 'B'], ['2', 'C'], ['3', 'D'], ['4', 'E'], ['5', 'F'], ['6', 'G'], ['7', 'H'],
['8', 'I'], ['9', 'J'], ['a', 'K'], ['b', 'L'], ['c', 'M'], ['d', 'N'], ['e', 'O'], ['f', 'P'],
['g', 'Q'], ['h', 'R'], ['i', 'S'], ['j', 'T'], ['k', 'U'], ['l', 'V'], ['m', 'W'], ['n', 'X'],
['o', 'Y'], ['p', 'Z'], ['q', '2'], ['r', '3'], ['s', '4'], ['t', '5'], ['u', '6'], ['v', '7'],
]);
const BIAS = [undefined, 0x100000000, 0x1000000, 0x10000, 0x100, 1];
const PADDINGS = [undefined, '======', '====', '===', '=', ''];
const CODE_LENGTHS = [undefined, 2, 4, 5, 7, 8];
/**
* Base32 characters to radix 32 code units
* ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 => 0123456789abcdefghijklmnopqrstuv
* @type {Map<string, string>}
*/
const BASE32_DECODE_MAPPING = new Map(Array.from(BASE32_ENCODE_MAPPING, ([k, v]) => [v, k]));
BASE32_DECODE_MAPPING.set('=', '=');
/**
* @param {number} value 40-bit integer
* @returns {string} Radix 32 codes
*/
const toRadix32 = value => value.toString(32).padStart(8, '0');
/**
* @param {string} digits Radix 32 codes
* @returns {number} 40-bit integer
*/
const fromRadix32 = digits => parseInt(digits, 32);
/**
* @param {Uint8Array} buffer
* @param {{alphabet?: string, omitPadding?: boolean}} [options]
* @returns {string}
*/
const encode = (buffer, options = undefined) => {
const {alphabet = 'base32', omitPadding = false} = options || {}; // ??
if (!['base32', 'base32hex'].includes(alphabet)) {
throw new TypeError(`Unsupported alphabet: ${alphabet}`);
}
const mapCodes = alphabet === 'base32'
? characters => Array.from(characters, c => BASE32_ENCODE_MAPPING.get(c)).join('')
: characters => characters.toUpperCase();
const outputGroups = [];
for (let i = 0; i < buffer.length; i += 5) {
const group = buffer.slice(i, i + 5);
// Bit-wise operation cannot be used for 40-bit integer
const quantum = group.reduce((a, c) => a * 256 + c, 0) * BIAS[group.length];
const characters = toRadix32(quantum);
const outputGroup = mapCodes(characters).slice(0, CODE_LENGTHS[group.length]);
outputGroups.push(outputGroup);
if (group.length < 5 && !omitPadding) {
outputGroups.push(PADDINGS[group.length]);
}
}
return outputGroups.join('');
};
/**
* @param {string} string
* @param {{alphabet?: string, lastChunkHandling?: string}} [options]
* @returns {Uint8Array}
*/
const decode = (string, options = undefined) => {
const {alphabet = 'base32', lastChunkHandling = 'loose'} = options || {}; // ??
if (!['base32', 'base32hex'].includes(alphabet)) {
throw new TypeError(`Unsupported alphabet: ${alphabet}`);
}
if (!['strict', 'loose', 'stop-before-partial'].includes(lastChunkHandling)) {
throw new TypeError(`Unsupported lastChunkHandling: ${lastChunkHandling}`);
}
string = string.replace(/[\t\n\f\r ]/g, '');
string = string.toUpperCase();
if (alphabet === 'base32') {
if (!/^[2-7A-Z=]*$/.test(string)) {
throw new SyntaxError(`Found a character that cannot be part of a valid ${alphabet} string`);
}
string = Array.from(string, c => BASE32_DECODE_MAPPING.get(c)).join('').toUpperCase();
} else {
if (!/^[\dA-V=]*$/.test(string)) {
throw new SyntaxError(`Found a character that cannot be part of a valid ${alphabet} string`);
}
}
if (lastChunkHandling === 'strict') {
if (!/^(?:[\dA-V]{8})*(?:[\dA-V][048CGKOS]======|[\dA-V]{3}[0G]====|[\dA-V]{4}[02468ACEGIKMOQSU]===|[\dA-V]{6}[08GO]=)?$/.test(string)) {
throw new SyntaxError(`Invalid ${alphabet} string`);
}
}
if (lastChunkHandling === 'loose') {
if (!/^(?:[\dA-V]{8})*(?:[\dA-V]{2}={0,6}|[\dA-V]{4}={0,4}|[\dA-V]{5}={0,3}|[\dA-V]{7}=?)?$/.test(string)) {
throw new SyntaxError(`Invalid ${alphabet} string`);
}
}
if (lastChunkHandling === 'stop-before-partial') {
if (!/^(?:[\dA-V]{8})*(?:[\dA-V](?:[048CGKOS]={0,6})?|[\dA-V](?:[\dA-V](?:[\dA-V](?:[0G]={0,4})?)?)?|[\dA-V](?:[\dA-V](?:[\dA-V](?:[\dA-V](?:[02468ACEGIKMOQSU]={0,3})?)?)?)?|[\dA-V](?:[\dA-V](?:[\dA-V](?:[\dA-V](?:[\dA-V](?:[\dA-V](?:[08GO]=?)?)?)?)?)?)?)?$/.test(string)) {
throw new SyntaxError(`Invalid ${alphabet} string`);
}
string = string.slice(0, string.length & -8);
}
string = string.replace(/=+$/, '');
const outputLength = Math.floor(string.length * 5 / 8);
string = string.padEnd((string.length + 7) & -8, '0');
const buffer = new ArrayBuffer(Math.floor(string.length * 5 / 8));
const view = new DataView(buffer);
let o = 0;
for (let i = 0; i < string.length; i += 8) {
const group = string.slice(i, i + 8);
const quantum = fromRadix32(group);
view.setInt8(o++, (quantum / 0x100000000) | 0);
view.setUint32(o, quantum);
o += 4;
}
return new Uint8Array(buffer, 0, outputLength);
}
module.exports = {
encode,
decode
};
'use strict';
const base32 = require('../src/base32');
const encoder = new TextEncoder();
const utf8 = input => encoder.encode(input)
const decoder = new TextDecoder();
const fromUtf8 = input => decoder.decode(input);
describe('RFC 4648: ', () => {
describe('Base 32', () => {
describe('RFC 4648 Test Vectors', () => {
it('should encode base32 strings with default options', () => {
const o = undefined;
expect(base32.encode(utf8(''), o)).toBe('');
expect(base32.encode(utf8('f'), o)).toBe('MY======');
expect(base32.encode(utf8('fo'), o)).toBe('MZXQ====');
expect(base32.encode(utf8('foo'), o)).toBe('MZXW6===');
expect(base32.encode(utf8('foob'), o)).toBe('MZXW6YQ=');
expect(base32.encode(utf8('fooba'), o)).toBe('MZXW6YTB');
expect(base32.encode(utf8('foobar'), o)).toBe('MZXW6YTBOI======');
});
it('should encode base32 strings with base32 alphabet', () => {
const o = {alphabet: 'base32'};
expect(base32.encode(utf8(''), o)).toBe('');
expect(base32.encode(utf8('f'), o)).toBe('MY======');
expect(base32.encode(utf8('fo'), o)).toBe('MZXQ====');
expect(base32.encode(utf8('foo'), o)).toBe('MZXW6===');
expect(base32.encode(utf8('foob'), o)).toBe('MZXW6YQ=');
expect(base32.encode(utf8('fooba'), o)).toBe('MZXW6YTB');
expect(base32.encode(utf8('foobar'), o)).toBe('MZXW6YTBOI======');
});
it('should encode base32 strings with base32 alphabet and no padding', () => {
const o = {alphabet: 'base32', omitPadding: true};
expect(base32.encode(utf8(''), o)).toBe('');
expect(base32.encode(utf8('f'), o)).toBe('MY');
expect(base32.encode(utf8('fo'), o)).toBe('MZXQ');
expect(base32.encode(utf8('foo'), o)).toBe('MZXW6');
expect(base32.encode(utf8('foob'), o)).toBe('MZXW6YQ');
expect(base32.encode(utf8('fooba'), o)).toBe('MZXW6YTB');
expect(base32.encode(utf8('foobar'), o)).toBe('MZXW6YTBOI');
});
it('should decode base32 strings with default options', () => {
const o = undefined;
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('MY', o))).toBe('f');
expect(fromUtf8(base32.decode('MZXQ', o))).toBe('fo');
expect(fromUtf8(base32.decode('MZXW6', o))).toBe('foo');
expect(fromUtf8(base32.decode('MZXW6YQ', o))).toBe('foob');
expect(fromUtf8(base32.decode('MZXW6YTB', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI', o))).toBe('foobar');
});
it('should decode base32 strings with base32 alphabet with strict handling', () => {
const o = {alphabet: 'base32', lastChunkHandling: 'strict'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('MY======', o))).toBe('f');
expect(fromUtf8(base32.decode('MZXQ====', o))).toBe('fo');
expect(fromUtf8(base32.decode('MZXW6===', o))).toBe('foo');
expect(fromUtf8(base32.decode('MZXW6YQ=', o))).toBe('foob');
expect(fromUtf8(base32.decode('MZXW6YTB', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI======', o))).toBe('foobar');
});
it('should decode base32 strings with base32 alphabet with loose handling', () => {
const o = {alphabet: 'base32', lastChunkHandling: 'loose'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('MY', o))).toBe('f');
expect(fromUtf8(base32.decode('MZXQ', o))).toBe('fo');
expect(fromUtf8(base32.decode('MZXW6', o))).toBe('foo');
expect(fromUtf8(base32.decode('MZXW6YQ', o))).toBe('foob');
expect(fromUtf8(base32.decode('MZXW6YTB', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI', o))).toBe('foobar');
});
it('should decode base32 strings with base32 alphabet with stop-before-partial handling', () => {
const o = {alphabet: 'base32', lastChunkHandling: 'stop-before-partial'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('MY', o))).toBe('');
expect(fromUtf8(base32.decode('MY=====', o))).toBe('');
expect(fromUtf8(base32.decode('MY======', o))).toBe('f');
expect(fromUtf8(base32.decode('M', o))).toBe('');
expect(fromUtf8(base32.decode('MZ', o))).toBe('');
expect(fromUtf8(base32.decode('MZX', o))).toBe('');
expect(fromUtf8(base32.decode('MZXQ', o))).toBe('');
expect(fromUtf8(base32.decode('MZXQ=', o))).toBe('');
expect(fromUtf8(base32.decode('MZXQ====', o))).toBe('fo');
expect(fromUtf8(base32.decode('MZXW6', o))).toBe('');
expect(fromUtf8(base32.decode('MZXW6==', o))).toBe('');
expect(fromUtf8(base32.decode('MZXW6===', o))).toBe('foo');
expect(fromUtf8(base32.decode('MZXW6YQ=', o))).toBe('foob');
expect(fromUtf8(base32.decode('MZXW6YQ', o))).toBe('');
expect(fromUtf8(base32.decode('MZXW6YTB', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBO', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI=====', o))).toBe('fooba');
expect(fromUtf8(base32.decode('MZXW6YTBOI======', o))).toBe('foobar');
});
});
describe('whitespace and case-insensitive decode', () => {
it('should ignore ASCII whitespace in input', () => {
expect(fromUtf8(base32.decode(' \tM\nZ\rX\fQ '))).toBe('fo');
});
it('should accept ASCII lowercase in input', () => {
expect(fromUtf8(base32.decode('mzxq===='))).toBe('fo');
});
});
describe('lastChunkHandling', () => {
it('strict: should accept only correctly padded strings and throw otherwise', () => {
expect(() => base32.decode('MY', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MY===', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MY======', {lastChunkHandling: 'strict'})).not.toThrow(); // 'f'
});
it('loose: should accept partially padded/unpadded last chunk', () => {
expect(fromUtf8(base32.decode('MY', {lastChunkHandling: 'loose'}))).toBe('f');
expect(fromUtf8(base32.decode('MY===', {lastChunkHandling: 'loose'}))).toBe('f');
expect(fromUtf8(base32.decode('MY======', {lastChunkHandling: 'loose'}))).toBe('f');
});
it('strict: should throw on invalid base32 strings even if correctly padded', () => {
expect(() => base32.decode('M=======', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('M3======', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MZX=====', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MZX7====', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MZXW7===', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MZXW6Y==', {lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('MZXW6YX=', {lastChunkHandling: 'strict'})).toThrow();
});
it('loose: should decode invalid base32 strings to best effort result', () => {
expect(() => base32.decode('M=======', {lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('M3======', {lastChunkHandling: 'loose'}))).toBe('f');
expect(() => base32.decode('MZX=====', {lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('MZX7====', {lastChunkHandling: 'loose'}))).toBe('fo');
expect(fromUtf8(base32.decode('MZXW7===', {lastChunkHandling: 'loose'}))).toBe('foo');
expect(() => base32.decode('MZXW6Y==', {lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('MZXW6YX=', {lastChunkHandling: 'loose'}))).toBe('foob');
});
});
});
describe('Base 32 Encoding with Extended Hex Alphabet', () => {
describe('RFC 4648 Test Vectors', () => {
it('should encode base32hex strings with padding', () => {
const o = {alphabet: 'base32hex'};
expect(base32.encode(utf8(''), o)).toBe('');
expect(base32.encode(utf8('f'), o)).toBe('CO======');
expect(base32.encode(utf8('fo'), o)).toBe('CPNG====');
expect(base32.encode(utf8('foo'), o)).toBe('CPNMU===');
expect(base32.encode(utf8('foob'), o)).toBe('CPNMUOG=');
expect(base32.encode(utf8('fooba'), o)).toBe('CPNMUOJ1');
expect(base32.encode(utf8('foobar'), o)).toBe('CPNMUOJ1E8======');
});
it('should encode base32hex strings without padding', () => {
const o = {alphabet: 'base32hex', omitPadding: true};
expect(base32.encode(utf8(''), o)).toBe('');
expect(base32.encode(utf8('f'), o)).toBe('CO');
expect(base32.encode(utf8('fo'), o)).toBe('CPNG');
expect(base32.encode(utf8('foo'), o)).toBe('CPNMU');
expect(base32.encode(utf8('foob'), o)).toBe('CPNMUOG');
expect(base32.encode(utf8('fooba'), o)).toBe('CPNMUOJ1');
expect(base32.encode(utf8('foobar'), o)).toBe('CPNMUOJ1E8');
});
it('should decode base32hex strings with default options', () => {
const o = {alphabet: 'base32hex'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('CO', o))).toBe('f');
expect(fromUtf8(base32.decode('CPNG', o))).toBe('fo');
expect(fromUtf8(base32.decode('CPNMU', o))).toBe('foo');
expect(fromUtf8(base32.decode('CPNMUOG', o))).toBe('foob');
expect(fromUtf8(base32.decode('CPNMUOJ1', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8', o))).toBe('foobar');
});
it('should decode base32hex strings with strict handling', () => {
const o = {alphabet: 'base32hex', lastChunkHandling: 'strict'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('CO======', o))).toBe('f');
expect(fromUtf8(base32.decode('CPNG====', o))).toBe('fo');
expect(fromUtf8(base32.decode('CPNMU===', o))).toBe('foo');
expect(fromUtf8(base32.decode('CPNMUOG=', o))).toBe('foob');
expect(fromUtf8(base32.decode('CPNMUOJ1', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8======', o))).toBe('foobar');
});
it('should decode base32hex strings with loose handling', () => {
const o = {alphabet: 'base32hex', lastChunkHandling: 'loose'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('CO', o))).toBe('f');
expect(fromUtf8(base32.decode('CPNG', o))).toBe('fo');
expect(fromUtf8(base32.decode('CPNMU', o))).toBe('foo');
expect(fromUtf8(base32.decode('CPNMUOG', o))).toBe('foob');
expect(fromUtf8(base32.decode('CPNMUOJ1', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8', o))).toBe('foobar');
});
it('should decode base32hex strings with stop-before-partial handling', () => {
const o = {alphabet: 'base32hex', lastChunkHandling: 'stop-before-partial'};
expect(fromUtf8(base32.decode('', o))).toBe('');
expect(fromUtf8(base32.decode('CO', o))).toBe('');
expect(fromUtf8(base32.decode('CO=====', o))).toBe('');
expect(fromUtf8(base32.decode('CO======', o))).toBe('f');
expect(fromUtf8(base32.decode('C', o))).toBe('');
expect(fromUtf8(base32.decode('CP', o))).toBe('');
expect(fromUtf8(base32.decode('CPN', o))).toBe('');
expect(fromUtf8(base32.decode('CPNG', o))).toBe('');
expect(fromUtf8(base32.decode('CPNG===', o))).toBe('');
expect(fromUtf8(base32.decode('CPNG====', o))).toBe('fo');
expect(fromUtf8(base32.decode('CPNMU', o))).toBe('');
expect(fromUtf8(base32.decode('CPNMU==', o))).toBe('');
expect(fromUtf8(base32.decode('CPNMU===', o))).toBe('foo');
expect(fromUtf8(base32.decode('CPNMUOG', o))).toBe('');
expect(fromUtf8(base32.decode('CPNMUOG=', o))).toBe('foob');
expect(fromUtf8(base32.decode('CPNMUOJ1', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8=====', o))).toBe('fooba');
expect(fromUtf8(base32.decode('CPNMUOJ1E8======', o))).toBe('foobar');
});
});
describe('whitespace and case-insensitive decode', () => {
it('should ignore ASCII whitespace in input', () => {
expect(fromUtf8(base32.decode(' \tC\nP\rN\fG ', {alphabet: 'base32hex'}))).toBe('fo');
});
it('should accept ASCII lowercase in input', () => {
expect(fromUtf8(base32.decode('cpng====', {alphabet: 'base32hex'}))).toBe('fo');
});
});
describe('lastChunkHandling', () => {
it('strict: should accept only correctly padded strings and throw otherwise', () => {
expect(() => base32.decode('CO', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CO===', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CO======', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).not.toThrow(); // 'f'
});
it('loose: should accept partially padded/unpadded last chunk', () => {
expect(fromUtf8(base32.decode('CO', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('f');
expect(fromUtf8(base32.decode('CO===', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('f');
expect(fromUtf8(base32.decode('CO======', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('f');
});
it('strict: should throw on invalid base32 strings even if correctly padded', () => {
expect(() => base32.decode('C=======', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CR======', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CPN=====', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CPNV====', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CPNMV===', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CPNMUO==', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
expect(() => base32.decode('CPNMUON=', {alphabet: 'base32hex', lastChunkHandling: 'strict'})).toThrow();
});
it('loose: should decode invalid base32 strings to best effort result', () => {
expect(() => base32.decode('C=======', {alphabet: 'base32hex', lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('CR======', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('f');
expect(() => base32.decode('CPN=====', {alphabet: 'base32hex', lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('CPNV====', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('fo');
expect(fromUtf8(base32.decode('CPNMV===', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('foo');
expect(() => base32.decode('CPNMUO==', {alphabet: 'base32hex', lastChunkHandling: 'loose'})).toThrow();
expect(fromUtf8(base32.decode('CPNMUON=', {alphabet: 'base32hex', lastChunkHandling: 'loose'}))).toBe('foob');
});
});
});
describe('round-trip arbitrary bytes', () => {
const cases = [
new Uint8Array([]),
new Uint8Array([0]),
new Uint8Array([0, 1]),
new Uint8Array([0, 1, 2]),
new Uint8Array([0, 1, 2, 3]),
new Uint8Array([0, 1, 2, 3, 4]),
new Uint8Array([255, 254, 253, 252, 251]),
new Uint8Array([0, 255, 16, 32, 64, 128, 255])
];
const optionsSet = [
undefined,
{alphabet: 'base32'},
{alphabet: 'base32hex'},
];
for (const bytes of cases) {
it(JSON.stringify(Array.from(bytes)), () => {
for (const options of optionsSet) {
const encoded = base32.encode(bytes, options);
const decoded = base32.decode(encoded, options);
expect(decoded).toEqual(bytes);
}
});
}
});
describe('error handling', () => {
it('encode should throw on unsupported alphabet', () => {
expect(() => base32.encode(encoder.encode(''), {alphabet: 'unsupported'})).toThrowError(TypeError);
});
it('decode should throw on unsupported lastChunkHandling', () => {
expect(() => base32.decode('', {lastChunkHandling: 'unsupported'})).toThrowError(TypeError);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment