mirror of
https://github.com/danbulant/oxc
synced 2026-05-21 05:08:45 +00:00
216 lines
6.6 KiB
Rust
216 lines
6.6 KiB
Rust
use std::{
|
|
collections::HashSet,
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
time::Duration,
|
|
};
|
|
|
|
use oxc_tasks_common::{agent, project_root};
|
|
use phf::{phf_set, Set};
|
|
|
|
use oxc_allocator::Allocator;
|
|
use oxc_codegen::{Codegen, CodegenOptions};
|
|
use oxc_parser::Parser;
|
|
use oxc_span::SourceType;
|
|
use serde_json::json;
|
|
|
|
use crate::{
|
|
suite::{Case, TestResult},
|
|
test262::{Test262Case, TestFlag},
|
|
};
|
|
|
|
pub const V8_TEST_262_FAILED_TESTS_PATH: &str = "tasks/coverage/src/runtime/v8_test262.status";
|
|
|
|
lazy_static::lazy_static! {
|
|
static ref V8_TEST_262_FAILED_TESTS: HashSet<String> = {
|
|
let mut set = HashSet::default();
|
|
fs::read_to_string(project_root().join(V8_TEST_262_FAILED_TESTS_PATH))
|
|
.expect("Failed to read v8_test262.status")
|
|
.lines()
|
|
.for_each(|line| {
|
|
set.insert(line.replace(".*", "").replace('*', ""));
|
|
});
|
|
set
|
|
};
|
|
}
|
|
|
|
static SKIP_EVALUATING_FEATURES: Set<&'static str> = phf_set! {
|
|
// Node's version of V8 doesn't implement these
|
|
"hashbang",
|
|
"legacy-regexp",
|
|
"regexp-duplicate-named-groups",
|
|
"symbols-as-weakmap-keys",
|
|
"tail-call-optimization",
|
|
|
|
// We don't care about API-related things
|
|
"ArrayBuffer",
|
|
"change-array-by-copy",
|
|
"DataView",
|
|
"resizable-arraybuffer",
|
|
"ShadowRealm",
|
|
"cross-realm",
|
|
"SharedArrayBuffer",
|
|
"String.prototype.toWellFormed",
|
|
"Symbol.match",
|
|
"Symbol.replace",
|
|
"Symbol.unscopables",
|
|
"Temporal",
|
|
"TypedArray",
|
|
|
|
// Added in oxc
|
|
"Array.fromAsync",
|
|
"IsHTMLDDA",
|
|
"iterator-helpers",
|
|
"set-methods",
|
|
"array-grouping",
|
|
|
|
// stage 2
|
|
"Intl.DurationFormat"
|
|
};
|
|
|
|
static SKIP_EVALUATING_THESE_INCLUDES: Set<&'static str> = phf_set! {
|
|
// We don't preserve "toString()" on functions
|
|
"nativeFunctionMatcher.js",
|
|
};
|
|
|
|
static SKIP_TEST_CASES: Set<&'static str> = phf_set! {
|
|
// For some unknown reason these tests are unstable, so we'll skip them for now.
|
|
"language/identifiers/start-unicode",
|
|
// Properly misconfigured test setup for `eval`, but can't figure out where
|
|
"annexB/language/eval-code",
|
|
"language/eval-code"
|
|
};
|
|
|
|
const FIXTURES_PATH: &str = "tasks/coverage/test262/test";
|
|
|
|
pub struct CodegenRuntimeTest262Case {
|
|
base: Test262Case,
|
|
test_root: PathBuf,
|
|
}
|
|
|
|
impl Case for CodegenRuntimeTest262Case {
|
|
fn new(path: PathBuf, code: String) -> Self {
|
|
Self { base: Test262Case::new(path, code), test_root: project_root().join(FIXTURES_PATH) }
|
|
}
|
|
|
|
fn code(&self) -> &str {
|
|
self.base.code()
|
|
}
|
|
|
|
fn path(&self) -> &Path {
|
|
self.base.path()
|
|
}
|
|
|
|
fn test_result(&self) -> &TestResult {
|
|
self.base.test_result()
|
|
}
|
|
|
|
fn skip_test_case(&self) -> bool {
|
|
let base_path = self.base.path().to_string_lossy();
|
|
self.base.should_fail()
|
|
|| base_path.starts_with("built-ins")
|
|
|| base_path.starts_with("staging")
|
|
|| base_path.starts_with("intl402")
|
|
// skip v8 test-262 failed tests
|
|
|| V8_TEST_262_FAILED_TESTS.iter().any(|test| base_path.contains(test))
|
|
|| self
|
|
.base
|
|
.meta()
|
|
.includes
|
|
.iter()
|
|
.any(|include| SKIP_EVALUATING_THESE_INCLUDES.contains(include))
|
|
|| self
|
|
.base
|
|
.meta()
|
|
.features
|
|
.iter()
|
|
.any(|feature| SKIP_EVALUATING_FEATURES.contains(feature))
|
|
|| SKIP_TEST_CASES.iter().any(|path| base_path.contains(path))
|
|
|| self.base.code().contains("$262")
|
|
|| self.base.code().contains("$DONOTEVALUATE()")
|
|
}
|
|
|
|
fn run(&mut self) {}
|
|
|
|
async fn run_async(&mut self) {
|
|
let result = async {
|
|
let codegen_source_text = {
|
|
let source_text = self.base.code();
|
|
let is_module = self.base.meta().flags.contains(&TestFlag::Module);
|
|
let is_only_strict = self.base.meta().flags.contains(&TestFlag::OnlyStrict);
|
|
let source_type = SourceType::default().with_module(is_module);
|
|
let allocator = Allocator::default();
|
|
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
|
let mut text =
|
|
Codegen::<false>::new("", source_text, ret.trivias, CodegenOptions::default())
|
|
.build(&ret.program)
|
|
.source_text;
|
|
if is_only_strict {
|
|
text = format!("\"use strict\";\n{text}");
|
|
}
|
|
if is_module {
|
|
text = format!("{text}\n export {{}}");
|
|
}
|
|
text
|
|
};
|
|
|
|
self.run_test_code(codegen_source_text).await
|
|
}
|
|
.await;
|
|
self.base.set_result(result);
|
|
}
|
|
}
|
|
|
|
impl CodegenRuntimeTest262Case {
|
|
async fn run_test_code(&self, codegen_text: String) -> TestResult {
|
|
let is_async = self.base.meta().flags.contains(&TestFlag::Async);
|
|
let is_module = self.base.meta().flags.contains(&TestFlag::Module);
|
|
let is_raw = self.base.meta().flags.contains(&TestFlag::Raw);
|
|
let import_dir = self
|
|
.test_root
|
|
.join(self.base.path().parent().expect("Failed to get parent directory"))
|
|
.to_string_lossy()
|
|
.to_string();
|
|
|
|
let result = request_run_code(json!({
|
|
"code": codegen_text,
|
|
"includes": self.base.meta().includes,
|
|
"isAsync": is_async,
|
|
"isModule": is_module,
|
|
"isRaw": is_raw,
|
|
"importDir": import_dir
|
|
}))
|
|
.await;
|
|
|
|
match result {
|
|
Ok(output) => {
|
|
if output.is_empty() {
|
|
TestResult::Passed
|
|
} else {
|
|
if let Some(negative) = &self.base.meta().negative {
|
|
if negative.phase.is_runtime()
|
|
&& output.starts_with(&negative.error_type.to_string())
|
|
{
|
|
return TestResult::Passed;
|
|
}
|
|
}
|
|
TestResult::RuntimeError(output)
|
|
}
|
|
}
|
|
Err(error) => TestResult::RuntimeError(error),
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn request_run_code(json: impl serde::Serialize + Send + 'static) -> Result<String, String> {
|
|
tokio::spawn(async move {
|
|
agent()
|
|
.post("http://localhost:32055/run")
|
|
.timeout(Duration::from_secs(10))
|
|
.send_json(json)
|
|
.map_err(|err| err.to_string())
|
|
.and_then(|res| res.into_string().map_err(|err| err.to_string()))
|
|
})
|
|
.await
|
|
.map_err(|err| err.to_string())?
|
|
}
|