Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/cli/tests/oracle/lexical/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Keep the lexical oracle implementations in isolated modules while Cargo
// builds one integration target.

use crate::quickjs_syntax_diagnostic_oracle;

mod oracle_string_escape_diagnostics;
169 changes: 169 additions & 0 deletions apps/cli/tests/oracle/lexical/oracle_string_escape_diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//! B12 (S2 C5/C6): malformed string-escape wording and unterminated-string
//! columns must match the pinned QuickJS byte-for-byte at the command line,
//! including the message text and the line:column location.

use super::quickjs_syntax_diagnostic_oracle::observe_cmdline_syntax_error as oracle_observation;
use quickjs_oxide::engine::api::{Context, Runtime, RuntimeError, Value};

/// (description, source, `SyntaxError|<message>|<line>:<column>`)
///
/// Locations are asserted against pinned QuickJS `qjs -e` output, so each
/// expectation is a copy of the pinned engine's emitted frame.
const CASES: &[(&str, &str, &str)] = &[
// --- C6: unterminated strings point at the opening quote ---
(
"newline-terminated single-quoted string",
"var s = 'abc\n",
"SyntaxError|unexpected end of string|1:9",
),
(
"crlf-terminated single-quoted string",
"var s = 'abc\r\n",
"SyntaxError|unexpected end of string|1:9",
),
(
"newline-terminated string on the second line",
"var t = 1;\nvar s = 'abc\n",
"SyntaxError|unexpected end of string|2:9",
),
(
"eof-terminated string already matched and keeps the quote",
"var s = 'abc",
"SyntaxError|unexpected end of string|1:9",
),
(
"bare backslash before a newline",
"var s = '\\\n",
"SyntaxError|unexpected end of string|1:9",
),
(
"bare backslash at end of file",
"var s = '\\",
"SyntaxError|unexpected end of string|1:9",
),
// --- C5: every malformed \x / \u escape shares one pinned message ---
(
"short fixed unicode escape",
"var s = '\\u00'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"non-hex fixed unicode escape",
"var s = '\\uz'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"unicode escape exhausted at end of file",
"var s = '\\u'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"non-hex hex escape",
"var s = '\\xZZ'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"hex escape exhausted at end of file",
"var s = '\\x'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"empty braced unicode escape",
"var s = '\\u{}'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"non-hex braced unicode escape",
"var s = '\\u{zz}'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"unterminated braced unicode escape",
"var s = '\\u{41'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"braced unicode escape beyond U+10FFFF",
"var s = '\\u{110000}'",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"double-quoted malformed escape behaves identically",
"var s = \"\\u00\"",
"SyntaxError|malformed escape sequence in string literal|1:10",
),
(
"strict mode \\8 uses the generic message",
"\"use strict\"; var s = \"a\\8b\"",
"SyntaxError|malformed escape sequence in string literal|1:25",
),
(
"strict mode \\9 uses the generic message",
"\"use strict\"; var s = \"a\\9b\"",
"SyntaxError|malformed escape sequence in string literal|1:25",
),
// --- unaffected surfaces that must not regress ---
(
"strict legacy octal keeps its dedicated message",
"\"use strict\"; var s = \"a\\07b\"",
"SyntaxError|octal escape sequences are not allowed in strict mode|1:25",
),
];

#[test]
fn string_escape_diagnostics_match_pinned_quickjs() {
for &(description, source, expected) in CASES {
assert_eq!(rust_observation(source), expected, "Rust: {description}");
}

let Some(oracle) = std::env::var_os("QJS_ORACLE") else {
eprintln!("SKIP string escape diagnostic differential: set QJS_ORACLE to upstream qjs");
return;
};
for &(description, source, expected) in CASES {
assert_eq!(
oracle_observation(&oracle, source),
expected,
"QuickJS: {description}"
);
}
}

