diff options
author | Luca Casonato <lucacasonato@yahoo.com> | 2021-01-27 15:06:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-27 15:06:18 +0100 |
commit | 2638aa03a5c3f7f4740ea7bee22127c01eb47a3c (patch) | |
tree | 16a27215e5a3105af51d3c4405a171eab6262148 /cli/tests | |
parent | ecfda65effab41b8ca0ab65955d0542304437491 (diff) |
tests: new typescript WPT runner (#9269)
Diffstat (limited to 'cli/tests')
-rw-r--r-- | cli/tests/WPT.md | 35 | ||||
-rw-r--r-- | cli/tests/integration_tests.rs | 246 | ||||
-rw-r--r-- | cli/tests/wpt.jsonc | 250 | ||||
-rw-r--r-- | cli/tests/wpt_testharnessconsolereporter.js | 129 |
4 files changed, 0 insertions, 660 deletions
diff --git a/cli/tests/WPT.md b/cli/tests/WPT.md deleted file mode 100644 index b6cd3bcea..000000000 --- a/cli/tests/WPT.md +++ /dev/null @@ -1,35 +0,0 @@ -## Web Platform Tests - -The WPT are test suites for Web platform specs, like Fetch, WHATWG Streams, or -console. Deno is able to run most `.any.js` and `.window.js` web platform tests. - -This directory contains a `wpt.jsonc` file that is used to configure our WPT -test runner. You can use this json file to set which WPT suites to run, and -which tests we expect to fail (due to bugs or because they are out of scope for -Deno). - -To include a new test file to run, add it to the array of test files for the -corresponding suite. For example we want to enable -`streams/readable-streams/general`. The file would then look like this: - -```json -{ - "streams": ["readable-streams/general"] -} -``` - -If you need more configurability over which test cases in a test file of a suite -to run, you can use the object representation. In the example below, we -configure `streams/readable-streams/general` to expect -`ReadableStream can't be constructed with an invalid type` to fail. - -```json -{ - "streams": [ - { - "name": "readable-streams/general", - "expectFail": ["ReadableStream can't be constructed with an invalid type"] - } - ] -} -``` diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 61893ab21..5830f8f20 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -6,12 +6,9 @@ use deno_core::url; use deno_runtime::deno_fetch::reqwest; use deno_runtime::deno_websocket::tokio_tungstenite; use std::io::{BufRead, Write}; -use std::path::Path; -use std::path::PathBuf; use std::process::Command; use tempfile::TempDir; use test_util as util; -use walkdir::WalkDir; macro_rules! itest( ($name:ident {$( $key:ident: $value:expr,)*}) => { @@ -5193,249 +5190,6 @@ fn denort_direct_use_error() { assert!(!status.success()); } -fn concat_bundle( - files: Vec<(PathBuf, String)>, - bundle_path: &Path, - init: String, -) -> String { - let bundle_url = url::Url::from_file_path(bundle_path).unwrap().to_string(); - - let mut bundle = init.clone(); - let mut bundle_line_count = init.lines().count() as u32; - let mut source_map = sourcemap::SourceMapBuilder::new(Some(&bundle_url)); - - // In classic workers, `importScripts()` performs an actual import. - // However, we don't implement that function in Deno as we want to enforce - // the use of ES6 modules. - // To work around this, we: - // 1. Define `importScripts()` as a no-op (code below) - // 2. Capture its parameter from the source code and add it to the list of - // files to concatenate. (see `web_platform_tests()`) - bundle.push_str("function importScripts() {}\n"); - bundle_line_count += 1; - - for (path, text) in files { - let path = std::fs::canonicalize(path).unwrap(); - let url = url::Url::from_file_path(path).unwrap().to_string(); - let src_id = source_map.add_source(&url); - source_map.set_source_contents(src_id, Some(&text)); - - for (line_index, line) in text.lines().enumerate() { - bundle.push_str(line); - bundle.push('\n'); - source_map.add_raw( - bundle_line_count, - 0, - line_index as u32, - 0, - Some(src_id), - None, - ); - - bundle_line_count += 1; - } - bundle.push('\n'); - bundle_line_count += 1; - } - - let mut source_map_buf: Vec<u8> = vec![]; - source_map - .into_sourcemap() - .to_writer(&mut source_map_buf) - .unwrap(); - - bundle.push_str("//# sourceMappingURL=data:application/json;base64,"); - let encoded_map = base64::encode(source_map_buf); - bundle.push_str(&encoded_map); - - bundle -} - -// TODO(lucacasonato): DRY with tsc_config.rs -/// Convert a jsonc libraries `JsonValue` to a serde `Value`. -fn jsonc_to_serde(j: jsonc_parser::JsonValue) -> serde_json::Value { - use jsonc_parser::JsonValue; - use serde_json::Value; - use std::str::FromStr; - match j { - JsonValue::Array(arr) => { - let vec = arr.into_iter().map(jsonc_to_serde).collect(); - Value::Array(vec) - } - JsonValue::Boolean(bool) => Value::Bool(bool), - JsonValue::Null => Value::Null, - JsonValue::Number(num) => { - let number = - serde_json::Number::from_str(&num).expect("could not parse number"); - Value::Number(number) - } - JsonValue::Object(obj) => { - let mut map = serde_json::map::Map::new(); - for (key, json_value) in obj.into_iter() { - map.insert(key, jsonc_to_serde(json_value)); - } - Value::Object(map) - } - JsonValue::String(str) => Value::String(str), - } -} - -#[test] -fn web_platform_tests() { - use deno_core::serde::Deserialize; - - #[derive(Deserialize)] - #[serde(untagged)] - enum WptConfig { - Simple(String), - #[serde(rename_all = "camelCase")] - Options { - name: String, - expect_fail: Vec<String>, - }, - } - - let text = - std::fs::read_to_string(util::tests_path().join("wpt.jsonc")).unwrap(); - let jsonc = jsonc_parser::parse_to_value(&text).unwrap().unwrap(); - let config: std::collections::HashMap<String, Vec<WptConfig>> = - deno_core::serde_json::from_value(jsonc_to_serde(jsonc)).unwrap(); - - for (suite_name, includes) in config.into_iter() { - let suite_path = util::wpt_path().join(suite_name); - let dir = WalkDir::new(&suite_path) - .into_iter() - .filter_map(Result::ok) - .filter(|e| e.file_type().is_file()) - .filter(|f| { - let filename = f.file_name().to_str().unwrap(); - filename.ends_with(".any.js") - || filename.ends_with(".window.js") - || filename.ends_with(".worker.js") - }) - .filter_map(|f| { - let path = f - .path() - .strip_prefix(&suite_path) - .unwrap() - .to_str() - .unwrap(); - for cfg in &includes { - match cfg { - WptConfig::Simple(name) if path.starts_with(name) => { - return Some((f.path().to_owned(), vec![])) - } - WptConfig::Options { name, expect_fail } - if path.starts_with(name) => - { - return Some((f.path().to_owned(), expect_fail.to_vec())) - } - _ => {} - } - } - None - }); - - let testharness_path = util::wpt_path().join("resources/testharness.js"); - let testharness_text = std::fs::read_to_string(&testharness_path) - .unwrap() - .replace("output:true", "output:false"); - let testharnessreporter_path = - util::tests_path().join("wpt_testharnessconsolereporter.js"); - let testharnessreporter_text = - std::fs::read_to_string(&testharnessreporter_path).unwrap(); - - for (test_file_path, expect_fail) in dir { - let test_file_text = std::fs::read_to_string(&test_file_path).unwrap(); - let imports: Vec<(PathBuf, String)> = test_file_text - .split('\n') - .into_iter() - .filter_map(|t| { - // Hack: we don't implement `importScripts()`, and instead capture the - // parameter in source code; see `concat_bundle()` for more details. - if let Some(rest_import_scripts) = t.strip_prefix("importScripts(\"") - { - if let Some(import_path) = rest_import_scripts.strip_suffix("\");") - { - // The code in `testharness.js` silences the test outputs. - if import_path != "/resources/testharness.js" { - return Some(import_path); - } - } - } - t.strip_prefix("// META: script=") - }) - .map(|s| { - let s = if s == "/resources/WebIDLParser.js" { - "/resources/webidl2/lib/webidl2.js" - } else { - s - }; - if s.starts_with('/') { - util::wpt_path().join(format!(".{}", s)) - } else { - test_file_path.parent().unwrap().join(s) - } - }) - .map(|path| { - let text = std::fs::read_to_string(&path).unwrap(); - (path, text) - }) - .collect(); - - let mut variants: Vec<&str> = test_file_text - .split('\n') - .into_iter() - .filter_map(|t| t.strip_prefix("// META: variant=")) - .collect(); - - if variants.is_empty() { - variants.push(""); - } - - for variant in variants { - let mut files = Vec::with_capacity(3 + imports.len()); - files.push((testharness_path.clone(), testharness_text.clone())); - files.push(( - testharnessreporter_path.clone(), - testharnessreporter_text.clone(), - )); - files.extend(imports.clone()); - files.push((test_file_path.clone(), test_file_text.clone())); - - let mut file = tempfile::Builder::new() - .prefix("wpt-bundle-") - .suffix(".js") - .rand_bytes(5) - .tempfile() - .unwrap(); - - let bundle = concat_bundle(files, file.path(), "".to_string()); - file.write_all(bundle.as_bytes()).unwrap(); - - let child = util::deno_cmd() - .current_dir(test_file_path.parent().unwrap()) - .arg("run") - .arg("--location") - .arg(&format!("http://web-platform-tests/?{}", variant)) - .arg("-A") - .arg(file.path()) - .arg(deno_core::serde_json::to_string(&expect_fail).unwrap()) - .arg("--quiet") - .stdin(std::process::Stdio::piped()) - .spawn() - .unwrap(); - - let output = child.wait_with_output().unwrap(); - if !output.status.success() { - file.keep().unwrap(); - } - assert!(output.status.success()); - } - } - } -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resolve_dns() { use std::collections::BTreeMap; diff --git a/cli/tests/wpt.jsonc b/cli/tests/wpt.jsonc deleted file mode 100644 index e207a9f90..000000000 --- a/cli/tests/wpt.jsonc +++ /dev/null @@ -1,250 +0,0 @@ -{ - "streams": [ - // "piping/abort", - // "piping/close-propagation-backward", - // "piping/close-propagation-forward", - // "piping/error-propagation-backward", - // "piping/error-propagation-forward", - "piping/flow-control", - // "piping/general", - "piping/multiple-propagation", - "piping/pipe-through", - "piping/then-interception", - // "piping/throwing-options", - // "piping/transform-streams", - "queuing-strategies.any", - // "readable-byte-streams", - // "readable-streams/async-iterator", - // "readable-streams/bad-strategies", - // "readable-streams/bad-underlying-source", - // "readable-streams/cancel", - // "readable-streams/constructor", - "readable-streams/count-queuing-strategy-integration", - "readable-streams/default-reader", - "readable-streams/floating-point-total-queue-size", - "readable-streams/garbage-collection", - "readable-streams/general", - { - "name": "readable-streams/patched-global", - "expectFail": [ - "ReadableStream async iterator should use the original values of getReader() and ReadableStreamDefaultReader methods" - ] - }, - "readable-streams/reentrant-strategies", - "readable-streams/tee", - // "readable-streams/templated", - "transform-streams/backpressure", - "transform-streams/errors", - "transform-streams/flush", - "transform-streams/general", - "transform-streams/lipfuzz", - // "transform-streams/patched-global", - "transform-streams/properties", - "transform-streams/reentrant-strategies", - "transform-streams/strategies", - // "transform-streams/terminate", - // "writable-streams/aborting", - // "writable-streams/bad-strategies", - "writable-streams/bad-underlying-sinks", - "writable-streams/byte-length-queuing-strategy", - // "writable-streams/close", - // "writable-streams/constructor", - "writable-streams/count-queuing-strategy", - "writable-streams/error", - "writable-streams/floating-point-total-queue-size", - "writable-streams/general", - "writable-streams/properties", - "writable-streams/reentrant-strategy", - "writable-streams/start", - "writable-streams/write" - ], - "encoding": [ - "api-basics", - "api-invalid-label", - "api-replacement-encodings", - "api-surrogates-utf8", - // TODO(lucacasonato): enable encodeInto. We have a bug in implementaiton. - // { - // "name": "encodeInto", - // "expectFail": [ - // "encodeInto() and a detached output buffer" - // ] - // }, - // "encodeInto", - // TODO(lucacasonato): enable when we support iso-2022-jp - // "iso-2022-jp-decoder", - // TODO(lucacasonato): uses XMLHttpRequest unnecessarily. should be fixed upstream before enabling - // "replacement-encodings", - "textdecoder-byte-order-marks", - { - "name": "textdecoder-copy", - "expectFail": [ - // TODO(lucacasonato): enable when we have stream support - "Modify buffer after passing it in (ArrayBuffer)", - "Modify buffer after passing it in (SharedArrayBuffer)" - ] - }, - "textdecoder-fatal-single-byte", - "textdecoder-fatal.", - "textdecoder-ignorebom", - { - "name": "textdecoder-labels", - "expectFail": [ - "cseucpkdfmtjapanese => EUC-JP", - "euc-jp => EUC-JP", - "x-euc-jp => EUC-JP", - "csiso2022jp => ISO-2022-JP", - "iso-2022-jp => ISO-2022-JP", - "csshiftjis => Shift_JIS", - "ms932 => Shift_JIS", - "ms_kanji => Shift_JIS", - "shift-jis => Shift_JIS", - "shift_jis => Shift_JIS", - "sjis => Shift_JIS", - "windows-31j => Shift_JIS", - "x-sjis => Shift_JIS", - "cseuckr => EUC-KR", - "csksc56011987 => EUC-KR", - "euc-kr => EUC-KR", - "iso-ir-149 => EUC-KR", - "korean => EUC-KR", - "ks_c_5601-1987 => EUC-KR", - "ks_c_5601-1989 => EUC-KR", - "ksc5601 => EUC-KR", - "ksc_5601 => EUC-KR", - "windows-949 => EUC-KR", - "x-user-defined => x-user-defined" - ] - }, - // TODO(lucacasonato): enable when we have stream support - // "textdecoder-streaming", - "textdecoder-utf16-surrogates", - { - "name": "textencoder-constructor-non-utf", - "expectFail": [ - "Encoding argument supported for decode: EUC-JP", - "Encoding argument supported for decode: ISO-2022-JP", - "Encoding argument supported for decode: Shift_JIS", - "Encoding argument supported for decode: EUC-KR", - "Encoding argument supported for decode: x-user-defined" - ] - }, - "textencoder-utf16-surrogates", - "legacy-mb-schinese" - // TODO(lucacasonato): uses XMLHttpRequest unnecessarily. should be fixed upstream before enabling - // "unsupported-encodings", - ], - "dom": [ - "abort/event" - ], - "hr-time": [ - "monotonic-clock" - ], - "html": [ - "webappapis/microtask-queuing/queue-microtask-exceptions.any", - "webappapis/microtask-queuing/queue-microtask.any", - "webappapis/timers" - ], - "user-timing": [ - "clear_all_marks", - "clear_all_measures", - "clear_non_existent_mark", - "clear_non_existent_measure", - "clear_one_mark", - "clear_one_measure", - "entry_type", - "mark-entry-constructor", - "mark-errors", - "mark-measure-return-objects", - "mark.any", - "measure_syntax_err", - "measure-l3", - "structured-serialize-detail", - "user_timing_exists" - ], - "wasm": [ - "jsapi/constructor/compile", - "jsapi/constructor/multi-value", - "jsapi/constructor/toStringTag", - "jsapi/constructor/validate", - "jsapi/global/constructor", - "jsapi/global/toString", - "jsapi/global/value-get-set", - "jsapi/global/valueOf", - "jsapi/instance/toString", - "jsapi/instance/constructor-caching", - "jsapi/memory/toString", - "jsapi/module/constructor", - "jsapi/module/customSections", - "jsapi/module/exports", - "jsapi/module/imports", - "jsapi/module/toString", - "jsapi/table/get-set", - "jsapi/table/toString", - "webapi/body", - "webapi/invalid-args", - "webapi/rejected-arg", - "webapi/status", - "webapi/create_multiple_memory", - "create_multiple_memory" - //FAILING TESTS - // "jsapi/constructor/instantiate-bad-imports", - // "jsapi/constructor/instantiate", - // "jsapi/global/type", - // "jsapi/instance/constructor-bad-imports", - // "jsapi/instance/constructor", - // "jsapi/instance/exports", - // "jsapi/memory/buffer", - // "jsapi/memory/constructor-shared", - // "jsapi/memory/constructor-types", - // "jsapi/memory/constructor", - // "jsapi/memory/grow", - // "jsapi/memory/type", - // "jsapi/table/constructor-types", - // "jsapi/table/constructor", - // "jsapi/table/grow-reftypes", - // "jsapi/table/grow", - // "jsapi/table/length", - // "jsapi/idlharness", - // "jsapi/instance", - // "jsapi/prototypes", - // "serialization/arraybuffer/transfer" - // "serialization/module/nested-worker-success", - // "serialization/module/serialization-via-idb", - // "serialization/module/serialization-via-notifications-api", - // "webapi/abort", - // "webapi/contenttype", - // "webapi/empty-body", - // "webapi/historical", - // "webapi/idlharness", - // "webapi/instantiateStreaming-bad-imports", - // "webapi/instantiateStreaming", - // "webapi/invalid-code", - // "webapi/origin", - ], - "console": [ - "console-is-a-namespace", - "console-label-conversion", - "console-namespace-object-class-string", - "console-tests-historical" - ], - "WebCryptoApi": [ - "getRandomValues" - ], - "WebIDL": [ - "ecmascript-binding/es-exceptions/DOMException-constants", - "ecmascript-binding/es-exceptions/DOMException-constructor-and-prototype", - "ecmascript-binding/es-exceptions/DOMException-constructor-behavior", - { - "name": "ecmascript-binding/es-exceptions/DOMException-custom-bindings", - "expectFail": [ - // TODO(kt3k): Enable this test. - // We can pass this test by using Object.setPrototypeOf(...) instead of - // class...extends, but that causes a problem in printing of uncaught - // DOMException. We might need to modify how to print uncaught error in - // `//core/error.rs`. - "does not inherit from Error: class-side" - ] - } - ] -}
\ No newline at end of file diff --git a/cli/tests/wpt_testharnessconsolereporter.js b/cli/tests/wpt_testharnessconsolereporter.js deleted file mode 100644 index 2e0e06c02..000000000 --- a/cli/tests/wpt_testharnessconsolereporter.js +++ /dev/null @@ -1,129 +0,0 @@ -const noColor = globalThis.Deno?.noColor ?? true; -const enabled = !noColor; - -function code(open, close) { - return { - open: `\x1b[${open.join(";")}m`, - close: `\x1b[${close}m`, - regexp: new RegExp(`\\x1b\\[${close}m`, "g"), - }; -} - -function run(str, code) { - return enabled - ? `${code.open}${str.replace(code.regexp, code.open)}${code.close}` - : str; -} - -function red(str) { - return run(str, code([31], 39)); -} - -export function green(str) { - return run(str, code([32], 39)); -} - -export function yellow(str) { - return run(str, code([33], 39)); -} - -const testResults = []; -const testsExpectFail = JSON.parse(Deno.args[0]); -function shouldExpectFail(name) { - if (testsExpectFail.includes(name)) return true; - for (const expectFail of testsExpectFail) { - if (name.startsWith(expectFail)) return true; - } - return false; -} - -window.add_result_callback(({ message, name, stack, status }) => { - const expectFail = shouldExpectFail(name); - testResults.push({ - name, - passed: status === 0, - expectFail, - message, - stack, - }); - let simpleMessage = `test ${name} ... `; - switch (status) { - case 0: - if (expectFail) { - simpleMessage += red("ok (expected fail)"); - } else { - simpleMessage += green("ok"); - if (Deno.args[1] == "--quiet") { - // don't print `ok` tests if --quiet is enabled - return; - } - } - break; - case 1: - if (expectFail) { - simpleMessage += yellow("failed (expected)"); - } else { - simpleMessage += red("failed"); - } - break; - case 2: - if (expectFail) { - simpleMessage += yellow("failed (expected)"); - } else { - simpleMessage += red("failed (timeout)"); - } - break; - case 3: - if (expectFail) { - simpleMessage += yellow("failed (expected)"); - } else { - simpleMessage += red("failed (incomplete)"); - } - break; - } - - console.log(simpleMessage); -}); - -window.add_completion_callback((tests, harnessStatus) => { - const failed = testResults.filter((t) => !t.expectFail && !t.passed); - const expectedFailedButPassed = testResults.filter((t) => - t.expectFail && t.passed - ); - const expectedFailedButPassedCount = expectedFailedButPassed.length; - const failedCount = failed.length + expectedFailedButPassedCount; - const expectedFailedAndFailedCount = testResults.filter((t) => - t.expectFail && !t.passed - ).length; - const totalCount = testResults.length; - const passedCount = totalCount - failedCount - expectedFailedAndFailedCount; - - if (failed.length > 0) { - console.log(`\nfailures:`); - } - for (const result of failed) { - console.log( - `\n${result.name}\n${result.message}\n${result.stack}`, - ); - } - - if (failed.length > 0) { - console.log(`\nfailures:\n`); - } - for (const result of failed) { - console.log(` ${result.name}`); - } - if (expectedFailedButPassedCount > 0) { - console.log(`\nexpected failures that passed:\n`); - } - for (const result of expectedFailedButPassed) { - console.log(` ${result.name}`); - } - console.log( - `\ntest result: ${ - failedCount > 0 ? red("failed") : green("ok") - }. ${passedCount} passed; ${failedCount} failed; ${expectedFailedAndFailedCount} expected failure; total ${totalCount}\n`, - ); - - Deno.exit(failedCount > 0 ? 1 : 0); -}); |