Skip to content

Commit

Permalink
Experimental test coverage support (#4060)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda authored Aug 11, 2024
1 parent 9a584e9 commit 402dae7
Show file tree
Hide file tree
Showing 22 changed files with 351 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@
* Added importing strings as `JsString` through `#[wasm_bindgen(thread_local, static_string)] static STRING: JsString = "a string literal";`.
[#4055](https://github.com/rustwasm/wasm-bindgen/pull/4055)

* Added experimental test coverage support for `wasm-bindgen-test-runner`, see the guide for more information.
[#4060](https://github.com/rustwasm/wasm-bindgen/pull/4060)

### Changed

* Stabilize Web Share API.
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ serde_derive = "1.0"
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(wasm_bindgen_unstable_test_coverage)',
] }

[workspace]
members = [
"benchmarks",
Expand Down
11 changes: 11 additions & 0 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ impl ToTokens for ast::Struct {
(quote! {
#[automatically_derived]
impl #wasm_bindgen::describe::WasmDescribe for #name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
use #wasm_bindgen::__wbindgen_if_not_std;
use #wasm_bindgen::describe::*;
Expand Down Expand Up @@ -293,6 +294,7 @@ impl ToTokens for ast::Struct {
#[doc(hidden)]
// `allow_delayed` is whether it's ok to not actually free the `ptr` immediately
// if it's still borrowed.
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub unsafe extern "C" fn #free_fn(ptr: u32, allow_delayed: u32) {
use #wasm_bindgen::__rt::alloc::rc::Rc;

Expand Down Expand Up @@ -401,6 +403,7 @@ impl ToTokens for ast::Struct {
}

impl #wasm_bindgen::describe::WasmDescribeVector for #name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe_vector() {
use #wasm_bindgen::describe::*;
inform(VECTOR);
Expand Down Expand Up @@ -484,6 +487,7 @@ impl ToTokens for ast::StructField {
const _: () = {
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), no_mangle)]
#[doc(hidden)]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub unsafe extern "C" fn #getter(js: u32)
-> #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi>
{
Expand Down Expand Up @@ -525,6 +529,7 @@ impl ToTokens for ast::StructField {
const _: () = {
#[no_mangle]
#[doc(hidden)]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub unsafe extern "C" fn #setter(
js: u32,
#(#args,)*
Expand Down Expand Up @@ -781,6 +786,7 @@ impl TryToTokens for ast::Export {
all(target_arch = "wasm32", target_os = "unknown"),
export_name = #export_name,
)]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
#start_check

Expand Down Expand Up @@ -932,6 +938,7 @@ impl ToTokens for ast::ImportType {
use #wasm_bindgen::__rt::core;

impl WasmDescribe for #rust_name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
#description
}
Expand Down Expand Up @@ -1222,6 +1229,7 @@ impl ToTokens for ast::StringEnum {

#[automatically_derived]
impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
use #wasm_bindgen::describe::*;
inform(STRING_ENUM);
Expand Down Expand Up @@ -1563,6 +1571,7 @@ impl ToTokens for ast::Enum {

#[automatically_derived]
impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
use #wasm_bindgen::describe::*;
inform(ENUM);
Expand Down Expand Up @@ -1599,6 +1608,7 @@ impl ToTokens for ast::Enum {
}

impl #wasm_bindgen::describe::WasmDescribeVector for #enum_name {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe_vector() {
use #wasm_bindgen::describe::*;
inform(VECTOR);
Expand Down Expand Up @@ -1795,6 +1805,7 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
#(#attrs)*
#[no_mangle]
#[doc(hidden)]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub extern "C" fn #name() {
use #wasm_bindgen::describe::*;
// See definition of `link_mem_intrinsics` for what this is doing
Expand Down
29 changes: 29 additions & 0 deletions crates/cli/src/bin/wasm-bindgen-test-runner/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use anyhow::{anyhow, bail, Context};
use log::error;
use std::env;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::thread;
use wasm_bindgen_cli_support::Bindgen;
Expand Down Expand Up @@ -222,6 +223,8 @@ fn main() -> anyhow::Result<()> {
b.split_linked_modules(true);
}

let coverage = coverage_args(&tmpdir);

b.debug(debug)
.input_module(module, wasm)
.keep_debug(false)
Expand Down Expand Up @@ -256,6 +259,7 @@ fn main() -> anyhow::Result<()> {
&tests,
test_mode,
std::env::var("WASM_BINDGEN_TEST_NO_ORIGIN_ISOLATION").is_err(),
coverage,
)
.context("failed to spawn server")?;
let addr = srv.server_addr();
Expand All @@ -282,3 +286,28 @@ fn main() -> anyhow::Result<()> {
}
Ok(())
}

fn coverage_args(tmpdir: &Path) -> PathBuf {
fn generated(tmpdir: &Path, prefix: &str) -> String {
let res = format!(
"{prefix}{}.profraw",
tmpdir.file_name().and_then(|s| s.to_str()).unwrap()
);
res
}

let prefix = env::var_os("WASM_BINDGEN_UNSTABLE_TEST_PROFRAW_PREFIX")
.map(|s| s.to_str().unwrap().to_string())
.unwrap_or_default();

match env::var_os("WASM_BINDGEN_UNSTABLE_TEST_PROFRAW_OUT") {
Some(s) => {
let mut buf = PathBuf::from(s);
if buf.is_dir() {
buf.push(generated(tmpdir, &prefix));
}
buf
}
None => PathBuf::from(generated(tmpdir, &prefix)),
}
}
47 changes: 46 additions & 1 deletion crates/cli/src/bin/wasm-bindgen-test-runner/server.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::borrow::Cow;
use std::ffi::OsString;
use std::fs;
use std::io::{Read, Write};
use std::net::SocketAddr;
use std::path::Path;
use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context, Error};
use rouille::{Request, Response, Server};
Expand All @@ -18,9 +19,24 @@ pub(crate) fn spawn(
tests: &[String],
test_mode: TestMode,
isolate_origin: bool,
coverage: PathBuf,
) -> Result<Server<impl Fn(&Request) -> Response + Send + Sync>, Error> {
let mut js_to_execute = String::new();

let cov_import = if test_mode.no_modules() {
"let __wbgtest_cov_dump = wasm_bindgen.__wbgtest_cov_dump;"
} else {
"__wbgtest_cov_dump,"
};
let cov_dump = r#"
// Dump the coverage data collected during the tests
const coverage = __wbgtest_cov_dump();
await fetch("/__wasm_bindgen/coverage", {
method: "POST",
body: coverage
});
"#;

let wbg_import_script = if test_mode.no_modules() {
String::from(
r#"
Expand All @@ -30,6 +46,7 @@ pub(crate) fn spawn(
let __wbgtest_console_info = wasm_bindgen.__wbgtest_console_info;
let __wbgtest_console_warn = wasm_bindgen.__wbgtest_console_warn;
let __wbgtest_console_error = wasm_bindgen.__wbgtest_console_error;
{cov_import}
let init = wasm_bindgen;
"#,
)
Expand All @@ -43,6 +60,7 @@ pub(crate) fn spawn(
__wbgtest_console_info,
__wbgtest_console_warn,
__wbgtest_console_error,
{cov_import}
default as init,
}} from './{}';
"#,
Expand Down Expand Up @@ -116,6 +134,7 @@ pub(crate) fn spawn(
cx.args({1:?});
await cx.run(tests.map(s => wasm[s]));
{cov_dump}
}}
port.onmessage = function(e) {{
Expand Down Expand Up @@ -250,6 +269,7 @@ pub(crate) fn spawn(
cx.args({1:?});
await cx.run(test.map(s => wasm[s]));
{cov_dump}
}}
const tests = [];
Expand Down Expand Up @@ -300,6 +320,16 @@ pub(crate) fn spawn(
}

return response;
} else if request.url() == "/__wasm_bindgen/coverage" {
return if let Err(e) = handle_coverage_dump(&coverage, request) {
let s: &str = &format!("Failed to dump coverage: {e}");
log::error!("{s}");
let mut ret = Response::text(s);
ret.status_code = 500;
ret
} else {
Response::empty_204()
};
}

// Otherwise we need to find the asset here. It may either be in our
Expand Down Expand Up @@ -351,6 +381,21 @@ pub(crate) fn spawn(
}
}

fn handle_coverage_dump(profraw_path: &Path, request: &Request) -> anyhow::Result<()> {
// This is run after all tests are done and dumps the data received in the request
// into a single profraw file
let mut profraw = std::fs::File::create(profraw_path)?;
let mut data = Vec::new();
if let Some(mut r_data) = request.data() {
r_data.read_to_end(&mut data)?;
}
// Warnings about empty data should have already been handled by
// the client

profraw.write_all(&data)?;
Ok(())
}

/*
* Set the Cross-Origin-Opener-Policy and Cross-Origin_Embedder-Policy headers
* on the Server response to enable worker context sharing, as described in:
Expand Down
5 changes: 5 additions & 0 deletions crates/macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ trybuild = "1.0"
wasm-bindgen = { path = "../.." }
wasm-bindgen-futures = { path = "../futures" }
web-sys = { path = "../web-sys", features = ["Worker"] }

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(wasm_bindgen_unstable_test_coverage)',
] }
17 changes: 17 additions & 0 deletions crates/macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-macro/0.2")]
#![cfg_attr(
wasm_bindgen_unstable_test_coverage,
feature(allow_internal_unstable),
allow(internal_features)
)]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_attribute]
#[cfg_attr(
wasm_bindgen_unstable_test_coverage,
allow_internal_unstable(coverage_attribute)
)]
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
match wasm_bindgen_macro_support::expand(attr.into(), input.into()) {
Ok(tokens) => {
Expand All @@ -32,6 +41,10 @@ pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
/// let worker = Worker::new(&wasm_bindgen::link_to!(module = "/src/worker.js"));
/// ```
#[proc_macro]
#[cfg_attr(
wasm_bindgen_unstable_test_coverage,
allow_internal_unstable(coverage_attribute)
)]
pub fn link_to(input: TokenStream) -> TokenStream {
match wasm_bindgen_macro_support::expand_link_to(input.into()) {
Ok(tokens) => {
Expand All @@ -48,6 +61,10 @@ pub fn link_to(input: TokenStream) -> TokenStream {
}

#[proc_macro_attribute]
#[cfg_attr(
wasm_bindgen_unstable_test_coverage,
allow_internal_unstable(coverage_attribute)
)]
pub fn __wasm_bindgen_class_marker(attr: TokenStream, input: TokenStream) -> TokenStream {
match wasm_bindgen_macro_support::expand_class_marker(attr.into(), input.into()) {
Ok(tokens) => {
Expand Down
5 changes: 5 additions & 0 deletions crates/test-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ syn = { version = "2.0", default-features = false, features = [ "parsing", "proc
[dev-dependencies]
wasm-bindgen-test = { path = "../test" }
trybuild = "1.0"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(wasm_bindgen_unstable_test_coverage)',
] }
11 changes: 11 additions & 0 deletions crates/test-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
//! See the README for `wasm-bindgen-test` for a bit more info about what's
//! going on here.

#![cfg_attr(
wasm_bindgen_unstable_test_coverage,
feature(allow_internal_unstable),
allow(internal_features)
)]

extern crate proc_macro;

use proc_macro2::*;
Expand All @@ -12,6 +18,10 @@ use std::sync::atomic::*;
static CNT: AtomicUsize = AtomicUsize::new(0);

#[proc_macro_attribute]
#[cfg_attr(
wasm_bindgen_unstable_test_coverage,
allow_internal_unstable(coverage_attribute)
)]
pub fn wasm_bindgen_test(
attr: proc_macro::TokenStream,
body: proc_macro::TokenStream,
Expand Down Expand Up @@ -102,6 +112,7 @@ pub fn wasm_bindgen_test(
tokens.extend(
quote! {
#[no_mangle]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
pub extern "C" fn #name(cx: &#wasm_bindgen_path::__rt::Context) {
let test_name = ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#ident));
#test_body
Expand Down
8 changes: 8 additions & 0 deletions crates/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,13 @@ wasm-bindgen-futures = { path = '../futures', version = '0.4.42' }
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.3.42' }
gg-alloc = { version = "1.0", optional = true }

[target.'cfg(all(target_arch = "wasm32", wasm_bindgen_unstable_test_coverage))'.dependencies]
minicov = "0.3"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(wasm_bindgen_unstable_test_coverage)',
] }

[lib]
test = false
Loading

0 comments on commit 402dae7

Please sign in to comment.