]> git.lizzy.rs Git - rust.git/blob - src/libtest/lib.rs
Rollup merge of #60885 - euclio:strip-synstructure-consts, r=GuillaumeGomez
[rust.git] / src / libtest / lib.rs
1 //! Support code for rustc's built in unit-test and micro-benchmarking
2 //! framework.
3 //!
4 //! Almost all user code will only be interested in `Bencher` and
5 //! `black_box`. All other interactions (such as writing tests and
6 //! benchmarks themselves) should be done via the `#[test]` and
7 //! `#[bench]` attributes.
8 //!
9 //! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.
10
11 // Currently, not much of this is meant for users. It is intended to
12 // support the simplest interface possible for representing and
13 // running tests while providing a base that other test frameworks may
14 // build off of.
15
16 // N.B., this is also specified in this crate's Cargo.toml, but libsyntax contains logic specific to
17 // this crate, which relies on this attribute (rather than the value of `--crate-name` passed by
18 // cargo) to detect this crate.
19
20 #![deny(rust_2018_idioms)]
21 #![crate_name = "test"]
22 #![unstable(feature = "test", issue = "27812")]
23 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
24 #![feature(asm)]
25 #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))]
26 #![feature(nll)]
27 #![feature(set_stdio)]
28 #![feature(panic_unwind)]
29 #![feature(staged_api)]
30 #![feature(termination_trait_lib)]
31 #![feature(test)]
32
33 use getopts;
34 #[cfg(any(unix, target_os = "cloudabi"))]
35 extern crate libc;
36 use term;
37
38 // FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
39 //                on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc
40 //                so we don't link libtest against libunwind (for the time being)
41 //                even though it means that libtest won't be fully functional on
42 //                these platforms.
43 //
44 // See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
45 #[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))]
46 extern crate panic_unwind;
47
48 pub use self::ColorConfig::*;
49 use self::NamePadding::*;
50 use self::OutputLocation::*;
51 use self::TestEvent::*;
52 pub use self::TestFn::*;
53 pub use self::TestName::*;
54 pub use self::TestResult::*;
55
56 use std::any::Any;
57 use std::borrow::Cow;
58 use std::cmp;
59 use std::collections::BTreeMap;
60 use std::env;
61 use std::fmt;
62 use std::fs::File;
63 use std::io;
64 use std::io::prelude::*;
65 use std::panic::{catch_unwind, AssertUnwindSafe};
66 use std::path::PathBuf;
67 use std::process;
68 use std::process::Termination;
69 use std::sync::mpsc::{channel, Sender};
70 use std::sync::{Arc, Mutex};
71 use std::thread;
72 use std::time::{Duration, Instant};
73
74 const TEST_WARN_TIMEOUT_S: u64 = 60;
75 const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
76
77 // to be used by rustc to compile tests in libtest
78 pub mod test {
79     pub use crate::{
80         assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
81         Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
82         StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
83         TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
84     };
85 }
86
87 mod formatters;
88 pub mod stats;
89
90 use crate::formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter};
91
92 /// Whether to execute tests concurrently or not
93 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
94 pub enum Concurrent {
95     Yes,
96     No,
97 }
98
99 // The name of a test. By convention this follows the rules for rust
100 // paths; i.e., it should be a series of identifiers separated by double
101 // colons. This way if some test runner wants to arrange the tests
102 // hierarchically it may.
103
104 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
105 pub enum TestName {
106     StaticTestName(&'static str),
107     DynTestName(String),
108     AlignedTestName(Cow<'static, str>, NamePadding),
109 }
110 impl TestName {
111     fn as_slice(&self) -> &str {
112         match *self {
113             StaticTestName(s) => s,
114             DynTestName(ref s) => s,
115             AlignedTestName(ref s, _) => &*s,
116         }
117     }
118
119     fn padding(&self) -> NamePadding {
120         match self {
121             &AlignedTestName(_, p) => p,
122             _ => PadNone,
123         }
124     }
125
126     fn with_padding(&self, padding: NamePadding) -> TestName {
127         let name = match self {
128             &TestName::StaticTestName(name) => Cow::Borrowed(name),
129             &TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
130             &TestName::AlignedTestName(ref name, _) => name.clone(),
131         };
132
133         TestName::AlignedTestName(name, padding)
134     }
135 }
136 impl fmt::Display for TestName {
137     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138         fmt::Display::fmt(self.as_slice(), f)
139     }
140 }
141
142 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
143 pub enum NamePadding {
144     PadNone,
145     PadOnRight,
146 }
147
148 impl TestDesc {
149     fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
150         let mut name = String::from(self.name.as_slice());
151         let fill = column_count.saturating_sub(name.len());
152         let pad = " ".repeat(fill);
153         match align {
154             PadNone => name,
155             PadOnRight => {
156                 name.push_str(&pad);
157                 name
158             }
159         }
160     }
161 }
162
163 /// Represents a benchmark function.
164 pub trait TDynBenchFn: Send {
165     fn run(&self, harness: &mut Bencher);
166 }
167
168 // A function that runs a test. If the function returns successfully,
169 // the test succeeds; if the function panics then the test fails. We
170 // may need to come up with a more clever definition of test in order
171 // to support isolation of tests into threads.
172 pub enum TestFn {
173     StaticTestFn(fn()),
174     StaticBenchFn(fn(&mut Bencher)),
175     DynTestFn(Box<dyn FnOnce() + Send>),
176     DynBenchFn(Box<dyn TDynBenchFn + 'static>),
177 }
178
179 impl TestFn {
180     fn padding(&self) -> NamePadding {
181         match *self {
182             StaticTestFn(..) => PadNone,
183             StaticBenchFn(..) => PadOnRight,
184             DynTestFn(..) => PadNone,
185             DynBenchFn(..) => PadOnRight,
186         }
187     }
188 }
189
190 impl fmt::Debug for TestFn {
191     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192         f.write_str(match *self {
193             StaticTestFn(..) => "StaticTestFn(..)",
194             StaticBenchFn(..) => "StaticBenchFn(..)",
195             DynTestFn(..) => "DynTestFn(..)",
196             DynBenchFn(..) => "DynBenchFn(..)",
197         })
198     }
199 }
200
201 /// Manager of the benchmarking runs.
202 ///
203 /// This is fed into functions marked with `#[bench]` to allow for
204 /// set-up & tear-down before running a piece of code repeatedly via a
205 /// call to `iter`.
206 #[derive(Clone)]
207 pub struct Bencher {
208     mode: BenchMode,
209     summary: Option<stats::Summary>,
210     pub bytes: u64,
211 }
212
213 #[derive(Clone, PartialEq, Eq)]
214 pub enum BenchMode {
215     Auto,
216     Single,
217 }
218
219 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
220 pub enum ShouldPanic {
221     No,
222     Yes,
223     YesWithMessage(&'static str),
224 }
225
226 // The definition of a single test. A test runner will run a list of
227 // these.
228 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
229 pub struct TestDesc {
230     pub name: TestName,
231     pub ignore: bool,
232     pub should_panic: ShouldPanic,
233     pub allow_fail: bool,
234 }
235
236 #[derive(Debug)]
237 pub struct TestDescAndFn {
238     pub desc: TestDesc,
239     pub testfn: TestFn,
240 }
241
242 #[derive(Clone, PartialEq, Debug, Copy)]
243 pub struct Metric {
244     value: f64,
245     noise: f64,
246 }
247
248 impl Metric {
249     pub fn new(value: f64, noise: f64) -> Metric {
250         Metric { value, noise }
251     }
252 }
253
254 /// In case we want to add other options as well, just add them in this struct.
255 #[derive(Copy, Clone, Debug)]
256 pub struct Options {
257     display_output: bool,
258 }
259
260 impl Options {
261     pub fn new() -> Options {
262         Options {
263             display_output: false,
264         }
265     }
266
267     pub fn display_output(mut self, display_output: bool) -> Options {
268         self.display_output = display_output;
269         self
270     }
271 }
272
273 // The default console test runner. It accepts the command line
274 // arguments and a vector of test_descs.
275 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
276     let mut opts = match parse_opts(args) {
277         Some(Ok(o)) => o,
278         Some(Err(msg)) => {
279             eprintln!("error: {}", msg);
280             process::exit(101);
281         }
282         None => return,
283     };
284
285     opts.options = options;
286     if opts.list {
287         if let Err(e) = list_tests_console(&opts, tests) {
288             eprintln!("error: io error when listing tests: {:?}", e);
289             process::exit(101);
290         }
291     } else {
292         match run_tests_console(&opts, tests) {
293             Ok(true) => {}
294             Ok(false) => process::exit(101),
295             Err(e) => {
296                 eprintln!("error: io error when listing tests: {:?}", e);
297                 process::exit(101);
298             }
299         }
300     }
301 }
302
303 // A variant optimized for invocation with a static test vector.
304 // This will panic (intentionally) when fed any dynamic tests, because
305 // it is copying the static values out into a dynamic vector and cannot
306 // copy dynamic values. It is doing this because from this point on
307 // a Vec<TestDescAndFn> is used in order to effect ownership-transfer
308 // semantics into parallel test runners, which in turn requires a Vec<>
309 // rather than a &[].
310 pub fn test_main_static(tests: &[&TestDescAndFn]) {
311     let args = env::args().collect::<Vec<_>>();
312     let owned_tests = tests
313         .iter()
314         .map(|t| match t.testfn {
315             StaticTestFn(f) => TestDescAndFn {
316                 testfn: StaticTestFn(f),
317                 desc: t.desc.clone(),
318             },
319             StaticBenchFn(f) => TestDescAndFn {
320                 testfn: StaticBenchFn(f),
321                 desc: t.desc.clone(),
322             },
323             _ => panic!("non-static tests passed to test::test_main_static"),
324         })
325         .collect();
326     test_main(&args, owned_tests, Options::new())
327 }
328
329 /// Invoked when unit tests terminate. Should panic if the unit
330 /// Tests is considered a failure. By default, invokes `report()`
331 /// and checks for a `0` result.
332 pub fn assert_test_result<T: Termination>(result: T) {
333     let code = result.report();
334     assert_eq!(
335         code, 0,
336         "the test returned a termination value with a non-zero status code ({}) \
337          which indicates a failure",
338         code
339     );
340 }
341
342 #[derive(Copy, Clone, Debug)]
343 pub enum ColorConfig {
344     AutoColor,
345     AlwaysColor,
346     NeverColor,
347 }
348
349 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
350 pub enum OutputFormat {
351     Pretty,
352     Terse,
353     Json,
354 }
355
356 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
357 pub enum RunIgnored {
358     Yes,
359     No,
360     Only,
361 }
362
363 #[derive(Debug)]
364 pub struct TestOpts {
365     pub list: bool,
366     pub filter: Option<String>,
367     pub filter_exact: bool,
368     pub exclude_should_panic: bool,
369     pub run_ignored: RunIgnored,
370     pub run_tests: bool,
371     pub bench_benchmarks: bool,
372     pub logfile: Option<PathBuf>,
373     pub nocapture: bool,
374     pub color: ColorConfig,
375     pub format: OutputFormat,
376     pub test_threads: Option<usize>,
377     pub skip: Vec<String>,
378     pub options: Options,
379 }
380
381 impl TestOpts {
382     #[cfg(test)]
383     fn new() -> TestOpts {
384         TestOpts {
385             list: false,
386             filter: None,
387             filter_exact: false,
388             exclude_should_panic: false,
389             run_ignored: RunIgnored::No,
390             run_tests: false,
391             bench_benchmarks: false,
392             logfile: None,
393             nocapture: false,
394             color: AutoColor,
395             format: OutputFormat::Pretty,
396             test_threads: None,
397             skip: vec![],
398             options: Options::new(),
399         }
400     }
401 }
402
403 /// Result of parsing the options.
404 pub type OptRes = Result<TestOpts, String>;
405
406 fn optgroups() -> getopts::Options {
407     let mut opts = getopts::Options::new();
408     opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
409         .optflag("", "ignored", "Run only ignored tests")
410         .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
411         .optflag("", "test", "Run tests and not benchmarks")
412         .optflag("", "bench", "Run benchmarks instead of tests")
413         .optflag("", "list", "List all tests and benchmarks")
414         .optflag("h", "help", "Display this message (longer with --help)")
415         .optopt(
416             "",
417             "logfile",
418             "Write logs to the specified file instead \
419              of stdout",
420             "PATH",
421         )
422         .optflag(
423             "",
424             "nocapture",
425             "don't capture stdout/stderr of each \
426              task, allow printing directly",
427         )
428         .optopt(
429             "",
430             "test-threads",
431             "Number of threads used for running tests \
432              in parallel",
433             "n_threads",
434         )
435         .optmulti(
436             "",
437             "skip",
438             "Skip tests whose names contain FILTER (this flag can \
439              be used multiple times)",
440             "FILTER",
441         )
442         .optflag(
443             "q",
444             "quiet",
445             "Display one character per test instead of one line. \
446              Alias to --format=terse",
447         )
448         .optflag(
449             "",
450             "exact",
451             "Exactly match filters rather than by substring",
452         )
453         .optopt(
454             "",
455             "color",
456             "Configure coloring of output:
457             auto   = colorize if stdout is a tty and tests are run on serially (default);
458             always = always colorize output;
459             never  = never colorize output;",
460             "auto|always|never",
461         )
462         .optopt(
463             "",
464             "format",
465             "Configure formatting of output:
466             pretty = Print verbose output;
467             terse  = Display one character per test;
468             json   = Output a json document",
469             "pretty|terse|json",
470         )
471         .optopt(
472             "Z",
473             "",
474             "Enable nightly-only flags:
475             unstable-options = Allow use of experimental features",
476             "unstable-options",
477         );
478     return opts;
479 }
480
481 fn usage(binary: &str, options: &getopts::Options) {
482     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
483     println!(
484         r#"{usage}
485
486 The FILTER string is tested against the name of all tests, and only those
487 tests whose names contain the filter are run.
488
489 By default, all tests are run in parallel. This can be altered with the
490 --test-threads flag or the RUST_TEST_THREADS environment variable when running
491 tests (set it to 1).
492
493 All tests have their standard output and standard error captured by default.
494 This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
495 environment variable to a value other than "0". Logging is not captured by default.
496
497 Test Attributes:
498
499     #[test]        - Indicates a function is a test to be run. This function
500                      takes no arguments.
501     #[bench]       - Indicates a function is a benchmark to be run. This
502                      function takes one argument (test::Bencher).
503     #[should_panic] - This function (also labeled with #[test]) will only pass if
504                      the code causes a panic (an assertion failure or panic!)
505                      A message may be provided, which the failure string must
506                      contain: #[should_panic(expected = "foo")].
507     #[ignore]      - When applied to a function which is already attributed as a
508                      test, then the test runner will ignore these tests during
509                      normal test runs. Running with --ignored or --include-ignored will run
510                      these tests."#,
511         usage = options.usage(&message)
512     );
513 }
514
515 // FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
516 fn is_nightly() -> bool {
517     // Whether this is a feature-staged build, i.e., on the beta or stable channel
518     let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
519     // Whether we should enable unstable features for bootstrapping
520     let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
521
522     bootstrap || !disable_unstable_features
523 }
524
525 // Parses command line arguments into test options
526 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
527     let mut allow_unstable = false;
528     let opts = optgroups();
529     let args = args.get(1..).unwrap_or(args);
530     let matches = match opts.parse(args) {
531         Ok(m) => m,
532         Err(f) => return Some(Err(f.to_string())),
533     };
534
535     if let Some(opt) = matches.opt_str("Z") {
536         if !is_nightly() {
537             return Some(Err(
538                 "the option `Z` is only accepted on the nightly compiler".into(),
539             ));
540         }
541
542         match &*opt {
543             "unstable-options" => {
544                 allow_unstable = true;
545             }
546             _ => {
547                 return Some(Err("Unrecognized option to `Z`".into()));
548             }
549         }
550     };
551
552     if matches.opt_present("h") {
553         usage(&args[0], &opts);
554         return None;
555     }
556
557     let filter = if !matches.free.is_empty() {
558         Some(matches.free[0].clone())
559     } else {
560         None
561     };
562
563     let exclude_should_panic = matches.opt_present("exclude-should-panic");
564     if !allow_unstable && exclude_should_panic {
565         return Some(Err(
566             "The \"exclude-should-panic\" flag is only accepted on the nightly compiler".into(),
567         ));
568     }
569
570     let include_ignored = matches.opt_present("include-ignored");
571     if !allow_unstable && include_ignored {
572         return Some(Err(
573             "The \"include-ignored\" flag is only accepted on the nightly compiler".into(),
574         ));
575     }
576
577     let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
578         (true, true) => {
579             return Some(Err(
580                 "the options --include-ignored and --ignored are mutually exclusive".into(),
581             ));
582         }
583         (true, false) => RunIgnored::Yes,
584         (false, true) => RunIgnored::Only,
585         (false, false) => RunIgnored::No,
586     };
587     let quiet = matches.opt_present("quiet");
588     let exact = matches.opt_present("exact");
589     let list = matches.opt_present("list");
590
591     let logfile = matches.opt_str("logfile");
592     let logfile = logfile.map(|s| PathBuf::from(&s));
593
594     let bench_benchmarks = matches.opt_present("bench");
595     let run_tests = !bench_benchmarks || matches.opt_present("test");
596
597     let mut nocapture = matches.opt_present("nocapture");
598     if !nocapture {
599         nocapture = match env::var("RUST_TEST_NOCAPTURE") {
600             Ok(val) => &val != "0",
601             Err(_) => false,
602         };
603     }
604
605     let test_threads = match matches.opt_str("test-threads") {
606         Some(n_str) => match n_str.parse::<usize>() {
607             Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
608             Ok(n) => Some(n),
609             Err(e) => {
610                 return Some(Err(format!(
611                     "argument for --test-threads must be a number > 0 \
612                      (error: {})",
613                     e
614                 )));
615             }
616         },
617         None => None,
618     };
619
620     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
621         Some("auto") | None => AutoColor,
622         Some("always") => AlwaysColor,
623         Some("never") => NeverColor,
624
625         Some(v) => {
626             return Some(Err(format!(
627                 "argument for --color must be auto, always, or never (was \
628                  {})",
629                 v
630             )));
631         }
632     };
633
634     let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
635         None if quiet => OutputFormat::Terse,
636         Some("pretty") | None => OutputFormat::Pretty,
637         Some("terse") => OutputFormat::Terse,
638         Some("json") => {
639             if !allow_unstable {
640                 return Some(Err(
641                     "The \"json\" format is only accepted on the nightly compiler".into(),
642                 ));
643             }
644             OutputFormat::Json
645         }
646
647         Some(v) => {
648             return Some(Err(format!(
649                 "argument for --format must be pretty, terse, or json (was \
650                  {})",
651                 v
652             )));
653         }
654     };
655
656     let test_opts = TestOpts {
657         list,
658         filter,
659         filter_exact: exact,
660         exclude_should_panic,
661         run_ignored,
662         run_tests,
663         bench_benchmarks,
664         logfile,
665         nocapture,
666         color,
667         format,
668         test_threads,
669         skip: matches.opt_strs("skip"),
670         options: Options::new(),
671     };
672
673     Some(Ok(test_opts))
674 }
675
676 #[derive(Clone, PartialEq)]
677 pub struct BenchSamples {
678     ns_iter_summ: stats::Summary,
679     mb_s: usize,
680 }
681
682 #[derive(Clone, PartialEq)]
683 pub enum TestResult {
684     TrOk,
685     TrFailed,
686     TrFailedMsg(String),
687     TrIgnored,
688     TrAllowedFail,
689     TrBench(BenchSamples),
690 }
691
692 unsafe impl Send for TestResult {}
693
694 enum OutputLocation<T> {
695     Pretty(Box<term::StdoutTerminal>),
696     Raw(T),
697 }
698
699 impl<T: Write> Write for OutputLocation<T> {
700     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
701         match *self {
702             Pretty(ref mut term) => term.write(buf),
703             Raw(ref mut stdout) => stdout.write(buf),
704         }
705     }
706
707     fn flush(&mut self) -> io::Result<()> {
708         match *self {
709             Pretty(ref mut term) => term.flush(),
710             Raw(ref mut stdout) => stdout.flush(),
711         }
712     }
713 }
714
715 struct ConsoleTestState {
716     log_out: Option<File>,
717     total: usize,
718     passed: usize,
719     failed: usize,
720     ignored: usize,
721     allowed_fail: usize,
722     filtered_out: usize,
723     measured: usize,
724     metrics: MetricMap,
725     failures: Vec<(TestDesc, Vec<u8>)>,
726     not_failures: Vec<(TestDesc, Vec<u8>)>,
727     options: Options,
728 }
729
730 impl ConsoleTestState {
731     pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
732         let log_out = match opts.logfile {
733             Some(ref path) => Some(File::create(path)?),
734             None => None,
735         };
736
737         Ok(ConsoleTestState {
738             log_out,
739             total: 0,
740             passed: 0,
741             failed: 0,
742             ignored: 0,
743             allowed_fail: 0,
744             filtered_out: 0,
745             measured: 0,
746             metrics: MetricMap::new(),
747             failures: Vec::new(),
748             not_failures: Vec::new(),
749             options: opts.options,
750         })
751     }
752
753     pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
754         let msg = msg.as_ref();
755         match self.log_out {
756             None => Ok(()),
757             Some(ref mut o) => o.write_all(msg.as_bytes()),
758         }
759     }
760
761     pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
762         self.write_log(format!(
763             "{} {}\n",
764             match *result {
765                 TrOk => "ok".to_owned(),
766                 TrFailed => "failed".to_owned(),
767                 TrFailedMsg(ref msg) => format!("failed: {}", msg),
768                 TrIgnored => "ignored".to_owned(),
769                 TrAllowedFail => "failed (allowed)".to_owned(),
770                 TrBench(ref bs) => fmt_bench_samples(bs),
771             },
772             test.name
773         ))
774     }
775
776     fn current_test_count(&self) -> usize {
777         self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
778     }
779 }
780
781 // Format a number with thousands separators
782 fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
783     use std::fmt::Write;
784     let mut output = String::new();
785     let mut trailing = false;
786     for &pow in &[9, 6, 3, 0] {
787         let base = 10_usize.pow(pow);
788         if pow == 0 || trailing || n / base != 0 {
789             if !trailing {
790                 output.write_fmt(format_args!("{}", n / base)).unwrap();
791             } else {
792                 output.write_fmt(format_args!("{:03}", n / base)).unwrap();
793             }
794             if pow != 0 {
795                 output.push(sep);
796             }
797             trailing = true;
798         }
799         n %= base;
800     }
801
802     output
803 }
804
805 pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
806     use std::fmt::Write;
807     let mut output = String::new();
808
809     let median = bs.ns_iter_summ.median as usize;
810     let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
811
812     output
813         .write_fmt(format_args!(
814             "{:>11} ns/iter (+/- {})",
815             fmt_thousands_sep(median, ','),
816             fmt_thousands_sep(deviation, ',')
817         ))
818         .unwrap();
819     if bs.mb_s != 0 {
820         output
821             .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
822             .unwrap();
823     }
824     output
825 }
826
827 // List the tests to console, and optionally to logfile. Filters are honored.
828 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
829     let mut output = match term::stdout() {
830         None => Raw(io::stdout()),
831         Some(t) => Pretty(t),
832     };
833
834     let quiet = opts.format == OutputFormat::Terse;
835     let mut st = ConsoleTestState::new(opts)?;
836
837     let mut ntest = 0;
838     let mut nbench = 0;
839
840     for test in filter_tests(&opts, tests) {
841         use crate::TestFn::*;
842
843         let TestDescAndFn {
844             desc: TestDesc { name, .. },
845             testfn,
846         } = test;
847
848         let fntype = match testfn {
849             StaticTestFn(..) | DynTestFn(..) => {
850                 ntest += 1;
851                 "test"
852             }
853             StaticBenchFn(..) | DynBenchFn(..) => {
854                 nbench += 1;
855                 "benchmark"
856             }
857         };
858
859         writeln!(output, "{}: {}", name, fntype)?;
860         st.write_log(format!("{} {}\n", fntype, name))?;
861     }
862
863     fn plural(count: u32, s: &str) -> String {
864         match count {
865             1 => format!("{} {}", 1, s),
866             n => format!("{} {}s", n, s),
867         }
868     }
869
870     if !quiet {
871         if ntest != 0 || nbench != 0 {
872             writeln!(output, "")?;
873         }
874
875         writeln!(
876             output,
877             "{}, {}",
878             plural(ntest, "test"),
879             plural(nbench, "benchmark")
880         )?;
881     }
882
883     Ok(())
884 }
885
886 // A simple console test runner
887 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
888     fn callback(
889         event: &TestEvent,
890         st: &mut ConsoleTestState,
891         out: &mut dyn OutputFormatter,
892     ) -> io::Result<()> {
893         match (*event).clone() {
894             TeFiltered(ref filtered_tests) => {
895                 st.total = filtered_tests.len();
896                 out.write_run_start(filtered_tests.len())
897             }
898             TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out),
899             TeWait(ref test) => out.write_test_start(test),
900             TeTimeout(ref test) => out.write_timeout(test),
901             TeResult(test, result, stdout) => {
902                 st.write_log_result(&test, &result)?;
903                 out.write_result(&test, &result, &*stdout)?;
904                 match result {
905                     TrOk => {
906                         st.passed += 1;
907                         st.not_failures.push((test, stdout));
908                     }
909                     TrIgnored => st.ignored += 1,
910                     TrAllowedFail => st.allowed_fail += 1,
911                     TrBench(bs) => {
912                         st.metrics.insert_metric(
913                             test.name.as_slice(),
914                             bs.ns_iter_summ.median,
915                             bs.ns_iter_summ.max - bs.ns_iter_summ.min,
916                         );
917                         st.measured += 1
918                     }
919                     TrFailed => {
920                         st.failed += 1;
921                         st.failures.push((test, stdout));
922                     }
923                     TrFailedMsg(msg) => {
924                         st.failed += 1;
925                         let mut stdout = stdout;
926                         stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
927                         st.failures.push((test, stdout));
928                     }
929                 }
930                 Ok(())
931             }
932         }
933     }
934
935     let output = match term::stdout() {
936         None => Raw(io::stdout()),
937         Some(t) => Pretty(t),
938     };
939
940     let max_name_len = tests
941         .iter()
942         .max_by_key(|t| len_if_padded(*t))
943         .map(|t| t.desc.name.as_slice().len())
944         .unwrap_or(0);
945
946     let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
947
948     let mut out: Box<dyn OutputFormatter> = match opts.format {
949         OutputFormat::Pretty => Box::new(PrettyFormatter::new(
950             output,
951             use_color(opts),
952             max_name_len,
953             is_multithreaded,
954         )),
955         OutputFormat::Terse => Box::new(TerseFormatter::new(
956             output,
957             use_color(opts),
958             max_name_len,
959             is_multithreaded,
960         )),
961         OutputFormat::Json => Box::new(JsonFormatter::new(output)),
962     };
963     let mut st = ConsoleTestState::new(opts)?;
964     fn len_if_padded(t: &TestDescAndFn) -> usize {
965         match t.testfn.padding() {
966             PadNone => 0,
967             PadOnRight => t.desc.name.as_slice().len(),
968         }
969     }
970
971     run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?;
972
973     assert!(st.current_test_count() == st.total);
974
975     return out.write_run_finish(&st);
976 }
977
978 #[test]
979 fn should_sort_failures_before_printing_them() {
980     let test_a = TestDesc {
981         name: StaticTestName("a"),
982         ignore: false,
983         should_panic: ShouldPanic::No,
984         allow_fail: false,
985     };
986
987     let test_b = TestDesc {
988         name: StaticTestName("b"),
989         ignore: false,
990         should_panic: ShouldPanic::No,
991         allow_fail: false,
992     };
993
994     let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false);
995
996     let st = ConsoleTestState {
997         log_out: None,
998         total: 0,
999         passed: 0,
1000         failed: 0,
1001         ignored: 0,
1002         allowed_fail: 0,
1003         filtered_out: 0,
1004         measured: 0,
1005         metrics: MetricMap::new(),
1006         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
1007         options: Options::new(),
1008         not_failures: Vec::new(),
1009     };
1010
1011     out.write_failures(&st).unwrap();
1012     let s = match out.output_location() {
1013         &Raw(ref m) => String::from_utf8_lossy(&m[..]),
1014         &Pretty(_) => unreachable!(),
1015     };
1016
1017     let apos = s.find("a").unwrap();
1018     let bpos = s.find("b").unwrap();
1019     assert!(apos < bpos);
1020 }
1021
1022 fn use_color(opts: &TestOpts) -> bool {
1023     match opts.color {
1024         AutoColor => !opts.nocapture && stdout_isatty(),
1025         AlwaysColor => true,
1026         NeverColor => false,
1027     }
1028 }
1029
1030 #[cfg(any(
1031     target_os = "cloudabi",
1032     target_os = "redox",
1033     all(target_arch = "wasm32", not(target_os = "emscripten")),
1034     all(target_vendor = "fortanix", target_env = "sgx")
1035 ))]
1036 fn stdout_isatty() -> bool {
1037     // FIXME: Implement isatty on Redox and SGX
1038     false
1039 }
1040 #[cfg(unix)]
1041 fn stdout_isatty() -> bool {
1042     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
1043 }
1044 #[cfg(windows)]
1045 fn stdout_isatty() -> bool {
1046     type DWORD = u32;
1047     type BOOL = i32;
1048     type HANDLE = *mut u8;
1049     type LPDWORD = *mut u32;
1050     const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
1051     extern "system" {
1052         fn GetStdHandle(which: DWORD) -> HANDLE;
1053         fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
1054     }
1055     unsafe {
1056         let handle = GetStdHandle(STD_OUTPUT_HANDLE);
1057         let mut out = 0;
1058         GetConsoleMode(handle, &mut out) != 0
1059     }
1060 }
1061
1062 #[derive(Clone)]
1063 pub enum TestEvent {
1064     TeFiltered(Vec<TestDesc>),
1065     TeWait(TestDesc),
1066     TeResult(TestDesc, TestResult, Vec<u8>),
1067     TeTimeout(TestDesc),
1068     TeFilteredOut(usize),
1069 }
1070
1071 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
1072
1073 struct Sink(Arc<Mutex<Vec<u8>>>);
1074 impl Write for Sink {
1075     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1076         Write::write(&mut *self.0.lock().unwrap(), data)
1077     }
1078     fn flush(&mut self) -> io::Result<()> {
1079         Ok(())
1080     }
1081 }
1082
1083 pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
1084 where
1085     F: FnMut(TestEvent) -> io::Result<()>,
1086 {
1087     use std::collections::{self, HashMap};
1088     use std::hash::BuildHasherDefault;
1089     use std::sync::mpsc::RecvTimeoutError;
1090     // Use a deterministic hasher
1091     type TestMap =
1092         HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
1093
1094     let tests_len = tests.len();
1095
1096     let mut filtered_tests = filter_tests(opts, tests);
1097     if !opts.bench_benchmarks {
1098         filtered_tests = convert_benchmarks_to_tests(filtered_tests);
1099     }
1100
1101     let filtered_tests = {
1102         let mut filtered_tests = filtered_tests;
1103         for test in filtered_tests.iter_mut() {
1104             test.desc.name = test.desc.name.with_padding(test.testfn.padding());
1105         }
1106
1107         filtered_tests
1108     };
1109
1110     let filtered_out = tests_len - filtered_tests.len();
1111     callback(TeFilteredOut(filtered_out))?;
1112
1113     let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
1114
1115     callback(TeFiltered(filtered_descs))?;
1116
1117     let (filtered_tests, filtered_benchs): (Vec<_>, _) =
1118         filtered_tests.into_iter().partition(|e| match e.testfn {
1119             StaticTestFn(_) | DynTestFn(_) => true,
1120             _ => false,
1121         });
1122
1123     let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
1124
1125     let mut remaining = filtered_tests;
1126     remaining.reverse();
1127     let mut pending = 0;
1128
1129     let (tx, rx) = channel::<MonitorMsg>();
1130
1131     let mut running_tests: TestMap = HashMap::default();
1132
1133     fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> {
1134         let now = Instant::now();
1135         let timed_out = running_tests
1136             .iter()
1137             .filter_map(|(desc, timeout)| {
1138                 if &now >= timeout {
1139                     Some(desc.clone())
1140                 } else {
1141                     None
1142                 }
1143             })
1144             .collect();
1145         for test in &timed_out {
1146             running_tests.remove(test);
1147         }
1148         timed_out
1149     };
1150
1151     fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
1152         running_tests.values().min().map(|next_timeout| {
1153             let now = Instant::now();
1154             if *next_timeout >= now {
1155                 *next_timeout - now
1156             } else {
1157                 Duration::new(0, 0)
1158             }
1159         })
1160     };
1161
1162     if concurrency == 1 {
1163         while !remaining.is_empty() {
1164             let test = remaining.pop().unwrap();
1165             callback(TeWait(test.desc.clone()))?;
1166             run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No);
1167             let (test, result, stdout) = rx.recv().unwrap();
1168             callback(TeResult(test, result, stdout))?;
1169         }
1170     } else {
1171         while pending > 0 || !remaining.is_empty() {
1172             while pending < concurrency && !remaining.is_empty() {
1173                 let test = remaining.pop().unwrap();
1174                 let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
1175                 running_tests.insert(test.desc.clone(), timeout);
1176                 callback(TeWait(test.desc.clone()))?; //here no pad
1177                 run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes);
1178                 pending += 1;
1179             }
1180
1181             let mut res;
1182             loop {
1183                 if let Some(timeout) = calc_timeout(&running_tests) {
1184                     res = rx.recv_timeout(timeout);
1185                     for test in get_timed_out_tests(&mut running_tests) {
1186                         callback(TeTimeout(test))?;
1187                     }
1188                     if res != Err(RecvTimeoutError::Timeout) {
1189                         break;
1190                     }
1191                 } else {
1192                     res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
1193                     break;
1194                 }
1195             }
1196
1197             let (desc, result, stdout) = res.unwrap();
1198             running_tests.remove(&desc);
1199
1200             callback(TeResult(desc, result, stdout))?;
1201             pending -= 1;
1202         }
1203     }
1204
1205     if opts.bench_benchmarks {
1206         // All benchmarks run at the end, in serial.
1207         for b in filtered_benchs {
1208             callback(TeWait(b.desc.clone()))?;
1209             run_test(opts, false, b, tx.clone(), Concurrent::No);
1210             let (test, result, stdout) = rx.recv().unwrap();
1211             callback(TeResult(test, result, stdout))?;
1212         }
1213     }
1214     Ok(())
1215 }
1216
1217 #[allow(deprecated)]
1218 fn get_concurrency() -> usize {
1219     return match env::var("RUST_TEST_THREADS") {
1220         Ok(s) => {
1221             let opt_n: Option<usize> = s.parse().ok();
1222             match opt_n {
1223                 Some(n) if n > 0 => n,
1224                 _ => panic!(
1225                     "RUST_TEST_THREADS is `{}`, should be a positive integer.",
1226                     s
1227                 ),
1228             }
1229         }
1230         Err(..) => num_cpus(),
1231     };
1232
1233     #[cfg(windows)]
1234     #[allow(nonstandard_style)]
1235     fn num_cpus() -> usize {
1236         #[repr(C)]
1237         struct SYSTEM_INFO {
1238             wProcessorArchitecture: u16,
1239             wReserved: u16,
1240             dwPageSize: u32,
1241             lpMinimumApplicationAddress: *mut u8,
1242             lpMaximumApplicationAddress: *mut u8,
1243             dwActiveProcessorMask: *mut u8,
1244             dwNumberOfProcessors: u32,
1245             dwProcessorType: u32,
1246             dwAllocationGranularity: u32,
1247             wProcessorLevel: u16,
1248             wProcessorRevision: u16,
1249         }
1250         extern "system" {
1251             fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
1252         }
1253         unsafe {
1254             let mut sysinfo = std::mem::zeroed();
1255             GetSystemInfo(&mut sysinfo);
1256             sysinfo.dwNumberOfProcessors as usize
1257         }
1258     }
1259
1260     #[cfg(target_os = "redox")]
1261     fn num_cpus() -> usize {
1262         // FIXME: Implement num_cpus on Redox
1263         1
1264     }
1265
1266     #[cfg(any(
1267         all(target_arch = "wasm32", not(target_os = "emscripten")),
1268         all(target_vendor = "fortanix", target_env = "sgx")
1269     ))]
1270     fn num_cpus() -> usize {
1271         1
1272     }
1273
1274     #[cfg(any(
1275         target_os = "android",
1276         target_os = "cloudabi",
1277         target_os = "emscripten",
1278         target_os = "fuchsia",
1279         target_os = "ios",
1280         target_os = "linux",
1281         target_os = "macos",
1282         target_os = "solaris"
1283     ))]
1284     fn num_cpus() -> usize {
1285         unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
1286     }
1287
1288     #[cfg(any(
1289         target_os = "freebsd",
1290         target_os = "dragonfly",
1291         target_os = "netbsd"
1292     ))]
1293     fn num_cpus() -> usize {
1294         use std::ptr;
1295
1296         let mut cpus: libc::c_uint = 0;
1297         let mut cpus_size = std::mem::size_of_val(&cpus);
1298
1299         unsafe {
1300             cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
1301         }
1302         if cpus < 1 {
1303             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1304             unsafe {
1305                 libc::sysctl(
1306                     mib.as_mut_ptr(),
1307                     2,
1308                     &mut cpus as *mut _ as *mut _,
1309                     &mut cpus_size as *mut _ as *mut _,
1310                     ptr::null_mut(),
1311                     0,
1312                 );
1313             }
1314             if cpus < 1 {
1315                 cpus = 1;
1316             }
1317         }
1318         cpus as usize
1319     }
1320
1321     #[cfg(target_os = "openbsd")]
1322     fn num_cpus() -> usize {
1323         use std::ptr;
1324
1325         let mut cpus: libc::c_uint = 0;
1326         let mut cpus_size = std::mem::size_of_val(&cpus);
1327         let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1328
1329         unsafe {
1330             libc::sysctl(
1331                 mib.as_mut_ptr(),
1332                 2,
1333                 &mut cpus as *mut _ as *mut _,
1334                 &mut cpus_size as *mut _ as *mut _,
1335                 ptr::null_mut(),
1336                 0,
1337             );
1338         }
1339         if cpus < 1 {
1340             cpus = 1;
1341         }
1342         cpus as usize
1343     }
1344
1345     #[cfg(target_os = "haiku")]
1346     fn num_cpus() -> usize {
1347         // FIXME: implement
1348         1
1349     }
1350
1351     #[cfg(target_os = "l4re")]
1352     fn num_cpus() -> usize {
1353         // FIXME: implement
1354         1
1355     }
1356 }
1357
1358 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1359     let mut filtered = tests;
1360     let matches_filter = |test: &TestDescAndFn, filter: &str| {
1361         let test_name = test.desc.name.as_slice();
1362
1363         match opts.filter_exact {
1364             true => test_name == filter,
1365             false => test_name.contains(filter),
1366         }
1367     };
1368
1369     // Remove tests that don't match the test filter
1370     if let Some(ref filter) = opts.filter {
1371         filtered.retain(|test| matches_filter(test, filter));
1372     }
1373
1374     // Skip tests that match any of the skip filters
1375     filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
1376
1377     // Excludes #[should_panic] tests
1378     if opts.exclude_should_panic {
1379         filtered.retain(|test| test.desc.should_panic == ShouldPanic::No);
1380     }
1381
1382     // maybe unignore tests
1383     match opts.run_ignored {
1384         RunIgnored::Yes => {
1385             filtered
1386                 .iter_mut()
1387                 .for_each(|test| test.desc.ignore = false);
1388         }
1389         RunIgnored::Only => {
1390             filtered.retain(|test| test.desc.ignore);
1391             filtered
1392                 .iter_mut()
1393                 .for_each(|test| test.desc.ignore = false);
1394         }
1395         RunIgnored::No => {}
1396     }
1397
1398     // Sort the tests alphabetically
1399     filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
1400
1401     filtered
1402 }
1403
1404 pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1405     // convert benchmarks to tests, if we're not benchmarking them
1406     tests
1407         .into_iter()
1408         .map(|x| {
1409             let testfn = match x.testfn {
1410                 DynBenchFn(bench) => DynTestFn(Box::new(move || {
1411                     bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b)))
1412                 })),
1413                 StaticBenchFn(benchfn) => DynTestFn(Box::new(move || {
1414                     bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
1415                 })),
1416                 f => f,
1417             };
1418             TestDescAndFn {
1419                 desc: x.desc,
1420                 testfn,
1421             }
1422         })
1423         .collect()
1424 }
1425
1426 pub fn run_test(
1427     opts: &TestOpts,
1428     force_ignore: bool,
1429     test: TestDescAndFn,
1430     monitor_ch: Sender<MonitorMsg>,
1431     concurrency: Concurrent,
1432 ) {
1433     let TestDescAndFn { desc, testfn } = test;
1434
1435     let ignore_because_panic_abort = cfg!(target_arch = "wasm32")
1436         && !cfg!(target_os = "emscripten")
1437         && desc.should_panic != ShouldPanic::No;
1438
1439     if force_ignore || desc.ignore || ignore_because_panic_abort {
1440         monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap();
1441         return;
1442     }
1443
1444     fn run_test_inner(
1445         desc: TestDesc,
1446         monitor_ch: Sender<MonitorMsg>,
1447         nocapture: bool,
1448         testfn: Box<dyn FnOnce() + Send>,
1449         concurrency: Concurrent,
1450     ) {
1451         // Buffer for capturing standard I/O
1452         let data = Arc::new(Mutex::new(Vec::new()));
1453         let data2 = data.clone();
1454
1455         let name = desc.name.clone();
1456         let runtest = move || {
1457             let oldio = if !nocapture {
1458                 Some((
1459                     io::set_print(Some(Box::new(Sink(data2.clone())))),
1460                     io::set_panic(Some(Box::new(Sink(data2)))),
1461                 ))
1462             } else {
1463                 None
1464             };
1465
1466             let result = catch_unwind(AssertUnwindSafe(testfn));
1467
1468             if let Some((printio, panicio)) = oldio {
1469                 io::set_print(printio);
1470                 io::set_panic(panicio);
1471             };
1472
1473             let test_result = calc_result(&desc, result);
1474             let stdout = data.lock().unwrap().to_vec();
1475             monitor_ch
1476                 .send((desc.clone(), test_result, stdout))
1477                 .unwrap();
1478         };
1479
1480         // If the platform is single-threaded we're just going to run
1481         // the test synchronously, regardless of the concurrency
1482         // level.
1483         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
1484         if concurrency == Concurrent::Yes && supports_threads {
1485             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
1486             cfg.spawn(runtest).unwrap();
1487         } else {
1488             runtest();
1489         }
1490     }
1491
1492     match testfn {
1493         DynBenchFn(bencher) => {
1494             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1495                 bencher.run(harness)
1496             });
1497         }
1498         StaticBenchFn(benchfn) => {
1499             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1500                 (benchfn.clone())(harness)
1501             });
1502         }
1503         DynTestFn(f) => {
1504             let cb = move || __rust_begin_short_backtrace(f);
1505             run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency)
1506         }
1507         StaticTestFn(f) => run_test_inner(
1508             desc,
1509             monitor_ch,
1510             opts.nocapture,
1511             Box::new(move || __rust_begin_short_backtrace(f)),
1512             concurrency,
1513         ),
1514     }
1515 }
1516
1517 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
1518 #[inline(never)]
1519 fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
1520     f()
1521 }
1522
1523 fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) -> TestResult {
1524     match (&desc.should_panic, task_result) {
1525         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
1526         (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
1527             if err
1528                 .downcast_ref::<String>()
1529                 .map(|e| &**e)
1530                 .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
1531                 .map(|e| e.contains(msg))
1532                 .unwrap_or(false)
1533             {
1534                 TrOk
1535             } else {
1536                 if desc.allow_fail {
1537                     TrAllowedFail
1538                 } else {
1539                     TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
1540                 }
1541             }
1542         }
1543         _ if desc.allow_fail => TrAllowedFail,
1544         _ => TrFailed,
1545     }
1546 }
1547
1548 #[derive(Clone, PartialEq)]
1549 pub struct MetricMap(BTreeMap<String, Metric>);
1550
1551 impl MetricMap {
1552     pub fn new() -> MetricMap {
1553         MetricMap(BTreeMap::new())
1554     }
1555
1556     /// Insert a named `value` (+/- `noise`) metric into the map. The value
1557     /// must be non-negative. The `noise` indicates the uncertainty of the
1558     /// metric, which doubles as the "noise range" of acceptable
1559     /// pairwise-regressions on this named value, when comparing from one
1560     /// metric to the next using `compare_to_old`.
1561     ///
1562     /// If `noise` is positive, then it means this metric is of a value
1563     /// you want to see grow smaller, so a change larger than `noise` in the
1564     /// positive direction represents a regression.
1565     ///
1566     /// If `noise` is negative, then it means this metric is of a value
1567     /// you want to see grow larger, so a change larger than `noise` in the
1568     /// negative direction represents a regression.
1569     pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
1570         let m = Metric { value, noise };
1571         self.0.insert(name.to_owned(), m);
1572     }
1573
1574     pub fn fmt_metrics(&self) -> String {
1575         let v = self
1576             .0
1577             .iter()
1578             .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
1579             .collect::<Vec<_>>();
1580         v.join(", ")
1581     }
1582 }
1583
1584 // Benchmarking
1585
1586 pub use std::hint::black_box;
1587
1588 impl Bencher {
1589     /// Callback for benchmark functions to run in their body.
1590     pub fn iter<T, F>(&mut self, mut inner: F)
1591     where
1592         F: FnMut() -> T,
1593     {
1594         if self.mode == BenchMode::Single {
1595             ns_iter_inner(&mut inner, 1);
1596             return;
1597         }
1598
1599         self.summary = Some(iter(&mut inner));
1600     }
1601
1602     pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
1603     where
1604         F: FnMut(&mut Bencher),
1605     {
1606         f(self);
1607         return self.summary;
1608     }
1609 }
1610
1611 fn ns_from_dur(dur: Duration) -> u64 {
1612     dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64)
1613 }
1614
1615 fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
1616 where
1617     F: FnMut() -> T,
1618 {
1619     let start = Instant::now();
1620     for _ in 0..k {
1621         black_box(inner());
1622     }
1623     return ns_from_dur(start.elapsed());
1624 }
1625
1626 pub fn iter<T, F>(inner: &mut F) -> stats::Summary
1627 where
1628     F: FnMut() -> T,
1629 {
1630     // Initial bench run to get ballpark figure.
1631     let ns_single = ns_iter_inner(inner, 1);
1632
1633     // Try to estimate iter count for 1ms falling back to 1m
1634     // iterations if first run took < 1ns.
1635     let ns_target_total = 1_000_000; // 1ms
1636     let mut n = ns_target_total / cmp::max(1, ns_single);
1637
1638     // if the first run took more than 1ms we don't want to just
1639     // be left doing 0 iterations on every loop. The unfortunate
1640     // side effect of not being able to do as many runs is
1641     // automatically handled by the statistical analysis below
1642     // (i.e., larger error bars).
1643     n = cmp::max(1, n);
1644
1645     let mut total_run = Duration::new(0, 0);
1646     let samples: &mut [f64] = &mut [0.0_f64; 50];
1647     loop {
1648         let loop_start = Instant::now();
1649
1650         for p in &mut *samples {
1651             *p = ns_iter_inner(inner, n) as f64 / n as f64;
1652         }
1653
1654         stats::winsorize(samples, 5.0);
1655         let summ = stats::Summary::new(samples);
1656
1657         for p in &mut *samples {
1658             let ns = ns_iter_inner(inner, 5 * n);
1659             *p = ns as f64 / (5 * n) as f64;
1660         }
1661
1662         stats::winsorize(samples, 5.0);
1663         let summ5 = stats::Summary::new(samples);
1664
1665         let loop_run = loop_start.elapsed();
1666
1667         // If we've run for 100ms and seem to have converged to a
1668         // stable median.
1669         if loop_run > Duration::from_millis(100)
1670             && summ.median_abs_dev_pct < 1.0
1671             && summ.median - summ5.median < summ5.median_abs_dev
1672         {
1673             return summ5;
1674         }
1675
1676         total_run = total_run + loop_run;
1677         // Longest we ever run for is 3s.
1678         if total_run > Duration::from_secs(3) {
1679             return summ5;
1680         }
1681
1682         // If we overflow here just return the results so far. We check a
1683         // multiplier of 10 because we're about to multiply by 2 and the
1684         // next iteration of the loop will also multiply by 5 (to calculate
1685         // the summ5 result)
1686         n = match n.checked_mul(10) {
1687             Some(_) => n * 2,
1688             None => {
1689                 return summ5;
1690             }
1691         };
1692     }
1693 }
1694
1695 pub mod bench {
1696     use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult};
1697     use crate::stats;
1698     use std::cmp;
1699     use std::io;
1700     use std::panic::{catch_unwind, AssertUnwindSafe};
1701     use std::sync::{Arc, Mutex};
1702
1703     pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F)
1704     where
1705         F: FnMut(&mut Bencher),
1706     {
1707         let mut bs = Bencher {
1708             mode: BenchMode::Auto,
1709             summary: None,
1710             bytes: 0,
1711         };
1712
1713         let data = Arc::new(Mutex::new(Vec::new()));
1714         let data2 = data.clone();
1715
1716         let oldio = if !nocapture {
1717             Some((
1718                 io::set_print(Some(Box::new(Sink(data2.clone())))),
1719                 io::set_panic(Some(Box::new(Sink(data2)))),
1720             ))
1721         } else {
1722             None
1723         };
1724
1725         let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
1726
1727         if let Some((printio, panicio)) = oldio {
1728             io::set_print(printio);
1729             io::set_panic(panicio);
1730         };
1731
1732         let test_result = match result {
1733             //bs.bench(f) {
1734             Ok(Some(ns_iter_summ)) => {
1735                 let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
1736                 let mb_s = bs.bytes * 1000 / ns_iter;
1737
1738                 let bs = BenchSamples {
1739                     ns_iter_summ,
1740                     mb_s: mb_s as usize,
1741                 };
1742                 TestResult::TrBench(bs)
1743             }
1744             Ok(None) => {
1745                 // iter not called, so no data.
1746                 // FIXME: error in this case?
1747                 let samples: &mut [f64] = &mut [0.0_f64; 1];
1748                 let bs = BenchSamples {
1749                     ns_iter_summ: stats::Summary::new(samples),
1750                     mb_s: 0,
1751                 };
1752                 TestResult::TrBench(bs)
1753             }
1754             Err(_) => TestResult::TrFailed,
1755         };
1756
1757         let stdout = data.lock().unwrap().to_vec();
1758         monitor_ch.send((desc, test_result, stdout)).unwrap();
1759     }
1760
1761     pub fn run_once<F>(f: F)
1762     where
1763         F: FnMut(&mut Bencher),
1764     {
1765         let mut bs = Bencher {
1766             mode: BenchMode::Single,
1767             summary: None,
1768             bytes: 0,
1769         };
1770         bs.bench(f);
1771     }
1772 }
1773
1774 #[cfg(test)]
1775 mod tests {
1776     use crate::bench;
1777     use crate::test::{
1778         filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
1779         ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
1780         TrIgnored, TrOk,
1781     };
1782     use crate::Bencher;
1783     use crate::Concurrent;
1784     use std::sync::mpsc::channel;
1785
1786     fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
1787         vec![
1788             TestDescAndFn {
1789                 desc: TestDesc {
1790                     name: StaticTestName("1"),
1791                     ignore: true,
1792                     should_panic: ShouldPanic::No,
1793                     allow_fail: false,
1794                 },
1795                 testfn: DynTestFn(Box::new(move || {})),
1796             },
1797             TestDescAndFn {
1798                 desc: TestDesc {
1799                     name: StaticTestName("2"),
1800                     ignore: false,
1801                     should_panic: ShouldPanic::No,
1802                     allow_fail: false,
1803                 },
1804                 testfn: DynTestFn(Box::new(move || {})),
1805             },
1806         ]
1807     }
1808
1809     #[test]
1810     pub fn do_not_run_ignored_tests() {
1811         fn f() {
1812             panic!();
1813         }
1814         let desc = TestDescAndFn {
1815             desc: TestDesc {
1816                 name: StaticTestName("whatever"),
1817                 ignore: true,
1818                 should_panic: ShouldPanic::No,
1819                 allow_fail: false,
1820             },
1821             testfn: DynTestFn(Box::new(f)),
1822         };
1823         let (tx, rx) = channel();
1824         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1825         let (_, res, _) = rx.recv().unwrap();
1826         assert!(res != TrOk);
1827     }
1828
1829     #[test]
1830     pub fn ignored_tests_result_in_ignored() {
1831         fn f() {}
1832         let desc = TestDescAndFn {
1833             desc: TestDesc {
1834                 name: StaticTestName("whatever"),
1835                 ignore: true,
1836                 should_panic: ShouldPanic::No,
1837                 allow_fail: false,
1838             },
1839             testfn: DynTestFn(Box::new(f)),
1840         };
1841         let (tx, rx) = channel();
1842         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1843         let (_, res, _) = rx.recv().unwrap();
1844         assert!(res == TrIgnored);
1845     }
1846
1847     #[test]
1848     fn test_should_panic() {
1849         fn f() {
1850             panic!();
1851         }
1852         let desc = TestDescAndFn {
1853             desc: TestDesc {
1854                 name: StaticTestName("whatever"),
1855                 ignore: false,
1856                 should_panic: ShouldPanic::Yes,
1857                 allow_fail: false,
1858             },
1859             testfn: DynTestFn(Box::new(f)),
1860         };
1861         let (tx, rx) = channel();
1862         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1863         let (_, res, _) = rx.recv().unwrap();
1864         assert!(res == TrOk);
1865     }
1866
1867     #[test]
1868     fn test_should_panic_good_message() {
1869         fn f() {
1870             panic!("an error message");
1871         }
1872         let desc = TestDescAndFn {
1873             desc: TestDesc {
1874                 name: StaticTestName("whatever"),
1875                 ignore: false,
1876                 should_panic: ShouldPanic::YesWithMessage("error message"),
1877                 allow_fail: false,
1878             },
1879             testfn: DynTestFn(Box::new(f)),
1880         };
1881         let (tx, rx) = channel();
1882         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1883         let (_, res, _) = rx.recv().unwrap();
1884         assert!(res == TrOk);
1885     }
1886
1887     #[test]
1888     fn test_should_panic_bad_message() {
1889         fn f() {
1890             panic!("an error message");
1891         }
1892         let expected = "foobar";
1893         let failed_msg = "Panic did not include expected string";
1894         let desc = TestDescAndFn {
1895             desc: TestDesc {
1896                 name: StaticTestName("whatever"),
1897                 ignore: false,
1898                 should_panic: ShouldPanic::YesWithMessage(expected),
1899                 allow_fail: false,
1900             },
1901             testfn: DynTestFn(Box::new(f)),
1902         };
1903         let (tx, rx) = channel();
1904         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1905         let (_, res, _) = rx.recv().unwrap();
1906         assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
1907     }
1908
1909     #[test]
1910     fn test_should_panic_but_succeeds() {
1911         fn f() {}
1912         let desc = TestDescAndFn {
1913             desc: TestDesc {
1914                 name: StaticTestName("whatever"),
1915                 ignore: false,
1916                 should_panic: ShouldPanic::Yes,
1917                 allow_fail: false,
1918             },
1919             testfn: DynTestFn(Box::new(f)),
1920         };
1921         let (tx, rx) = channel();
1922         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1923         let (_, res, _) = rx.recv().unwrap();
1924         assert!(res == TrFailed);
1925     }
1926
1927     #[test]
1928     fn parse_ignored_flag() {
1929         let args = vec![
1930             "progname".to_string(),
1931             "filter".to_string(),
1932             "--ignored".to_string(),
1933         ];
1934         let opts = parse_opts(&args).unwrap().unwrap();
1935         assert_eq!(opts.run_ignored, RunIgnored::Only);
1936     }
1937
1938     #[test]
1939     fn parse_include_ignored_flag() {
1940         let args = vec![
1941             "progname".to_string(),
1942             "filter".to_string(),
1943             "-Zunstable-options".to_string(),
1944             "--include-ignored".to_string(),
1945         ];
1946         let opts = parse_opts(&args).unwrap().unwrap();
1947         assert_eq!(opts.run_ignored, RunIgnored::Yes);
1948     }
1949
1950     #[test]
1951     pub fn filter_for_ignored_option() {
1952         // When we run ignored tests the test filter should filter out all the
1953         // unignored tests and flip the ignore flag on the rest to false
1954
1955         let mut opts = TestOpts::new();
1956         opts.run_tests = true;
1957         opts.run_ignored = RunIgnored::Only;
1958
1959         let tests = one_ignored_one_unignored_test();
1960         let filtered = filter_tests(&opts, tests);
1961
1962         assert_eq!(filtered.len(), 1);
1963         assert_eq!(filtered[0].desc.name.to_string(), "1");
1964         assert!(!filtered[0].desc.ignore);
1965     }
1966
1967     #[test]
1968     pub fn run_include_ignored_option() {
1969         // When we "--include-ignored" tests, the ignore flag should be set to false on
1970         // all tests and no test filtered out
1971
1972         let mut opts = TestOpts::new();
1973         opts.run_tests = true;
1974         opts.run_ignored = RunIgnored::Yes;
1975
1976         let tests = one_ignored_one_unignored_test();
1977         let filtered = filter_tests(&opts, tests);
1978
1979         assert_eq!(filtered.len(), 2);
1980         assert!(!filtered[0].desc.ignore);
1981         assert!(!filtered[1].desc.ignore);
1982     }
1983
1984     #[test]
1985     pub fn exclude_should_panic_option() {
1986         let mut opts = TestOpts::new();
1987         opts.run_tests = true;
1988         opts.exclude_should_panic = true;
1989
1990         let mut tests = one_ignored_one_unignored_test();
1991         tests.push(TestDescAndFn {
1992             desc: TestDesc {
1993                 name: StaticTestName("3"),
1994                 ignore: false,
1995                 should_panic: ShouldPanic::Yes,
1996                 allow_fail: false,
1997             },
1998             testfn: DynTestFn(Box::new(move || {})),
1999         });
2000
2001         let filtered = filter_tests(&opts, tests);
2002
2003         assert_eq!(filtered.len(), 2);
2004         assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
2005     }
2006
2007     #[test]
2008     pub fn exact_filter_match() {
2009         fn tests() -> Vec<TestDescAndFn> {
2010             vec!["base", "base::test", "base::test1", "base::test2"]
2011                 .into_iter()
2012                 .map(|name| TestDescAndFn {
2013                     desc: TestDesc {
2014                         name: StaticTestName(name),
2015                         ignore: false,
2016                         should_panic: ShouldPanic::No,
2017                         allow_fail: false,
2018                     },
2019                     testfn: DynTestFn(Box::new(move || {})),
2020                 })
2021                 .collect()
2022         }
2023
2024         let substr = filter_tests(
2025             &TestOpts {
2026                 filter: Some("base".into()),
2027                 ..TestOpts::new()
2028             },
2029             tests(),
2030         );
2031         assert_eq!(substr.len(), 4);
2032
2033         let substr = filter_tests(
2034             &TestOpts {
2035                 filter: Some("bas".into()),
2036                 ..TestOpts::new()
2037             },
2038             tests(),
2039         );
2040         assert_eq!(substr.len(), 4);
2041
2042         let substr = filter_tests(
2043             &TestOpts {
2044                 filter: Some("::test".into()),
2045                 ..TestOpts::new()
2046             },
2047             tests(),
2048         );
2049         assert_eq!(substr.len(), 3);
2050
2051         let substr = filter_tests(
2052             &TestOpts {
2053                 filter: Some("base::test".into()),
2054                 ..TestOpts::new()
2055             },
2056             tests(),
2057         );
2058         assert_eq!(substr.len(), 3);
2059
2060         let exact = filter_tests(
2061             &TestOpts {
2062                 filter: Some("base".into()),
2063                 filter_exact: true,
2064                 ..TestOpts::new()
2065             },
2066             tests(),
2067         );
2068         assert_eq!(exact.len(), 1);
2069
2070         let exact = filter_tests(
2071             &TestOpts {
2072                 filter: Some("bas".into()),
2073                 filter_exact: true,
2074                 ..TestOpts::new()
2075             },
2076             tests(),
2077         );
2078         assert_eq!(exact.len(), 0);
2079
2080         let exact = filter_tests(
2081             &TestOpts {
2082                 filter: Some("::test".into()),
2083                 filter_exact: true,
2084                 ..TestOpts::new()
2085             },
2086             tests(),
2087         );
2088         assert_eq!(exact.len(), 0);
2089
2090         let exact = filter_tests(
2091             &TestOpts {
2092                 filter: Some("base::test".into()),
2093                 filter_exact: true,
2094                 ..TestOpts::new()
2095             },
2096             tests(),
2097         );
2098         assert_eq!(exact.len(), 1);
2099     }
2100
2101     #[test]
2102     pub fn sort_tests() {
2103         let mut opts = TestOpts::new();
2104         opts.run_tests = true;
2105
2106         let names = vec![
2107             "sha1::test".to_string(),
2108             "isize::test_to_str".to_string(),
2109             "isize::test_pow".to_string(),
2110             "test::do_not_run_ignored_tests".to_string(),
2111             "test::ignored_tests_result_in_ignored".to_string(),
2112             "test::first_free_arg_should_be_a_filter".to_string(),
2113             "test::parse_ignored_flag".to_string(),
2114             "test::parse_include_ignored_flag".to_string(),
2115             "test::filter_for_ignored_option".to_string(),
2116             "test::run_include_ignored_option".to_string(),
2117             "test::sort_tests".to_string(),
2118         ];
2119         let tests = {
2120             fn testfn() {}
2121             let mut tests = Vec::new();
2122             for name in &names {
2123                 let test = TestDescAndFn {
2124                     desc: TestDesc {
2125                         name: DynTestName((*name).clone()),
2126                         ignore: false,
2127                         should_panic: ShouldPanic::No,
2128                         allow_fail: false,
2129                     },
2130                     testfn: DynTestFn(Box::new(testfn)),
2131                 };
2132                 tests.push(test);
2133             }
2134             tests
2135         };
2136         let filtered = filter_tests(&opts, tests);
2137
2138         let expected = vec![
2139             "isize::test_pow".to_string(),
2140             "isize::test_to_str".to_string(),
2141             "sha1::test".to_string(),
2142             "test::do_not_run_ignored_tests".to_string(),
2143             "test::filter_for_ignored_option".to_string(),
2144             "test::first_free_arg_should_be_a_filter".to_string(),
2145             "test::ignored_tests_result_in_ignored".to_string(),
2146             "test::parse_ignored_flag".to_string(),
2147             "test::parse_include_ignored_flag".to_string(),
2148             "test::run_include_ignored_option".to_string(),
2149             "test::sort_tests".to_string(),
2150         ];
2151
2152         for (a, b) in expected.iter().zip(filtered) {
2153             assert!(*a == b.desc.name.to_string());
2154         }
2155     }
2156
2157     #[test]
2158     pub fn test_metricmap_compare() {
2159         let mut m1 = MetricMap::new();
2160         let mut m2 = MetricMap::new();
2161         m1.insert_metric("in-both-noise", 1000.0, 200.0);
2162         m2.insert_metric("in-both-noise", 1100.0, 200.0);
2163
2164         m1.insert_metric("in-first-noise", 1000.0, 2.0);
2165         m2.insert_metric("in-second-noise", 1000.0, 2.0);
2166
2167         m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
2168         m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
2169
2170         m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
2171         m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
2172
2173         m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
2174         m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
2175
2176         m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
2177         m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
2178     }
2179
2180     #[test]
2181     pub fn test_bench_once_no_iter() {
2182         fn f(_: &mut Bencher) {}
2183         bench::run_once(f);
2184     }
2185
2186     #[test]
2187     pub fn test_bench_once_iter() {
2188         fn f(b: &mut Bencher) {
2189             b.iter(|| {})
2190         }
2191         bench::run_once(f);
2192     }
2193
2194     #[test]
2195     pub fn test_bench_no_iter() {
2196         fn f(_: &mut Bencher) {}
2197
2198         let (tx, rx) = channel();
2199
2200         let desc = TestDesc {
2201             name: StaticTestName("f"),
2202             ignore: false,
2203             should_panic: ShouldPanic::No,
2204             allow_fail: false,
2205         };
2206
2207         crate::bench::benchmark(desc, tx, true, f);
2208         rx.recv().unwrap();
2209     }
2210
2211     #[test]
2212     pub fn test_bench_iter() {
2213         fn f(b: &mut Bencher) {
2214             b.iter(|| {})
2215         }
2216
2217         let (tx, rx) = channel();
2218
2219         let desc = TestDesc {
2220             name: StaticTestName("f"),
2221             ignore: false,
2222             should_panic: ShouldPanic::No,
2223             allow_fail: false,
2224         };
2225
2226         crate::bench::benchmark(desc, tx, true, f);
2227         rx.recv().unwrap();
2228     }
2229 }