From cc38810f50fa4d9628efd0a5518c87f527a9a3ae Mon Sep 17 00:00:00 2001 From: Iban Eguia Moraza Date: Wed, 12 Apr 2023 11:44:42 +0200 Subject: [PATCH] Removed the boa_testing crate --- Cargo.lock | 10 +- Cargo.toml | 12 +- boa_runtime/Cargo.toml | 2 +- boa_runtime/src/console/tests.rs | 2 +- boa_runtime/src/lib.rs | 204 +++++++++++++++++++ boa_testing/Cargo.toml | 15 -- boa_testing/src/lib.rs | 327 ------------------------------- 7 files changed, 212 insertions(+), 360 deletions(-) delete mode 100644 boa_testing/Cargo.toml delete mode 100644 boa_testing/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c594b741af2..6188a15a7d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,9 +534,9 @@ version = "0.16.0" dependencies = [ "boa_engine", "boa_gc", - "boa_testing", "indoc", "rustc-hash", + "textwrap 0.16.0", ] [[package]] @@ -562,14 +562,6 @@ dependencies = [ "toml 0.7.3", ] -[[package]] -name = "boa_testing" -version = "0.16.0" -dependencies = [ - "boa_engine", - "textwrap 0.16.0", -] - [[package]] name = "boa_unicode" version = "0.16.0" diff --git a/Cargo.toml b/Cargo.toml index 06c6c4ad02f..d47cb01a06e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "boa_profiler", "boa_runtime", "boa_tester", - "boa_testing", "boa_unicode", "boa_wasm", ] @@ -28,17 +27,16 @@ license = "Unlicense/MIT" description = "Boa is a Javascript lexer, parser and compiler written in Rust. Currently, it has support for some of the language." [workspace.dependencies] +boa_ast = { version = "0.16.0", path = "boa_ast" } boa_engine = { version = "0.16.0", path = "boa_engine" } -boa_interner = { version = "0.16.0", path = "boa_interner" } boa_gc = { version = "0.16.0", path = "boa_gc" } -boa_profiler = { version = "0.16.0", path = "boa_profiler" } -boa_unicode = { version = "0.16.0", path = "boa_unicode" } +boa_icu_provider = { version = "0.16.0", path = "boa_icu_provider" } +boa_interner = { version = "0.16.0", path = "boa_interner" } boa_macros = { version = "0.16.0", path = "boa_macros" } -boa_ast = { version = "0.16.0", path = "boa_ast" } boa_parser = { version = "0.16.0", path = "boa_parser" } -boa_icu_provider = { version = "0.16.0", path = "boa_icu_provider" } +boa_profiler = { version = "0.16.0", path = "boa_profiler" } boa_runtime = { version = "0.16.0", path = "boa_runtime" } -boa_testing = { version = "0.16.0", path = "boa_testing" } +boa_unicode = { version = "0.16.0", path = "boa_unicode" } [workspace.metadata.workspaces] allow_branch = "main" diff --git a/boa_runtime/Cargo.toml b/boa_runtime/Cargo.toml index 963a4a88241..d7ab96c0f10 100644 --- a/boa_runtime/Cargo.toml +++ b/boa_runtime/Cargo.toml @@ -17,5 +17,5 @@ boa_gc.workspace = true rustc-hash = "1.1.0" [dev-dependencies] -boa_testing.workspace = true indoc = "2.0.1" +textwrap = "0.16.0" diff --git a/boa_runtime/src/console/tests.rs b/boa_runtime/src/console/tests.rs index b24014254a5..1b030256716 100644 --- a/boa_runtime/src/console/tests.rs +++ b/boa_runtime/src/console/tests.rs @@ -1,6 +1,6 @@ use super::{formatter, Console}; +use crate::test::{run_test_actions, run_test_actions_with, TestAction}; use boa_engine::{property::Attribute, Context, JsValue}; -use boa_testing::{run_test_actions, run_test_actions_with, TestAction}; use indoc::indoc; #[test] diff --git a/boa_runtime/src/lib.rs b/boa_runtime/src/lib.rs index 9169b487b07..965025d997c 100644 --- a/boa_runtime/src/lib.rs +++ b/boa_runtime/src/lib.rs @@ -71,3 +71,207 @@ mod console; #[doc(inline)] pub use console::Console; + +#[cfg(test)] +pub(crate) mod test { + use boa_engine::{builtins, Context, JsResult, JsValue, Source}; + use std::borrow::Cow; + + /// A test action executed in a test function. + #[allow(missing_debug_implementations)] + #[derive(Clone)] + pub(crate) struct TestAction(Inner); + + #[derive(Clone)] + #[allow(dead_code)] + enum Inner { + RunHarness, + Run { + source: Cow<'static, str>, + }, + InspectContext { + op: fn(&mut Context<'_>), + }, + Assert { + source: Cow<'static, str>, + }, + AssertEq { + source: Cow<'static, str>, + expected: JsValue, + }, + AssertWithOp { + source: Cow<'static, str>, + op: fn(JsValue, &mut Context<'_>) -> bool, + }, + AssertOpaqueError { + source: Cow<'static, str>, + expected: JsValue, + }, + AssertNativeError { + source: Cow<'static, str>, + kind: builtins::error::ErrorKind, + message: &'static str, + }, + AssertContext { + op: fn(&mut Context<'_>) -> bool, + }, + } + + impl TestAction { + /// Runs `source`, panicking if the execution throws. + pub(crate) fn run(source: impl Into>) -> Self { + Self(Inner::Run { + source: source.into(), + }) + } + + /// Executes `op` with the currently active context. + /// + /// Useful to make custom assertions that must be done from Rust code. + pub(crate) fn inspect_context(op: fn(&mut Context<'_>)) -> Self { + Self(Inner::InspectContext { op }) + } + } + + /// Executes a list of test actions on a new, default context. + #[track_caller] + pub(crate) fn run_test_actions(actions: impl IntoIterator) { + let context = &mut Context::default(); + run_test_actions_with(actions, context); + } + + /// Executes a list of test actions on the provided context. + #[track_caller] + #[allow(clippy::too_many_lines, clippy::missing_panics_doc)] + pub(crate) fn run_test_actions_with( + actions: impl IntoIterator, + context: &mut Context<'_>, + ) { + #[track_caller] + fn forward_val(context: &mut Context<'_>, source: &str) -> JsResult { + context.eval_script(Source::from_bytes(source)) + } + + #[track_caller] + fn fmt_test(source: &str, test: usize) -> String { + format!( + "\n\nTest case {test}: \n```\n{}\n```", + textwrap::indent(source, " ") + ) + } + + // Some unwrapping patterns look weird because they're replaceable + // by simpler patterns like `unwrap_or_else` or `unwrap_err + let mut i = 1; + for action in actions.into_iter().map(|a| a.0) { + match action { + Inner::RunHarness => { + // add utility functions for testing + // TODO: extract to a file + forward_val( + context, + r#" + function equals(a, b) { + if (Array.isArray(a) && Array.isArray(b)) { + return arrayEquals(a, b); + } + return a === b; + } + function arrayEquals(a, b) { + return Array.isArray(a) && + Array.isArray(b) && + a.length === b.length && + a.every((val, index) => equals(val, b[index])); + } + "#, + ) + .expect("failed to evaluate test harness"); + } + Inner::Run { source } => { + if let Err(e) = forward_val(context, &source) { + panic!("{}\nUncaught {e}", fmt_test(&source, i)); + } + } + Inner::InspectContext { op } => { + op(context); + } + Inner::Assert { source } => { + let val = match forward_val(context, &source) { + Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), + Ok(v) => v, + }; + let Some(val) = val.as_boolean() else { + panic!( + "{}\nTried to assert with the non-boolean value `{}`", + fmt_test(&source, i), + val.display() + ) + }; + assert!(val, "{}", fmt_test(&source, i)); + i += 1; + } + Inner::AssertEq { source, expected } => { + let val = match forward_val(context, &source) { + Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), + Ok(v) => v, + }; + assert_eq!(val, expected, "{}", fmt_test(&source, i)); + i += 1; + } + Inner::AssertWithOp { source, op } => { + let val = match forward_val(context, &source) { + Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), + Ok(v) => v, + }; + assert!(op(val, context), "{}", fmt_test(&source, i)); + i += 1; + } + Inner::AssertOpaqueError { source, expected } => { + let err = match forward_val(context, &source) { + Ok(v) => panic!( + "{}\nExpected error, got value `{}`", + fmt_test(&source, i), + v.display() + ), + Err(e) => e, + }; + let Some(err) = err.as_opaque() else { + panic!("{}\nExpected opaque error, got native error `{}`", fmt_test(&source, i), err) + }; + + assert_eq!(err, &expected, "{}", fmt_test(&source, i)); + i += 1; + } + Inner::AssertNativeError { + source, + kind, + message, + } => { + let err = match forward_val(context, &source) { + Ok(v) => panic!( + "{}\nExpected error, got value `{}`", + fmt_test(&source, i), + v.display() + ), + Err(e) => e, + }; + let native = match err.try_native(context) { + Ok(err) => err, + Err(e) => panic!( + "{}\nCouldn't obtain a native error: {e}", + fmt_test(&source, i) + ), + }; + + assert_eq!(&native.kind, &kind, "{}", fmt_test(&source, i)); + assert_eq!(native.message(), message, "{}", fmt_test(&source, i)); + i += 1; + } + Inner::AssertContext { op } => { + assert!(op(context), "Test case {i}"); + i += 1; + } + } + } + } +} diff --git a/boa_testing/Cargo.toml b/boa_testing/Cargo.toml deleted file mode 100644 index 12b4bf7a143..00000000000 --- a/boa_testing/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "boa_testing" -description = "Helper crate for Boa testing." -keywords = ["javascript", "js", "testing"] -publich = false -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true -repository.workspace = true -rust-version.workspace = true - -[dependencies] -boa_engine.workspace = true -textwrap = "0.16.0" diff --git a/boa_testing/src/lib.rs b/boa_testing/src/lib.rs deleted file mode 100644 index 07f53eded50..00000000000 --- a/boa_testing/src/lib.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! Helper crate used for testing Boa - -#![doc( - html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg" -)] -#![cfg_attr(not(test), forbid(clippy::unwrap_used))] -#![warn(missing_docs, clippy::dbg_macro)] -#![deny( - // rustc lint groups https://doc.rust-lang.org/rustc/lints/groups.html - warnings, - future_incompatible, - let_underscore, - nonstandard_style, - rust_2018_compatibility, - rust_2018_idioms, - rust_2021_compatibility, - unused, - - // rustc allowed-by-default lints https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html - macro_use_extern_crate, - meta_variable_misuse, - missing_abi, - missing_copy_implementations, - missing_debug_implementations, - non_ascii_idents, - noop_method_call, - single_use_lifetimes, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unsafe_op_in_unsafe_fn, - unused_crate_dependencies, - unused_import_braces, - unused_lifetimes, - unused_qualifications, - unused_tuple_struct_fields, - variant_size_differences, - - // rustdoc lints https://doc.rust-lang.org/rustdoc/lints.html - rustdoc::broken_intra_doc_links, - rustdoc::private_intra_doc_links, - rustdoc::missing_crate_level_docs, - rustdoc::private_doc_tests, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_rust_codeblocks, - rustdoc::bare_urls, - - // clippy categories https://doc.rust-lang.org/clippy/ - clippy::all, - clippy::correctness, - clippy::suspicious, - clippy::style, - clippy::complexity, - clippy::perf, - clippy::pedantic, - clippy::nursery, - clippy::undocumented_unsafe_blocks -)] -#![allow( - clippy::module_name_repetitions, - clippy::redundant_pub_crate, - clippy::let_unit_value -)] - -use boa_engine::{builtins, Context, JsResult, JsValue, Source}; -use std::borrow::Cow; - -/// A test action executed in a test function. -#[allow(missing_debug_implementations)] -#[derive(Clone)] -pub struct TestAction(Inner); - -#[derive(Clone)] -#[allow(dead_code)] -enum Inner { - RunHarness, - Run { - source: Cow<'static, str>, - }, - InspectContext { - op: fn(&mut Context<'_>), - }, - Assert { - source: Cow<'static, str>, - }, - AssertEq { - source: Cow<'static, str>, - expected: JsValue, - }, - AssertWithOp { - source: Cow<'static, str>, - op: fn(JsValue, &mut Context<'_>) -> bool, - }, - AssertOpaqueError { - source: Cow<'static, str>, - expected: JsValue, - }, - AssertNativeError { - source: Cow<'static, str>, - kind: builtins::error::ErrorKind, - message: &'static str, - }, - AssertContext { - op: fn(&mut Context<'_>) -> bool, - }, -} - -impl TestAction { - /// Evaluates some utility functions used in tests. - pub const fn run_harness() -> Self { - Self(Inner::RunHarness) - } - - /// Runs `source`, panicking if the execution throws. - pub fn run(source: impl Into>) -> Self { - Self(Inner::Run { - source: source.into(), - }) - } - - /// Executes `op` with the currently active context. - /// - /// Useful to make custom assertions that must be done from Rust code. - pub fn inspect_context(op: fn(&mut Context<'_>)) -> Self { - Self(Inner::InspectContext { op }) - } - - /// Asserts that evaluating `source` returns the `true` value. - pub fn assert(source: impl Into>) -> Self { - Self(Inner::Assert { - source: source.into(), - }) - } - - /// Asserts that the script returns `expected` when evaluating `source`. - pub fn assert_eq(source: impl Into>, expected: impl Into) -> Self { - Self(Inner::AssertEq { - source: source.into(), - expected: expected.into(), - }) - } - - /// Asserts that calling `op` with the value obtained from evaluating `source` returns `true`. - /// - /// Useful to check properties of the obtained value that cannot be checked from JS code. - pub fn assert_with_op( - source: impl Into>, - op: fn(JsValue, &mut Context<'_>) -> bool, - ) -> Self { - Self(Inner::AssertWithOp { - source: source.into(), - op, - }) - } - - /// Asserts that evaluating `source` throws the opaque error `value`. - pub fn assert_opaque_error( - source: impl Into>, - value: impl Into, - ) -> Self { - Self(Inner::AssertOpaqueError { - source: source.into(), - expected: value.into(), - }) - } - - /// Asserts that evaluating `source` throws a native error of `kind` and `message`. - pub fn assert_native_error( - source: impl Into>, - kind: builtins::error::ErrorKind, - message: &'static str, - ) -> Self { - Self(Inner::AssertNativeError { - source: source.into(), - kind, - message, - }) - } - - /// Asserts that calling `op` with the currently executing context returns `true`. - pub fn assert_context(op: fn(&mut Context<'_>) -> bool) -> Self { - Self(Inner::AssertContext { op }) - } -} - -/// Executes a list of test actions on a new, default context. -#[track_caller] -pub fn run_test_actions(actions: impl IntoIterator) { - let context = &mut Context::default(); - run_test_actions_with(actions, context); -} - -/// Executes a list of test actions on the provided context. -#[track_caller] -#[allow(clippy::too_many_lines, clippy::missing_panics_doc)] -pub fn run_test_actions_with( - actions: impl IntoIterator, - context: &mut Context<'_>, -) { - #[track_caller] - fn forward_val(context: &mut Context<'_>, source: &str) -> JsResult { - context.eval_script(Source::from_bytes(source)) - } - - #[track_caller] - fn fmt_test(source: &str, test: usize) -> String { - format!( - "\n\nTest case {test}: \n```\n{}\n```", - textwrap::indent(source, " ") - ) - } - - // Some unwrapping patterns look weird because they're replaceable - // by simpler patterns like `unwrap_or_else` or `unwrap_err - let mut i = 1; - for action in actions.into_iter().map(|a| a.0) { - match action { - Inner::RunHarness => { - // add utility functions for testing - // TODO: extract to a file - forward_val( - context, - r#" - function equals(a, b) { - if (Array.isArray(a) && Array.isArray(b)) { - return arrayEquals(a, b); - } - return a === b; - } - function arrayEquals(a, b) { - return Array.isArray(a) && - Array.isArray(b) && - a.length === b.length && - a.every((val, index) => equals(val, b[index])); - } - "#, - ) - .expect("failed to evaluate test harness"); - } - Inner::Run { source } => { - if let Err(e) = forward_val(context, &source) { - panic!("{}\nUncaught {e}", fmt_test(&source, i)); - } - } - Inner::InspectContext { op } => { - op(context); - } - Inner::Assert { source } => { - let val = match forward_val(context, &source) { - Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), - Ok(v) => v, - }; - let Some(val) = val.as_boolean() else { - panic!( - "{}\nTried to assert with the non-boolean value `{}`", - fmt_test(&source, i), - val.display() - ) - }; - assert!(val, "{}", fmt_test(&source, i)); - i += 1; - } - Inner::AssertEq { source, expected } => { - let val = match forward_val(context, &source) { - Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), - Ok(v) => v, - }; - assert_eq!(val, expected, "{}", fmt_test(&source, i)); - i += 1; - } - Inner::AssertWithOp { source, op } => { - let val = match forward_val(context, &source) { - Err(e) => panic!("{}\nUncaught {e}", fmt_test(&source, i)), - Ok(v) => v, - }; - assert!(op(val, context), "{}", fmt_test(&source, i)); - i += 1; - } - Inner::AssertOpaqueError { source, expected } => { - let err = match forward_val(context, &source) { - Ok(v) => panic!( - "{}\nExpected error, got value `{}`", - fmt_test(&source, i), - v.display() - ), - Err(e) => e, - }; - let Some(err) = err.as_opaque() else { - panic!("{}\nExpected opaque error, got native error `{}`", fmt_test(&source, i), err) - }; - - assert_eq!(err, &expected, "{}", fmt_test(&source, i)); - i += 1; - } - Inner::AssertNativeError { - source, - kind, - message, - } => { - let err = match forward_val(context, &source) { - Ok(v) => panic!( - "{}\nExpected error, got value `{}`", - fmt_test(&source, i), - v.display() - ), - Err(e) => e, - }; - let native = match err.try_native(context) { - Ok(err) => err, - Err(e) => panic!( - "{}\nCouldn't obtain a native error: {e}", - fmt_test(&source, i) - ), - }; - - assert_eq!(&native.kind, &kind, "{}", fmt_test(&source, i)); - assert_eq!(native.message(), message, "{}", fmt_test(&source, i)); - i += 1; - } - Inner::AssertContext { op } => { - assert!(op(context), "Test case {i}"); - i += 1; - } - } - } -}