Files
SnowLuma/packages/proton/test/__tests__/runtime-map-fallback.test.ts
2026-10-12 15:43:34 +08:00

114 lines
3.5 KiB
TypeScript

import { afterEach, describe, expect, it } from 'vitest';
import { analyzeSource } from '../../src/ast/analyzer';
import { createRuntimeMap } from '../../src/runtime-map';
import {
protobuf_decode,
protobuf_disableRuntimeMapFallback,
protobuf_enableRuntimeMapFallback,
protobuf_encode,
} from '../../src/runtime';
function captureFrameFromThrow(
fn: () => unknown,
sourceFile: string,
): { line: number; column: number } {
try {
fn();
} catch (err) {
const stack = err instanceof Error ? (err.stack ?? '') : '';
for (const raw of stack.split('\n')) {
const line = raw.trim();
if (!line.includes(sourceFile)) {
continue;
}
const location =
line.endsWith(')') && line.includes('(')
? line.slice(line.lastIndexOf('(') + 1, -1)
: line.replace(/^at\s+/, '');
const lastColon = location.lastIndexOf(':');
const secondLastColon = location.lastIndexOf(':', lastColon - 1);
if (lastColon < 0 || secondLastColon < 0) {
continue;
}
const parsedLine = Number(location.slice(secondLastColon + 1, lastColon));
const parsedColumn = Number(location.slice(lastColon + 1));
if (Number.isFinite(parsedLine) && Number.isFinite(parsedColumn)) {
return { line: parsedLine, column: parsedColumn };
}
}
}
throw new Error(`Unable to capture stack frame for ${sourceFile}`);
}
function invokeEncode(): Uint8Array {
return new Function(
'protobuf_encode',
`\n//# sourceURL=runtime-map-encode.js\nreturn protobuf_encode({ value: 7 });`,
)(protobuf_encode) as Uint8Array;
}
function invokeDecode(data: Uint8Array): any {
return new Function(
'protobuf_decode',
'data',
`\n//# sourceURL=runtime-map-decode.js\nreturn protobuf_decode(data);`,
)(protobuf_decode, data);
}
describe('runtime map fallback', () => {
afterEach(() => {
protobuf_disableRuntimeMapFallback();
});
it('dynamically generates encode/decode from runtime map when enabled', () => {
const schema = `
interface SimpleMsg {
value: pb<1, uint_32>;
}
`;
const registry = analyzeSource(schema, 'schema.ts');
const encodeFrame = captureFrameFromThrow(invokeEncode, 'runtime-map-encode.js');
const decodeFrame = captureFrameFromThrow(
() => invokeDecode(new Uint8Array([0x08, 0x07])),
'runtime-map-decode.js',
);
const runtimeMap = createRuntimeMap({
messages: registry,
callSites: [
{
file: 'runtime-map-encode.js',
line: encodeFrame.line,
column: encodeFrame.column,
fnName: 'protobuf_encode',
typeName: 'SimpleMsg',
},
{
file: 'runtime-map-decode.js',
line: decodeFrame.line,
column: decodeFrame.column,
fnName: 'protobuf_decode',
typeName: 'SimpleMsg',
},
],
});
protobuf_enableRuntimeMapFallback(runtimeMap);
const encoded = invokeEncode();
expect([...encoded]).toEqual([0x08, 0x07]);
const decoded = invokeDecode(encoded);
expect(decoded.value).toBe(7);
});
});