diff --git a/tasks/coverage/snapshots/runtime.snap b/tasks/coverage/snapshots/runtime.snap index 4a439857c8..7148ff4b9a 100644 --- a/tasks/coverage/snapshots/runtime.snap +++ b/tasks/coverage/snapshots/runtime.snap @@ -1,8 +1,8 @@ commit: 7ab7fafa runtime Summary: -AST Parsed : 18281/18281 (100.00%) -Positive Passed: 17306/18281 (94.67%) +AST Parsed : 18277/18277 (100.00%) +Positive Passed: 17306/18277 (94.69%) minify Error: tasks/coverage/test262/test/language/computed-property-names/class/static/generator-prototype.js Test262Error: Expected a TypeError to be thrown but no exception was thrown at all @@ -1074,18 +1074,9 @@ Test262Error: The expression should evaluate to the result Expected SameValue(« transform Error: tasks/coverage/test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-sub.js Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true -codegen Error: tasks/coverage/test262/test/language/expressions/delete/super-property-uninitialized-this.js -Test262Error: Expected a ReferenceError but got a Test262Error - minify Error: tasks/coverage/test262/test/language/expressions/does-not-equals/S11.9.2_A7.8.js Test262Error: #7: (1 != {valueOf: function() {throw "error"}, toString: function() {return 1}}) throw "error" -minify Error: tasks/coverage/test262/test/language/expressions/does-not-equals/bigint-and-number-extremes.js -Test262Error: The result of (0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n != Number.MAX_VALUE) is false Expected SameValue(«true», «false») to be true - -minify Error: tasks/coverage/test262/test/language/expressions/equals/bigint-and-number-extremes.js -Test262Error: The result of (0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n == Number.MAX_VALUE) is true Expected SameValue(«false», «true») to be true - minify Error: tasks/coverage/test262/test/language/expressions/equals/coerce-symbol-to-prim-err.js Test262Error: Expected a Test262Error to be thrown but no exception was thrown at all @@ -1377,9 +1368,6 @@ TypeError: Cannot read properties of undefined (reading 'enumerable') minify Error: tasks/coverage/test262/test/language/expressions/optional-chaining/member-expression.js Test262Error: Expected SameValue(«"a"», «""») to be true -transform Error: tasks/coverage/test262/test/language/expressions/typeof/symbol.js -timeout: global - minify Error: tasks/coverage/test262/test/language/function-code/block-decl-onlystrict.js TypeError: Cannot read properties of undefined (reading 'constructor') diff --git a/tasks/coverage/src/runtime/.gitignore b/tasks/coverage/src/runtime/.gitignore index 4d11f40def..3516f8a3da 100644 --- a/tasks/coverage/src/runtime/.gitignore +++ b/tasks/coverage/src/runtime/.gitignore @@ -1 +1 @@ -v8_test262.status +v8_test262*.status diff --git a/tasks/coverage/src/runtime/test262_status.rs b/tasks/coverage/src/runtime/test262_status.rs index ed9cc0c984..9562edaaac 100644 --- a/tasks/coverage/src/runtime/test262_status.rs +++ b/tasks/coverage/src/runtime/test262_status.rs @@ -1,40 +1,68 @@ -use std::{fs, sync::OnceLock}; +use std::{fs, process::Command, sync::OnceLock}; use lazy_regex::Regex; use oxc_tasks_common::agent; use crate::workspace_root; -/// Generate v8 test262 status file, which is used to skip failed tests -/// see +/// Cases V8 itself expects to fail, skipped so the runtime suite reports oxc's +/// failures rather than the engine's. +/// +/// The list is V8's `test262.status` at the V8 version bundled in the `node` on +/// `PATH`, since that engine executes the cases. V8's `main` branch is wrong in +/// both directions: it un-skips cases V8 fixed after Node's branch cut, and it +/// skips cases for test262 files newer than the pinned checkout. +/// +/// The parsed list is cached per V8 version in a gitignored file. /// /// # Panics +/// Panics if `node` cannot be run or the status file cannot be fetched. pub fn get_v8_test262_failure_paths() -> &'static Vec { static STATUS: OnceLock> = OnceLock::new(); STATUS.get_or_init(|| { - let path = workspace_root().join("src/runtime/v8_test262.status"); - + let version = node_v8_version(); + let path = workspace_root().join(format!("src/runtime/v8_test262_{version}.status")); if path.exists() { - fs::read_to_string(&path).unwrap().lines().map(ToString::to_string).collect::>() - } else { - let res = agent() - .get("http://raw.githubusercontent.com/v8/v8/main/test/test262/test262.status") - .call() - .unwrap() - .body_mut() - .read_to_string() - .unwrap(); - let mut tests = Regex::new(r"'(.+)': \[(FAIL|SKIP)\]") - .unwrap() - .captures_iter(&res) - .filter_map(|capture| capture.get(1)) - .filter(|m| m.as_str() != "*") - .map(|m| m.as_str().to_string()) - .collect::>(); - tests.sort_unstable(); - tests.dedup(); - fs::write(path, tests.join("\n")).unwrap(); - tests + return fs::read_to_string(&path).unwrap().lines().map(ToString::to_string).collect(); } + + let status = fetch_status(&version); + let mut tests = Regex::new(r"'(.+)': \[(FAIL|SKIP)\]") + .unwrap() + .captures_iter(&status) + .filter_map(|capture| capture.get(1)) + .filter(|m| m.as_str() != "*") + .map(|m| m.as_str().to_string()) + .collect::>(); + tests.sort_unstable(); + tests.dedup(); + fs::write(path, tests.join("\n")).unwrap(); + tests }) } + +/// `process.versions.v8` without Node's `-node.N` suffix, e.g. `14.6.202.34`. +fn node_v8_version() -> String { + let output = Command::new("node") + .args(["-p", "process.versions.v8"]) + .output() + .expect("Failed to run node - ensure Node.js is installed"); + assert!(output.status.success(), "`node -p process.versions.v8` failed"); + let version = String::from_utf8(output.stdout).unwrap(); + version.trim().split('-').next().unwrap().to_string() +} + +/// V8 tags every release, so the file at `version` is the list that shipped +/// with Node's engine. A version without a tag falls back to `main`. +fn fetch_status(version: &str) -> String { + let url = |git_ref: &str| { + format!("https://raw.githubusercontent.com/v8/v8/{git_ref}/test/test262/test262.status") + }; + match agent().get(&url(version)).call() { + Ok(mut res) => res.body_mut().read_to_string().unwrap(), + Err(err) => { + println!("V8 test262.status for {version} is unavailable ({err}), using main instead"); + agent().get(&url("main")).call().unwrap().body_mut().read_to_string().unwrap() + } + } +}