From 2472fa6d64f59b8dcadf146d36189d2f79f39803 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Wed, 16 Sep 2026 12:24:30 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20test262=20runner=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=8F=91=E7=8E=B0=E4=B8=8E=E8=B7=B3=E8=BF=87=E9=97=A8?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E6=88=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_test262/src/discovery.rs | 115 ++++++++++++++++++++++++++ crates/oxide_test262/src/main.rs | 111 +------------------------ 2 files changed, 117 insertions(+), 109 deletions(-) create mode 100644 crates/oxide_test262/src/discovery.rs diff --git a/crates/oxide_test262/src/discovery.rs b/crates/oxide_test262/src/discovery.rs new file mode 100644 index 00000000..15010ec5 --- /dev/null +++ b/crates/oxide_test262/src/discovery.rs @@ -0,0 +1,115 @@ +//! test262 测试发现与跳过门:`discover_tests` 递归发现与三道跳过门 +//! (`is_skipped`/`eval_family_excluded`/`pre_existing_excluded`)。 +//! 4 函数放宽 `pub(crate)` 供 crate 内跨模块访问;`process_path` 五道门调用点与顺序居 main.rs。 + +use crate::meta::TestMeta; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +/// 递归发现 test262 根目录下全部 `.js` 测试文件(排序后返回)。 +pub(crate) fn discover_tests(test262_root: &Path) -> Vec { + let mut paths: Vec = WalkDir::new(test262_root) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.path().extension().is_some_and(|ext| ext == "js")) + .map(|e| e.path().to_path_buf()) + .collect(); + paths.sort(); + paths +} + +/// 按测试元数据的 flags/features 判断是否应跳过,返回跳过原因(None 表示不跳过)。 +pub(crate) fn is_skipped(meta: &TestMeta) -> Option { + for flag in &meta.flags { + if flag.as_str() == "raw" { + return Some("raw tests excluded".into()); + } + // noStrict 测试放行——很多在严格模式下仍可通过;运行时跳过逻辑会捕获失败。 + } + + // 保持大范围已实现 feature tag 可运行;只排除真正未实现的子特性。 + // 其余一切让测试实际运行,依赖运行时跳过逻辑 + // ("too many registers"、"not yet implemented" 等)判定失败。 + let excluded_features = [ + "Proxy", + "Intl", + "Atomics", + "SharedArrayBuffer", + "cross-realm", + // await-dictionary(Promise.allKeyed/allSettledKeyed)是 2025 proposal,未实现。 + "await-dictionary", + ]; + + for feat in &meta.features { + if excluded_features.contains(&feat.as_str()) || feat.starts_with("Intl") { + return Some(format!("excluded feature: {feat}")); + } + } + + None +} + +/// eval 相关子族精确排除(档 1+2 后): +/// built-ins/eval 与 eval-code 的完成值/解析失败/非字符串/this-value-global/间接环境族放行; +/// 仅排除确定失败的 arguments/super/strict/块声明 等子族。 +pub(crate) fn eval_family_excluded(path: &str) -> Option<&'static str> { + if !path.contains("/eval-code/") { + return None; + } + let is_direct = path.contains("eval-code/direct/"); + let common = [ + "declare-arguments", // 直接 eval 的 arguments 语义族(档 3) + "this-value-func", // 调用者 this 传递(档 3) + "new.target", // new.target 语义(档 3) + "strict-caller", // 严格调用者传播(档 3) + "strict-source", + "strictness-override", // 直接 eval 严格性覆盖 + "onlystrict", // onlyStrict 块声明族 + "always-non-strict", // 依赖隐式全局写同步(既有债务) + "block-decl", // 块级函数声明(Annex B 严格变体) + "switch-case-decl", + "switch-dflt-decl", + ]; + if common.iter().any(|s| path.contains(s)) { + return Some("eval 子族未实现(档 1-2 边界)"); + } + if is_direct { + // 直接 eval:调用者作用域交互族(函数上下文 var/let + super 方法上下文),档 3 前失败 + if ["var-env-", "lex-env-", "super-prop", "super-call-arrow", "super-call-method"] + .iter() + .any(|s| path.contains(s)) + { + return Some("直接 eval 作用域族未实现(档 3)"); + } + } else if [ + "super-", + "var-env-func-strict", + "var-env-var-strict", + "var-env-global-lex", + "var-env-lower-lex", + ] + .iter() + .any(|s| path.contains(s)) + { + return Some("间接 eval 严格/词法冲突族未实现"); + } + None +} + +/// 确定性 pre-existing 失败白名单:引擎既有语义债务(非近期改动引入), +/// 修复前归入 skip 以免噪音掩盖真实回归;对应缺口修好后移出本列表。 +pub(crate) fn pre_existing_excluded(path: &str) -> Option<&'static str> { + const LIST: &[(&str, &str)] = &[ + ( + "expressions/tagged-template/template-object-frozen-non-strict.js", + "sloppy 只读静默写未实现(引擎统一抛 TypeError)", + ), + ( + "expressions/tagged-template/cache-eval-inner-function.js", + "eval 不共享调用方作用域(既有 eval 作用域限制)", + ), + ]; + LIST.iter() + .find(|(suffix, _)| path.ends_with(suffix)) + .map(|(_, reason)| *reason) +} diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index d685ec0a..b60db331 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -10,13 +10,14 @@ use std::process::Command; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, OnceLock, RwLock}; use std::time::{Duration, Instant}; -use walkdir::WalkDir; mod config; +mod discovery; mod meta; mod report; mod test262_log; use config::RunConfig; +use discovery::{discover_tests, eval_family_excluded, is_skipped, pre_existing_excluded}; use meta::{parse_meta, strip_meta, Negative, TestMeta}; use oxide_log::{Level, LogConfig, Output, SUBSYSTEM_COUNT}; use report::{ @@ -310,102 +311,6 @@ fn get_harness_prefix( Ok(source) } -/// 按测试元数据的 flags/features 判断是否应跳过,返回跳过原因(None 表示不跳过)。 -fn is_skipped(meta: &TestMeta) -> Option { - for flag in &meta.flags { - if flag.as_str() == "raw" { - return Some("raw tests excluded".into()); - } - // noStrict 测试放行——很多在严格模式下仍可通过;运行时跳过逻辑会捕获失败。 - } - - // 保持大范围已实现 feature tag 可运行;只排除真正未实现的子特性。 - // 其余一切让测试实际运行,依赖运行时跳过逻辑 - // ("too many registers"、"not yet implemented" 等)判定失败。 - let excluded_features = [ - "Proxy", - "Intl", - "Atomics", - "SharedArrayBuffer", - "cross-realm", - // await-dictionary(Promise.allKeyed/allSettledKeyed)是 2025 proposal,未实现。 - "await-dictionary", - ]; - - for feat in &meta.features { - if excluded_features.contains(&feat.as_str()) || feat.starts_with("Intl") { - return Some(format!("excluded feature: {feat}")); - } - } - - None -} - -/// eval 相关子族精确排除(档 1+2 后): -/// built-ins/eval 与 eval-code 的完成值/解析失败/非字符串/this-value-global/间接环境族放行; -/// 仅排除确定失败的 arguments/super/strict/块声明 等子族。 -fn eval_family_excluded(path: &str) -> Option<&'static str> { - if !path.contains("/eval-code/") { - return None; - } - let is_direct = path.contains("eval-code/direct/"); - let common = [ - "declare-arguments", // 直接 eval 的 arguments 语义族(档 3) - "this-value-func", // 调用者 this 传递(档 3) - "new.target", // new.target 语义(档 3) - "strict-caller", // 严格调用者传播(档 3) - "strict-source", - "strictness-override", // 直接 eval 严格性覆盖 - "onlystrict", // onlyStrict 块声明族 - "always-non-strict", // 依赖隐式全局写同步(既有债务) - "block-decl", // 块级函数声明(Annex B 严格变体) - "switch-case-decl", - "switch-dflt-decl", - ]; - if common.iter().any(|s| path.contains(s)) { - return Some("eval 子族未实现(档 1-2 边界)"); - } - if is_direct { - // 直接 eval:调用者作用域交互族(函数上下文 var/let + super 方法上下文),档 3 前失败 - if ["var-env-", "lex-env-", "super-prop", "super-call-arrow", "super-call-method"] - .iter() - .any(|s| path.contains(s)) - { - return Some("直接 eval 作用域族未实现(档 3)"); - } - } else if [ - "super-", - "var-env-func-strict", - "var-env-var-strict", - "var-env-global-lex", - "var-env-lower-lex", - ] - .iter() - .any(|s| path.contains(s)) - { - return Some("间接 eval 严格/词法冲突族未实现"); - } - None -} - -/// 确定性 pre-existing 失败白名单:引擎既有语义债务(非近期改动引入), -/// 修复前归入 skip 以免噪音掩盖真实回归;对应缺口修好后移出本列表。 -fn pre_existing_excluded(path: &str) -> Option<&'static str> { - const LIST: &[(&str, &str)] = &[ - ( - "expressions/tagged-template/template-object-frozen-non-strict.js", - "sloppy 只读静默写未实现(引擎统一抛 TypeError)", - ), - ( - "expressions/tagged-template/cache-eval-inner-function.js", - "eval 不共享调用方作用域(既有 eval 作用域限制)", - ), - ]; - LIST.iter() - .find(|(suffix, _)| path.ends_with(suffix)) - .map(|(_, reason)| *reason) -} - /// 在 catch_unwind 保护下运行单个测试,把引擎 panic 记为失败。 #[expect(clippy::too_many_arguments)] fn run_test( @@ -752,18 +657,6 @@ fn classify_vm_error(e: &str, neg: Option<&Negative>, no_skip: bool) -> TestOutc TestOutcome::Fail(format!("vm error: {e}")) } -/// 递归发现 test262 根目录下全部 `.js` 测试文件(排序后返回)。 -fn discover_tests(test262_root: &Path) -> Vec { - let mut paths: Vec = WalkDir::new(test262_root) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.path().extension().is_some_and(|ext| ext == "js")) - .map(|e| e.path().to_path_buf()) - .collect(); - paths.sort(); - paths -} - /// 从子进程 stdout 中解析形如 `label : N` 的汇总行。 fn parse_summary_count(stdout: &str, label: &str) -> Option { stdout.lines().find_map(|line| {