mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
refactor: test262 runner 测试发现与跳过门独立成模块
This commit is contained in:
@@ -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<PathBuf> {
|
||||||
|
let mut paths: Vec<PathBuf> = 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<String> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -10,13 +10,14 @@ use std::process::Command;
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, OnceLock, RwLock};
|
use std::sync::{Arc, OnceLock, RwLock};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use walkdir::WalkDir;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod discovery;
|
||||||
mod meta;
|
mod meta;
|
||||||
mod report;
|
mod report;
|
||||||
mod test262_log;
|
mod test262_log;
|
||||||
use config::RunConfig;
|
use config::RunConfig;
|
||||||
|
use discovery::{discover_tests, eval_family_excluded, is_skipped, pre_existing_excluded};
|
||||||
use meta::{parse_meta, strip_meta, Negative, TestMeta};
|
use meta::{parse_meta, strip_meta, Negative, TestMeta};
|
||||||
use oxide_log::{Level, LogConfig, Output, SUBSYSTEM_COUNT};
|
use oxide_log::{Level, LogConfig, Output, SUBSYSTEM_COUNT};
|
||||||
use report::{
|
use report::{
|
||||||
@@ -310,102 +311,6 @@ fn get_harness_prefix(
|
|||||||
Ok(source)
|
Ok(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 按测试元数据的 flags/features 判断是否应跳过,返回跳过原因(None 表示不跳过)。
|
|
||||||
fn is_skipped(meta: &TestMeta) -> Option<String> {
|
|
||||||
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 记为失败。
|
/// 在 catch_unwind 保护下运行单个测试,把引擎 panic 记为失败。
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
fn run_test(
|
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}"))
|
TestOutcome::Fail(format!("vm error: {e}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 递归发现 test262 根目录下全部 `.js` 测试文件(排序后返回)。
|
|
||||||
fn discover_tests(test262_root: &Path) -> Vec<PathBuf> {
|
|
||||||
let mut paths: Vec<PathBuf> = 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` 的汇总行。
|
/// 从子进程 stdout 中解析形如 `label : N` 的汇总行。
|
||||||
fn parse_summary_count(stdout: &str, label: &str) -> Option<usize> {
|
fn parse_summary_count(stdout: &str, label: &str) -> Option<usize> {
|
||||||
stdout.lines().find_map(|line| {
|
stdout.lines().find_map(|line| {
|
||||||
|
|||||||
Reference in New Issue
Block a user