UNPKG

@flowscripter/mpeg-sdl-parser

Version:

ISO/IEC 14496-34 Syntactic Description Language (MPEG SDL) parser implemented in TypeScript

196 lines (164 loc) 7.32 kB
import { describe, expect, test } from "bun:test"; import { type Buffer } from "node:buffer"; import path from "node:path"; import { promises as fs } from "node:fs"; import HistoryRecordingNodeHandler, { expectedHistory, } from "./fixtures/HistoryRecordingNodeHandler.ts"; import { buildAst } from "../src/ast/buildAst.ts"; import { createLenientSdlParser, createStrictSdlParser, } from "../src/lezer/createSdlParser.ts"; import { collateParseErrors, dispatchNodeHandler, prettyPrint, } from "../src/parseHelper.ts"; import { SdlStringInput } from "../src/lezer/SdlStringInput.ts"; const strictSdlParser = createStrictSdlParser(); const lenientSdlParser = createLenientSdlParser(); describe("Parse Helper Tests", () => { test("Test collateParseErrors", async () => { const sdlString = await fs.readFile( path.join(__dirname, "./sample_specifications/invalid.sdl"), ).then((buffer: Buffer) => buffer.toString()); const sdlStringInput = new SdlStringInput(sdlString); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors).toHaveLength(3); expect(parseErrors[0].errorLine).toEqual( " bit transport_priority;", ); expect(parseErrors[1].errorLine).toEqual(" unsigned int N = 184;"); expect(parseErrors[2].errorLine).toEqual( " if (adaptation_ field_control == 0b01 || adaptation_field_control == 0b11) {", ); expect(parseErrors[0].location!.column).toEqual(17); expect(parseErrors[1].location!.column).toEqual(16); expect(parseErrors[2].location!.column).toEqual(19); }); test("Test collateParseErrors - no class parameter values in parenthesis fails to parse", () => { const sdlStringInput = new SdlStringInput("class A {ClassD d();}"); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 19, position: 18 }", ); }); test("Test collateParseErrors - unexpected token fails to parse", () => { const sdlStringInput = new SdlStringInput("class A {ClassD computed d;}"); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Unexpected token => { row: 1, column: 17, position: 16 }", ); }); test("Test collateParseErrors - trailing comma in class parameter values fails to parse", () => { const sdlStringInput = new SdlStringInput("class A {ClassD d(3,);}"); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 21, position: 20 }", ); }); test("Test collateParseErrors - mix of concatenated string literal types fails to parse", () => { const sdlStringInput = new SdlStringInput( 'class A {utf8string d = "hello" u"world";}', ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 25, position: 24 }", ); }); test("Test collateParseErrors - both legacy and reserved together fails to parse", () => { const sdlStringInput = new SdlStringInput( "class A {reserved legacy utfstring foo;}", ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 19, position: 18 }", ); }); test("Test collateParseErrors - unexpected prefix for string literal", () => { const sdlStringInput = new SdlStringInput( 'class A {base64string foo = u"aGVsbG8K";}', ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Unexpected token => { row: 1, column: 29, position: 28 }", ); }); test("Test collateParseErrors - invalid basic string literal type fails to parse", () => { const sdlStringInput = new SdlStringInput( 'class A {utf8string foo = "hello";}', ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 27, position: 26 }", ); }); test("Test collateParseErrors - invalid prefix for string literal", () => { const sdlStringInput = new SdlStringInput( 'class A {utf8string foo = u8"hello";}', ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Unexpected token => { row: 1, column: 28, position: 27 }", ); }); test("Test collateParseErrors - illegal alignment bit count value fails to parse", () => { const sdlStringInput = new SdlStringInput( "class A {aligned(17) utf8string foo;}", ); const parseTree = lenientSdlParser.parse(sdlStringInput); const parseErrors = collateParseErrors(parseTree, sdlStringInput); expect(parseErrors[0].message).toBe( "SYNTACTIC ERROR: Missing expected token => { row: 1, column: 18, position: 17 }", ); }); test("Test prettyPrint", async () => { const sdlString = await fs.readFile( path.join(__dirname, "./sample_specifications/various_elements.sdl"), ).then((buffer: Buffer) => buffer.toString()); let expectedSdlString = await fs.readFile( path.join( __dirname, "./sample_specifications/prettified_various_elements.sdl", ), ).then((buffer: Buffer) => buffer.toString()); expectedSdlString = expectedSdlString.replace(/\r/g, ""); const sdlStringInput = new SdlStringInput(sdlString); const parseTree = strictSdlParser.parse(sdlStringInput); const specification = buildAst(parseTree, sdlStringInput); const prettifiedSdlString = await prettyPrint( specification, sdlStringInput, ); expect( prettifiedSdlString, ).toEqual( expectedSdlString, ); }); test("Test dispatchNodeHandler", async () => { const sdlString = await fs.readFile( path.join(__dirname, "./sample_specifications/sample.sdl"), ).then((buffer: Buffer) => buffer.toString()); const sdlStringInput = new SdlStringInput(sdlString); const parseTree = strictSdlParser.parse(sdlStringInput); const specification = buildAst(parseTree, sdlStringInput); const historyRecordingNodeHandler = new HistoryRecordingNodeHandler(); dispatchNodeHandler(specification, historyRecordingNodeHandler); expect( historyRecordingNodeHandler.nodeHistory, ).toEqual( expectedHistory, ); }); });