Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
refactor(experimental): errors: codecs-strings package
Browse files Browse the repository at this point in the history
  • Loading branch information
buffalojoec committed Feb 28, 2024
1 parent b8479fc commit 128710c
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 14 deletions.
3 changes: 2 additions & 1 deletion packages/codecs-strings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
},
"dependencies": {
"@solana/codecs-core": "workspace:*",
"@solana/codecs-numbers": "workspace:*"
"@solana/codecs-numbers": "workspace:*",
"@solana/errors": "workspace:*"
},
"devDependencies": {
"@solana/build-scripts": "workspace:*",
Expand Down
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base10-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase10Codec } from '../base10';

describe('getBase10Codec', () => {
Expand Down Expand Up @@ -25,6 +27,12 @@ describe('getBase10Codec', () => {
expect(base10.encode('65535')).toStrictEqual(new Uint8Array([255, 255]));
expect(base10.read(new Uint8Array([255, 255]), 0)).toStrictEqual(['65535', 2]);

expect(() => base10.encode('INVALID_INPUT')).toThrow('Expected a string of base 10, got [INVALID_INPUT].');
expect(() => base10.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '0123456789',
base: 10,
value: 'INVALID_INPUT',
}),
);
});
});
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base16-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase16Codec } from '../base16';

describe('getBase16Codec', () => {
Expand All @@ -24,6 +26,12 @@ describe('getBase16Codec', () => {
expect(base16.encode('ffff')).toStrictEqual(new Uint8Array([255, 255]));
expect(base16.read(new Uint8Array([255, 255]), 0)).toStrictEqual(['ffff', 2]);

expect(() => base16.encode('INVALID_INPUT')).toThrow('Expected a string of base 16, got [INVALID_INPUT].');
expect(() => base16.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '0123456789abcdef',
base: 16,
value: 'INVALID_INPUT',
}),
);
});
});
10 changes: 9 additions & 1 deletion packages/codecs-strings/src/__tests__/base58-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase58Codec } from '../base58';

describe('getBase58Codec', () => {
Expand Down Expand Up @@ -37,7 +39,13 @@ describe('getBase58Codec', () => {
expect(base58.encode(pubkey)).toStrictEqual(bytes);
expect(base58.read(bytes, 0)).toStrictEqual([pubkey, 32]);

expect(() => base58.encode('INVALID_INPUT')).toThrow('Expected a string of base 58, got [INVALID_INPUT].');
expect(() => base58.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
base: 58,
value: 'INVALID_INPUT',
}),
);
});

