From 7ed4604b7777b32b539caa58354e016282498200 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Tue, 13 Oct 2026 19:26:12 +0800 Subject: [PATCH] test(lexer): pin BOM emission parity and span coordinates The lexer already accepts U+FEFF as trivia (W1). The test now proves the BOM-prefixed program emits identically to the BOM-less one, and records the span contract: the BOM stays inside the source coordinate space at 1:1, shifting the first token to 1:2. Fixes #427 --- crates/workshop-rs/tests/audit_regressions.rs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/workshop-rs/tests/audit_regressions.rs b/crates/workshop-rs/tests/audit_regressions.rs index 9772b2d8..05633a04 100644 --- a/crates/workshop-rs/tests/audit_regressions.rs +++ b/crates/workshop-rs/tests/audit_regressions.rs @@ -8,11 +8,32 @@ use workshop_rs::settings::{ SettingId, SettingOperationError, SettingTarget, SettingValue, definitions, definitions_by_id, }; -/// W1: a leading UTF-8 BOM must not be a lex error. +/// W1: a leading UTF-8 BOM must not be a lex error. The BOM stays inside +/// the source coordinate space — it occupies 1:1, so the `rule` keyword +/// starts at 1:2 rather than 1:1 — and emission is identical to the +/// BOM-less input. #[test] fn utf8_bom_is_accepted() { - let source = "\u{FEFF}rule(\"r\")\n{\n event\n {\n Ongoing - Global;\n }\n}"; - internal::parse(source); + let plain = "rule(\"r\")\n{\n event\n {\n Ongoing - Global;\n }\n}"; + let source = format!("\u{FEFF}{plain}"); + let program = internal::parse(&source); + assert_eq!( + internal::emit(&program), + internal::emit(&internal::parse(plain)), + "a BOM-prefixed program emits identically to the BOM-less one" + ); + let span = program + .rules + .iter() + .next() + .unwrap() + .span + .expect("rule span"); + assert_eq!( + (span.start.line, span.start.col), + (1, 2), + "spans index the authored text including the BOM" + ); } /// W2: a backslash in a rule name must re-escape on emission so the name