1 use super::*;
2 
3 use crate::{
4     bench::Bencher,
5     console::OutputLocation,
6     formatters::PrettyFormatter,
7     options::OutputFormat,
8     test::{
9         filter_tests,
10         parse_opts,
11         run_test,
12         DynTestFn,
13         DynTestName,
14         MetricMap,
15         RunIgnored,
16         RunStrategy,
17         ShouldPanic,
18         StaticTestName,
19         TestDesc,
20         TestDescAndFn,
21         TestOpts,
22         TrIgnored,
23         TrOk,
24         // FIXME (introduced by #65251)
25         // ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions,
26         // TestType, TrFailedMsg, TrIgnored, TrOk,
27     },
28     time::{TestTimeOptions, TimeThreshold},
29 };
30 use std::any::TypeId;
31 use std::sync::mpsc::channel;
32 use std::time::Duration;
33 
34 impl TestOpts {
new() -> TestOpts35     fn new() -> TestOpts {
36         TestOpts {
37             list: false,
38             filters: vec![],
39             filter_exact: false,
40             force_run_in_process: false,
41             exclude_should_panic: false,
42             run_ignored: RunIgnored::No,
43             run_tests: false,
44             bench_benchmarks: false,
45             logfile: None,
46             nocapture: false,
47             color: AutoColor,
48             format: OutputFormat::Pretty,
49             test_threads: None,
50             skip: vec![],
51             time_options: None,
52             options: Options::new(),
53         }
54     }
55 }
56 
one_ignored_one_unignored_test() -> Vec<TestDescAndFn>57 fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
58     vec![
59         TestDescAndFn {
60             desc: TestDesc {
61                 name: StaticTestName("1"),
62                 ignore: true,
63                 should_panic: ShouldPanic::No,
64                 allow_fail: false,
65                 test_type: TestType::Unknown,
66             },
67             testfn: DynTestFn(Box::new(move || {})),
68         },
69         TestDescAndFn {
70             desc: TestDesc {
71                 name: StaticTestName("2"),
72                 ignore: false,
73                 should_panic: ShouldPanic::No,
74                 allow_fail: false,
75                 test_type: TestType::Unknown,
76             },
77             testfn: DynTestFn(Box::new(move || {})),
78         },
79     ]
80 }
81 
82 #[test]
do_not_run_ignored_tests()83 pub fn do_not_run_ignored_tests() {
84     fn f() {
85         panic!();
86     }
87     let desc = TestDescAndFn {
88         desc: TestDesc {
89             name: StaticTestName("whatever"),
90             ignore: true,
91             should_panic: ShouldPanic::No,
92             allow_fail: false,
93             test_type: TestType::Unknown,
94         },
95         testfn: DynTestFn(Box::new(f)),
96     };
97     let (tx, rx) = channel();
98     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
99     let result = rx.recv().unwrap().result;
100     assert_ne!(result, TrOk);
101 }
102 
103 #[test]
ignored_tests_result_in_ignored()104 pub fn ignored_tests_result_in_ignored() {
105     fn f() {}
106     let desc = TestDescAndFn {
107         desc: TestDesc {
108             name: StaticTestName("whatever"),
109             ignore: true,
110             should_panic: ShouldPanic::No,
111             allow_fail: false,
112             test_type: TestType::Unknown,
113         },
114         testfn: DynTestFn(Box::new(f)),
115     };
116     let (tx, rx) = channel();
117     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
118     let result = rx.recv().unwrap().result;
119     assert_eq!(result, TrIgnored);
120 }
121 
122 // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
123 #[test]
124 #[cfg(not(target_os = "emscripten"))]
test_should_panic()125 fn test_should_panic() {
126     fn f() {
127         panic!();
128     }
129     let desc = TestDescAndFn {
130         desc: TestDesc {
131             name: StaticTestName("whatever"),
132             ignore: false,
133             should_panic: ShouldPanic::Yes,
134             allow_fail: false,
135             test_type: TestType::Unknown,
136         },
137         testfn: DynTestFn(Box::new(f)),
138     };
139     let (tx, rx) = channel();
140     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
141     let result = rx.recv().unwrap().result;
142     assert_eq!(result, TrOk);
143 }
144 
145 // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
146 #[test]
147 #[cfg(not(target_os = "emscripten"))]
test_should_panic_good_message()148 fn test_should_panic_good_message() {
149     fn f() {
150         panic!("an error message");
151     }
152     let desc = TestDescAndFn {
153         desc: TestDesc {
154             name: StaticTestName("whatever"),
155             ignore: false,
156             should_panic: ShouldPanic::YesWithMessage("error message"),
157             allow_fail: false,
158             test_type: TestType::Unknown,
159         },
160         testfn: DynTestFn(Box::new(f)),
161     };
162     let (tx, rx) = channel();
163     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
164     let result = rx.recv().unwrap().result;
165     assert_eq!(result, TrOk);
166 }
167 
168 // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
169 #[test]
170 #[cfg(not(target_os = "emscripten"))]
test_should_panic_bad_message()171 fn test_should_panic_bad_message() {
172     use crate::tests::TrFailedMsg;
173     fn f() {
174         panic!("an error message");
175     }
176     let expected = "foobar";
177     let failed_msg = r#"panic did not contain expected string
178       panic message: `"an error message"`,
179  expected substring: `"foobar"`"#;
180     let desc = TestDescAndFn {
181         desc: TestDesc {
182             name: StaticTestName("whatever"),
183             ignore: false,
184             should_panic: ShouldPanic::YesWithMessage(expected),
185             allow_fail: false,
186             test_type: TestType::Unknown,
187         },
188         testfn: DynTestFn(Box::new(f)),
189     };
190     let (tx, rx) = channel();
191     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
192     let result = rx.recv().unwrap().result;
193     assert_eq!(result, TrFailedMsg(failed_msg.to_string()));
194 }
195 
196 // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
197 #[test]
198 #[cfg(not(target_os = "emscripten"))]
test_should_panic_non_string_message_type()199 fn test_should_panic_non_string_message_type() {
200     use crate::tests::TrFailedMsg;
201     fn f() {
202         panic!(1i32);
203     }
204     let expected = "foobar";
205     let failed_msg = format!(
206         r#"expected panic with string value,
207  found non-string value: `{:?}`
208      expected substring: `"foobar"`"#,
209         TypeId::of::<i32>()
210     );
211     let desc = TestDescAndFn {
212         desc: TestDesc {
213             name: StaticTestName("whatever"),
214             ignore: false,
215             should_panic: ShouldPanic::YesWithMessage(expected),
216             allow_fail: false,
217             test_type: TestType::Unknown,
218         },
219         testfn: DynTestFn(Box::new(f)),
220     };
221     let (tx, rx) = channel();
222     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
223     let result = rx.recv().unwrap().result;
224     assert_eq!(result, TrFailedMsg(failed_msg));
225 }
226 
227 // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
228 #[test]
229 #[cfg(not(target_os = "emscripten"))]
test_should_panic_but_succeeds()230 fn test_should_panic_but_succeeds() {
231     fn f() {}
232     let desc = TestDescAndFn {
233         desc: TestDesc {
234             name: StaticTestName("whatever"),
235             ignore: false,
236             should_panic: ShouldPanic::Yes,
237             allow_fail: false,
238             test_type: TestType::Unknown,
239         },
240         testfn: DynTestFn(Box::new(f)),
241     };
242     let (tx, rx) = channel();
243     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
244     let result = rx.recv().unwrap().result;
245     assert_eq!(result, TrFailedMsg("test did not panic as expected".to_string()));
246 }
247 
report_time_test_template(report_time: bool) -> Option<TestExecTime>248 fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
249     fn f() {}
250     let desc = TestDescAndFn {
251         desc: TestDesc {
252             name: StaticTestName("whatever"),
253             ignore: false,
254             should_panic: ShouldPanic::No,
255             allow_fail: false,
256             test_type: TestType::Unknown,
257         },
258         testfn: DynTestFn(Box::new(f)),
259     };
260     let time_options = if report_time { Some(TestTimeOptions::default()) } else { None };
261 
262     let test_opts = TestOpts { time_options, ..TestOpts::new() };
263     let (tx, rx) = channel();
264     run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No);
265     let exec_time = rx.recv().unwrap().exec_time;
266     exec_time
267 }
268 
269 #[test]
test_should_not_report_time()270 fn test_should_not_report_time() {
271     let exec_time = report_time_test_template(false);
272     assert!(exec_time.is_none());
273 }
274 
275 #[test]
test_should_report_time()276 fn test_should_report_time() {
277     let exec_time = report_time_test_template(true);
278     assert!(exec_time.is_some());
279 }
280 
time_test_failure_template(test_type: TestType) -> TestResult281 fn time_test_failure_template(test_type: TestType) -> TestResult {
282     fn f() {}
283     let desc = TestDescAndFn {
284         desc: TestDesc {
285             name: StaticTestName("whatever"),
286             ignore: false,
287             should_panic: ShouldPanic::No,
288             allow_fail: false,
289             test_type,
290         },
291         testfn: DynTestFn(Box::new(f)),
292     };
293     // `Default` will initialize all the thresholds to 0 milliseconds.
294     let mut time_options = TestTimeOptions::default();
295     time_options.error_on_excess = true;
296 
297     let test_opts = TestOpts { time_options: Some(time_options), ..TestOpts::new() };
298     let (tx, rx) = channel();
299     run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No);
300     let result = rx.recv().unwrap().result;
301 
302     result
303 }
304 
305 #[test]
test_error_on_exceed()306 fn test_error_on_exceed() {
307     let types = [TestType::UnitTest, TestType::IntegrationTest, TestType::DocTest];
308 
309     for test_type in types.iter() {
310         let result = time_test_failure_template(*test_type);
311 
312         assert_eq!(result, TestResult::TrTimedFail);
313     }
314 
315     // Check that for unknown tests thresholds aren't applied.
316     let result = time_test_failure_template(TestType::Unknown);
317     assert_eq!(result, TestResult::TrOk);
318 }
319 
typed_test_desc(test_type: TestType) -> TestDesc320 fn typed_test_desc(test_type: TestType) -> TestDesc {
321     TestDesc {
322         name: StaticTestName("whatever"),
323         ignore: false,
324         should_panic: ShouldPanic::No,
325         allow_fail: false,
326         test_type,
327     }
328 }
329 
test_exec_time(millis: u64) -> TestExecTime330 fn test_exec_time(millis: u64) -> TestExecTime {
331     TestExecTime(Duration::from_millis(millis))
332 }
333 
334 #[test]
test_time_options_threshold()335 fn test_time_options_threshold() {
336     let unit = TimeThreshold::new(Duration::from_millis(50), Duration::from_millis(100));
337     let integration = TimeThreshold::new(Duration::from_millis(500), Duration::from_millis(1000));
338     let doc = TimeThreshold::new(Duration::from_millis(5000), Duration::from_millis(10000));
339 
340     let options = TestTimeOptions {
341         error_on_excess: false,
342         colored: false,
343         unit_threshold: unit.clone(),
344         integration_threshold: integration.clone(),
345         doctest_threshold: doc.clone(),
346     };
347 
348     let test_vector = [
349         (TestType::UnitTest, unit.warn.as_millis() - 1, false, false),
350         (TestType::UnitTest, unit.warn.as_millis(), true, false),
351         (TestType::UnitTest, unit.critical.as_millis(), true, true),
352         (TestType::IntegrationTest, integration.warn.as_millis() - 1, false, false),
353         (TestType::IntegrationTest, integration.warn.as_millis(), true, false),
354         (TestType::IntegrationTest, integration.critical.as_millis(), true, true),
355         (TestType::DocTest, doc.warn.as_millis() - 1, false, false),
356         (TestType::DocTest, doc.warn.as_millis(), true, false),
357         (TestType::DocTest, doc.critical.as_millis(), true, true),
358     ];
359 
360     for (test_type, time, expected_warn, expected_critical) in test_vector.iter() {
361         let test_desc = typed_test_desc(*test_type);
362         let exec_time = test_exec_time(*time as u64);
363 
364         assert_eq!(options.is_warn(&test_desc, &exec_time), *expected_warn);
365         assert_eq!(options.is_critical(&test_desc, &exec_time), *expected_critical);
366     }
367 }
368 
369 #[test]
parse_ignored_flag()370 fn parse_ignored_flag() {
371     let args = vec!["progname".to_string(), "filter".to_string(), "--ignored".to_string()];
372     let opts = parse_opts(&args).unwrap().unwrap();
373     assert_eq!(opts.run_ignored, RunIgnored::Only);
374 }
375 
376 #[test]
parse_show_output_flag()377 fn parse_show_output_flag() {
378     let args = vec!["progname".to_string(), "filter".to_string(), "--show-output".to_string()];
379     let opts = parse_opts(&args).unwrap().unwrap();
380     assert!(opts.options.display_output);
381 }
382 
383 #[test]
parse_include_ignored_flag()384 fn parse_include_ignored_flag() {
385     let args = vec![
386         "progname".to_string(),
387         "filter".to_string(),
388         "-Zunstable-options".to_string(),
389         "--include-ignored".to_string(),
390     ];
391     let opts = parse_opts(&args).unwrap().unwrap();
392     assert_eq!(opts.run_ignored, RunIgnored::Yes);
393 }
394 
395 #[test]
filter_for_ignored_option()396 pub fn filter_for_ignored_option() {
397     // When we run ignored tests the test filter should filter out all the
398     // unignored tests and flip the ignore flag on the rest to false
399 
400     let mut opts = TestOpts::new();
401     opts.run_tests = true;
402     opts.run_ignored = RunIgnored::Only;
403 
404     let tests = one_ignored_one_unignored_test();
405     let filtered = filter_tests(&opts, tests);
406 
407     assert_eq!(filtered.len(), 1);
408     assert_eq!(filtered[0].desc.name.to_string(), "1");
409     assert!(!filtered[0].desc.ignore);
410 }
411 
412 #[test]
run_include_ignored_option()413 pub fn run_include_ignored_option() {
414     // When we "--include-ignored" tests, the ignore flag should be set to false on
415     // all tests and no test filtered out
416 
417     let mut opts = TestOpts::new();
418     opts.run_tests = true;
419     opts.run_ignored = RunIgnored::Yes;
420 
421     let tests = one_ignored_one_unignored_test();
422     let filtered = filter_tests(&opts, tests);
423 
424     assert_eq!(filtered.len(), 2);
425     assert!(!filtered[0].desc.ignore);
426     assert!(!filtered[1].desc.ignore);
427 }
428 
429 #[test]
exclude_should_panic_option()430 pub fn exclude_should_panic_option() {
431     let mut opts = TestOpts::new();
432     opts.run_tests = true;
433     opts.exclude_should_panic = true;
434 
435     let mut tests = one_ignored_one_unignored_test();
436     tests.push(TestDescAndFn {
437         desc: TestDesc {
438             name: StaticTestName("3"),
439             ignore: false,
440             should_panic: ShouldPanic::Yes,
441             allow_fail: false,
442             test_type: TestType::Unknown,
443         },
444         testfn: DynTestFn(Box::new(move || {})),
445     });
446 
447     let filtered = filter_tests(&opts, tests);
448 
449     assert_eq!(filtered.len(), 2);
450     assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
451 }
452 
453 #[test]
exact_filter_match()454 pub fn exact_filter_match() {
455     fn tests() -> Vec<TestDescAndFn> {
456         vec!["base", "base::test", "base::test1", "base::test2"]
457             .into_iter()
458             .map(|name| TestDescAndFn {
459                 desc: TestDesc {
460                     name: StaticTestName(name),
461                     ignore: false,
462                     should_panic: ShouldPanic::No,
463                     allow_fail: false,
464                     test_type: TestType::Unknown,
465                 },
466                 testfn: DynTestFn(Box::new(move || {})),
467             })
468             .collect()
469     }
470 
471     let substr =
472         filter_tests(&TestOpts { filters: vec!["base".into()], ..TestOpts::new() }, tests());
473     assert_eq!(substr.len(), 4);
474 
475     let substr = filter_tests(&TestOpts { filters: vec!["bas".into()], ..TestOpts::new() }, tests());
476     assert_eq!(substr.len(), 4);
477 
478     let substr =
479         filter_tests(&TestOpts { filters: vec!["::test".into()], ..TestOpts::new() }, tests());
480     assert_eq!(substr.len(), 3);
481 
482     let substr =
483         filter_tests(&TestOpts { filters: vec!["base::test".into()], ..TestOpts::new() }, tests());
484     assert_eq!(substr.len(), 3);
485 
486     let substr = filter_tests(
487         &TestOpts { filters: vec!["test1".into(), "test2".into()], ..TestOpts::new() },
488         tests(),
489     );
490     assert_eq!(substr.len(), 2);
491 
492     let exact = filter_tests(
493         &TestOpts { filters: vec!["base".into()], filter_exact: true, ..TestOpts::new() },
494         tests(),
495     );
496     assert_eq!(exact.len(), 1);
497 
498     let exact = filter_tests(
499         &TestOpts { filters: vec!["bas".into()], filter_exact: true, ..TestOpts::new() },
500         tests(),
501     );
502     assert_eq!(exact.len(), 0);
503 
504     let exact = filter_tests(
505         &TestOpts { filters: vec!["::test".into()], filter_exact: true, ..TestOpts::new() },
506         tests(),
507     );
508     assert_eq!(exact.len(), 0);
509 
510     let exact = filter_tests(
511         &TestOpts { filters: vec!["base::test".into()], filter_exact: true, ..TestOpts::new() },
512         tests(),
513     );
514     assert_eq!(exact.len(), 1);
515 
516     let exact = filter_tests(
517         &TestOpts {
518             filters: vec!["base".into(), "base::test".into()],
519             filter_exact: true,
520             ..TestOpts::new()
521         },
522         tests(),
523     );
524     assert_eq!(exact.len(), 2);
525 }
526 
527 #[test]
sort_tests()528 pub fn sort_tests() {
529     let mut opts = TestOpts::new();
530     opts.run_tests = true;
531 
532     let names = vec![
533         "sha1::test".to_string(),
534         "isize::test_to_str".to_string(),
535         "isize::test_pow".to_string(),
536         "test::do_not_run_ignored_tests".to_string(),
537         "test::ignored_tests_result_in_ignored".to_string(),
538         "test::first_free_arg_should_be_a_filter".to_string(),
539         "test::parse_ignored_flag".to_string(),
540         "test::parse_include_ignored_flag".to_string(),
541         "test::filter_for_ignored_option".to_string(),
542         "test::run_include_ignored_option".to_string(),
543         "test::sort_tests".to_string(),
544     ];
545     let tests = {
546         fn testfn() {}
547         let mut tests = Vec::new();
548         for name in &names {
549             let test = TestDescAndFn {
550                 desc: TestDesc {
551                     name: DynTestName((*name).clone()),
552                     ignore: false,
553                     should_panic: ShouldPanic::No,
554                     allow_fail: false,
555                     test_type: TestType::Unknown,
556                 },
557                 testfn: DynTestFn(Box::new(testfn)),
558             };
559             tests.push(test);
560         }
561         tests
562     };
563     let filtered = filter_tests(&opts, tests);
564 
565     let expected = vec![
566         "isize::test_pow".to_string(),
567         "isize::test_to_str".to_string(),
568         "sha1::test".to_string(),
569         "test::do_not_run_ignored_tests".to_string(),
570         "test::filter_for_ignored_option".to_string(),
571         "test::first_free_arg_should_be_a_filter".to_string(),
572         "test::ignored_tests_result_in_ignored".to_string(),
573         "test::parse_ignored_flag".to_string(),
574         "test::parse_include_ignored_flag".to_string(),
575         "test::run_include_ignored_option".to_string(),
576         "test::sort_tests".to_string(),
577     ];
578 
579     for (a, b) in expected.iter().zip(filtered) {
580         assert_eq!(*a, b.desc.name.to_string());
581     }
582 }
583 
584 #[test]
test_metricmap_compare()585 pub fn test_metricmap_compare() {
586     let mut m1 = MetricMap::new();
587     let mut m2 = MetricMap::new();
588     m1.insert_metric("in-both-noise", 1000.0, 200.0);
589     m2.insert_metric("in-both-noise", 1100.0, 200.0);
590 
591     m1.insert_metric("in-first-noise", 1000.0, 2.0);
592     m2.insert_metric("in-second-noise", 1000.0, 2.0);
593 
594     m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
595     m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
596 
597     m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
598     m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
599 
600     m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
601     m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
602 
603     m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
604     m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
605 }
606 
607 #[test]
test_bench_once_no_iter()608 pub fn test_bench_once_no_iter() {
609     fn f(_: &mut Bencher) {}
610     bench::run_once(f);
611 }
612 
613 #[test]
test_bench_once_iter()614 pub fn test_bench_once_iter() {
615     fn f(b: &mut Bencher) {
616         b.iter(|| {})
617     }
618     bench::run_once(f);
619 }
620 
621 #[test]
test_bench_no_iter()622 pub fn test_bench_no_iter() {
623     fn f(_: &mut Bencher) {}
624 
625     let (tx, rx) = channel();
626 
627     let desc = TestDesc {
628         name: StaticTestName("f"),
629         ignore: false,
630         should_panic: ShouldPanic::No,
631         allow_fail: false,
632         test_type: TestType::Unknown,
633     };
634 
635     crate::bench::benchmark(desc, tx, true, f);
636     rx.recv().unwrap();
637 }
638 
639 #[test]
test_bench_iter()640 pub fn test_bench_iter() {
641     fn f(b: &mut Bencher) {
642         b.iter(|| {})
643     }
644 
645     let (tx, rx) = channel();
646 
647     let desc = TestDesc {
648         name: StaticTestName("f"),
649         ignore: false,
650         should_panic: ShouldPanic::No,
651         allow_fail: false,
652         test_type: TestType::Unknown,
653     };
654 
655     crate::bench::benchmark(desc, tx, true, f);
656     rx.recv().unwrap();
657 }
658 
659 #[test]
should_sort_failures_before_printing_them()660 fn should_sort_failures_before_printing_them() {
661     let test_a = TestDesc {
662         name: StaticTestName("a"),
663         ignore: false,
664         should_panic: ShouldPanic::No,
665         allow_fail: false,
666         test_type: TestType::Unknown,
667     };
668 
669     let test_b = TestDesc {
670         name: StaticTestName("b"),
671         ignore: false,
672         should_panic: ShouldPanic::No,
673         allow_fail: false,
674         test_type: TestType::Unknown,
675     };
676 
677     let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
678 
679     let st = console::ConsoleTestState {
680         log_out: None,
681         total: 0,
682         passed: 0,
683         failed: 0,
684         ignored: 0,
685         allowed_fail: 0,
686         filtered_out: 0,
687         measured: 0,
688         exec_time: None,
689         metrics: MetricMap::new(),
690         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
691         options: Options::new(),
692         not_failures: Vec::new(),
693         time_failures: Vec::new(),
694     };
695 
696     out.write_failures(&st).unwrap();
697     let s = match out.output_location() {
698         &OutputLocation::Raw(ref m) => String::from_utf8_lossy(&m[..]),
699         &OutputLocation::Pretty(_) => unreachable!(),
700     };
701 
702     let apos = s.find("a").unwrap();
703     let bpos = s.find("b").unwrap();
704     assert!(apos < bpos);
705 }
706