test: test262 支持不跳过测试模式
This commit is contained in:
@@ -108,6 +108,48 @@ struct RunStats {
|
|||||||
fail_categories: HashMap<String, usize>,
|
fail_categories: HashMap<String, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct RunConfig {
|
||||||
|
test262_root: Option<PathBuf>,
|
||||||
|
filter: Option<String>,
|
||||||
|
no_skip: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunConfig {
|
||||||
|
fn parse(args: &[String]) -> Result<Self, String> {
|
||||||
|
let mut config = Self::default();
|
||||||
|
let mut positional = Vec::new();
|
||||||
|
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
match arg.as_str() {
|
||||||
|
"--no-skip" => config.no_skip = true,
|
||||||
|
"--help" | "-h" => return Err(Self::usage()),
|
||||||
|
_ if arg.starts_with("--") => return Err(format!("unknown option: {arg}\n\n{}", Self::usage())),
|
||||||
|
_ => positional.push(arg.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(root) = positional.first() {
|
||||||
|
config.test262_root = Some(PathBuf::from(root));
|
||||||
|
}
|
||||||
|
if let Some(filter) = positional.get(1) {
|
||||||
|
config.filter = Some(filter.clone());
|
||||||
|
}
|
||||||
|
if positional.len() > 2 {
|
||||||
|
return Err(format!("too many positional arguments\n\n{}", Self::usage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage() -> String {
|
||||||
|
"usage: test262-runner [--no-skip] [test262-root] [path-filter]\n\
|
||||||
|
\n\
|
||||||
|
--no-skip Run capability-excluded tests and count unsupported compile/runtime results as failures."
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_skipped(meta: &TestMeta) -> Option<String> {
|
fn is_skipped(meta: &TestMeta) -> Option<String> {
|
||||||
for flag in &meta.flags {
|
for flag in &meta.flags {
|
||||||
match flag.as_str() {
|
match flag.as_str() {
|
||||||
@@ -202,11 +244,12 @@ Test262Error.prototype.constructor = Test262Error;
|
|||||||
|
|
||||||
fn run_test(
|
fn run_test(
|
||||||
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<OxideKernel>, harness_module: &CompiledModule,
|
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<OxideKernel>, harness_module: &CompiledModule,
|
||||||
|
no_skip: bool,
|
||||||
) -> TestResult {
|
) -> TestResult {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
run_test_inner(path, source, meta, kernel, harness_module)
|
run_test_inner(path, source, meta, kernel, harness_module, no_skip)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
@@ -220,6 +263,7 @@ fn run_test(
|
|||||||
|
|
||||||
fn run_test_inner(
|
fn run_test_inner(
|
||||||
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<OxideKernel>, harness_module: &CompiledModule,
|
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<OxideKernel>, harness_module: &CompiledModule,
|
||||||
|
no_skip: bool,
|
||||||
) -> TestResult {
|
) -> TestResult {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
@@ -259,6 +303,9 @@ fn run_test_inner(
|
|||||||
|| e.contains("before initialization")
|
|| e.contains("before initialization")
|
||||||
|| e.contains("parser panicked")
|
|| e.contains("parser panicked")
|
||||||
{
|
{
|
||||||
|
if no_skip {
|
||||||
|
return TestResult::fail(path.to_path_buf(), dur, msg);
|
||||||
|
}
|
||||||
return TestResult::skip(path.to_path_buf(), msg);
|
return TestResult::skip(path.to_path_buf(), msg);
|
||||||
}
|
}
|
||||||
return TestResult::fail(path.to_path_buf(), dur, msg);
|
return TestResult::fail(path.to_path_buf(), dur, msg);
|
||||||
@@ -268,8 +315,12 @@ fn run_test_inner(
|
|||||||
let mut vm = Vm::with_kernel(Arc::clone(kernel));
|
let mut vm = Vm::with_kernel(Arc::clone(kernel));
|
||||||
|
|
||||||
if let Err(e) = vm.run(harness_module) {
|
if let Err(e) = vm.run(harness_module) {
|
||||||
let _dur = start.elapsed().as_millis() as u64;
|
let dur = start.elapsed().as_millis() as u64;
|
||||||
return TestResult::skip(path.to_path_buf(), format!("harness injection failed: {e}"));
|
let msg = format!("harness injection failed: {e}");
|
||||||
|
if no_skip {
|
||||||
|
return TestResult::fail(path.to_path_buf(), dur, msg);
|
||||||
|
}
|
||||||
|
return TestResult::skip(path.to_path_buf(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
match vm.run(&module) {
|
match vm.run(&module) {
|
||||||
@@ -309,6 +360,9 @@ fn run_test_inner(
|
|||||||
|| e.contains("NEW_EXPRESSION")
|
|| e.contains("NEW_EXPRESSION")
|
||||||
|| e.contains("RangeError")
|
|| e.contains("RangeError")
|
||||||
{
|
{
|
||||||
|
if no_skip {
|
||||||
|
return TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"));
|
||||||
|
}
|
||||||
TestResult::skip(path.to_path_buf(), format!("vm: {e}"))
|
TestResult::skip(path.to_path_buf(), format!("vm: {e}"))
|
||||||
} else {
|
} else {
|
||||||
TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"))
|
TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"))
|
||||||
@@ -386,9 +440,16 @@ fn main() {
|
|||||||
|
|
||||||
fn run_tests() -> bool {
|
fn run_tests() -> bool {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
let config = match RunConfig::parse(&args) {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(msg) => {
|
||||||
|
eprintln!("{msg}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let test262_root = if args.len() > 1 {
|
let test262_root = if let Some(root) = config.test262_root.clone() {
|
||||||
PathBuf::from(&args[1])
|
root
|
||||||
} else {
|
} else {
|
||||||
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
p.pop();
|
p.pop();
|
||||||
@@ -410,9 +471,12 @@ fn run_tests() -> bool {
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = if args.len() > 2 { Some(args[2].clone()) } else { None };
|
let filter = config.filter.clone();
|
||||||
|
|
||||||
eprintln!("discovering tests in: {}", test262_root.display());
|
eprintln!("discovering tests in: {}", test262_root.display());
|
||||||
|
if config.no_skip {
|
||||||
|
eprintln!("no-skip mode: capability filters disabled; unsupported results count as failures");
|
||||||
|
}
|
||||||
let paths = discover_tests(&test262_root);
|
let paths = discover_tests(&test262_root);
|
||||||
eprintln!("found {} test files", paths.len());
|
eprintln!("found {} test files", paths.len());
|
||||||
|
|
||||||
@@ -478,13 +542,15 @@ fn run_tests() -> bool {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(reason) = is_skipped(&meta) {
|
if !config.no_skip {
|
||||||
results.push(TestResult::skip(path.clone(), reason));
|
if let Some(reason) = is_skipped(&meta) {
|
||||||
stats.skip += 1;
|
results.push(TestResult::skip(path.clone(), reason));
|
||||||
continue;
|
stats.skip += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = run_test(path, &source, &meta, &kernel, &harness_module);
|
let result = run_test(path, &source, &meta, &kernel, &harness_module, config.no_skip);
|
||||||
match &result.outcome {
|
match &result.outcome {
|
||||||
TestOutcome::Pass(_) => stats.pass += 1,
|
TestOutcome::Pass(_) => stats.pass += 1,
|
||||||
TestOutcome::Fail(msg) => {
|
TestOutcome::Fail(msg) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user