From 7585a8dc73e3d0a82d6d6df1efafc0a71708e840 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 23 Sep 2024 15:34:13 -0700 Subject: [PATCH 01/15] Add a URL class (with caveats) Some methods are NOT currently supported (some don' make sense outside of a browser context). They are still implemented but will throw a JavaScript Error. Supported methods should follow the specification perfectly. --- Cargo.lock | 1 + cli/src/main.rs | 11 +- core/runtime/Cargo.toml | 5 + core/runtime/src/console/mod.rs | 4 +- core/runtime/src/lib.rs | 47 ++++++ core/runtime/src/url.rs | 279 ++++++++++++++++++++++++++++++++ core/string/src/lib.rs | 13 ++ 7 files changed, 350 insertions(+), 10 deletions(-) create mode 100644 core/runtime/src/url.rs diff --git a/Cargo.lock b/Cargo.lock index 4727d3126ad..55c5fd59a38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -540,6 +540,7 @@ dependencies = [ "indoc", "rustc-hash 2.0.0", "textwrap", + "url", ] [[package]] diff --git a/cli/src/main.rs b/cli/src/main.rs index d43335df528..899b73f3139 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -14,15 +14,12 @@ use boa_engine::{ builtins::promise::PromiseState, context::ContextBuilder, job::{FutureJob, JobQueue, NativeJob}, - js_string, module::{Module, SimpleModuleLoader}, optimizer::OptimizerOptions, - property::Attribute, script::Script, vm::flowgraph::{Direction, Graph}, Context, JsError, JsNativeError, JsResult, Source, }; -use boa_runtime::Console; use clap::{Parser, ValueEnum, ValueHint}; use colored::Colorize; use debug::init_boa_debug_object; @@ -442,12 +439,10 @@ fn main() -> Result<(), io::Error> { Ok(()) } -/// Adds the CLI runtime to the context. +/// Adds the CLI runtime to the context with default options. fn add_runtime(context: &mut Context) { - let console = Console::init(context); - context - .register_global_property(js_string!(Console::NAME), console, Attribute::all()) - .expect("the console object shouldn't exist"); + boa_runtime::register(context, boa_runtime::RegisterOptions::new()) + .expect("should not fail while registering the runtime"); } #[derive(Default)] diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 62a0a4907f6..95c743b9841 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,6 +15,7 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } +url = { version = "2.5.2", optional = true } [dev-dependencies] indoc.workspace = true @@ -25,3 +26,7 @@ workspace = true [package.metadata.docs.rs] all-features = true + +[features] +default = ["all"] +all = ["url"] diff --git a/core/runtime/src/console/mod.rs b/core/runtime/src/console/mod.rs index 2eda34cb586..70bc45ad75a 100644 --- a/core/runtime/src/console/mod.rs +++ b/core/runtime/src/console/mod.rs @@ -58,8 +58,8 @@ pub trait Logger: Trace + Sized { /// Implements the [`Logger`] trait and output errors to stderr and all /// the others to stdout. Will add indentation based on the number of /// groups. -#[derive(Trace, Finalize)] -struct DefaultLogger; +#[derive(Debug, Trace, Finalize)] +pub struct DefaultLogger; impl Logger for DefaultLogger { #[inline] diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 58fbe5116cf..62e67bc4fd9 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -61,6 +61,53 @@ mod text; #[doc(inline)] pub use text::{TextDecoder, TextEncoder}; +pub mod url; + +/// Options used when registering all built-in objects and functions of the WebAPI runtime. +#[derive(Debug)] +pub struct RegisterOptions { + console_logger: L, +} + +impl Default for RegisterOptions { + fn default() -> Self { + Self { + console_logger: console::DefaultLogger, + } + } +} + +impl RegisterOptions { + /// Create a new `RegisterOptions` with the default options. + pub fn new() -> Self { + Self::default() + } +} + +impl RegisterOptions { + /// Set the logger for the console object. + pub fn with_console_logger(self, logger: L2) -> RegisterOptions { + RegisterOptions:: { + console_logger: logger, + } + } +} + +/// Register all the built-in objects and functions of the WebAPI runtime. +pub fn register( + ctx: &mut boa_engine::Context, + options: RegisterOptions, +) -> boa_engine::JsResult<()> { + Console::register_with_logger(ctx, options.console_logger)?; + TextDecoder::register(ctx)?; + TextEncoder::register(ctx)?; + + #[cfg(feature = "url")] + url::Url::register(ctx)?; + + Ok(()) +} + #[cfg(test)] pub(crate) mod test { use boa_engine::{builtins, Context, JsResult, JsValue, Source}; diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs new file mode 100644 index 00000000000..c67cd68610d --- /dev/null +++ b/core/runtime/src/url.rs @@ -0,0 +1,279 @@ +//! Boa's implementation of JavaScript's `URL` Web API class. +//! +//! The `URL` class can be instantiated from any global object. +//! This relies on the `url` feature. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [WHATWG `URL` specification][spec] +//! +//! [spec]: https://url.spec.whatwg.org/ +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/URL +#![cfg(feature = "url")] + +use boa_engine::value::Convert; +use boa_engine::{ + js_error, js_string, Context, Finalize, JsData, JsResult, JsString, JsValue, Trace, +}; +use boa_interop::{js_class, IntoJsFunctionCopied, JsClass}; +use std::fmt::Display; + +/// The `URL` class represents a (properly parsed) Uniform Resource Locator. +#[derive(Debug, Clone, JsData, Trace, Finalize)] +pub struct Url(#[unsafe_ignore_trace] url::Url); + +impl Url { + /// Register the `URL` class into the realm. + /// + /// # Errors + /// This will error if the context or realm cannot register the class. + pub fn register(context: &mut Context) -> JsResult<()> { + context.register_global_class::()?; + Ok(()) + } + + /// Create a new `URL` object. Meant to be called from the JavaScript constructor. + /// + /// # Errors + /// Any errors that might occur during URL parsing. + fn js_new(Convert(ref url): Convert, base: Option>) -> JsResult { + if let Some(Convert(ref base)) = base { + let base_url = url::Url::parse(&base) + .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; + if base_url.cannot_be_a_base() { + return Err(js_error!(TypeError: "Base URL {} cannot be a base", base)); + } + + let url = base_url + .join(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } else { + let url = url::Url::parse(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } + } +} + +impl Display for Url { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for Url { + fn from(url: url::Url) -> Self { + Self(url) + } +} + +impl From for url::Url { + fn from(url: Url) -> url::Url { + // Cannot avoid cloning here, unfortunately, as we would need to replace + // the internal URL with something else. + url.0.clone() + } +} + +js_class! { + class Url as "URL" { + property hash { + fn get(this: JsClass) -> JsString { + if let Some(f) = this.borrow().0.fragment() { + JsString::from(format!("#{}", f)) + } else { + js_string!("") + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + this.borrow_mut().0.set_fragment(None); + } else { + if let Some(fragment) = value.0.strip_prefix('#') { + this.borrow_mut().0.set_fragment(Some(fragment)); + } else { + this.borrow_mut().0.set_fragment(Some(&value.0)); + } + } + } + } + + property host { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.host_str().unwrap_or("")) + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_host(None); + } else { + let _ = this.borrow_mut().0.set_host(Some(&value.0)); + } + } + } + + property hostname { + fn get(this: JsClass) -> JsString { + let host = this.borrow().0.host_str().unwrap_or("").to_string(); + if let Some(port) = this.borrow().0.port() { + JsString::from(format!("{}:{}", host, port)) + } else { + JsString::from(host) + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_host(None); + } else { + let _ = this.borrow_mut().0.set_host(Some(&value.0)); + } + } + } + + property href { + fn get(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) -> JsResult<()> { + let url = url::Url::parse(&value.0) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + *this.borrow_mut() = url.into(); + Ok(()) + } + } + + property origin { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.origin().ascii_serialization()) + } + } + + property password { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.password().unwrap_or("").to_string()) + } + + fn set(this: JsClass, value: Convert) { + let _ = this.borrow_mut().0.set_password(Some(&value.0)); + } + } + + property pathname { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.path()) + } + + fn set(this: JsClass, value: Convert) { + this.borrow_mut().0.set_path(&value.0); + } + } + + property port { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.port().map_or(String::new(), |p| p.to_string()).to_string()) + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_port(None); + } else if let Ok(value) = value.0.to_std_string_lossy().parse::() { + let _ = this.borrow_mut().0.set_port(Some(value)); + } + } + } + + property protocol { + fn get(this: JsClass) -> JsString { + // The URL crate returns without a colon, but the web API requires it. + JsString::from(format!("{}:", this.borrow().0.scheme())) + } + + fn set(this: JsClass, value: Convert) { + // Ignore errors. + let _ = this.borrow_mut().0.set_scheme(&value.0); + } + } + + property search { + fn get(this: JsClass) -> JsString { + if let Some(query) = this.borrow().0.query() { + JsString::from(format!("?{}", query)) + } else { + js_string!("") + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + this.borrow_mut().0.set_query(None); + } else { + if let Some(query) = value.0.strip_prefix('?') { + this.borrow_mut().0.set_query(Some(query)); + } else { + this.borrow_mut().0.set_query(Some(&value.0)); + } + } + } + } + + property search_params as "searchParams" { + fn get() -> JsResult<()> { + Err(js_error!(Error: "URL.searchParams is not implemented")) + } + } + + property username { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.username()) + } + + fn set(this: JsClass, value: Convert) { + let _ = this.borrow_mut().0.set_username(&value.0); + } + } + + constructor(url: Convert, base: Option>) { + Self::js_new(url, base) + } + + init(class: &mut ClassBuilder) -> JsResult<()> { + let create_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.createObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + let can_parse = (|url: Convert, base: Option>| { + Url::js_new(url, base).is_ok() + }) + .into_js_function_copied(class.context()); + let parse = (|url: Convert, base: Option>, context: &mut Context| { + Url::js_new(url, base) + .map_or(Ok(JsValue::null()), |u| Url::from_data(u, context).map(JsValue::from)) + }) + .into_js_function_copied(class.context()); + let revoke_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.revokeObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + + class + .static_method(js_string!("createObjectURL"), 1, create_object_url) + .static_method(js_string!("canParse"), 2, can_parse) + .static_method(js_string!("parse"), 2, parse) + .static_method(js_string!("revokeObjectUrl"), 1, revoke_object_url); + + Ok(()) + } + + fn to_string as "toString"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + + fn to_json as "toJSON"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + } +} diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index ecacaa1d56a..26922832aea 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -454,6 +454,19 @@ impl JsString { self.to_string_escaped() } + /// Decodes a [`JsString`] into a [`String`], replacing invalid data with the + /// replacement character U+FFFD. + #[inline] + #[must_use] + pub fn to_std_string_lossy(&self) -> String { + self.code_points() + .map(|cp| match cp { + CodePoint::Unicode(c) => c, + CodePoint::UnpairedSurrogate(_) => '\u{FFFD}', + }) + .collect() + } + /// Decodes a [`JsString`] into a [`String`], returning /// /// # Errors From 22558318a44af17b6512a357098cebb441c2cae1 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 23 Sep 2024 21:02:28 -0700 Subject: [PATCH 02/15] Adding tests and using url::quirks for simpler getters/setters --- core/runtime/src/lib.rs | 2 + core/runtime/src/url.rs | 92 ++++++++------------------- core/runtime/src/url/tests.rs | 113 ++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 67 deletions(-) create mode 100644 core/runtime/src/url/tests.rs diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 62e67bc4fd9..d24b9d18a50 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -110,6 +110,7 @@ pub fn register( #[cfg(test)] pub(crate) mod test { + use crate::register; use boa_engine::{builtins, Context, JsResult, JsValue, Source}; use std::borrow::Cow; @@ -173,6 +174,7 @@ pub(crate) mod test { #[track_caller] pub(crate) fn run_test_actions(actions: impl IntoIterator) { let context = &mut Context::default(); + register(context, Default::default()).expect("failed to register WebAPI objects"); run_test_actions_with(actions, context); } diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs index c67cd68610d..d0f61a34205 100644 --- a/core/runtime/src/url.rs +++ b/core/runtime/src/url.rs @@ -11,6 +11,9 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/URL #![cfg(feature = "url")] +#[cfg(test)] +mod tests; + use boa_engine::value::Convert; use boa_engine::{ js_error, js_string, Context, Finalize, JsData, JsResult, JsString, JsValue, Trace, @@ -80,143 +83,98 @@ js_class! { class Url as "URL" { property hash { fn get(this: JsClass) -> JsString { - if let Some(f) = this.borrow().0.fragment() { - JsString::from(format!("#{}", f)) - } else { - js_string!("") - } + JsString::from(url::quirks::hash(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - if value.0.is_empty() { - this.borrow_mut().0.set_fragment(None); - } else { - if let Some(fragment) = value.0.strip_prefix('#') { - this.borrow_mut().0.set_fragment(Some(fragment)); - } else { - this.borrow_mut().0.set_fragment(Some(&value.0)); - } - } + url::quirks::set_hash(&mut this.borrow_mut().0, &value.0); } } - property host { + property hostname { fn get(this: JsClass) -> JsString { - JsString::from(this.borrow().0.host_str().unwrap_or("")) + JsString::from(url::quirks::hostname(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - if value.0.is_empty() { - let _ = this.borrow_mut().0.set_host(None); - } else { - let _ = this.borrow_mut().0.set_host(Some(&value.0)); - } + let _ = url::quirks::set_hostname(&mut this.borrow_mut().0, &value.0); } } - property hostname { + property host { fn get(this: JsClass) -> JsString { - let host = this.borrow().0.host_str().unwrap_or("").to_string(); - if let Some(port) = this.borrow().0.port() { - JsString::from(format!("{}:{}", host, port)) - } else { - JsString::from(host) - } + JsString::from(url::quirks::host(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - if value.0.is_empty() { - let _ = this.borrow_mut().0.set_host(None); - } else { - let _ = this.borrow_mut().0.set_host(Some(&value.0)); - } + let _ = url::quirks::set_host(&mut this.borrow_mut().0, &value.0); } } property href { fn get(this: JsClass) -> JsString { - JsString::from(format!("{}", this.borrow().0)) + JsString::from(url::quirks::href(&this.borrow().0)) } fn set(this: JsClass, value: Convert) -> JsResult<()> { - let url = url::Url::parse(&value.0) - .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; - *this.borrow_mut() = url.into(); - Ok(()) + url::quirks::set_href(&mut this.borrow_mut().0, &value.0) + .map_err(|e| js_error!(TypeError: "Failed to set href: {}", e)) } } property origin { fn get(this: JsClass) -> JsString { - JsString::from(this.borrow().0.origin().ascii_serialization()) + JsString::from(url::quirks::origin(&this.borrow().0)) } } property password { fn get(this: JsClass) -> JsString { - JsString::from(this.borrow().0.password().unwrap_or("").to_string()) + JsString::from(url::quirks::password(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - let _ = this.borrow_mut().0.set_password(Some(&value.0)); + let _ = url::quirks::set_password(&mut this.borrow_mut().0, &value.0); } } property pathname { fn get(this: JsClass) -> JsString { - JsString::from(this.borrow().0.path()) + JsString::from(url::quirks::pathname(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - this.borrow_mut().0.set_path(&value.0); + let _ = url::quirks::set_pathname(&mut this.borrow_mut().0, &value.0); } } property port { fn get(this: JsClass) -> JsString { - JsString::from(this.borrow().0.port().map_or(String::new(), |p| p.to_string()).to_string()) + JsString::from(url::quirks::port(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - if value.0.is_empty() { - let _ = this.borrow_mut().0.set_port(None); - } else if let Ok(value) = value.0.to_std_string_lossy().parse::() { - let _ = this.borrow_mut().0.set_port(Some(value)); - } + let _ = url::quirks::set_port(&mut this.borrow_mut().0, &value.0.to_std_string_lossy()); } } property protocol { fn get(this: JsClass) -> JsString { - // The URL crate returns without a colon, but the web API requires it. - JsString::from(format!("{}:", this.borrow().0.scheme())) + JsString::from(url::quirks::protocol(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - // Ignore errors. - let _ = this.borrow_mut().0.set_scheme(&value.0); + let _ = url::quirks::set_protocol(&mut this.borrow_mut().0, &value.0); } } property search { fn get(this: JsClass) -> JsString { - if let Some(query) = this.borrow().0.query() { - JsString::from(format!("?{}", query)) - } else { - js_string!("") - } + JsString::from(url::quirks::search(&this.borrow().0)) } fn set(this: JsClass, value: Convert) { - if value.0.is_empty() { - this.borrow_mut().0.set_query(None); - } else { - if let Some(query) = value.0.strip_prefix('?') { - this.borrow_mut().0.set_query(Some(query)); - } else { - this.borrow_mut().0.set_query(Some(&value.0)); - } - } + url::quirks::set_search(&mut this.borrow_mut().0, &value.0); } } diff --git a/core/runtime/src/url/tests.rs b/core/runtime/src/url/tests.rs new file mode 100644 index 00000000000..bca79102cb8 --- /dev/null +++ b/core/runtime/src/url/tests.rs @@ -0,0 +1,113 @@ +use crate::test::{run_test_actions, TestAction}; + +const TEST_HARNESS: &'static str = r#" +function assert(condition, message) { + if (!condition) { + if (!message) { + message = "Assertion failed"; + } + throw new Error(message); + } +} + +function assert_eq(a, b, message) { + if (a !== b) { + throw new Error(`${message} (${JSON.stringify(a)} !== ${JSON.stringify(b)})`); + } +} +"#; + +#[test] +fn url_basic() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment"); + assert(url instanceof URL); + assert_eq(url.href, "https://example.com:8080/path/to/resource?query#fragment"); + assert_eq(url.protocol, "https:"); + assert_eq(url.host, "example.com:8080"); + assert_eq(url.hostname, "example.com"); + assert_eq(url.port, "8080"); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + ]); +} + +#[test] +fn url_base() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment", "http://example.org/"); + assert_eq(url.href, "https://example.com:8080/path/to/resource?query#fragment"); + assert_eq(url.protocol, "https:"); + assert_eq(url.host, "example.com:8080"); + assert_eq(url.hostname, "example.com"); + assert_eq(url.port, "8080"); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + TestAction::run( + r##" + url = new URL("/path/to/resource?query#fragment", "http://example.org/"); + assert_eq(url.href, "http://example.org/path/to/resource?query#fragment"); + assert_eq(url.protocol, "http:"); + assert_eq(url.host, "example.org"); + assert_eq(url.hostname, "example.org"); + assert_eq(url.port, ""); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + ]); +} + +#[test] +fn url_setters() { + // These were double checked against Firefox. + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment"); + url.protocol = "http:"; + url.host = "example.org:80"; // Since protocol is http, port is removed. + url.pathname = "/new/path"; + url.search = "?new-query"; + url.hash = "#new-fragment"; + assert_eq(url.href, "http://example.org/new/path?new-query#new-fragment"); + assert_eq(url.protocol, "http:"); + assert_eq(url.host, "example.org"); + assert_eq(url.hostname, "example.org"); + assert_eq(url.port, ""); + assert_eq(url.pathname, "/new/path"); + assert_eq(url.search, "?new-query"); + assert_eq(url.hash, "#new-fragment"); + "##, + ), + ]); +} + +#[test] +fn url_static_methods() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + assert(URL.canParse("http://example.org/new/path?new-query#new-fragment")); + assert(!URL.canParse("http//:example.org/new/path?new-query#new-fragment")); + assert(!URL.canParse("http://example.org/new/path?new-query#new-fragment", "http:")); + assert(URL.canParse("/new/path?new-query#new-fragment", "http://example.org/")); + "##, + ), + ]); +} From dd551d1bb00fc6ba24100d31e1323db276057382 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 23 Sep 2024 21:08:25 -0700 Subject: [PATCH 03/15] clippies --- core/runtime/src/lib.rs | 12 ++++++++---- core/runtime/src/url.rs | 14 +++++++------- core/runtime/src/url/tests.rs | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index d24b9d18a50..36a18418e4d 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -63,7 +63,7 @@ pub use text::{TextDecoder, TextEncoder}; pub mod url; -/// Options used when registering all built-in objects and functions of the WebAPI runtime. +/// Options used when registering all built-in objects and functions of the `WebAPI` runtime. #[derive(Debug)] pub struct RegisterOptions { console_logger: L, @@ -79,6 +79,7 @@ impl Default for RegisterOptions { impl RegisterOptions { /// Create a new `RegisterOptions` with the default options. + #[must_use] pub fn new() -> Self { Self::default() } @@ -93,7 +94,10 @@ impl RegisterOptions { } } -/// Register all the built-in objects and functions of the WebAPI runtime. +/// Register all the built-in objects and functions of the `WebAPI` runtime. +/// +/// # Errors +/// This will error is any of the built-in objects or functions cannot be registered. pub fn register( ctx: &mut boa_engine::Context, options: RegisterOptions, @@ -110,7 +114,7 @@ pub fn register( #[cfg(test)] pub(crate) mod test { - use crate::register; + use crate::{register, RegisterOptions}; use boa_engine::{builtins, Context, JsResult, JsValue, Source}; use std::borrow::Cow; @@ -174,7 +178,7 @@ pub(crate) mod test { #[track_caller] pub(crate) fn run_test_actions(actions: impl IntoIterator) { let context = &mut Context::default(); - register(context, Default::default()).expect("failed to register WebAPI objects"); + register(context, RegisterOptions::default()).expect("failed to register WebAPI objects"); run_test_actions_with(actions, context); } diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs index d0f61a34205..6d857a5453a 100644 --- a/core/runtime/src/url.rs +++ b/core/runtime/src/url.rs @@ -39,9 +39,9 @@ impl Url { /// /// # Errors /// Any errors that might occur during URL parsing. - fn js_new(Convert(ref url): Convert, base: Option>) -> JsResult { - if let Some(Convert(ref base)) = base { - let base_url = url::Url::parse(&base) + fn js_new(Convert(ref url): Convert, base: &Option>) -> JsResult { + if let Some(Convert(base)) = base { + let base_url = url::Url::parse(base) .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; if base_url.cannot_be_a_base() { return Err(js_error!(TypeError: "Base URL {} cannot be a base", base)); @@ -144,7 +144,7 @@ js_class! { } fn set(this: JsClass, value: Convert) { - let _ = url::quirks::set_pathname(&mut this.borrow_mut().0, &value.0); + let () = url::quirks::set_pathname(&mut this.borrow_mut().0, &value.0); } } @@ -195,7 +195,7 @@ js_class! { } constructor(url: Convert, base: Option>) { - Self::js_new(url, base) + Self::js_new(url, &base) } init(class: &mut ClassBuilder) -> JsResult<()> { @@ -204,11 +204,11 @@ js_class! { }) .into_js_function_copied(class.context()); let can_parse = (|url: Convert, base: Option>| { - Url::js_new(url, base).is_ok() + Url::js_new(url, &base).is_ok() }) .into_js_function_copied(class.context()); let parse = (|url: Convert, base: Option>, context: &mut Context| { - Url::js_new(url, base) + Url::js_new(url, &base) .map_or(Ok(JsValue::null()), |u| Url::from_data(u, context).map(JsValue::from)) }) .into_js_function_copied(class.context()); diff --git a/core/runtime/src/url/tests.rs b/core/runtime/src/url/tests.rs index bca79102cb8..685efc6df1b 100644 --- a/core/runtime/src/url/tests.rs +++ b/core/runtime/src/url/tests.rs @@ -1,6 +1,6 @@ use crate::test::{run_test_actions, TestAction}; -const TEST_HARNESS: &'static str = r#" +const TEST_HARNESS: &str = r#" function assert(condition, message) { if (!condition) { if (!message) { From c445a06fe1497d425beb84b49807bd6d8b940db0 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 25 Sep 2024 22:23:09 -0700 Subject: [PATCH 04/15] Add WPT as optional tests for boa_runtime To run the tests, you require adding the `wpt-tests` feature and setting the `WPT_ROOT` environment variable on the command line. This is currently depending on a pending rstest PR: https://github.com/la10736/rstest/pull/277 The current set of curated tests are all working. --- Cargo.lock | 626 +++++++++++++++++++++--------- Cargo.toml | 1 + cli/src/main.rs | 11 +- core/runtime/Cargo.toml | 8 + core/runtime/src/console/mod.rs | 30 +- core/runtime/src/console/tests.rs | 4 +- core/runtime/src/lib.rs | 51 ++- core/runtime/src/url.rs | 284 ++++++++++++++ core/runtime/tests/logger/mod.rs | 94 +++++ core/runtime/tests/wpt.rs | 332 ++++++++++++++++ core/string/src/lib.rs | 13 + 11 files changed, 1260 insertions(+), 194 deletions(-) create mode 100644 core/runtime/src/url.rs create mode 100644 core/runtime/tests/logger/mod.rs create mode 100644 core/runtime/tests/wpt.rs diff --git a/Cargo.lock b/Cargo.lock index fb210c9032c..9f8b4945095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -52,9 +58,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -73,27 +79,27 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -139,13 +145,13 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-lite 2.3.0", "slab", ] @@ -163,9 +169,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock", "cfg-if", @@ -173,11 +179,11 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.2", + "polling 3.7.3", "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -204,9 +210,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", @@ -219,14 +225,13 @@ dependencies = [ "futures-lite 2.3.0", "rustix", "tracing", - "windows-sys 0.52.0", ] [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", "async-lock", @@ -237,7 +242,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -268,7 +273,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -538,8 +543,10 @@ dependencies = [ "boa_gc", "boa_interop", "indoc", + "rstest", "rustc-hash 2.0.0", "textwrap", + "url", ] [[package]] @@ -588,6 +595,29 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "boa_wpt" +version = "0.19.0" +dependencies = [ + "boa_engine", + "boa_gc", + "boa_interop", + "boa_runtime", + "clap", + "clap-verbosity-flag", + "color-eyre", + "fast-glob", + "quick-junit", + "regex", + "rustc-hash 2.0.0", + "serde", + "time", + "toml 0.8.19", + "tracing", + "tracing-subscriber", + "walkdir", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -616,9 +646,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", @@ -633,9 +663,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "calendrical_calculations" @@ -649,9 +679,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -693,9 +723,12 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.100" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -709,6 +742,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "num-traits", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -746,6 +788,16 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-verbosity-flag" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d19864d6b68464c59f7162c9914a0b569ddc2926b4a2d71afe62a9738eff53" +dependencies = [ + "clap", + "log", +] + [[package]] name = "clap_builder" version = "4.5.18" @@ -772,15 +824,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clipboard-win" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ "error-code", ] @@ -820,9 +872,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -921,9 +973,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" [[package]] name = "crossbeam-channel" @@ -1004,9 +1056,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.72+curl-8.6.0" +version = "0.4.76+curl-8.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "00462dbe9cbb9344e1b2be34d9094d74e3b8aac59a883495b335eafd02e25120" dependencies = [ "cc", "libc", @@ -1137,6 +1189,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -1173,9 +1231,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "event-listener" @@ -1220,6 +1278,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c" +[[package]] +name = "fast-glob" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb10ed0f8a3dca52477be37ac0fb8f9d1fd4cd8d311b4484bdd45c1c56e0c9ec" + [[package]] name = "fastrand" version = "1.9.0" @@ -1231,9 +1295,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fd-lock" @@ -1260,12 +1324,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1292,12 +1356,48 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -1325,7 +1425,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -1343,21 +1443,37 @@ dependencies = [ "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + [[package]] name = "futures-task" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1973,20 +2089,20 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "isahc" @@ -2085,9 +2201,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -2107,9 +2223,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -2150,9 +2266,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matrixmultiply" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", "rawpointer", @@ -2221,6 +2337,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mintex" version = "0.1.3" @@ -2240,6 +2365,15 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "newtype-uuid" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526cb7c660872e401beaf3297f95f548ce3b4b4bdd8121b7c0713771d7c4a6e" +dependencies = [ + "uuid", +] + [[package]] name = "nix" version = "0.28.0" @@ -2252,6 +2386,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2369,9 +2513,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl-probe" @@ -2381,9 +2525,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -2391,6 +2535,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owo-colors" version = "3.5.0" @@ -2399,9 +2549,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2423,7 +2573,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2523,26 +2673,26 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -2553,15 +2703,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -2584,9 +2734,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.2" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", @@ -2594,7 +2744,7 @@ dependencies = [ "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2611,12 +2761,13 @@ checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -2628,17 +2779,20 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -2650,6 +2804,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-junit" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc1a6a5406a114913df2df8507998c755311b55b78584bed5f6e88f6417c4d4" +dependencies = [ + "chrono", + "indexmap", + "newtype-uuid", + "quick-xml", + "strip-ansi-escapes", + "thiserror", + "uuid", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.37" @@ -2717,9 +2895,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -2779,6 +2957,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "ring" version = "0.17.8" @@ -2794,6 +2978,32 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rstest" +version = "0.23.0-dev" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0-dev" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2812,11 +3022,20 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -2827,11 +3046,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -2841,15 +3061,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -2917,11 +3137,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3009,9 +3229,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3038,6 +3258,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3151,6 +3377,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strip-ansi-escapes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3386,9 +3621,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3417,7 +3652,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit", ] [[package]] @@ -3431,26 +3666,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] @@ -3506,15 +3730,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "nu-ansi-term", "sharded-slab", + "smallvec", "thread_local", "tracing-core", + "tracing-log", ] [[package]] @@ -3550,9 +3788,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-linebreak" @@ -3562,24 +3800,24 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unsafe-libyaml" @@ -3595,9 +3833,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.7" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64", "flate2", @@ -3605,7 +3843,6 @@ dependencies = [ "once_cell", "rustls", "rustls-pki-types", - "rustls-webpki", "url", "webpki-roots", ] @@ -3639,6 +3876,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + [[package]] name = "valuable" version = "0.1.0" @@ -3653,9 +3896,29 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" +dependencies = [ + "proc-macro2", + "quote", +] [[package]] name = "waker-fn" @@ -3814,9 +4077,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -3834,9 +4097,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -3859,11 +4122,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3887,7 +4150,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -3907,18 +4179,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3929,9 +4201,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3941,9 +4213,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3953,15 +4225,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3971,9 +4243,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3983,9 +4255,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3995,9 +4267,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4007,24 +4279,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -4070,18 +4333,19 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index f5651d63b55..72ad4007b4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,6 +117,7 @@ criterion = "0.5.1" float-cmp = "0.9.0" futures-lite = "2.3.0" test-case = "3.3.1" +rstest = { path = "../rstest/rstest" } winapi = { version = "0.3.9", default-features = false } # ICU4X diff --git a/cli/src/main.rs b/cli/src/main.rs index d43335df528..899b73f3139 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -14,15 +14,12 @@ use boa_engine::{ builtins::promise::PromiseState, context::ContextBuilder, job::{FutureJob, JobQueue, NativeJob}, - js_string, module::{Module, SimpleModuleLoader}, optimizer::OptimizerOptions, - property::Attribute, script::Script, vm::flowgraph::{Direction, Graph}, Context, JsError, JsNativeError, JsResult, Source, }; -use boa_runtime::Console; use clap::{Parser, ValueEnum, ValueHint}; use colored::Colorize; use debug::init_boa_debug_object; @@ -442,12 +439,10 @@ fn main() -> Result<(), io::Error> { Ok(()) } -/// Adds the CLI runtime to the context. +/// Adds the CLI runtime to the context with default options. fn add_runtime(context: &mut Context) { - let console = Console::init(context); - context - .register_global_property(js_string!(Console::NAME), console, Attribute::all()) - .expect("the console object shouldn't exist"); + boa_runtime::register(context, boa_runtime::RegisterOptions::new()) + .expect("should not fail while registering the runtime"); } #[derive(Default)] diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 62a0a4907f6..2059dd3a4ee 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,9 +15,12 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } +url = { version = "2.5.2", optional = true } [dev-dependencies] +boa_interop.workspace = true indoc.workspace = true +rstest.workspace = true textwrap.workspace = true [lints] @@ -25,3 +28,8 @@ workspace = true [package.metadata.docs.rs] all-features = true + +[features] +default = ["all"] +all = ["url"] +wpt-tests = [] diff --git a/core/runtime/src/console/mod.rs b/core/runtime/src/console/mod.rs index bc2efa8bc86..b17ded5d5e6 100644 --- a/core/runtime/src/console/mod.rs +++ b/core/runtime/src/console/mod.rs @@ -58,8 +58,8 @@ pub trait Logger: Trace + Sized { /// Implements the [`Logger`] trait and output errors to stderr and all /// the others to stdout. Will add indentation based on the number of /// groups. -#[derive(Trace, Finalize)] -struct DefaultLogger; +#[derive(Debug, Trace, Finalize)] +pub struct DefaultLogger; impl Logger for DefaultLogger { #[inline] @@ -85,6 +85,32 @@ impl Logger for DefaultLogger { } } +/// A logger that drops all logging. Useful for testing. +#[derive(Debug, Trace, Finalize)] +pub struct NullLogger; + +impl Logger for NullLogger { + #[inline] + fn log(&self, _: String, _: &ConsoleState, _: &mut Context) -> JsResult<()> { + Ok(()) + } + + #[inline] + fn info(&self, _: String, _: &ConsoleState, _: &mut Context) -> JsResult<()> { + Ok(()) + } + + #[inline] + fn warn(&self, _: String, _: &ConsoleState, _: &mut Context) -> JsResult<()> { + Ok(()) + } + + #[inline] + fn error(&self, _: String, _: &ConsoleState, _: &mut Context) -> JsResult<()> { + Ok(()) + } +} + /// This represents the `console` formatter. fn formatter(data: &[JsValue], context: &mut Context) -> JsResult { fn to_string(value: &JsValue, context: &mut Context) -> JsResult { diff --git a/core/runtime/src/console/tests.rs b/core/runtime/src/console/tests.rs index d521575e34e..4243f3499b2 100644 --- a/core/runtime/src/console/tests.rs +++ b/core/runtime/src/console/tests.rs @@ -1,6 +1,6 @@ use super::{formatter, Console, ConsoleState}; use crate::test::{run_test_actions, run_test_actions_with, TestAction}; -use crate::Logger; +use crate::{Logger, NullLogger}; use boa_engine::{js_string, property::Attribute, Context, JsError, JsResult, JsValue}; use boa_gc::{Gc, GcRefCell}; use indoc::indoc; @@ -97,7 +97,7 @@ fn formatter_float_format_works() { #[test] fn console_log_cyclic() { let mut context = Context::default(); - let console = Console::init(&mut context); + let console = Console::init_with_logger(&mut context, NullLogger); context .register_global_property(js_string!(Console::NAME), console, Attribute::all()) .unwrap(); diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 38dea056c27..6164013359b 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -45,6 +45,8 @@ )] #![cfg_attr(test, allow(clippy::needless_raw_string_hashes))] // Makes strings a bit more copy-pastable #![cfg_attr(not(test), forbid(clippy::unwrap_used))] +// Currently throws a false positive regarding dependencies that are only used in tests. +#![allow(unused_crate_dependencies)] #![allow( clippy::module_name_repetitions, clippy::redundant_pub_crate, @@ -54,13 +56,60 @@ mod console; #[doc(inline)] -pub use console::{Console, ConsoleState, Logger}; +pub use console::{Console, ConsoleState, DefaultLogger, Logger, NullLogger}; mod text; #[doc(inline)] pub use text::{TextDecoder, TextEncoder}; +pub mod url; + +/// Options used when registering all built-in objects and functions of the WebAPI runtime. +#[derive(Debug)] +pub struct RegisterOptions { + console_logger: L, +} + +impl Default for RegisterOptions { + fn default() -> Self { + Self { + console_logger: DefaultLogger, + } + } +} + +impl RegisterOptions { + /// Create a new `RegisterOptions` with the default options. + pub fn new() -> Self { + Self::default() + } +} + +impl RegisterOptions { + /// Set the logger for the console object. + pub fn with_console_logger(self, logger: L2) -> RegisterOptions { + RegisterOptions:: { + console_logger: logger, + } + } +} + +/// Register all the built-in objects and functions of the WebAPI runtime. +pub fn register( + ctx: &mut boa_engine::Context, + options: RegisterOptions, +) -> boa_engine::JsResult<()> { + Console::register_with_logger(ctx, options.console_logger)?; + TextDecoder::register(ctx)?; + TextEncoder::register(ctx)?; + + #[cfg(feature = "url")] + url::Url::register(ctx)?; + + Ok(()) +} + #[cfg(test)] pub(crate) mod test { use boa_engine::{builtins, Context, JsResult, JsValue, Source}; diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs new file mode 100644 index 00000000000..fab80827d8b --- /dev/null +++ b/core/runtime/src/url.rs @@ -0,0 +1,284 @@ +//! Boa's implementation of JavaScript's `URL` Web API class. +//! +//! The `URL` class can be instantiated from any global object. +//! This relies on the `url` feature. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [WHATWG `URL` specification][spec] +//! +//! [spec]: https://url.spec.whatwg.org/ +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/URL +#![cfg(feature = "url")] + +use boa_engine::value::Convert; +use boa_engine::{ + js_error, js_string, Context, Finalize, JsData, JsResult, JsString, JsValue, Trace, +}; +use boa_interop::{js_class, IntoJsFunctionCopied, JsClass}; +use std::fmt::Display; + +/// The `URL` class represents a (properly parsed) Uniform Resource Locator. +#[derive(Debug, Clone, JsData, Trace, Finalize)] +pub struct Url(#[unsafe_ignore_trace] url::Url); + +impl Url { + /// Register the `URL` class into the realm. + /// + /// # Errors + /// This will error if the context or realm cannot register the class. + pub fn register(context: &mut Context) -> JsResult<()> { + context.register_global_class::()?; + Ok(()) + } + + /// Create a new `URL` object from a `url::Url`. + pub fn new>(url: T) -> Result { + url.try_into().map(Self) + } + + /// Create a new `URL` object. Meant to be called from the JavaScript constructor. + /// + /// # Errors + /// Any errors that might occur during URL parsing. + fn js_new(Convert(ref url): Convert, base: Option>) -> JsResult { + if let Some(Convert(ref base)) = base { + let base_url = url::Url::parse(&base) + .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; + if base_url.cannot_be_a_base() { + return Err(js_error!(TypeError: "Base URL {} cannot be a base", base)); + } + + let url = base_url + .join(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } else { + let url = url::Url::parse(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } + } +} + +impl Display for Url { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for Url { + fn from(url: url::Url) -> Self { + Self(url) + } +} + +impl From for url::Url { + fn from(url: Url) -> url::Url { + // Cannot avoid cloning here, unfortunately, as we would need to replace + // the internal URL with something else. + url.0.clone() + } +} + +js_class! { + class Url as "URL" { + property hash { + fn get(this: JsClass) -> JsString { + if let Some(f) = this.borrow().0.fragment() { + JsString::from(format!("#{}", f)) + } else { + js_string!("") + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + this.borrow_mut().0.set_fragment(None); + } else { + if let Some(fragment) = value.0.strip_prefix('#') { + this.borrow_mut().0.set_fragment(Some(fragment)); + } else { + this.borrow_mut().0.set_fragment(Some(&value.0)); + } + } + } + } + + property host { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.host_str().unwrap_or("")) + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_host(None); + } else { + let _ = this.borrow_mut().0.set_host(Some(&value.0)); + } + } + } + + property hostname { + fn get(this: JsClass) -> JsString { + let host = this.borrow().0.host_str().unwrap_or("").to_string(); + if let Some(port) = this.borrow().0.port() { + JsString::from(format!("{}:{}", host, port)) + } else { + JsString::from(host) + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_host(None); + } else { + let _ = this.borrow_mut().0.set_host(Some(&value.0)); + } + } + } + + property href { + fn get(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) -> JsResult<()> { + let url = url::Url::parse(&value.0) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + *this.borrow_mut() = url.into(); + Ok(()) + } + } + + property origin { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.origin().ascii_serialization()) + } + } + + property password { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.password().unwrap_or("").to_string()) + } + + fn set(this: JsClass, value: Convert) { + let _ = this.borrow_mut().0.set_password(Some(&value.0)); + } + } + + property pathname { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.path()) + } + + fn set(this: JsClass, value: Convert) { + this.borrow_mut().0.set_path(&value.0); + } + } + + property port { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.port().map_or(String::new(), |p| p.to_string()).to_string()) + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + let _ = this.borrow_mut().0.set_port(None); + } else if let Ok(value) = value.0.to_std_string_lossy().parse::() { + let _ = this.borrow_mut().0.set_port(Some(value)); + } + } + } + + property protocol { + fn get(this: JsClass) -> JsString { + // The URL crate returns without a colon, but the web API requires it. + JsString::from(format!("{}:", this.borrow().0.scheme())) + } + + fn set(this: JsClass, value: Convert) { + // Ignore errors. + let _ = this.borrow_mut().0.set_scheme(&value.0); + } + } + + property search { + fn get(this: JsClass) -> JsString { + if let Some(query) = this.borrow().0.query() { + JsString::from(format!("?{}", query)) + } else { + js_string!("") + } + } + + fn set(this: JsClass, value: Convert) { + if value.0.is_empty() { + this.borrow_mut().0.set_query(None); + } else { + if let Some(query) = value.0.strip_prefix('?') { + this.borrow_mut().0.set_query(Some(query)); + } else { + this.borrow_mut().0.set_query(Some(&value.0)); + } + } + } + } + + property search_params as "searchParams" { + fn get() -> JsResult<()> { + Err(js_error!(Error: "URL.searchParams is not implemented")) + } + } + + property username { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.username()) + } + + fn set(this: JsClass, value: Convert) { + let _ = this.borrow_mut().0.set_username(&value.0); + } + } + + constructor(url: Convert, base: Option>) { + Self::js_new(url, base) + } + + init(class: &mut ClassBuilder) -> JsResult<()> { + let create_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.createObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + let can_parse = (|url: Convert, base: Option>| { + Url::js_new(url, base).is_ok() + }) + .into_js_function_copied(class.context()); + let parse = (|url: Convert, base: Option>, context: &mut Context| { + Url::js_new(url, base) + .map_or(Ok(JsValue::null()), |u| Url::from_data(u, context).map(JsValue::from)) + }) + .into_js_function_copied(class.context()); + let revoke_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.revokeObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + + class + .static_method(js_string!("createObjectURL"), 1, create_object_url) + .static_method(js_string!("canParse"), 2, can_parse) + .static_method(js_string!("parse"), 2, parse) + .static_method(js_string!("revokeObjectUrl"), 1, revoke_object_url); + + Ok(()) + } + + fn to_string as "toString"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + + fn to_json as "toJSON"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + } +} diff --git a/core/runtime/tests/logger/mod.rs b/core/runtime/tests/logger/mod.rs new file mode 100644 index 00000000000..29a6fbf7b22 --- /dev/null +++ b/core/runtime/tests/logger/mod.rs @@ -0,0 +1,94 @@ +use boa_engine::{Context, Finalize, JsData, JsResult, Trace}; +use boa_gc::{Gc, GcRefCell}; +use boa_runtime::{ConsoleState, Logger}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// A unique index of all logs. +static UNIQUE: AtomicUsize = AtomicUsize::new(0); + +#[derive(Clone, Debug, Trace, Finalize, JsData)] +pub(crate) struct RecordingLogEvent { + pub index: usize, + pub indent: usize, + pub msg: String, +} + +impl RecordingLogEvent { + pub(crate) fn new(msg: String, state: &ConsoleState) -> Self { + Self { + index: UNIQUE.fetch_add(1, Ordering::SeqCst), + indent: state.indent(), + msg, + } + } +} + +#[derive(Trace, Finalize, JsData)] +struct RecordingLoggerInner { + pub log: Vec, + pub error: Vec, +} + +#[derive(Clone, Trace, Finalize, JsData)] +pub(crate) struct RecordingLogger { + inner: Gc>, +} + +impl Logger for RecordingLogger { + fn log(&self, msg: String, state: &ConsoleState, _: &mut Context) -> JsResult<()> { + self.inner + .borrow_mut() + .log + .push(RecordingLogEvent::new(msg, state)); + Ok(()) + } + + fn info(&self, msg: String, state: &ConsoleState, _: &mut Context) -> JsResult<()> { + self.inner + .borrow_mut() + .log + .push(RecordingLogEvent::new(msg, state)); + Ok(()) + } + + fn warn(&self, msg: String, state: &ConsoleState, _: &mut Context) -> JsResult<()> { + self.inner + .borrow_mut() + .log + .push(RecordingLogEvent::new(msg, state)); + Ok(()) + } + + fn error(&self, msg: String, state: &ConsoleState, _: &mut Context) -> JsResult<()> { + self.inner + .borrow_mut() + .error + .push(RecordingLogEvent::new(msg, state)); + Ok(()) + } +} + +impl RecordingLogger { + pub(crate) fn new() -> Self { + Self { + inner: Gc::new(GcRefCell::new(RecordingLoggerInner { + log: Vec::new(), + error: Vec::new(), + })), + } + } + + pub(crate) fn all_logs(&self) -> Vec { + let mut all: Vec = self.log().into_iter().chain(self.error()).collect(); + all.sort_by_key(|x| x.index); + all + } + + pub(crate) fn log(&self) -> Vec { + self.inner.borrow().log.clone() + } + + pub(crate) fn error(&self) -> Vec { + self.inner.borrow().error.clone() + } +} diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs new file mode 100644 index 00000000000..27175110c5b --- /dev/null +++ b/core/runtime/tests/wpt.rs @@ -0,0 +1,332 @@ +//! Integration tests running the Web Platform Tests (WPT) for the `boa_runtime` crate. +//! +//! In order to run these tests, the `wpt-tests` feature must be enabled on the command line. +#![allow(unused_crate_dependencies)] +#![cfg(feature = "wpt-tests")] + +use boa_engine::class::Class; +use boa_engine::parser::source::UTF8Input; +use boa_engine::property::Attribute; +use boa_engine::value::TryFromJs; +use boa_engine::{ + js_error, js_str, js_string, Context, Finalize, JsData, JsResult, JsString, JsValue, Source, + Trace, +}; +use boa_gc::Gc; +use boa_interop::{ContextData, IntoJsFunctionCopied}; +use boa_runtime::url::Url; +use boa_runtime::RegisterOptions; +use std::collections::BTreeMap; +use std::fs::File; +use std::io::BufReader; +use std::path::{Path, PathBuf}; +use std::sync::atomic::AtomicBool; + +mod logger; + +/// The test status JavaScript type from WPT. This is defined in the test harness. +#[derive(Debug, Clone, PartialEq, Eq)] +enum TestStatus { + Pass = 0, + Fail = 1, + Timeout = 2, + NotRun = 3, + PreconditionFailed = 4, +} + +impl std::fmt::Display for TestStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Pass => write!(f, "PASS"), + Self::Fail => write!(f, "FAIL"), + Self::Timeout => write!(f, "TIMEOUT"), + Self::NotRun => write!(f, "NOTRUN"), + Self::PreconditionFailed => write!(f, "PRECONDITION FAILED"), + } + } +} + +impl TryFromJs for TestStatus { + fn try_from_js(value: &JsValue, context: &mut Context) -> JsResult { + match value.to_u32(context) { + Ok(0) => Ok(Self::Pass), + Ok(1) => Ok(Self::Fail), + Ok(2) => Ok(Self::Timeout), + Ok(3) => Ok(Self::NotRun), + Ok(4) => Ok(Self::PreconditionFailed), + _ => Err(js_error!("Invalid test status")), + } + } +} + +/// A single test serialization. +#[derive(TryFromJs)] +struct Test { + name: JsString, + status: TestStatus, + message: Option, + properties: BTreeMap, +} + +/// A Test suite source code. +struct TestSuiteSource { + path: PathBuf, +} + +impl TestSuiteSource { + /// Create a new test suite source. + fn new(source: impl AsRef) -> Self { + Self { + path: source.as_ref().to_path_buf(), + } + } + + fn source(&self) -> Result>>, Box> { + Ok(Source::from_filepath(&self.path)?) + } + + fn meta(&self) -> Result>, Box> { + let mut meta: BTreeMap> = BTreeMap::new(); + + // Read the whole file and extract the metadata. + let content = std::fs::read_to_string(&self.path)?; + for line in content.lines() { + if let Some(kv) = line.strip_prefix("// META:") { + let kv = kv.trim(); + if let Some((key, value)) = kv.split_once("=") { + meta.entry(key.to_string()) + .or_default() + .push(value.to_string()); + } + } else if !line.starts_with("//") && !line.is_empty() { + break; + } + } + + Ok(meta) + } +} + +/// Create the BOA context and add the necessary global objects for WPT. +fn create_context(wpt_path: &Path) -> (Context, logger::RecordingLogger) { + let mut context = Context::default(); + let logger = logger::RecordingLogger::new(); + boa_runtime::register( + &mut context, + RegisterOptions::new().with_console_logger(logger.clone()), + ) + .expect("Failed to register boa_runtime"); + + // Define self as the globalThis. + let global_this = context.global_object(); + context + .register_global_property(js_str!("self"), global_this, Attribute::all()) + .unwrap(); + + // Define location to be an empty URL. + let location = Url::new("about:blank").expect("Could not parse the location URL"); + let location = + Url::from_data(location, &mut context).expect("Could not create the location URL"); + context + .register_global_property(js_str!("location"), location, Attribute::all()) + .unwrap(); + + let harness_path = wpt_path.join("resources/testharness.js"); + let harness = Source::from_filepath(&harness_path).expect("Could not create source."); + + context + .eval(harness) + .expect("Failed to eval testharness.js"); + + (context, logger) +} + +/// The result callback for the WPT test. +fn result_callback__( + ContextData(logger): ContextData, + test: Test, + context: &mut Context, +) -> JsResult<()> { + // Check the logs if the test succeeded. + if test.status != TestStatus::Pass { + panic!( + "Test {:?} failed with message:\n {:?}", + test.name.to_std_string_lossy(), + test.message.unwrap_or_default() + ) + } + + // Check the logs. + let logs = logger.all_logs(); + if let Some(log_regex) = test.properties.get(&js_string!("logs")) { + if let Ok(logs_re) = log_regex.try_js_into::>(context) { + for re in logs_re { + if let Some(re) = re.as_regexp() { + if !logs.iter().any(|log| { + let s = JsString::from(log.msg.clone()); + re.test(s, context).unwrap_or(false) + }) { + panic!( + "Test {:?} failed to find log regex: {}", + test.name.to_std_string_lossy(), + re.to_string(context).unwrap() + ); + } + } else { + let re_str = re.to_string(context)?.to_std_string_escaped(); + if !logs.iter().any(|log| log.msg.contains(&re_str)) { + panic!( + "Test {:?} failed to find log: {:#?}", + test.name.to_std_string_lossy(), + re + ); + } + } + } + } + } + + Ok(()) +} + +fn complete_callback__(ContextData(test_done): ContextData) { + test_done.done(); +} + +#[derive(Debug, Clone, Trace, Finalize, JsData)] +struct TestCompletion(Gc); + +impl TestCompletion { + fn new() -> Self { + Self(Gc::new(AtomicBool::new(false))) + } + + fn done(&self) { + self.0.store(true, std::sync::atomic::Ordering::SeqCst); + } + + fn is_done(&self) -> bool { + self.0.load(std::sync::atomic::Ordering::SeqCst) + } +} + +/// Load and execute the test file. +fn execute_test_file(path: &Path) { + let dir = path.parent().unwrap(); + let wpt_path = PathBuf::from( + std::env::var("WPT_ROOT").expect("Could not find WPT_ROOT environment variable"), + ); + let (mut context, logger) = create_context(&wpt_path); + let test_done = TestCompletion::new(); + + // Insert the logger to be able to access the logs after the test is done. + context.insert_data(logger.clone()); + context.insert_data(test_done.clone()); + + let function = result_callback__ + .into_js_function_copied(&mut context) + .to_js_function(context.realm()); + context + .register_global_property(js_str!("result_callback__"), function, Attribute::all()) + .expect("Could not register result_callback__"); + context + .eval(Source::from_bytes( + b"add_result_callback(result_callback__);", + )) + .expect("Could not eval add_result_callback"); + + let function = complete_callback__ + .into_js_function_copied(&mut context) + .to_js_function(context.realm()); + context + .register_global_property(js_str!("complete_callback__"), function, Attribute::all()) + .expect("Could not register complete_callback__"); + context + .eval(Source::from_bytes( + b"add_completion_callback(complete_callback__);", + )) + .expect("Could not eval add_completion_callback"); + + // Load the test. + let source = TestSuiteSource::new(path); + const EMPTY: Vec = vec![]; + for script in source + .meta() + .expect("Could not get meta from source") + .get("script") + .unwrap_or(&EMPTY) + { + // Resolve the source path relative to the script path, but under the wpt_path. + let script_path = Path::new(script); + let path = if script_path.is_relative() { + dir.join(script_path) + } else { + wpt_path.join(script_path.to_string_lossy().trim_start_matches('/')) + }; + + if path.exists() { + let source = Source::from_filepath(&path).expect("Could not parse source."); + if let Err(err) = context.eval(source) { + panic!("Could not eval script, path = {path:?}, err = {err:?}"); + } + } else { + panic!("Script does not exist, path = {path:?}"); + } + } + context + .eval(source.source().expect("Could not get source")) + .unwrap(); + context.run_jobs(); + + // Done() + context + .eval(Source::from_bytes(b"done()")) + .expect("Done unexpectedly threw an error."); + + let start = std::time::Instant::now(); + while !test_done.is_done() { + context.run_jobs(); + if start.elapsed().as_secs() > 10 { + panic!("Test did not complete in 10 seconds."); + } + } +} + +/// Test the console with the WPT test suite. +#[rstest::rstest] +fn console( + #[base_dir = "${WPT_ROOT}"] + #[files("console/*.any.js")] + // TODO: The console-log-large-array.any.js test is too slow. + #[exclude("console-log-large-array.any.js")] + #[exclude("idlharness")] + path: PathBuf, +) { + execute_test_file(&path); +} + +/// Test the text encoder/decoder with the WPT test suite. +#[ignore] // TODO: support all encodings. +#[rstest::rstest] +fn encoding( + #[base_dir = "${WPT_ROOT}"] + #[files("encoding/textdecoder-*.any.js")] + #[exclude("idlharness")] + path: PathBuf, +) { + execute_test_file(&path); +} + +/// Test the URL class with the WPT test suite. +// A bunch of these tests are failing due to lack of support in the URL class, +// or missing APIs such as fetch. +#[rstest::rstest] +fn url( + #[base_dir = "${WPT_ROOT}"] + #[files("url/url-tojson.any.js")] + #[files("url/url-statics-*.any.js")] + #[exclude("idlharness")] + path: PathBuf, +) { + execute_test_file(&path); +} diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index ecacaa1d56a..26922832aea 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -454,6 +454,19 @@ impl JsString { self.to_string_escaped() } + /// Decodes a [`JsString`] into a [`String`], replacing invalid data with the + /// replacement character U+FFFD. + #[inline] + #[must_use] + pub fn to_std_string_lossy(&self) -> String { + self.code_points() + .map(|cp| match cp { + CodePoint::Unicode(c) => c, + CodePoint::UnpairedSurrogate(_) => '\u{FFFD}', + }) + .collect() + } + /// Decodes a [`JsString`] into a [`String`], returning /// /// # Errors From 08b64fbcf5dfb5921426a4f7fa0d3bd7c4add944 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 25 Sep 2024 22:27:12 -0700 Subject: [PATCH 05/15] Rebuilding Cargo.toml --- Cargo.lock | 146 ----------------------------------------------------- 1 file changed, 146 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f8b4945095..05d0b3f8953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -595,29 +595,6 @@ dependencies = [ "wasm-bindgen-test", ] -[[package]] -name = "boa_wpt" -version = "0.19.0" -dependencies = [ - "boa_engine", - "boa_gc", - "boa_interop", - "boa_runtime", - "clap", - "clap-verbosity-flag", - "color-eyre", - "fast-glob", - "quick-junit", - "regex", - "rustc-hash 2.0.0", - "serde", - "time", - "toml 0.8.19", - "tracing", - "tracing-subscriber", - "walkdir", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -742,15 +719,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "num-traits", -] - [[package]] name = "ciborium" version = "0.2.2" @@ -788,16 +756,6 @@ dependencies = [ "clap_derive", ] -[[package]] -name = "clap-verbosity-flag" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d19864d6b68464c59f7162c9914a0b569ddc2926b4a2d71afe62a9738eff53" -dependencies = [ - "clap", - "log", -] - [[package]] name = "clap_builder" version = "4.5.18" @@ -1278,12 +1236,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c" -[[package]] -name = "fast-glob" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb10ed0f8a3dca52477be37ac0fb8f9d1fd4cd8d311b4484bdd45c1c56e0c9ec" - [[package]] name = "fastrand" version = "1.9.0" @@ -2365,15 +2317,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "newtype-uuid" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526cb7c660872e401beaf3297f95f548ce3b4b4bdd8121b7c0713771d7c4a6e" -dependencies = [ - "uuid", -] - [[package]] name = "nix" version = "0.28.0" @@ -2386,16 +2329,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -2535,12 +2468,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "owo-colors" version = "3.5.0" @@ -2804,30 +2731,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-junit" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc1a6a5406a114913df2df8507998c755311b55b78584bed5f6e88f6417c4d4" -dependencies = [ - "chrono", - "indexmap", - "newtype-uuid", - "quick-xml", - "strip-ansi-escapes", - "thiserror", - "uuid", -] - -[[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.37" @@ -3377,15 +3280,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strip-ansi-escapes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" -dependencies = [ - "vte", -] - [[package]] name = "strsim" version = "0.11.1" @@ -3730,29 +3624,15 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "nu-ansi-term", "sharded-slab", - "smallvec", "thread_local", "tracing-core", - "tracing-log", ] [[package]] @@ -3876,12 +3756,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" - [[package]] name = "valuable" version = "0.1.0" @@ -3900,26 +3774,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vte" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" -dependencies = [ - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "waker-fn" version = "1.2.0" From c17f3a65b4819498cce85b08622a76be5822efe0 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 25 Sep 2024 22:32:05 -0700 Subject: [PATCH 06/15] clippies --- core/runtime/src/lib.rs | 6 +++--- core/runtime/src/url.rs | 26 +++++++++++--------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 6164013359b..c2e973d5f6a 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -65,7 +65,7 @@ pub use text::{TextDecoder, TextEncoder}; pub mod url; -/// Options used when registering all built-in objects and functions of the WebAPI runtime. +/// Options used when registering all built-in objects and functions of the `WebAPI` runtime. #[derive(Debug)] pub struct RegisterOptions { console_logger: L, @@ -81,7 +81,7 @@ impl Default for RegisterOptions { impl RegisterOptions { /// Create a new `RegisterOptions` with the default options. - pub fn new() -> Self { + #[must_use] pub fn new() -> Self { Self::default() } } @@ -95,7 +95,7 @@ impl RegisterOptions { } } -/// Register all the built-in objects and functions of the WebAPI runtime. +/// Register all the built-in objects and functions of the `WebAPI` runtime. pub fn register( ctx: &mut boa_engine::Context, options: RegisterOptions, diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs index fab80827d8b..9c9629ea1d8 100644 --- a/core/runtime/src/url.rs +++ b/core/runtime/src/url.rs @@ -43,7 +43,7 @@ impl Url { /// Any errors that might occur during URL parsing. fn js_new(Convert(ref url): Convert, base: Option>) -> JsResult { if let Some(Convert(ref base)) = base { - let base_url = url::Url::parse(&base) + let base_url = url::Url::parse(base) .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; if base_url.cannot_be_a_base() { return Err(js_error!(TypeError: "Base URL {} cannot be a base", base)); @@ -86,7 +86,7 @@ js_class! { property hash { fn get(this: JsClass) -> JsString { if let Some(f) = this.borrow().0.fragment() { - JsString::from(format!("#{}", f)) + JsString::from(format!("#{f}")) } else { js_string!("") } @@ -95,12 +95,10 @@ js_class! { fn set(this: JsClass, value: Convert) { if value.0.is_empty() { this.borrow_mut().0.set_fragment(None); - } else { - if let Some(fragment) = value.0.strip_prefix('#') { - this.borrow_mut().0.set_fragment(Some(fragment)); - } else { - this.borrow_mut().0.set_fragment(Some(&value.0)); - } + } else if let Some(fragment) = value.0.strip_prefix('#') { + this.borrow_mut().0.set_fragment(Some(fragment)); + } else { + this.borrow_mut().0.set_fragment(Some(&value.0)); } } } @@ -123,7 +121,7 @@ js_class! { fn get(this: JsClass) -> JsString { let host = this.borrow().0.host_str().unwrap_or("").to_string(); if let Some(port) = this.borrow().0.port() { - JsString::from(format!("{}:{}", host, port)) + JsString::from(format!("{host}:{port}")) } else { JsString::from(host) } @@ -206,7 +204,7 @@ js_class! { property search { fn get(this: JsClass) -> JsString { if let Some(query) = this.borrow().0.query() { - JsString::from(format!("?{}", query)) + JsString::from(format!("?{query}")) } else { js_string!("") } @@ -215,12 +213,10 @@ js_class! { fn set(this: JsClass, value: Convert) { if value.0.is_empty() { this.borrow_mut().0.set_query(None); + } else if let Some(query) = value.0.strip_prefix('?') { + this.borrow_mut().0.set_query(Some(query)); } else { - if let Some(query) = value.0.strip_prefix('?') { - this.borrow_mut().0.set_query(Some(query)); - } else { - this.borrow_mut().0.set_query(Some(&value.0)); - } + this.borrow_mut().0.set_query(Some(&value.0)); } } } From 11a283a9d1d5615cfe68086b9c371c9d2e298ceb Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 26 Sep 2024 12:12:48 -0700 Subject: [PATCH 07/15] clippies and cleanup --- core/runtime/tests/wpt.rs | 65 ++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs index 279b4a3046d..d25bc9e73e1 100644 --- a/core/runtime/tests/wpt.rs +++ b/core/runtime/tests/wpt.rs @@ -4,6 +4,7 @@ #![allow(unused_crate_dependencies)] #![cfg(feature = "wpt-tests")] +use crate::logger::RecordingLogEvent; use boa_engine::class::Class; use boa_engine::parser::source::UTF8Input; use boa_engine::property::Attribute; @@ -93,7 +94,7 @@ impl TestSuiteSource { for line in content.lines() { if let Some(kv) = line.strip_prefix("// META:") { let kv = kv.trim(); - if let Some((key, value)) = kv.split_once("=") { + if let Some((key, value)) = kv.split_once('=') { meta.entry(key.to_string()) .or_default() .push(value.to_string()); @@ -148,40 +149,35 @@ fn result_callback__( context: &mut Context, ) -> JsResult<()> { // Check the logs if the test succeeded. - if test.status != TestStatus::Pass { - panic!( - "Test {:?} failed with message:\n {:?}", - test.name.to_std_string_lossy(), - test.message.unwrap_or_default() - ) - } + assert_eq!( + test.status, + TestStatus::Pass, + "Test {:?} failed with message:\n {:?}", + test.name.to_std_string_lossy(), + test.message.unwrap_or_default() + ); // Check the logs. let logs = logger.all_logs(); if let Some(log_regex) = test.properties.get(&js_string!("logs")) { if let Ok(logs_re) = log_regex.try_js_into::>(context) { for re in logs_re { - if let Some(re) = re.as_regexp() { - if !logs.iter().any(|log| { + let passes = if let Some(re) = re.as_regexp() { + logs.iter().any(|log: &RecordingLogEvent| -> bool { let s = JsString::from(log.msg.clone()); re.test(s, context).unwrap_or(false) - }) { - panic!( - "Test {:?} failed to find log regex: {}", - test.name.to_std_string_lossy(), - re.to_string(context).unwrap() - ); - } + }) } else { let re_str = re.to_string(context)?.to_std_string_escaped(); - if !logs.iter().any(|log| log.msg.contains(&re_str)) { - panic!( - "Test {:?} failed to find log: {:#?}", - test.name.to_std_string_lossy(), - re - ); - } - } + logs.iter() + .any(|log: &RecordingLogEvent| -> bool { log.msg.contains(&re_str) }) + }; + assert!( + passes, + "Test {:?} failed to find log: {}", + test.name.to_std_string_lossy(), + re.display() + ); } } } @@ -249,13 +245,8 @@ fn execute_test_file(path: &Path) { // Load the test. let source = TestSuiteSource::new(path); - const EMPTY: Vec = vec![]; - for script in source - .meta() - .expect("Could not get meta from source") - .get("script") - .unwrap_or(&EMPTY) - { + let meta = source.meta().expect("Could not get meta from source"); + for script in meta.get("script").unwrap_or(&Vec::new()) { // Resolve the source path relative to the script path, but under the wpt_path. let script_path = Path::new(script); let path = if script_path.is_relative() { @@ -286,9 +277,11 @@ fn execute_test_file(path: &Path) { let start = std::time::Instant::now(); while !test_done.is_done() { context.run_jobs(); - if start.elapsed().as_secs() > 10 { - panic!("Test did not complete in 10 seconds."); - } + + assert!( + start.elapsed().as_secs() < 10, + "Test did not complete in 10 seconds." + ); } } @@ -332,6 +325,8 @@ fn url( #[exclude("url-origin.any.js")] #[exclude("url-setters.any.js")] #[exclude("url-constructor.any.js")] + // Issue https://github.com/servo/rust-url/issues/974 + #[exclude("url-setters-stripping.any.js")] path: PathBuf, ) { execute_test_file(&path); From f4359312809370e305969685dc2dac53049c8b1b Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 26 Sep 2024 12:17:42 -0700 Subject: [PATCH 08/15] disable clippy on rstest which would fail without the right env var --- core/runtime/Cargo.toml | 6 ++++++ core/runtime/tests/wpt.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 2059dd3a4ee..4c0e8d4bed8 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -33,3 +33,9 @@ all-features = true default = ["all"] all = ["url"] wpt-tests = [] +# This feature is used to disable compiling the WPT tests in the CI +# when using `--all-features`. If this feature is enabled, we disable +# the compilation of the WPT tests (since they will panic). +# Clippy will be disabled for those methods as well, but they're one +# line long. +wpt-tests-do-not-use = [] diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs index d25bc9e73e1..153984f4362 100644 --- a/core/runtime/tests/wpt.rs +++ b/core/runtime/tests/wpt.rs @@ -207,6 +207,9 @@ impl TestCompletion { } /// Load and execute the test file. +// This can be marked as allow unused because it would give false positives +// in clippy. +#[allow(unused)] fn execute_test_file(path: &Path) { let dir = path.parent().unwrap(); let wpt_path = PathBuf::from( @@ -286,6 +289,7 @@ fn execute_test_file(path: &Path) { } /// Test the console with the WPT test suite. +#[cfg(not(feature = "wpt-tests-do-not-use"))] #[rstest::rstest] fn console( #[base_dir = "${WPT_ROOT}"] @@ -300,6 +304,7 @@ fn console( /// Test the text encoder/decoder with the WPT test suite. #[ignore] // TODO: support all encodings. +#[cfg(not(feature = "wpt-tests-do-not-use"))] #[rstest::rstest] fn encoding( #[base_dir = "${WPT_ROOT}"] @@ -313,6 +318,7 @@ fn encoding( /// Test the URL class with the WPT test suite. // A bunch of these tests are failing due to lack of support in the URL class, // or missing APIs such as fetch. +#[cfg(not(feature = "wpt-tests-do-not-use"))] #[rstest::rstest] fn url( #[base_dir = "${WPT_ROOT}"] From 6c0abbc57e94b0a3a5b35517b68de85c27f2edf2 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Sun, 29 Sep 2024 20:51:00 -0700 Subject: [PATCH 09/15] Move to a release of rstest that has la10736/rstest#277 merged --- Cargo.lock | 12 ++++++++---- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05d0b3f8953..094af9f4797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2883,7 +2883,9 @@ dependencies = [ [[package]] name = "rstest" -version = "0.23.0-dev" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" dependencies = [ "futures", "futures-timer", @@ -2893,7 +2895,9 @@ dependencies = [ [[package]] name = "rstest_macros" -version = "0.23.0-dev" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" dependencies = [ "cfg-if", "glob", @@ -3313,9 +3317,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 72ad4007b4d..f976840deb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,7 +117,7 @@ criterion = "0.5.1" float-cmp = "0.9.0" futures-lite = "2.3.0" test-case = "3.3.1" -rstest = { path = "../rstest/rstest" } +rstest = "0.23.0" winapi = { version = "0.3.9", default-features = false } # ICU4X From 9e9a37cf751e580235ab9e33eeeb9c494db773e7 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 30 Sep 2024 13:37:25 -0700 Subject: [PATCH 10/15] Load UTF16 files and move to using latest URL --- Cargo.lock | 46 ++++++++++++++++++---- core/runtime/Cargo.toml | 3 +- core/runtime/tests/wpt.rs | 80 +++++++++++++++++++++++++++++++++------ 3 files changed, 110 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 094af9f4797..f6dc6c50726 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -546,7 +546,7 @@ dependencies = [ "rstest", "rustc-hash 2.0.0", "textwrap", - "url", + "url 2.5.2 (git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567)", ] [[package]] @@ -1305,7 +1305,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "percent-encoding", + "percent-encoding 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567#7eccac9a0b763145ab1bb67a50576a34cc750567" +dependencies = [ + "percent-encoding 2.3.1 (git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567)", ] [[package]] @@ -1993,6 +2001,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567#7eccac9a0b763145ab1bb67a50576a34cc750567" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indenter" version = "0.3.3" @@ -2079,7 +2096,7 @@ dependencies = [ "sluice", "tracing", "tracing-futures", - "url", + "url 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "waker-fn", ] @@ -2515,6 +2532,11 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567#7eccac9a0b763145ab1bb67a50576a34cc750567" + [[package]] name = "perf-event-open-sys" version = "3.0.0" @@ -3727,7 +3749,7 @@ dependencies = [ "once_cell", "rustls", "rustls-pki-types", - "url", + "url 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "webpki-roots", ] @@ -3737,9 +3759,19 @@ version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "form_urlencoded 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url" +version = "2.5.2" +source = "git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567#7eccac9a0b763145ab1bb67a50576a34cc750567" +dependencies = [ + "form_urlencoded 1.2.1 (git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567)", + "idna 0.5.0 (git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567)", + "percent-encoding 2.3.1 (git+https://github.com/servo/rust-url.git?rev=7eccac9a0b763145ab1bb67a50576a34cc750567)", ] [[package]] diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 4c0e8d4bed8..1974cc8b378 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,7 +15,8 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } -url = { version = "2.5.2", optional = true } +# We need a new release to fix the URL bug. +url = { git = "https://github.com/servo/rust-url.git", rev = "7eccac9a0b763145ab1bb67a50576a34cc750567", optional = true } [dev-dependencies] boa_interop.workspace = true diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs index 153984f4362..3e8a8af629c 100644 --- a/core/runtime/tests/wpt.rs +++ b/core/runtime/tests/wpt.rs @@ -6,7 +6,7 @@ use crate::logger::RecordingLogEvent; use boa_engine::class::Class; -use boa_engine::parser::source::UTF8Input; +use boa_engine::parser::source::UTF16Input; use boa_engine::property::Attribute; use boa_engine::value::TryFromJs; use boa_engine::{ @@ -17,9 +17,8 @@ use boa_gc::Gc; use boa_interop::{ContextData, IntoJsFunctionCopied}; use boa_runtime::url::Url; use boa_runtime::RegisterOptions; +use std::cell::OnceCell; use std::collections::BTreeMap; -use std::fs::File; -use std::io::BufReader; use std::path::{Path, PathBuf}; use std::sync::atomic::AtomicBool; @@ -72,25 +71,87 @@ struct Test { /// A Test suite source code. struct TestSuiteSource { path: PathBuf, + bytes: OnceCell>, } +const REWRITE_RULES: &[(&str, &str)] = &[( + "/resources/WebIDLParser.js", + "/resources/webidl2/webidl2.js", +)]; + impl TestSuiteSource { /// Create a new test suite source. fn new(source: impl AsRef) -> Self { Self { path: source.as_ref().to_path_buf(), + bytes: OnceCell::new(), + } + } + + fn read_to_string(&self) -> Result> { + fn read_string(slice: &[u8], size: usize) -> Option { + assert!(2 * size <= slice.len()); + let iter = (0..size).map(|i| u16::from_be_bytes([slice[2 * i], slice[2 * i + 1]])); + + std::char::decode_utf16(iter) + .collect::>() + .ok() + } + let buffer = std::fs::read(&self.path)?; + // Check if buffer contains UTF8 or UTF16. + let maybe_utf8 = String::from_utf8(buffer.clone()); + if let Ok(utf8) = maybe_utf8 { + Ok(utf8) + } else if let Some(utf16) = read_string(&buffer, buffer.len() / 2) { + Ok(utf16) + } else { + Err("Could not determine encoding".into()) } } - fn source(&self) -> Result>>, Box> { - Ok(Source::from_filepath(&self.path)?) + fn source(&self) -> Result>, Box> { + let b = self.bytes.get_or_init(|| { + self.read_to_string() + .unwrap() + .encode_utf16() + .collect::>() + }); + Ok(Source::from_utf16(b).with_path(&self.path)) + } + + fn scripts(&self) -> Result, Box> { + let mut scripts: Vec = Vec::new(); + let dir = self.path.parent().expect("Could not get parent directory"); + + 'outer: for script in self.meta()?.get("script").unwrap_or(&Vec::new()) { + let script = script + .split_once('?') + .map_or(script.to_string(), |(s, _)| s.to_string()); + + // Resolve the source path relative to the script path, but under the wpt_path. + let script_path = Path::new(&script); + let path = if script_path.is_relative() { + dir.join(script_path) + } else { + script_path.to_path_buf() + }; + + for (from, to) in REWRITE_RULES { + if path.to_string_lossy().as_ref() == *from { + scripts.push(to.to_string()); + continue 'outer; + } + } + scripts.push(path.to_string_lossy().to_string()); + } + Ok(scripts) } fn meta(&self) -> Result>, Box> { let mut meta: BTreeMap> = BTreeMap::new(); // Read the whole file and extract the metadata. - let content = std::fs::read_to_string(&self.path)?; + let content = self.read_to_string()?; for line in content.lines() { if let Some(kv) = line.strip_prefix("// META:") { let kv = kv.trim(); @@ -248,10 +309,9 @@ fn execute_test_file(path: &Path) { // Load the test. let source = TestSuiteSource::new(path); - let meta = source.meta().expect("Could not get meta from source"); - for script in meta.get("script").unwrap_or(&Vec::new()) { + for script in source.scripts().expect("Could not get scripts") { // Resolve the source path relative to the script path, but under the wpt_path. - let script_path = Path::new(script); + let script_path = Path::new(&script); let path = if script_path.is_relative() { dir.join(script_path) } else { @@ -331,8 +391,6 @@ fn url( #[exclude("url-origin.any.js")] #[exclude("url-setters.any.js")] #[exclude("url-constructor.any.js")] - // Issue https://github.com/servo/rust-url/issues/974 - #[exclude("url-setters-stripping.any.js")] path: PathBuf, ) { execute_test_file(&path); From 3f2f19ae3ee4850cd2a921fc402401a356b21e0a Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Sun, 20 Oct 2024 17:09:47 -0700 Subject: [PATCH 11/15] Remove code in comment --- core/runtime/tests/wpt.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs index 3e8a8af629c..9fcf4731567 100644 --- a/core/runtime/tests/wpt.rs +++ b/core/runtime/tests/wpt.rs @@ -383,7 +383,6 @@ fn encoding( fn url( #[base_dir = "${WPT_ROOT}"] #[files("url/url-*.any.js")] - // #[files("url/url-statics-*.any.js")] #[exclude("idlharness")] // "Base URL about:blank cannot be a base" #[exclude("url-searchparams.any.js")] From 23b6b1b9d4b52f1edee95e982deff4131a7d4619 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 4 Nov 2024 20:51:39 -0800 Subject: [PATCH 12/15] fix some compiler warnings --- core/runtime/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 557fe3cb8c6..0e3cfdec918 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -71,15 +71,15 @@ pub struct RegisterOptions { console_logger: L, } -impl Default for RegisterOptions { +impl Default for RegisterOptions { fn default() -> Self { Self { - console_logger: console::DefaultLogger, + console_logger: DefaultLogger, } } } -impl RegisterOptions { +impl RegisterOptions { /// Create a new `RegisterOptions` with the default options. #[must_use] pub fn new() -> Self { From d68a460f7105e0043874d7873ef780a4afda9929 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 4 Nov 2024 20:54:28 -0800 Subject: [PATCH 13/15] clippies --- core/runtime/tests/wpt.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/runtime/tests/wpt.rs b/core/runtime/tests/wpt.rs index 9fcf4731567..98d5dbfcfb0 100644 --- a/core/runtime/tests/wpt.rs +++ b/core/runtime/tests/wpt.rs @@ -109,14 +109,14 @@ impl TestSuiteSource { } } - fn source(&self) -> Result>, Box> { + fn source(&self) -> Source<'_, UTF16Input<'_>> { let b = self.bytes.get_or_init(|| { self.read_to_string() .unwrap() .encode_utf16() .collect::>() }); - Ok(Source::from_utf16(b).with_path(&self.path)) + Source::from_utf16(b).with_path(&self.path) } fn scripts(&self) -> Result, Box> { @@ -138,7 +138,7 @@ impl TestSuiteSource { for (from, to) in REWRITE_RULES { if path.to_string_lossy().as_ref() == *from { - scripts.push(to.to_string()); + scripts.push((*to).to_string()); continue 'outer; } } @@ -328,8 +328,8 @@ fn execute_test_file(path: &Path) { } } context - .eval(source.source().expect("Could not get source")) - .unwrap(); + .eval(source.source()) + .expect("Could not evaluate source"); context.run_jobs(); // Done() From 4d88940cea1a0f450368cc0a2a44881c7193b944 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 9 Jan 2025 15:12:58 -0800 Subject: [PATCH 14/15] Move WPT tests to their own crate --- Cargo.lock | 98 ------------------- Cargo.toml | 1 + core/runtime/Cargo.toml | 9 -- tests/wpt/Cargo.toml | 12 +++ .../tests/wpt.rs => tests/wpt/src/lib.rs | 11 +-- .../tests => tests/wpt/src}/logger/mod.rs | 0 6 files changed, 17 insertions(+), 114 deletions(-) create mode 100644 tests/wpt/Cargo.toml rename core/runtime/tests/wpt.rs => tests/wpt/src/lib.rs (97%) rename {core/runtime/tests => tests/wpt/src}/logger/mod.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 6009fe141cb..fb50dd15808 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,7 +553,6 @@ dependencies = [ "boa_gc", "boa_interop", "indoc", - "rstest", "rustc-hash 2.1.0", "textwrap", "url", @@ -1342,48 +1341,12 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - [[package]] name = "futures-io" version = "0.3.31" @@ -1429,37 +1392,21 @@ dependencies = [ "syn", ] -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", - "futures-io", "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", @@ -3065,12 +3012,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "relative-path" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" - [[package]] name = "ring" version = "0.17.8" @@ -3086,36 +3027,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rstest" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" -dependencies = [ - "cfg-if", - "glob", - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "relative-path", - "rustc_version", - "syn", - "unicode-ident", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3134,15 +3045,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.43" diff --git a/Cargo.toml b/Cargo.toml index 3059bb45836..e2efa66e050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ exclude = [ "tests/fuzz", # Does weird things on Windows tests "tests/src", # Just a hack to have fuzz inside tests + "tests/wpt", # This requires special environment settings to run the tests ] [workspace.package] diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 01d4363bd75..821c1c4838d 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -18,9 +18,7 @@ rustc-hash = { workspace = true, features = ["std"] } url = { workspace = true, optional = true } [dev-dependencies] -boa_interop.workspace = true indoc.workspace = true -rstest.workspace = true textwrap.workspace = true [lints] @@ -33,10 +31,3 @@ all-features = true default = ["all"] all = ["url"] url = ["dep:url"] -wpt-tests = [] -# This feature is used to disable compiling the WPT tests in the CI -# when using `--all-features`. If this feature is enabled, we disable -# the compilation of the WPT tests (since they will panic). -# Clippy will be disabled for those methods as well, but they're one -# line long. -wpt-tests-do-not-use = [] diff --git a/tests/wpt/Cargo.toml b/tests/wpt/Cargo.toml new file mode 100644 index 00000000000..42f8405b1e4 --- /dev/null +++ b/tests/wpt/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "boa_wpt" +publish = false +version = "0.1.0" +edition = "2021" + +[dependencies] +boa_engine.workspace = true +boa_gc.workspace = true +boa_interop.workspace = true +boa_runtime.workspace = true +rstest.workspace = true diff --git a/core/runtime/tests/wpt.rs b/tests/wpt/src/lib.rs similarity index 97% rename from core/runtime/tests/wpt.rs rename to tests/wpt/src/lib.rs index 98d5dbfcfb0..4658e3303fa 100644 --- a/core/runtime/tests/wpt.rs +++ b/tests/wpt/src/lib.rs @@ -1,10 +1,6 @@ //! Integration tests running the Web Platform Tests (WPT) for the `boa_runtime` crate. -//! -//! In order to run these tests, the `wpt-tests` feature must be enabled on the command line. #![allow(unused_crate_dependencies)] -#![cfg(feature = "wpt-tests")] -use crate::logger::RecordingLogEvent; use boa_engine::class::Class; use boa_engine::parser::source::UTF16Input; use boa_engine::property::Attribute; @@ -17,6 +13,7 @@ use boa_gc::Gc; use boa_interop::{ContextData, IntoJsFunctionCopied}; use boa_runtime::url::Url; use boa_runtime::RegisterOptions; +use logger::RecordingLogEvent; use std::cell::OnceCell; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; @@ -349,7 +346,7 @@ fn execute_test_file(path: &Path) { } /// Test the console with the WPT test suite. -#[cfg(not(feature = "wpt-tests-do-not-use"))] +#[cfg(not(clippy))] #[rstest::rstest] fn console( #[base_dir = "${WPT_ROOT}"] @@ -363,8 +360,8 @@ fn console( } /// Test the text encoder/decoder with the WPT test suite. +#[cfg(not(clippy))] #[ignore] // TODO: support all encodings. -#[cfg(not(feature = "wpt-tests-do-not-use"))] #[rstest::rstest] fn encoding( #[base_dir = "${WPT_ROOT}"] @@ -378,7 +375,7 @@ fn encoding( /// Test the URL class with the WPT test suite. // A bunch of these tests are failing due to lack of support in the URL class, // or missing APIs such as fetch. -#[cfg(not(feature = "wpt-tests-do-not-use"))] +#[cfg(not(clippy))] #[rstest::rstest] fn url( #[base_dir = "${WPT_ROOT}"] diff --git a/core/runtime/tests/logger/mod.rs b/tests/wpt/src/logger/mod.rs similarity index 100% rename from core/runtime/tests/logger/mod.rs rename to tests/wpt/src/logger/mod.rs From b113e760e711bdd4ead298e9533186eec4fcee65 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 9 Jan 2025 15:25:19 -0800 Subject: [PATCH 15/15] Exclude the WPT tests from the default members --- Cargo.lock | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 +++++-- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb50dd15808..ece4451fcb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -605,6 +605,17 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "boa_wpt" +version = "0.1.0" +dependencies = [ + "boa_engine", + "boa_gc", + "boa_interop", + "boa_runtime", + "rstest", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -1341,12 +1352,48 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1392,21 +1439,37 @@ dependencies = [ "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -3012,6 +3075,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "ring" version = "0.17.8" @@ -3027,6 +3096,36 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3045,6 +3144,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.43" diff --git a/Cargo.toml b/Cargo.toml index e2efa66e050..e50f4fa96eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,14 +12,21 @@ members = [ # OTHERS "examples", "cli", - # TOOLS - "tools/*", ] exclude = [ "tests/fuzz", # Does weird things on Windows tests "tests/src", # Just a hack to have fuzz inside tests - "tests/wpt", # This requires special environment settings to run the tests +] + +default-members = [ + "core/*", + "ffi/*", + "tests/macros", + "tests/tester", + "tools/*", + "examples", + "cli", ] [workspace.package]