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