it('computes the buffer size of base 58 strings', () => {
Expand Down
26 changes: 23 additions & 3 deletions packages/codecs-strings/src/__tests__/base64-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { getBase16Codec } from '../base16';
import { getBase64Codec } from '../base64';

Expand Down Expand Up @@ -27,7 +29,13 @@ describe('getBase64Codec', () => {
expect(base64.encode(sentence)).toStrictEqual(bytes);
expect(base64.read(bytes, 0)).toStrictEqual([sentence, 27]);

expect(() => base64.encode('INVALID_INPUT')).toThrow('Expected a string of base 64, got [INVALID_INPUT].');
expect(() => base64.encode('INVALID_INPUT')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'INVALID_INPUT',
}),
);

const base64TokenData =
'AShNrkm2joOHhfQnRCzfSbrtDUkUcJSS7PJryR4PPjsnyyIWxL0ESVFoE7QWBowtz2B/iTtUGdb2EEyKbLuN5gEAAAAAAAAAAQAAAGCtpnOhgF7t+dM8By+nG51mKI9Dgb0RtO/6xvPX1w52AgAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
Expand All @@ -41,8 +49,20 @@ describe('getBase64Codec', () => {
if (__BROWSER__) {
it('fails if base64 strings do not have the expected padding', () => {
// This is because atob is not tolerant to missing padding.
expect(() => base64.encode('A')).toThrow('Expected a string of base 64, got [A].');
expect(() => base64.encode('AA=')).toThrow('Expected a string of base 64, got [AA=].');
expect(() => base64.encode('A')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'A',
}),
);
expect(() => base64.encode('AA=')).toThrow(
new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base: 64,
value: 'AA=',
}),
);
});
} else {
it('tolerate base64 string with less padding than expected', () => {
Expand Down
9 changes: 7 additions & 2 deletions packages/codecs-strings/src/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

/**
* Asserts that a given string matches a given alphabet.
*/
export function assertValidBaseString(alphabet: string, testValue: string, givenValue = testValue) {
if (!testValue.match(new RegExp(`^[${alphabet}]*$`))) {
// TODO: Coded error.
throw new Error(`Expected a string of base ${alphabet.length}, got [${givenValue}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: alphabet.length,
value: givenValue,
});
}
}
15 changes: 11 additions & 4 deletions packages/codecs-strings/src/base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
VariableSizeDecoder,
VariableSizeEncoder,
} from '@solana/codecs-core';
import { SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, SolanaError } from '@solana/errors';

import { assertValidBaseString } from './assertions';
import { getBaseXResliceDecoder, getBaseXResliceEncoder } from './baseX-reslice';
Expand All @@ -22,8 +23,11 @@ export const getBase64Encoder = (): VariableSizeEncoder<string> => {
try {
return (atob as Window['atob'])(value).length;
} catch (e) {
// TODO: Coded error.
throw new Error(`Expected a string of base 64, got [${value}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: 64,
value,
});
}
},
write(value: string, bytes, offset) {
Expand All @@ -34,8 +38,11 @@ export const getBase64Encoder = (): VariableSizeEncoder<string> => {
bytes.set(bytesToAdd, offset);
return bytesToAdd.length + offset;
} catch (e) {
// TODO: Coded error.
throw new Error(`Expected a string of base 64, got [${value}].`);
throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE, {
alphabet,
base: 64,
value,
});
}
},
});
Expand Down
4 changes: 3 additions & 1 deletion packages/errors/src/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC = 43 a
export const SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX = 44 as const;
export const SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE = 45 as const;
export const SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE = 46 as const;
export const SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE = 47 as const;

/**
* A union of every Solana error code
Expand Down Expand Up @@ -114,4 +115,5 @@ export type SolanaErrorCode =
| typeof SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC
| typeof SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX
| typeof SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE
| typeof SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE;
| typeof SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE
| typeof SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE;
6 changes: 6 additions & 0 deletions packages/errors/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SOLANA_ERROR__CODECS_FIXED_SIZE_ENCODER_DECODER_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE,
SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE,
SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_BYTES,
Expand Down Expand Up @@ -73,6 +74,11 @@ export type SolanaErrorContext = DefaultUnspecifiedErrorContextToUndefined<{
value: number | string;
variants: string[];
};
[SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE]: {
alphabet: string;
base: number;
value: string;
};
[SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE]: {
codecDescription: string;
max: bigint | number;
Expand Down
2 changes: 2 additions & 0 deletions packages/errors/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
SOLANA_ERROR__CODECS_FIXED_SIZE_ENCODER_DECODER_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT,
SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE,
SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE,
SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH,
SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_BYTES,
Expand Down Expand Up @@ -84,6 +85,7 @@ export const SolanaErrorMessages: Readonly<{
'Invalid data enum variant. Expected one of [$variants], got $value.',
[SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT]:
'Invalid scalar enum variant. Expected one of [$variants] or a number between $minRange and $maxRange, got $value.',
[SOLANA_ERROR__CODECS_INVALID_STRING_FOR_BASE]: 'Invalid value $value for base $base with alphabet $alphabet.',
[SOLANA_ERROR__CODECS_NUMBER_OUT_OF_RANGE]:
'Codec [$codecDescription] expected number to be in the range [$min, $max], got $value.',
[SOLANA_ERROR__CODECS_VARIABLE_SIZE_ENCODER_DECODER_MAX_SIZE_MISMATCH]:
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 128710c

Please sign in to comment.