nextest_runner/reporter/displayer/
status_level.rs1use super::TestOutputDisplay;
9use crate::reporter::events::CancelReason;
10use serde::Deserialize;
11
12#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
17#[cfg_attr(test, derive(test_strategy::Arbitrary))]
18#[serde(rename_all = "kebab-case")]
19#[non_exhaustive]
20pub enum StatusLevel {
21 None,
23
24 Fail,
26
27 Retry,
29
30 Slow,
32
33 Leak,
35
36 Pass,
38
39 Skip,
41
42 All,
44}
45
46#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
54#[cfg_attr(test, derive(test_strategy::Arbitrary))]
55#[serde(rename_all = "kebab-case")]
56#[non_exhaustive]
57pub enum FinalStatusLevel {
58 None,
60
61 Fail,
63
64 #[serde(alias = "retry")]
66 Flaky,
67
68 Slow,
70
71 Skip,
73
74 Leak,
76
77 Pass,
79
80 All,
82}
83
84pub(crate) struct StatusLevels {
85 pub(crate) status_level: StatusLevel,
86 pub(crate) final_status_level: FinalStatusLevel,
87}
88
89impl StatusLevels {
90 pub(super) fn compute_output_on_test_finished(
91 &self,
92 display: TestOutputDisplay,
93 cancel_status: Option<CancelReason>,
94 test_status_level: StatusLevel,
95 test_final_status_level: FinalStatusLevel,
96 ) -> OutputOnTestFinished {
97 let write_status_line = self.status_level >= test_status_level;
98
99 let is_immediate = display.is_immediate();
100 let is_final = display.is_final() || self.final_status_level >= test_final_status_level;
103
104 let show_immediate = is_immediate && cancel_status <= Some(CancelReason::Signal);
128
129 let store_final = if is_final && cancel_status < Some(CancelReason::Signal)
130 || !is_immediate && is_final && cancel_status == Some(CancelReason::Signal)
131 {
132 OutputStoreFinal::Yes {
133 display_output: display.is_final(),
134 }
135 } else if is_immediate && is_final && cancel_status == Some(CancelReason::Signal) {
136 OutputStoreFinal::Yes {
139 display_output: false,
140 }
141 } else {
142 OutputStoreFinal::No
143 };
144
145 OutputOnTestFinished {
146 write_status_line,
147 show_immediate,
148 store_final,
149 }
150 }
151}
152
153#[derive(Debug, PartialEq, Eq)]
154pub(super) struct OutputOnTestFinished {
155 pub(super) write_status_line: bool,
156 pub(super) show_immediate: bool,
157 pub(super) store_final: OutputStoreFinal,
158}
159
160#[derive(Debug, PartialEq, Eq)]
161pub(super) enum OutputStoreFinal {
162 No,
164
165 Yes { display_output: bool },
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use test_strategy::proptest;
174
175 #[proptest(cases = 64)]
181 fn on_test_finished_dont_write_status_line(
182 display: TestOutputDisplay,
183 cancel_status: Option<CancelReason>,
184 #[filter(StatusLevel::Pass < #test_status_level)] test_status_level: StatusLevel,
185 test_final_status_level: FinalStatusLevel,
186 ) {
187 let status_levels = StatusLevels {
188 status_level: StatusLevel::Pass,
189 final_status_level: FinalStatusLevel::Fail,
190 };
191
192 let actual = status_levels.compute_output_on_test_finished(
193 display,
194 cancel_status,
195 test_status_level,
196 test_final_status_level,
197 );
198
199 assert!(!actual.write_status_line);
200 }
201
202 #[proptest(cases = 64)]
203 fn on_test_finished_write_status_line(
204 display: TestOutputDisplay,
205 cancel_status: Option<CancelReason>,
206 #[filter(StatusLevel::Pass >= #test_status_level)] test_status_level: StatusLevel,
207 test_final_status_level: FinalStatusLevel,
208 ) {
209 let status_levels = StatusLevels {
210 status_level: StatusLevel::Pass,
211 final_status_level: FinalStatusLevel::Fail,
212 };
213
214 let actual = status_levels.compute_output_on_test_finished(
215 display,
216 cancel_status,
217 test_status_level,
218 test_final_status_level,
219 );
220 assert!(actual.write_status_line);
221 }
222
223 #[proptest(cases = 64)]
224 fn on_test_finished_with_interrupt(
225 display: TestOutputDisplay,
227 test_status_level: StatusLevel,
231 test_final_status_level: FinalStatusLevel,
232 ) {
233 let status_levels = StatusLevels {
234 status_level: StatusLevel::Pass,
235 final_status_level: FinalStatusLevel::Fail,
236 };
237
238 let actual = status_levels.compute_output_on_test_finished(
239 display,
240 Some(CancelReason::Interrupt),
241 test_status_level,
242 test_final_status_level,
243 );
244 assert!(!actual.show_immediate);
245 assert_eq!(actual.store_final, OutputStoreFinal::No);
246 }
247
248 #[proptest(cases = 64)]
249 fn on_test_finished_dont_show_immediate(
250 #[filter(!#display.is_immediate())] display: TestOutputDisplay,
251 cancel_status: Option<CancelReason>,
252 test_status_level: StatusLevel,
254 test_final_status_level: FinalStatusLevel,
255 ) {
256 let status_levels = StatusLevels {
257 status_level: StatusLevel::Pass,
258 final_status_level: FinalStatusLevel::Fail,
259 };
260
261 let actual = status_levels.compute_output_on_test_finished(
262 display,
263 cancel_status,
264 test_status_level,
265 test_final_status_level,
266 );
267 assert!(!actual.show_immediate);
268 }
269
270 #[proptest(cases = 64)]
271 fn on_test_finished_show_immediate(
272 #[filter(#display.is_immediate())] display: TestOutputDisplay,
273 #[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
274 test_status_level: StatusLevel,
276 test_final_status_level: FinalStatusLevel,
277 ) {
278 let status_levels = StatusLevels {
279 status_level: StatusLevel::Pass,
280 final_status_level: FinalStatusLevel::Fail,
281 };
282
283 let actual = status_levels.compute_output_on_test_finished(
284 display,
285 cancel_status,
286 test_status_level,
287 test_final_status_level,
288 );
289 assert!(actual.show_immediate);
290 }
291
292 #[proptest(cases = 64)]
295 fn on_test_finished_dont_store_final(
296 #[filter(!#display.is_final())] display: TestOutputDisplay,
297 cancel_status: Option<CancelReason>,
298 test_status_level: StatusLevel,
300 #[filter(FinalStatusLevel::Fail < #test_final_status_level)]
302 test_final_status_level: FinalStatusLevel,
303 ) {
304 let status_levels = StatusLevels {
305 status_level: StatusLevel::Pass,
306 final_status_level: FinalStatusLevel::Fail,
307 };
308
309 let actual = status_levels.compute_output_on_test_finished(
310 display,
311 cancel_status,
312 test_status_level,
313 test_final_status_level,
314 );
315 assert_eq!(actual.store_final, OutputStoreFinal::No);
316 }
317
318 #[proptest(cases = 64)]
321 fn on_test_finished_store_final_1(
322 #[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
323 test_status_level: StatusLevel,
325 test_final_status_level: FinalStatusLevel,
326 ) {
327 let status_levels = StatusLevels {
328 status_level: StatusLevel::Pass,
329 final_status_level: FinalStatusLevel::Fail,
330 };
331
332 let actual = status_levels.compute_output_on_test_finished(
333 TestOutputDisplay::Final,
334 cancel_status,
335 test_status_level,
336 test_final_status_level,
337 );
338 assert_eq!(
339 actual.store_final,
340 OutputStoreFinal::Yes {
341 display_output: true
342 }
343 );
344 }
345
346 #[proptest(cases = 64)]
349 fn on_test_finished_store_final_2(
350 #[filter(#cancel_status < Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
351 test_status_level: StatusLevel,
352 test_final_status_level: FinalStatusLevel,
353 ) {
354 let status_levels = StatusLevels {
355 status_level: StatusLevel::Pass,
356 final_status_level: FinalStatusLevel::Fail,
357 };
358
359 let actual = status_levels.compute_output_on_test_finished(
360 TestOutputDisplay::ImmediateFinal,
361 cancel_status,
362 test_status_level,
363 test_final_status_level,
364 );
365 assert_eq!(
366 actual.store_final,
367 OutputStoreFinal::Yes {
368 display_output: true
369 }
370 );
371 }
372
373 #[proptest(cases = 64)]
376 fn on_test_finished_store_final_3(
377 test_status_level: StatusLevel,
378 test_final_status_level: FinalStatusLevel,
379 ) {
380 let status_levels = StatusLevels {
381 status_level: StatusLevel::Pass,
382 final_status_level: FinalStatusLevel::Fail,
383 };
384
385 let actual = status_levels.compute_output_on_test_finished(
386 TestOutputDisplay::ImmediateFinal,
387 Some(CancelReason::Signal),
388 test_status_level,
389 test_final_status_level,
390 );
391 assert_eq!(
392 actual.store_final,
393 OutputStoreFinal::Yes {
394 display_output: false,
395 }
396 );
397 }
398
399 #[proptest(cases = 64)]
401 fn on_test_finished_store_final_4(
402 #[filter(!#display.is_final())] display: TestOutputDisplay,
403 #[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
404 test_status_level: StatusLevel,
406 #[filter(FinalStatusLevel::Fail >= #test_final_status_level)]
408 test_final_status_level: FinalStatusLevel,
409 ) {
410 let status_levels = StatusLevels {
411 status_level: StatusLevel::Pass,
412 final_status_level: FinalStatusLevel::Fail,
413 };
414
415 let actual = status_levels.compute_output_on_test_finished(
416 display,
417 cancel_status,
418 test_status_level,
419 test_final_status_level,
420 );
421 assert_eq!(
422 actual.store_final,
423 OutputStoreFinal::Yes {
424 display_output: false,
425 }
426 );
427 }
428}