fn rust_observation(source: &str) -> String {
let runtime =
Runtime::new_with_host_services(quickjs_oxide_host::SystemHostServices::default());
let mut context = runtime.new_context();
assert_eq!(
context.eval(source),
Err(RuntimeError::Exception),
"Rust accepted {source:?}"
);
let Value::Object(error) = context
.take_exception()
.unwrap()
.unwrap_or_else(|| panic!("Rust produced no exception for {source:?}"))
else {
panic!("Rust exception was not an Error object for {source:?}");
};
let read = |context: &mut Context, name: &str| {
let key = runtime.intern_property_key(name).unwrap();
context.get_property(&error, &key).unwrap()
};
let Value::String(name) = read(&mut context, "name") else {
panic!("Rust Error.name was not a string for {source:?}");
};
let Value::String(message) = read(&mut context, "message") else {
panic!("Rust Error.message was not a string for {source:?}");
};
let Value::Int(line) = read(&mut context, "lineNumber") else {
panic!("Rust Error.lineNumber was not an integer for {source:?}");
};
let Value::Int(column) = read(&mut context, "columnNumber") else {
panic!("Rust Error.columnNumber was not an integer for {source:?}");
};
format!(
"{}|{}|{line}:{column}",
name.to_utf8_lossy(),
message.to_utf8_lossy()
)
}
1 change: 1 addition & 0 deletions apps/cli/tests/oracle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ mod generator_yield_star_depth;
mod global;
mod iterator;
mod json;
mod lexical;
mod math_intrinsic;
mod member_access;
mod module_reentry;
Expand Down
14 changes: 14 additions & 0 deletions compat/test262-oxide.conf
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,11 @@ test/language/import/escaped-as-namespace-import.js
test/language/import/escaped-from.js
test/language/import/import-attributes/json-invalid.js
test/language/import/import-attributes/json-named-bindings.js
test/language/literals/bigint/binary-invalid-digit.js
test/language/literals/bigint/exponent-part.js
test/language/literals/bigint/hexadecimal-invalid-digit.js
test/language/literals/bigint/mv-is-not-integer-dil-dot-dds.js
test/language/literals/bigint/mv-is-not-integer-dot-dds.js
test/language/literals/bigint/numeric-separators/numeric-separator-literal-bil-bd-nsl-bd-err.js
test/language/literals/bigint/numeric-separators/numeric-separator-literal-bil-nsl-bd-dunder-err.js
test/language/literals/bigint/numeric-separators/numeric-separator-literal-bil-nsl-bd-err.js
Expand All @@ -1838,6 +1843,13 @@ test/language/literals/bigint/numeric-separators/numeric-separator-literal-oil-n
test/language/literals/bigint/numeric-separators/numeric-separator-literal-oil-nsl-od-err.js
test/language/literals/bigint/numeric-separators/numeric-separator-literal-oil-od-nsl-od-err.js
test/language/literals/bigint/numeric-separators/numeric-separator-literal-unicode-err.js
test/language/literals/bigint/octal-invalid-digit.js
test/language/literals/numeric/S7.8.3_A6.1_T1.js
test/language/literals/numeric/S7.8.3_A6.1_T2.js
test/language/literals/numeric/S7.8.3_A6.2_T1.js
test/language/literals/numeric/S7.8.3_A6.2_T2.js
test/language/literals/numeric/binary-invalid-digit.js
test/language/literals/numeric/binary-invalid-truncated.js
test/language/literals/numeric/numeric-separators/numeric-separator-literal-bil-bd-nsl-bd-err.js
test/language/literals/numeric/numeric-separators/numeric-separator-literal-bil-nsl-bd-dunder-err.js
test/language/literals/numeric/numeric-separators/numeric-separator-literal-bil-nsl-bd-err.js
Expand Down Expand Up @@ -1871,6 +1883,8 @@ test/language/literals/numeric/numeric-separators/numeric-separator-literal-oil-
test/language/literals/numeric/numeric-separators/numeric-separator-literal-oil-nsl-od-err.js
test/language/literals/numeric/numeric-separators/numeric-separator-literal-oil-od-nsl-od-err.js
test/language/literals/numeric/numeric-separators/numeric-separator-literal-unicode-err.js
test/language/literals/numeric/octal-invalid-digit.js
test/language/literals/numeric/octal-invalid-truncated.js
test/language/literals/regexp/early-err-arithmetic-modifiers-add-remove-i.js
test/language/literals/regexp/early-err-arithmetic-modifiers-add-remove-m.js
test/language/literals/regexp/early-err-arithmetic-modifiers-add-remove-multi-duplicate.js
Expand Down
2 changes: 1 addition & 1 deletion compat/upstream.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ config_sha256 = "79c64748ff1182baf5433d0a8378e3666738a785d02faf71f0d459ed42ae897
test_count = 53125
metadata_records_sha256 = "a37219960819e56a5c5c1723d31d6a33095c778bf5347385187fde96f927a06a"
oxide_profile = "compat/test262-oxide.conf"
oxide_profile_sha256 = "aa9fa3581c86cf1f1ef786a54c2023107f3a99002129b726024ddd8ea0838d67"
oxide_profile_sha256 = "5b7327f5f3606ed732a799241efec90f4ce01d6e08e2477745fc1a9e4dce4cfe"
expected_errors = "test262_errors.txt"

