Files
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

213 lines
7.8 KiB
TypeScript

import { deepStrictEqual } from 'node:assert';
import { describe, it, expect } from 'vitest';
import { schemaRegistry } from '../schema';
import { generateCode } from '../../../src/codegen/generator';
const code = generateCode(
schemaRegistry(`
interface Text { value: pb<1,string>; }
interface Nested { texts: pb_repeated<1,Text>; }
`),
);
const { encode, decode, encodeNested, decodeNested } = new Function(`${code}
return {
encode: protobuf_encode_Text, decode: protobuf_decode_Text,
encodeNested: protobuf_encode_Nested, decodeNested: protobuf_decode_Nested,
};`)() as {
decode(bytes: Uint8Array): { value: string };
encode(value: { value: string }): Uint8Array;
encodeNested(value: { texts: { value: string }[] }): Uint8Array;
decodeNested(bytes: Uint8Array): { texts: { value: string }[] };
};
const encoder = new TextEncoder();
const decoder = new TextDecoder();
function wire(payload: Uint8Array): Uint8Array {
const prefix = [10];
let length = payload.length;
do {
prefix.push((length & 127) | (length >= 128 ? 128 : 0));
length >>>= 7;
} while (length);
return Uint8Array.from([...prefix, ...payload]);
}
describe('UTF-8 codecs', () => {
it('matches TextEncoder across native encoding boundaries, including unpaired surrogates', () => {
for (const length of [31, 32, 33, 42, 43, 63, 64, 65, 127, 128, 129, 4096]) {
for (const unit of ['a', 'é', '中文', '🚀', '\ud800', '\udc00', 'a\ud800']) {
const value = unit.repeat(length);
// Generic iterable equality repeats per-byte work on these large views.
deepStrictEqual(encode({ value }), wire(encoder.encode(value)));
}
}
});
it('preserves every ASCII byte across short and native decoding boundaries', () => {
for (const length of [
0, 1, 3, 4, 7, 8, 15, 16, 23, 24, 30, 31, 32, 33, 63, 64, 127, 128, 4096,
]) {
for (let byte = 0; byte < 128; byte++) {
const value = String.fromCharCode(byte).repeat(length);
deepStrictEqual(
encode({ value }),
length ? wire(encoder.encode(value)) : new Uint8Array(),
);
expect(decode(wire(encoder.encode(value)))).toEqual({ value });
}
}
});
it('matches TextDecoder for Unicode after ASCII prefixes and at slice boundaries', () => {
const suffixes = [
'\u0080',
'é',
'\u07ff',
'\u0800',
'中文',
'\ud7ff',
'\ue000',
'\uffff',
'🚀',
'\u{10000}',
'\u{10ffff}',
'\ufeff',
'\ufeffx\ufeff',
'\ud800',
'\udc00',
];
for (let length = 0; length <= 64; length++) {
for (const suffix of suffixes) {
const value = 'a'.repeat(length) + suffix;
const payload = encoder.encode(value);
const bytes = wire(payload);
const padded = Uint8Array.from([255, 255, ...bytes, 128, 128]);
expect(decode(padded.subarray(2, 2 + bytes.length)).value).toBe(
decoder.decode(payload),
);
}
}
});
it('matches replacement behavior for all one-byte and two-byte sequences', () => {
const payload = new Uint8Array(2);
for (let first = 0; first < 256; first++) {
payload[0] = first;
const one = payload.subarray(0, 1);
expect(decode(wire(one)).value).toBe(decoder.decode(one));
for (let second = 0; second < 256; second++) {
payload[1] = second;
expect(decode(wire(payload)).value).toBe(decoder.decode(payload));
}
}
});
it('matches TextDecoder across randomized valid Unicode strings', () => {
let state = 0x5a17cafe;
for (let sample = 0; sample < 5000; sample++) {
let value = 'a'.repeat(sample % 17);
for (let index = 0; index < sample % 21; index++) {
state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
value += String.fromCodePoint(state % 0x110000);
}
const payload = encoder.encode(value);
expect(decode(wire(payload)).value).toBe(decoder.decode(payload));
}
});
it('matches TextDecoder for invalid and truncated multibyte sequences', () => {
const sequences = [
[0xe0, 0x80, 0x80],
[0xed, 0xa0, 0x80],
[0xf0, 0x80, 0x80, 0x80],
[0xf4, 0x90, 0x80, 0x80],
[0xf5, 0x80, 0x80, 0x80],
[0xff],
[0xc2],
[0xe1, 0x80],
[0xf1, 0x80, 0x80],
[0xe1, 65, 0x80],
[0xf1, 0x80, 65, 0x80],
[0xef, 0xbb, 0xbf, 0xff],
];
for (let length = 0; length <= 33; length++) {
for (const sequence of sequences) {
const payload = Uint8Array.from([...Array(length).fill(65), ...sequence]);
expect(decode(wire(payload)).value).toBe(decoder.decode(payload));
}
}
let state = 0x42abcdef;
for (let sample = 0; sample < 5000; sample++) {
const payload = Uint8Array.from({ length: sample % 65 }, () => {
state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
return state >>> 24;
});
expect(decode(wire(payload)).value).toBe(decoder.decode(payload));
}
});
it('keeps nested and repeated strings independent', () => {
const texts = [
'',
'ascii',
'a'.repeat(31),
'a'.repeat(32),
'中文🚀',
'a\ufeffb',
'\ufeffx',
'中文🚀'.repeat(64),
].map((value) => ({ value }));
expect(decodeNested(encodeNested({ texts }))).toEqual({
texts: texts.map(({ value }) => ({ value: decoder.decode(encoder.encode(value)) })),
});
// A truncated UTF-8 sequence must not consume bytes from the following field.
const first = wire(Uint8Array.from([0xf0, 0x9f]));
const second = wire(encoder.encode('next'));
const nested = Uint8Array.from([10, first.length, ...first, 10, second.length, ...second]);
expect(decodeNested(nested)).toEqual({ texts: [{ value: '�' }, { value: 'next' }] });
});
it('measures UTF-8 correctly when a code point crosses a scratch-buffer boundary', () => {
for (const length of [4093, 4094, 4095, 4096, 4097, 8191]) {
for (const suffix of ['é', '中', '🚀', '\ud800', '\udc00', '\ud800x']) {
const value = 'a'.repeat(length) + suffix + '中文🚀'.repeat(4000);
deepStrictEqual(encode({ value }), wire(encoder.encode(value)));
}
}
});
it('preserves replacement and BOM behavior after long malformed inputs', () => {
for (const length of [127, 128, 129, 255, 4095, 4096, 4097]) {
for (const sequence of [
[0xff],
[0xe0, 0x80, 0x80],
[0xed, 0xa0, 0x80],
[0xf0, 0x9f],
[0xef, 0xbb, 0xbf],
]) {
for (const prefix of [[], [0xef, 0xbb, 0xbf]]) {
const payload = Uint8Array.from([
...prefix,
...Array(length).fill(65),
...sequence,
]);
expect(decode(wire(payload)).value).toBe(decoder.decode(payload));
const valid = encoder.encode('中文🚀'.repeat(64));
expect(decode(wire(valid)).value).toBe(decoder.decode(valid));
}
}
}
});
});