Skip to content

Commit efcda24

Browse files
authored
fix(harness): Report cases as we discover them (#120)
This can run some level of discovery logic during discovery but more is needed for cases like `tidy.rs`
2 parents 0e20a5a + ea51760 commit efcda24

File tree

8 files changed

+356
-370
lines changed

8 files changed

+356
-370
lines changed

DESIGN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Decisions
3838
- There is likely not enough value add in the failure message
3939
- This puts more of a burden on custom test harnesses for their implementation than is strictly needed
4040
- Report failures separate from test-complete so we can have multiple
41+
- `DiscoverCase` order is unspecified so we can report them as found rather than waiting for a sort phase so users can identify slow discovery
4142

4243
### Prior Art
4344

crates/libtest-json/event.schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
]
136136
},
137137
"DiscoverCase": {
138+
"description": "A test case was found\n\nThe order these are returned in is unspecified and is unrelated to the order they are run in.",
138139
"type": "object",
139140
"properties": {
140141
"name": {

crates/libtest-json/src/event.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ impl DiscoverStart {
115115
}
116116
}
117117

118+
/// A test case was found
119+
///
120+
/// The order these are returned in is unspecified and is unrelated to the order they are run in.
118121
#[derive(Clone, Debug)]
119122
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
120123
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]

crates/libtest2-harness/src/harness.rs

Lines changed: 55 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -93,22 +93,49 @@ impl Harness<StateParsed> {
9393
mut self,
9494
cases: impl IntoIterator<Item = impl Case + 'static>,
9595
) -> std::io::Result<Harness<StateDiscovered>> {
96-
let mut cases = cases
97-
.into_iter()
98-
.map(|c| Box::new(c) as Box<dyn Case>)
99-
.collect();
100-
discover(
101-
&self.state.start,
102-
&self.state.opts,
103-
&mut cases,
104-
self.state.notifier.as_mut(),
96+
self.state.notifier.notify(
97+
notify::event::DiscoverStart {
98+
elapsed_s: Some(notify::Elapsed(self.state.start.elapsed())),
99+
}
100+
.into(),
101+
)?;
102+
103+
let mut selected_cases = Vec::new();
104+
for case in cases {
105+
let selected = case_priority(&case, &self.state.opts).is_some();
106+
self.state.notifier.notify(
107+
notify::event::DiscoverCase {
108+
name: case.name().to_owned(),
109+
mode: RunMode::Test,
110+
selected,
111+
elapsed_s: Some(notify::Elapsed(self.state.start.elapsed())),
112+
}
113+
.into(),
114+
)?;
115+
if selected {
116+
selected_cases.push(Box::new(case) as Box<dyn Case>);
117+
}
118+
}
119+
120+
selected_cases.sort_unstable_by_key(|case| {
121+
let priority = case_priority(case.as_ref(), &self.state.opts);
122+
let name = case.name().to_owned();
123+
(priority, name)
124+
});
125+
126+
self.state.notifier.notify(
127+
notify::event::DiscoverComplete {
128+
elapsed_s: Some(notify::Elapsed(self.state.start.elapsed())),
129+
}
130+
.into(),
105131
)?;
132+
106133
Ok(Harness {
107134
state: StateDiscovered {
108135
start: self.state.start,
109136
opts: self.state.opts,
110137
notifier: self.state.notifier,
111-
cases,
138+
cases: selected_cases,
112139
},
113140
})
114141
}
@@ -238,73 +265,27 @@ fn notifier(opts: &libtest_lexarg::TestOpts) -> Box<dyn notify::Notifier> {
238265
}
239266
}
240267

241-
fn discover(
242-
start: &std::time::Instant,
243-
opts: &libtest_lexarg::TestOpts,
244-
cases: &mut Vec<Box<dyn Case>>,
245-
notifier: &mut dyn notify::Notifier,
246-
) -> std::io::Result<()> {
247-
notifier.notify(
248-
notify::event::DiscoverStart {
249-
elapsed_s: Some(notify::Elapsed(start.elapsed())),
250-
}
251-
.into(),
252-
)?;
253-
254-
let matches_filter = |case: &dyn Case, filter: &str| {
255-
let test_name = case.name();
256-
257-
match opts.filter_exact {
258-
true => test_name == filter,
259-
false => test_name.contains(filter),
260-
}
261-
};
262-
263-
// Do this first so it applies to both discover and running
264-
cases.sort_unstable_by_key(|case| {
265-
let priority = if opts.filters.is_empty() {
266-
Some(0)
267-
} else {
268-
opts.filters
269-
.iter()
270-
.position(|filter| matches_filter(case.as_ref(), filter))
271-
};
272-
let name = case.name().to_owned();
273-
(priority, name)
274-
});
275-
276-
let mut retain_cases = Vec::with_capacity(cases.len());
277-
for case in cases.iter() {
278-
let filtered_in = opts.filters.is_empty()
279-
|| opts
280-
.filters
281-
.iter()
282-
.any(|filter| matches_filter(case.as_ref(), filter));
283-
let filtered_out =
284-
!opts.skip.is_empty() && opts.skip.iter().any(|sf| matches_filter(case.as_ref(), sf));
285-
let retain_case = filtered_in && !filtered_out;
286-
retain_cases.push(retain_case);
287-
notifier.notify(
288-
notify::event::DiscoverCase {
289-
name: case.name().to_owned(),
290-
mode: RunMode::Test,
291-
selected: retain_case,
292-
elapsed_s: Some(notify::Elapsed(start.elapsed())),
293-
}
294-
.into(),
295-
)?;
268+
fn case_priority(case: &dyn Case, opts: &libtest_lexarg::TestOpts) -> Option<usize> {
269+
let filtered_out =
270+
!opts.skip.is_empty() && opts.skip.iter().any(|sf| matches_filter(case, sf, opts));
271+
if filtered_out {
272+
None
273+
} else if opts.filters.is_empty() {
274+
Some(0)
275+
} else {
276+
opts.filters
277+
.iter()
278+
.position(|filter| matches_filter(case, filter, opts))
296279
}
297-
let mut retain_cases = retain_cases.into_iter();
298-
cases.retain(|_| retain_cases.next().unwrap());
280+
}
299281

300-
notifier.notify(
301-
notify::event::DiscoverComplete {
302-
elapsed_s: Some(notify::Elapsed(start.elapsed())),
303-
}
304-
.into(),
305-
)?;
282+
fn matches_filter(case: &dyn Case, filter: &str, opts: &libtest_lexarg::TestOpts) -> bool {
283+
let test_name = case.name();
306284

307-
Ok(())
285+
match opts.filter_exact {
286+
true => test_name == filter,
287+
false => test_name.contains(filter),
288+
}
308289
}
309290

310291
fn run(

crates/libtest2-mimic/tests/testsuite/argfile.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,17 @@ fn list() {
9090
0,
9191
str![[r#"
9292
one: test
93-
one_two: test
94-
three: test
9593
two: test
94+
three: test
95+
one_two: test
9696
9797
4 tests
9898
9999
100100
"#]],
101101
str![[r#"
102102
one: test
103-
one_two: test
103+
two: test
104104
...
105105
106106
4 tests

0 commit comments

Comments
 (0)