Skip to content

Commit 95cd15d

Browse files
authored
De-duplicate test filtering (#4373)
1 parent f817a79 commit 95cd15d

File tree

6 files changed

+94
-112
lines changed

6 files changed

+94
-112
lines changed

crates/cli/src/bin/wasm-bindgen-test-runner/deno.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use std::{fs, process};
44

55
use anyhow::{Context, Error};
66

7+
use crate::Tests;
78
use crate::{node::SHARED_SETUP, Cli};
89

9-
pub fn execute(module: &str, tmpdir: &Path, cli: Cli, tests: &[String]) -> Result<(), Error> {
10+
pub fn execute(module: &str, tmpdir: &Path, cli: Cli, tests: Tests) -> Result<(), Error> {
1011
let mut js_to_execute = format!(
1112
r#"import * as wasm from "./{module}.js";
1213
@@ -21,11 +22,11 @@ pub fn execute(module: &str, tmpdir: &Path, cli: Cli, tests: &[String]) -> Resul
2122
"#,
2223
nocapture = cli.nocapture.clone(),
2324
console_override = SHARED_SETUP,
24-
args = cli.into_args(),
25+
args = cli.into_args(&tests),
2526
);
2627

27-
for test in tests {
28-
js_to_execute.push_str(&format!("tests.push('{}')\n", test));
28+
for test in tests.tests {
29+
js_to_execute.push_str(&format!("tests.push('{}')\n", test.name));
2930
}
3031

3132
js_to_execute.push_str(

crates/cli/src/bin/wasm-bindgen-test-runner/main.rs

+70-40
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,41 @@ struct Cli {
7171
}
7272

7373
impl Cli {
74-
fn into_args(self) -> String {
74+
fn into_args(self, tests: &Tests) -> String {
7575
let include_ignored = self.include_ignored;
7676
let ignored = self.ignored;
77-
let exact = self.exact;
78-
let skip = self.skip;
79-
let filter = if let Some(filter) = self.filter {
80-
&format!("\"{filter}\"")
81-
} else {
82-
"undefined"
83-
};
77+
let filtered = tests.filtered;
8478

8579
format!(
8680
r#"
8781
// Forward runtime arguments.
8882
cx.include_ignored({include_ignored:?});
8983
cx.ignored({ignored:?});
90-
cx.exact({exact:?});
91-
cx.skip({skip:?});
92-
cx.filter({filter});
84+
cx.filtered_count({filtered});
9385
"#
9486
)
9587
}
9688
}
9789

90+
struct Tests {
91+
tests: Vec<Test>,
92+
filtered: usize,
93+
}
94+
95+
impl Tests {
96+
fn new() -> Self {
97+
Self {
98+
tests: Vec::new(),
99+
filtered: 0,
100+
}
101+
}
102+
}
103+
104+
struct Test {
105+
name: String,
106+
ignored: bool,
107+
}
108+
98109
fn main() -> anyhow::Result<()> {
99110
env_logger::init();
100111

@@ -114,36 +125,55 @@ fn main() -> anyhow::Result<()> {
114125
let wasm = fs::read(&cli.file).context("failed to read Wasm file")?;
115126
let mut wasm =
116127
walrus::Module::from_buffer(&wasm).context("failed to deserialize Wasm module")?;
117-
let mut tests = Vec::new();
128+
let mut tests = Tests::new();
118129

119-
for export in wasm.exports.iter() {
120-
if export.name.starts_with("__wbgt_") {
121-
tests.push(export.name.to_string());
130+
'outer: for export in wasm.exports.iter() {
131+
let Some(name) = export.name.strip_prefix("__wbgt_") else {
132+
continue;
133+
};
134+
let modifiers = name.split_once('_').expect("found invalid identifier").0;
135+
let test = Test {
136+
name: export.name.clone(),
137+
ignored: modifiers.contains('$'),
138+
};
139+
140+
if let Some(filter) = &cli.filter {
141+
let matches = if cli.exact {
142+
name == *filter
143+
} else {
144+
name.contains(filter)
145+
};
146+
147+
if !matches {
148+
tests.filtered += 1;
149+
continue;
150+
}
122151
}
123-
}
124152

125-
if cli.list {
126-
'outer: for test in tests {
127-
if !cli.ignored || test.starts_with("__wbgt_$") {
128-
if let Some(filter) = &cli.filter {
129-
let matches = if cli.exact {
130-
test == *filter
131-
} else {
132-
test.contains(filter)
133-
};
134-
135-
if !matches {
136-
continue;
137-
}
138-
}
153+
for skip in &cli.skip {
154+
let matches = if cli.exact {
155+
name == *skip
156+
} else {
157+
name.contains(skip)
158+
};
139159

140-
for skip in &cli.skip {
141-
if test.contains(skip) {
142-
continue 'outer;
143-
}
144-
}
160+
if matches {
161+
tests.filtered += 1;
162+
continue 'outer;
163+
}
164+
}
145165

146-
println!("{}: test", test.split_once("::").unwrap().1);
166+
if !test.ignored && cli.ignored {
167+
tests.filtered += 1;
168+
} else {
169+
tests.tests.push(test);
170+
}
171+
}
172+
173+
if cli.list {
174+
for test in tests.tests {
175+
if !cli.ignored || test.ignored {
176+
println!("{}: test", test.name.split_once("::").unwrap().1);
147177
}
148178
}
149179

@@ -159,7 +189,7 @@ fn main() -> anyhow::Result<()> {
159189
// Right now there's a bug where if no tests are present then the
160190
// `wasm-bindgen-test` runtime support isn't linked in, so just bail out
161191
// early saying everything is ok.
162-
if tests.is_empty() {
192+
if tests.tests.is_empty() {
163193
println!("no tests to run!");
164194
return Ok(());
165195
}
@@ -288,9 +318,9 @@ fn main() -> anyhow::Result<()> {
288318

289319
match test_mode {
290320
TestMode::Node { no_modules } => {
291-
node::execute(module, tmpdir.path(), cli, &tests, !no_modules, coverage)?
321+
node::execute(module, tmpdir.path(), cli, tests, !no_modules, coverage)?
292322
}
293-
TestMode::Deno => deno::execute(module, tmpdir.path(), cli, &tests)?,
323+
TestMode::Deno => deno::execute(module, tmpdir.path(), cli, tests)?,
294324
TestMode::Browser { .. }
295325
| TestMode::DedicatedWorker { .. }
296326
| TestMode::SharedWorker { .. }
@@ -307,7 +337,7 @@ fn main() -> anyhow::Result<()> {
307337
module,
308338
tmpdir.path(),
309339
cli,
310-
&tests,
340+
tests,
311341
test_mode,
312342
std::env::var("WASM_BINDGEN_TEST_NO_ORIGIN_ISOLATION").is_err(),
313343
coverage,

crates/cli/src/bin/wasm-bindgen-test-runner/node.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::process::Command;
77
use anyhow::{Context, Error};
88

99
use crate::Cli;
10+
use crate::Tests;
1011

1112
// depends on the variable 'wasm' and initializes te WasmBindgenTestContext cx
1213
pub const SHARED_SETUP: &str = r#"
@@ -48,7 +49,7 @@ pub fn execute(
4849
module: &str,
4950
tmpdir: &Path,
5051
cli: Cli,
51-
tests: &[String],
52+
tests: Tests,
5253
module_format: bool,
5354
coverage: PathBuf,
5455
) -> Result<(), Error> {
@@ -96,14 +97,14 @@ pub fn execute(
9697
coverage = coverage.display(),
9798
nocapture = cli.nocapture.clone(),
9899
console_override = SHARED_SETUP,
99-
args = cli.into_args(),
100+
args = cli.into_args(&tests),
100101
);
101102

102103
// Note that we're collecting *JS objects* that represent the functions to
103104
// execute, and then those objects are passed into Wasm for it to execute
104105
// when it sees fit.
105-
for test in tests {
106-
js_to_execute.push_str(&format!("tests.push('{}')\n", test));
106+
for test in tests.tests {
107+
js_to_execute.push_str(&format!("tests.push('{}')\n", test.name));
107108
}
108109
// And as a final addendum, exit with a nonzero code if any tests fail.
109110
js_to_execute.push_str(

crates/cli/src/bin/wasm-bindgen-test-runner/server.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use std::path::{Path, PathBuf};
77
use anyhow::{anyhow, Context, Error};
88
use rouille::{Request, Response, Server};
99

10-
use crate::{Cli, TestMode};
10+
use crate::{Cli, TestMode, Tests};
1111

1212
pub(crate) fn spawn(
1313
addr: &SocketAddr,
1414
headless: bool,
1515
module: &'static str,
1616
tmpdir: &Path,
1717
cli: Cli,
18-
tests: &[String],
18+
tests: Tests,
1919
test_mode: TestMode,
2020
isolate_origin: bool,
2121
coverage: PathBuf,
@@ -71,7 +71,7 @@ pub(crate) fn spawn(
7171
};
7272

7373
let nocapture = cli.nocapture;
74-
let args = cli.into_args();
74+
let args = cli.into_args(&tests);
7575

7676
if test_mode.is_worker() {
7777
let mut worker_script = if test_mode.no_modules() {
@@ -281,8 +281,8 @@ pub(crate) fn spawn(
281281
"#,
282282
));
283283
}
284-
for test in tests {
285-
js_to_execute.push_str(&format!("tests.push('{}');\n", test));
284+
for test in tests.tests {
285+
js_to_execute.push_str(&format!("tests.push('{}');\n", test.name));
286286
}
287287
js_to_execute.push_str("main(tests);\n");
288288

crates/test-macro/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub fn wasm_bindgen_test(
9797
quote! {
9898
const _: () = {
9999
#wasm_bindgen_path::__rt::wasm_bindgen::__wbindgen_coverage! {
100-
#[export_name = ::core::concat!("__wbgt_", #ignore_name, ::core::module_path!(), "::", ::core::stringify!(#ident))]
100+
#[export_name = ::core::concat!("__wbgt_", #ignore_name, "_", ::core::module_path!(), "::", ::core::stringify!(#ident))]
101101
#[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
102102
extern "C" fn __wbgt_test(cx: &#wasm_bindgen_path::__rt::Context) {
103103
let test_name = ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#ident));

crates/test/src/rt/mod.rs

+8-58
Original file line numberDiff line numberDiff line change
@@ -127,31 +127,19 @@ pub struct Context {
127127
}
128128

129129
struct State {
130-
/// An optional filter used to restrict which tests are actually executed
131-
/// and which are ignored. This is passed via the `args` function which
132-
/// comes from the command line of `wasm-bindgen-test-runner`. Currently
133-
/// this is the only "CLI option"
134-
filter: RefCell<Option<String>>,
135-
136130
/// Include ignored tests.
137131
include_ignored: Cell<bool>,
138132

139-
/// Include ignored tests.
133+
/// Only run ignored tests.
140134
ignored: Cell<bool>,
141135

142-
/// Only execute with exactly matching name.
143-
exact: Cell<bool>,
144-
145-
/// Tests to skip.
146-
skip: RefCell<Vec<String>>,
147-
148136
/// Counter of the number of tests that have succeeded.
149137
succeeded_count: Cell<usize>,
150138

151-
/// Counter of the number of tests that have been filtered
139+
/// Number of tests that have been filtered.
152140
filtered_count: Cell<usize>,
153141

154-
/// Counter of the number of tests that have been ignored
142+
/// Number of tests that have been ignored.
155143
ignored_count: Cell<usize>,
156144

157145
/// A list of all tests which have failed.
@@ -353,17 +341,14 @@ impl Context {
353341

354342
Context {
355343
state: Rc::new(State {
356-
filter: Default::default(),
357344
include_ignored: Default::default(),
358345
ignored: Default::default(),
359-
exact: Default::default(),
360-
skip: Default::default(),
361346
failures: Default::default(),
347+
succeeded_count: Default::default(),
362348
filtered_count: Default::default(),
363349
ignored_count: Default::default(),
364350
remaining: Default::default(),
365351
running: Default::default(),
366-
succeeded_count: Default::default(),
367352
formatter,
368353
timer,
369354
}),
@@ -380,19 +365,9 @@ impl Context {
380365
self.state.ignored.set(ignored);
381366
}
382367

383-
/// Handle `--exact` flag.
384-
pub fn exact(&mut self, exact: bool) {
385-
self.state.exact.set(exact);
386-
}
387-
388-
/// Handle `--skip` arguments.
389-
pub fn skip(&mut self, skip: Vec<String>) {
390-
*self.state.skip.borrow_mut() = skip;
391-
}
392-
393368
/// Handle filter argument.
394-
pub fn filter(&mut self, filter: Option<String>) {
395-
*self.state.filter.borrow_mut() = filter;
369+
pub fn filtered_count(&mut self, filtered: usize) {
370+
self.state.filtered_count.set(filtered);
396371
}
397372

398373
/// Executes a list of tests, returning a promise representing their
@@ -558,34 +533,9 @@ impl Context {
558533
should_panic: Option<Option<&'static str>>,
559534
ignore: Option<Option<&'static str>>,
560535
) {
561-
// Split away
536+
// Remove the crate name to mimic libtest more closely.
537+
// This also removes our `__wbgt_` prefix and the `ignored` and `should_panic` modifiers.
562538
let name = name.split_once("::").unwrap().1;
563-
// If our test is filtered out, record that it was filtered and move
564-
// on, nothing to do here.
565-
let filter = self.state.filter.borrow();
566-
if let Some(filter) = &*filter {
567-
let exact = self.state.exact.get();
568-
569-
let matches = if exact {
570-
name == filter
571-
} else {
572-
name.contains(filter)
573-
};
574-
575-
if !matches {
576-
let filtered = self.state.filtered_count.get();
577-
self.state.filtered_count.set(filtered + 1);
578-
return;
579-
}
580-
}
581-
582-
for skip in &*self.state.skip.borrow() {
583-
if name.contains(skip) {
584-
let filtered = self.state.filtered_count.get();
585-
self.state.filtered_count.set(filtered + 1);
586-
return;
587-
}
588-
}
589539

590540
if self.state.ignored.get() && ignore.is_none() {
591541
let filtered = self.state.filtered_count.get();

0 commit comments

Comments
 (0)