Ctrl K
ComunidadGuías…

test/scripts/tla-cpd/lex.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { assertEquals, assertNotEquals, assertThrows } from "@std/assert";
import { tokenizeTla } from "#scripts/tla-cpd/lex.ts";
import { prepareSource } from "#scripts/tla-cpd/prepare.ts";

Deno.test("TLA comments nest and leave token boundaries intact", () => {
  const source =
    "left(* outer (* nested *) remaining *)right \\* ignored\nnext";
  assertEquals(
    tokenizeTla(source).map(({ text }) => text),
    ["left", "right", "next"],
  );
  assertEquals(
    tokenizeTla("left right next").map(({ text }) => text),
    ["left", "right", "next"],
  );
  assertEquals(
    tokenizeTla("left \\* comment at EOF").map(({ text }) => text),
    ["left"],
  );
  assertNotEquals(
    prepareSource("a", "left right").encoded,
    prepareSource("a", "leftright").encoded,
  );
});

Deno.test("TLA strings retain comment markers, escapes and literal identity", () => {
  const source = String.raw`"(* not a comment *) \\* neither \"quoted\"" "different"`;
  const tokens = tokenizeTla(source);
  assertEquals(
    tokens.map(({ kind }) => kind),
    ["string", "string"],
  );
  assertEquals(
    tokens[0]?.text,
    String.raw`"(* not a comment *) \\* neither \"quoted\""`,
  );
  assertNotEquals(
    prepareSource("a", '"one"').encoded,
    prepareSource("a", '"two"').encoded,
  );
  assertNotEquals(
    prepareSource("a", '"name"').encoded,
    prepareSource("a", "name").encoded,
  );
});

Deno.test("Primes are independent operators, not quote delimiters", () => {
  assertEquals(
    tokenizeTla("state' = state /\\ next' = TRUE").map(({ text }) => text),
    ["state", "'", "=", "state", "/\\", "next", "'", "=", "TRUE"],
  );
  assertNotEquals(
    prepareSource("a", "state'").encoded,
    prepareSource("a", "state").encoded,
  );
});

Deno.test("TLA identifiers, literals and maximal operators remain distinct", () => {
  assertEquals(
    tokenizeTla(String.raw`value_1 |-> 12.5 .. 20 /\ x \in S`).map(
      ({ text }) => text,
    ),
    ["value_1", "|->", "12.5", "..", "20", "/\\", "x", "\\in", "S"],
  );
  assertEquals(
    tokenizeTla(String.raw`\b101 \o17 \hAF`).map(({ kind }) => kind),
    ["number", "number", "number"],
  );
  assertNotEquals(
    prepareSource("a", "x <= y").encoded,
    prepareSource("a", "x < = y").encoded,
  );
  assertEquals(
    tokenizeTla("x^+ (+) y <: z").map(({ text }) => text),
    ["x", "^+", "(+)", "y", "<:", "z"],
  );
  assertEquals(
    tokenizeTla("---- MODULE Example ----\n====").map(({ text }) => text),
    ["----", "MODULE", "Example", "----", "===="],
  );
  assertNotEquals(
    prepareSource("a", "123name").encoded,
    prepareSource("a", "123 name").encoded,
  );
});

Deno.test("Set difference stays distinct from named set operators", () => {
  assertEquals(
    tokenizeTla(String.raw`States \ Known \cup Extra`).map(
      ({ kind, text }) => ({
        kind,
        text,
      }),
    ),
    [
      { kind: "identifier", text: "States" },
      { kind: "operator", text: "\\" },
      { kind: "identifier", text: "Known" },
      { kind: "operator", text: "\\cup" },
      { kind: "identifier", text: "Extra" },
    ],
  );
});

Deno.test("Source positions preserve CRLF and Unicode UTF-16 offsets", () => {
  const tokens = tokenizeTla('α\r\n(* 😀 *)\r\n"😀"\nβ');
  assertEquals(tokens[0]?.start, { column: 1, line: 1, position: 0 });
  assertEquals(tokens[1]?.start, { column: 1, line: 3, position: 13 });
  assertEquals(tokens[1]?.end, { column: 5, line: 3, position: 17 });
  assertEquals(tokens[2]?.start, { column: 1, line: 4, position: 18 });
  assertEquals(tokenizeTla("a\rb")[1]?.start, {
    column: 1,
    line: 2,
    position: 2,
  });
});

Deno.test("Canonical tokens contain only lexer-safe ASCII words", () => {
  const prepared = prepareSource(
    "sample.tla",
    String.raw`x' = "// (* \"safe\" *)" /\ α \in {1}`,
  );
  assertEquals(prepared.encoded.split("\n").length, prepared.tokens.length);
  assertEquals(/^[a-zA-Z0-9\n]+$/.test(prepared.encoded), true);
  assertEquals(
    prepareSource("a", "x (* comment *) = 1").encoded,
    prepareSource("b", "x\r\n= 1").encoded,
  );
  assertNotEquals(
    prepareSource("a", '"\ud800"').encoded,
    prepareSource("b", '"\ufffd"').encoded,
  );
});

Deno.test("Malformed lexical input fails rather than disappearing", () => {
  for (const source of [
    '"unterminated',
    '"line\nbreak"',
    String.raw`"bad\q"`,
    '"bad\\',
    "(* unfinished",
    "*)",
    "😀",
  ]) {
    assertThrows(() => tokenizeTla(source));
  }
  assertEquals(
    prepareSource("empty", "\\* comment\n(* nested (* comment *) *)").tokens,
    [],
  );
});