[test262_es5]
Expand Down
14 changes: 7 additions & 7 deletions dev-support/test262/current.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ engine_semantics_trees=src
engine_semantics_sha256=f61afc7314c09e4b507468ca9bffdeb920d3e9c896068b3a9f39b4587caa0333
upstream=compat/upstream.toml
upstream_lines=28
upstream_sha256=ec5d1af6ad36f69946588dc959f1a2fc7a183999a9cf914812f114453e1cc9c3
upstream_sha256=fa83c501ada9e5a687f0015a371075dbd870e3d98bb92a408b8ee3d77286a0cf
admissions=dev-support/test262/admissions.tsv
admissions_lines=1310
admissions_sha256=64bb20004f7b85ff5327aa241400547fa66e15cc4b673fd01602873ca9464ec5
profile=compat/test262-oxide.conf
profile_lines=3194
profile_sha256=aa9fa3581c86cf1f1ef786a54c2023107f3a99002129b726024ddd8ea0838d67
profile_lines=3208
profile_sha256=5b7327f5f3606ed732a799241efec90f4ce01d6e08e2477745fc1a9e4dce4cfe
negative_diagnostics=dev-support/test262/negative-diagnostics.tsv
negative_diagnostics_lines=2945
negative_diagnostics_sha256=0f20554444b18fe2a714732b392a72785d88e8b315620bd619b473c93b7f01bf
negative_diagnostics_lines=2973
negative_diagnostics_sha256=e4cf946bd0e83f8ad1271a29a1486506f33f116e415cdb21ea2709ab183025ac
negative_diagnostic_rules=dev-support/test262/negative-diagnostic-rules.tsv
negative_diagnostic_rules_lines=78
negative_diagnostic_rules_sha256=e238443877c19f6f1086a97d34adc755a62970e7e31dc800619291c68dcc0fcc
negative_diagnostic_rules_lines=79
negative_diagnostic_rules_sha256=c3cafa5a9d697fc6247171aa189a86cce53664338007df5148ba8b4b62cafc89
negative_diagnostic_audit_tool=scripts/test262/audit-negative-diagnostics.mjs
negative_diagnostic_audit_tool_lines=942
negative_diagnostic_audit_tool_sha256=8f84d6d3a95297862c47e04e37372aec18f73f7fb09f830971725fd3b7c0228e
Expand Down
1 change: 1 addition & 0 deletions dev-support/test262/negative-diagnostic-rules.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module.missing-export js_resolve_export_throw_error module resolution reports a
module.tla-dependency-rejection js_async_module_execution_rejected async module evaluation propagates the dependency rejection unchanged
module.top-level-await.escaped-keyword js_parse_error_reserved_identifier the await terminal cannot contain Unicode escapes
module.top-level-await.function-context js_parse_unary the Await grammar parameter does not propagate into nested function syntax
numeric-literal.invalid js_parse_get_number malformed numeric and BigInt literals share the single QuickJS invalid number literal diagnostic
object-literal.private-name js_parse_object_literal private names are invalid object literal properties
optional-chaining.invalid-assignment-target get_lvalue optional chains are not assignment targets
regexp.flags.unicode-mode-conflict lre_compile the u and v Unicode modes are mutually exclusive
Expand Down
28 changes: 28 additions & 0 deletions dev-support/test262/negative-diagnostics.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,34 @@ test/language/identifier-resolution/static-init-invalid-await.js sloppy 255d713c
test/language/identifier-resolution/static-init-invalid-await.js strict 255d713c335cc9ffcaad5cec3e350d7ee20f8dce60e882f66a71388bd6a74ffb parse SyntaxError class-static-block.await-context unexpected 'await' keyword 24 5 exact
test/language/import/import-attributes/json-invalid.js sloppy 721e75c25d4839b55206c70b09d12fbd7e6f37d36081f1c982a11e4aebfa3e76 resolution SyntaxError module.json-parse expecting property name 2 3 exact
test/language/import/import-attributes/json-named-bindings.js sloppy f6725a7d6e92ff06fd725a05fb8402bc9952f29357a344660378b37fa556a1dd resolution SyntaxError module.missing-export Could not find export 'name' in module 'test/language/import/import-attributes/json-named-bindings_FIXTURE.json' absent
test/language/literals/bigint/binary-invalid-digit.js sloppy e7e79e572d5ad384bccacd1791828292eee524854c7614fda3007bebb4a73491 parse SyntaxError numeric-literal.invalid invalid number literal 26 1 exact
test/language/literals/bigint/binary-invalid-digit.js strict e7e79e572d5ad384bccacd1791828292eee524854c7614fda3007bebb4a73491 parse SyntaxError numeric-literal.invalid invalid number literal 27 1 exact
test/language/literals/bigint/exponent-part.js sloppy aa28ffdf429c4cf0ce43fc705fc98594ab1607a2d19f4762cf02f55404ba6cdc parse SyntaxError numeric-literal.invalid invalid number literal 16 1 exact
test/language/literals/bigint/exponent-part.js strict aa28ffdf429c4cf0ce43fc705fc98594ab1607a2d19f4762cf02f55404ba6cdc parse SyntaxError numeric-literal.invalid invalid number literal 17 1 exact
test/language/literals/bigint/hexadecimal-invalid-digit.js sloppy b1cbede6feac553e3bf1a3ede63ebcfcd9f4d17bee81a610bbbb8614212315c7 parse SyntaxError numeric-literal.invalid invalid number literal 26 1 exact
test/language/literals/bigint/hexadecimal-invalid-digit.js strict b1cbede6feac553e3bf1a3ede63ebcfcd9f4d17bee81a610bbbb8614212315c7 parse SyntaxError numeric-literal.invalid invalid number literal 27 1 exact
test/language/literals/bigint/mv-is-not-integer-dil-dot-dds.js sloppy b311e04e37639ee42799be9a7c3560bc9561264fed953992b474eeef75b5e846 parse SyntaxError numeric-literal.invalid invalid number literal 27 1 exact
test/language/literals/bigint/mv-is-not-integer-dil-dot-dds.js strict b311e04e37639ee42799be9a7c3560bc9561264fed953992b474eeef75b5e846 parse SyntaxError numeric-literal.invalid invalid number literal 28 1 exact
test/language/literals/bigint/mv-is-not-integer-dot-dds.js sloppy 1b12408b8c3347301244e76e7fa77d7cfcd0d8aa4369e2c18db2a8cc498b6496 parse SyntaxError numeric-literal.invalid invalid number literal 27 1 exact
test/language/literals/bigint/mv-is-not-integer-dot-dds.js strict 1b12408b8c3347301244e76e7fa77d7cfcd0d8aa4369e2c18db2a8cc498b6496 parse SyntaxError numeric-literal.invalid invalid number literal 28 1 exact
test/language/literals/bigint/octal-invalid-digit.js sloppy e5a5e3dd821b995f2f541c96998c3763faeaefc419e26a139afc20d3b140f884 parse SyntaxError numeric-literal.invalid invalid number literal 26 1 exact
test/language/literals/bigint/octal-invalid-digit.js strict e5a5e3dd821b995f2f541c96998c3763faeaefc419e26a139afc20d3b140f884 parse SyntaxError numeric-literal.invalid invalid number literal 27 1 exact
test/language/literals/numeric/S7.8.3_A6.1_T1.js sloppy 01d2089310638f3ca289b808ef5c6d1dc9f08c6b6bdc6e8bfbf5389d6f9aafc8 parse SyntaxError numeric-literal.invalid invalid number literal 16 1 exact
test/language/literals/numeric/S7.8.3_A6.1_T1.js strict 01d2089310638f3ca289b808ef5c6d1dc9f08c6b6bdc6e8bfbf5389d6f9aafc8 parse SyntaxError numeric-literal.invalid invalid number literal 17 1 exact
test/language/literals/numeric/S7.8.3_A6.1_T2.js sloppy 01f2d2e116ac0b6fd3bb4c5415ca130a0d1b58987f52ef99b667c9309b32df87 parse SyntaxError numeric-literal.invalid invalid number literal 16 1 exact
test/language/literals/numeric/S7.8.3_A6.1_T2.js strict 01f2d2e116ac0b6fd3bb4c5415ca130a0d1b58987f52ef99b667c9309b32df87 parse SyntaxError numeric-literal.invalid invalid number literal 17 1 exact
test/language/literals/numeric/S7.8.3_A6.2_T1.js sloppy b86e909498e91bc5ff23fd6d7ba67500d0114f0f00781ebe9a9a4f1059ac8997 parse SyntaxError numeric-literal.invalid invalid number literal 16 1 exact
test/language/literals/numeric/S7.8.3_A6.2_T1.js strict b86e909498e91bc5ff23fd6d7ba67500d0114f0f00781ebe9a9a4f1059ac8997 parse SyntaxError numeric-literal.invalid invalid number literal 17 1 exact
test/language/literals/numeric/S7.8.3_A6.2_T2.js sloppy 7546b6bce1526552b9b602ee8e81cbb73055c51a353598af2f2b05d67fb8b44e parse SyntaxError numeric-literal.invalid invalid number literal 16 1 exact
test/language/literals/numeric/S7.8.3_A6.2_T2.js strict 7546b6bce1526552b9b602ee8e81cbb73055c51a353598af2f2b05d67fb8b44e parse SyntaxError numeric-literal.invalid invalid number literal 17 1 exact
test/language/literals/numeric/binary-invalid-digit.js sloppy 497cf540a29de8280c08931c0142b34aab8d5aae0f78108393e7c02fd9c2b943 parse SyntaxError numeric-literal.invalid invalid number literal 23 1 exact
test/language/literals/numeric/binary-invalid-digit.js strict 497cf540a29de8280c08931c0142b34aab8d5aae0f78108393e7c02fd9c2b943 parse SyntaxError numeric-literal.invalid invalid number literal 24 1 exact
test/language/literals/numeric/binary-invalid-truncated.js sloppy 831cd030540a182e06e59dac3e12f74d9b7dafbe3a2842de3af648f37b662a7e parse SyntaxError numeric-literal.invalid invalid number literal 23 1 exact
test/language/literals/numeric/binary-invalid-truncated.js strict 831cd030540a182e06e59dac3e12f74d9b7dafbe3a2842de3af648f37b662a7e parse SyntaxError numeric-literal.invalid invalid number literal 24 1 exact
test/language/literals/numeric/octal-invalid-digit.js sloppy eabf1f14e9cb59d585e6c703993883f81fee710fd53702731af862dd974747be parse SyntaxError numeric-literal.invalid invalid number literal 23 1 exact
test/language/literals/numeric/octal-invalid-digit.js strict eabf1f14e9cb59d585e6c703993883f81fee710fd53702731af862dd974747be parse SyntaxError numeric-literal.invalid invalid number literal 24 1 exact
test/language/literals/numeric/octal-invalid-truncated.js sloppy a995268a8f2f49c1a137c2eb08b7d7c86716b7134113408c3898a28d4a7437cc parse SyntaxError numeric-literal.invalid invalid number literal 23 1 exact
test/language/literals/numeric/octal-invalid-truncated.js strict a995268a8f2f49c1a137c2eb08b7d7c86716b7134113408c3898a28d4a7437cc parse SyntaxError numeric-literal.invalid invalid number literal 24 1 exact
test/language/module-code/early-import-arguments.js sloppy f7bd4a8d7f839d89ed84922588b5242f5bdd9d9e01114ebe2b1dbe827cc8fd50 parse SyntaxError module.invalid-import-binding invalid import binding 35 20 exact
test/language/module-code/early-import-as-arguments.js sloppy d2761605cdd1657cb54fdbca1b45d9d46a6a6063523e884783c2c80909cae753 parse SyntaxError module.invalid-import-binding invalid import binding 35 25 exact
test/language/module-code/early-import-as-eval.js sloppy 742fbd6917df4cb1fe5e0058504c83afe15ac2588ef370977962672d61ccf230 parse SyntaxError module.invalid-import-binding invalid import binding 35 20 exact
Expand Down
Loading