]> git.lizzy.rs Git - rust.git/blob - src/libtest/lib.rs
Auto merge of #59042 - ljedrz:HirIdification_rework_map, r=Zoxc
[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, so we don't link libtest against
41 //                libunwind (for the time being), even though it means that
42 //                libtest won't be fully functional on this platform.
43 //
44 // See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
45 #[cfg(not(all(windows, target_arch = "aarch64")))]
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::boxed::FnBox;
59 use std::cmp;
60 use std::collections::BTreeMap;
61 use std::env;
62 use std::fmt;
63 use std::fs::File;
64 use std::io;
65 use std::io::prelude::*;
66 use std::panic::{catch_unwind, AssertUnwindSafe};
67 use std::path::PathBuf;
68 use std::process;
69 use std::process::Termination;
70 use std::sync::mpsc::{channel, Sender};
71 use std::sync::{Arc, Mutex};
72 use std::thread;
73 use std::time::{Duration, Instant};
74
75 const TEST_WARN_TIMEOUT_S: u64 = 60;
76 const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
77
78 // to be used by rustc to compile tests in libtest
79 pub mod test {
80     pub use crate::{
81         assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
82         Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
83         StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
84         TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
85     };
86 }
87
88 mod formatters;
89 pub mod stats;
90
91 use crate::formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter};
92
93 /// Whether to execute tests concurrently or not
94 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
95 pub enum Concurrent {
96     Yes,
97     No,
98 }
99
100 // The name of a test. By convention this follows the rules for rust
101 // paths; i.e., it should be a series of identifiers separated by double
102 // colons. This way if some test runner wants to arrange the tests
103 // hierarchically it may.
104
105 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
106 pub enum TestName {
107     StaticTestName(&'static str),
108     DynTestName(String),
109     AlignedTestName(Cow<'static, str>, NamePadding),
110 }
111 impl TestName {
112     fn as_slice(&self) -> &str {
113         match *self {
114             StaticTestName(s) => s,
115             DynTestName(ref s) => s,
116             AlignedTestName(ref s, _) => &*s,
117         }
118     }
119
120     fn padding(&self) -> NamePadding {
121         match self {
122             &AlignedTestName(_, p) => p,
123             _ => PadNone,
124         }
125     }
126
127     fn with_padding(&self, padding: NamePadding) -> TestName {
128         let name = match self {
129             &TestName::StaticTestName(name) => Cow::Borrowed(name),
130             &TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
131             &TestName::AlignedTestName(ref name, _) => name.clone(),
132         };
133
134         TestName::AlignedTestName(name, padding)
135     }
136 }
137 impl fmt::Display for TestName {
138     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139         fmt::Display::fmt(self.as_slice(), f)
140     }
141 }
142
143 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
144 pub enum NamePadding {
145     PadNone,
146     PadOnRight,
147 }
148
149 impl TestDesc {
150     fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
151         let mut name = String::from(self.name.as_slice());
152         let fill = column_count.saturating_sub(name.len());
153         let pad = " ".repeat(fill);
154         match align {
155             PadNone => name,
156             PadOnRight => {
157                 name.push_str(&pad);
158                 name
159             }
160         }
161     }
162 }
163
164 /// Represents a benchmark function.
165 pub trait TDynBenchFn: Send {
166     fn run(&self, harness: &mut Bencher);
167 }
168
169 // A function that runs a test. If the function returns successfully,
170 // the test succeeds; if the function panics then the test fails. We
171 // may need to come up with a more clever definition of test in order
172 // to support isolation of tests into threads.
173 pub enum TestFn {
174     StaticTestFn(fn()),
175     StaticBenchFn(fn(&mut Bencher)),
176     DynTestFn(Box<dyn FnBox() + Send>),
177     DynBenchFn(Box<dyn TDynBenchFn + 'static>),
178 }
179
180 impl TestFn {
181     fn padding(&self) -> NamePadding {
182         match *self {
183             StaticTestFn(..) => PadNone,
184             StaticBenchFn(..) => PadOnRight,
185             DynTestFn(..) => PadNone,
186             DynBenchFn(..) => PadOnRight,
187         }
188     }
189 }
190
191 impl fmt::Debug for TestFn {
192     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193         f.write_str(match *self {
194             StaticTestFn(..) => "StaticTestFn(..)",
195             StaticBenchFn(..) => "StaticBenchFn(..)",
196             DynTestFn(..) => "DynTestFn(..)",
197             DynBenchFn(..) => "DynBenchFn(..)",
198         })
199     }
200 }
201
202 /// Manager of the benchmarking runs.
203 ///
204 /// This is fed into functions marked with `#[bench]` to allow for
205 /// set-up & tear-down before running a piece of code repeatedly via a
206 /// call to `iter`.
207 #[derive(Clone)]
208 pub struct Bencher {
209     mode: BenchMode,
210     summary: Option<stats::Summary>,
211     pub bytes: u64,
212 }
213
214 #[derive(Clone, PartialEq, Eq)]
215 pub enum BenchMode {
216     Auto,
217     Single,
218 }
219
220 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
221 pub enum ShouldPanic {
222     No,
223     Yes,
224     YesWithMessage(&'static str),
225 }
226
227 // The definition of a single test. A test runner will run a list of
228 // these.
229 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
230 pub struct TestDesc {
231     pub name: TestName,
232     pub ignore: bool,
233     pub should_panic: ShouldPanic,
234     pub allow_fail: bool,
235 }
236
237 #[derive(Debug)]
238 pub struct TestDescAndFn {
239     pub desc: TestDesc,
240     pub testfn: TestFn,
241 }
242
243 #[derive(Clone, PartialEq, Debug, Copy)]
244 pub struct Metric {
245     value: f64,
246     noise: f64,
247 }
248
249 impl Metric {
250     pub fn new(value: f64, noise: f64) -> Metric {
251         Metric { value, noise }
252     }
253 }
254
255 /// In case we want to add other options as well, just add them in this struct.
256 #[derive(Copy, Clone, Debug)]
257 pub struct Options {
258     display_output: bool,
259 }
260
261 impl Options {
262     pub fn new() -> Options {
263         Options {
264             display_output: false,
265         }
266     }
267
268     pub fn display_output(mut self, display_output: bool) -> Options {
269         self.display_output = display_output;
270         self
271     }
272 }
273
274 // The default console test runner. It accepts the command line
275 // arguments and a vector of test_descs.
276 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
277     let mut opts = match parse_opts(args) {
278         Some(Ok(o)) => o,
279         Some(Err(msg)) => {
280             eprintln!("error: {}", msg);
281             process::exit(101);
282         }
283         None => return,
284     };
285
286     opts.options = options;
287     if opts.list {
288         if let Err(e) = list_tests_console(&opts, tests) {
289             eprintln!("error: io error when listing tests: {:?}", e);
290             process::exit(101);
291         }
292     } else {
293         match run_tests_console(&opts, tests) {
294             Ok(true) => {}
295             Ok(false) => process::exit(101),
296             Err(e) => {
297                 eprintln!("error: io error when listing tests: {:?}", e);
298                 process::exit(101);
299             }
300         }
301     }
302 }
303
304 // A variant optimized for invocation with a static test vector.
305 // This will panic (intentionally) when fed any dynamic tests, because
306 // it is copying the static values out into a dynamic vector and cannot
307 // copy dynamic values. It is doing this because from this point on
308 // a Vec<TestDescAndFn> is used in order to effect ownership-transfer
309 // semantics into parallel test runners, which in turn requires a Vec<>
310 // rather than a &[].
311 pub fn test_main_static(tests: &[&TestDescAndFn]) {
312     let args = env::args().collect::<Vec<_>>();
313     let owned_tests = tests
314         .iter()
315         .map(|t| match t.testfn {
316             StaticTestFn(f) => TestDescAndFn {
317                 testfn: StaticTestFn(f),
318                 desc: t.desc.clone(),
319             },
320             StaticBenchFn(f) => TestDescAndFn {
321                 testfn: StaticBenchFn(f),
322                 desc: t.desc.clone(),
323             },
324             _ => panic!("non-static tests passed to test::test_main_static"),
325         })
326         .collect();
327     test_main(&args, owned_tests, Options::new())
328 }
329
330 /// Invoked when unit tests terminate. Should panic if the unit
331 /// Tests is considered a failure. By default, invokes `report()`
332 /// and checks for a `0` result.
333 pub fn assert_test_result<T: Termination>(result: T) {
334     let code = result.report();
335     assert_eq!(
336         code, 0,
337         "the test returned a termination value with a non-zero status code ({}) \
338          which indicates a failure",
339         code
340     );
341 }
342
343 #[derive(Copy, Clone, Debug)]
344 pub enum ColorConfig {
345     AutoColor,
346     AlwaysColor,
347     NeverColor,
348 }
349
350 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
351 pub enum OutputFormat {
352     Pretty,
353     Terse,
354     Json,
355 }
356
357 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
358 pub enum RunIgnored {
359     Yes,
360     No,
361     Only,
362 }
363
364 #[derive(Debug)]
365 pub struct TestOpts {
366     pub list: bool,
367     pub filter: Option<String>,
368     pub filter_exact: bool,
369     pub exclude_should_panic: bool,
370     pub run_ignored: RunIgnored,
371     pub run_tests: bool,
372     pub bench_benchmarks: bool,
373     pub logfile: Option<PathBuf>,
374     pub nocapture: bool,
375     pub color: ColorConfig,
376     pub format: OutputFormat,
377     pub test_threads: Option<usize>,
378     pub skip: Vec<String>,
379     pub options: Options,
380 }
381
382 impl TestOpts {
383     #[cfg(test)]
384     fn new() -> TestOpts {
385         TestOpts {
386             list: false,
387             filter: None,
388             filter_exact: false,
389             exclude_should_panic: false,
390             run_ignored: RunIgnored::No,
391             run_tests: false,
392             bench_benchmarks: false,
393             logfile: None,
394             nocapture: false,
395             color: AutoColor,
396             format: OutputFormat::Pretty,
397             test_threads: None,
398             skip: vec![],
399             options: Options::new(),
400         }
401     }
402 }
403
404 /// Result of parsing the options.
405 pub type OptRes = Result<TestOpts, String>;
406
407 fn optgroups() -> getopts::Options {
408     let mut opts = getopts::Options::new();
409     opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
410         .optflag("", "ignored", "Run only ignored tests")
411         .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
412         .optflag("", "test", "Run tests and not benchmarks")
413         .optflag("", "bench", "Run benchmarks instead of tests")
414         .optflag("", "list", "List all tests and benchmarks")
415         .optflag("h", "help", "Display this message (longer with --help)")
416         .optopt(
417             "",
418             "logfile",
419             "Write logs to the specified file instead \
420              of stdout",
421             "PATH",
422         )
423         .optflag(
424             "",
425             "nocapture",
426             "don't capture stdout/stderr of each \
427              task, allow printing directly",
428         )
429         .optopt(
430             "",
431             "test-threads",
432             "Number of threads used for running tests \
433              in parallel",
434             "n_threads",
435         )
436         .optmulti(
437             "",
438             "skip",
439             "Skip tests whose names contain FILTER (this flag can \
440              be used multiple times)",
441             "FILTER",
442         )
443         .optflag(
444             "q",
445             "quiet",
446             "Display one character per test instead of one line. \
447              Alias to --format=terse",
448         )
449         .optflag(
450             "",
451             "exact",
452             "Exactly match filters rather than by substring",
453         )
454         .optopt(
455             "",
456             "color",
457             "Configure coloring of output:
458             auto   = colorize if stdout is a tty and tests are run on serially (default);
459             always = always colorize output;
460             never  = never colorize output;",
461             "auto|always|never",
462         )
463         .optopt(
464             "",
465             "format",
466             "Configure formatting of output:
467             pretty = Print verbose output;
468             terse  = Display one character per test;
469             json   = Output a json document",
470             "pretty|terse|json",
471         )
472         .optopt(
473             "Z",
474             "",
475             "Enable nightly-only flags:
476             unstable-options = Allow use of experimental features",
477             "unstable-options",
478         );
479     return opts;
480 }
481
482 fn usage(binary: &str, options: &getopts::Options) {
483     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
484     println!(
485         r#"{usage}
486
487 The FILTER string is tested against the name of all tests, and only those
488 tests whose names contain the filter are run.
489
490 By default, all tests are run in parallel. This can be altered with the
491 --test-threads flag or the RUST_TEST_THREADS environment variable when running
492 tests (set it to 1).
493
494 All tests have their standard output and standard error captured by default.
495 This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
496 environment variable to a value other than "0". Logging is not captured by default.
497
498 Test Attributes:
499
500     #[test]        - Indicates a function is a test to be run. This function
501                      takes no arguments.
502     #[bench]       - Indicates a function is a benchmark to be run. This
503                      function takes one argument (test::Bencher).
504     #[should_panic] - This function (also labeled with #[test]) will only pass if
505                      the code causes a panic (an assertion failure or panic!)
506                      A message may be provided, which the failure string must
507                      contain: #[should_panic(expected = "foo")].
508     #[ignore]      - When applied to a function which is already attributed as a
509                      test, then the test runner will ignore these tests during
510                      normal test runs. Running with --ignored or --include-ignored will run
511                      these tests."#,
512         usage = options.usage(&message)
513     );
514 }
515
516 // FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
517 fn is_nightly() -> bool {
518     // Whether this is a feature-staged build, i.e., on the beta or stable channel
519     let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
520     // Whether we should enable unstable features for bootstrapping
521     let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
522
523     bootstrap || !disable_unstable_features
524 }
525
526 // Parses command line arguments into test options
527 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
528     let mut allow_unstable = false;
529     let opts = optgroups();
530     let args = args.get(1..).unwrap_or(args);
531     let matches = match opts.parse(args) {
532         Ok(m) => m,
533         Err(f) => return Some(Err(f.to_string())),
534     };
535
536     if let Some(opt) = matches.opt_str("Z") {
537         if !is_nightly() {
538             return Some(Err(
539                 "the option `Z` is only accepted on the nightly compiler".into(),
540             ));
541         }
542
543         match &*opt {
544             "unstable-options" => {
545                 allow_unstable = true;
546             }
547             _ => {
548                 return Some(Err("Unrecognized option to `Z`".into()));
549             }
550         }
551     };
552
553     if matches.opt_present("h") {
554         usage(&args[0], &opts);
555         return None;
556     }
557
558     let filter = if !matches.free.is_empty() {
559         Some(matches.free[0].clone())
560     } else {
561         None
562     };
563
564     let exclude_should_panic = matches.opt_present("exclude-should-panic");
565     if !allow_unstable && exclude_should_panic {
566         return Some(Err(
567             "The \"exclude-should-panic\" flag is only accepted on the nightly compiler".into(),
568         ));
569     }
570
571     let include_ignored = matches.opt_present("include-ignored");
572     if !allow_unstable && include_ignored {
573         return Some(Err(
574             "The \"include-ignored\" flag is only accepted on the nightly compiler".into(),
575         ));
576     }
577
578     let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
579         (true, true) => {
580             return Some(Err(
581                 "the options --include-ignored and --ignored are mutually exclusive".into(),
582             ));
583         }
584         (true, false) => RunIgnored::Yes,
585         (false, true) => RunIgnored::Only,
586         (false, false) => RunIgnored::No,
587     };
588     let quiet = matches.opt_present("quiet");
589     let exact = matches.opt_present("exact");
590     let list = matches.opt_present("list");
591
592     let logfile = matches.opt_str("logfile");
593     let logfile = logfile.map(|s| PathBuf::from(&s));
594
595     let bench_benchmarks = matches.opt_present("bench");
596     let run_tests = !bench_benchmarks || matches.opt_present("test");
597
598     let mut nocapture = matches.opt_present("nocapture");
599     if !nocapture {
600         nocapture = match env::var("RUST_TEST_NOCAPTURE") {
601             Ok(val) => &val != "0",
602             Err(_) => false,
603         };
604     }
605
606     let test_threads = match matches.opt_str("test-threads") {
607         Some(n_str) => match n_str.parse::<usize>() {
608             Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
609             Ok(n) => Some(n),
610             Err(e) => {
611                 return Some(Err(format!(
612                     "argument for --test-threads must be a number > 0 \
613                      (error: {})",
614                     e
615                 )));
616             }
617         },
618         None => None,
619     };
620
621     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
622         Some("auto") | None => AutoColor,
623         Some("always") => AlwaysColor,
624         Some("never") => NeverColor,
625
626         Some(v) => {
627             return Some(Err(format!(
628                 "argument for --color must be auto, always, or never (was \
629                  {})",
630                 v
631             )));
632         }
633     };
634
635     let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
636         None if quiet => OutputFormat::Terse,
637         Some("pretty") | None => OutputFormat::Pretty,
638         Some("terse") => OutputFormat::Terse,
639         Some("json") => {
640             if !allow_unstable {
641                 return Some(Err(
642                     "The \"json\" format is only accepted on the nightly compiler".into(),
643                 ));
644             }
645             OutputFormat::Json
646         }
647
648         Some(v) => {
649             return Some(Err(format!(
650                 "argument for --format must be pretty, terse, or json (was \
651                  {})",
652                 v
653             )));
654         }
655     };
656
657     let test_opts = TestOpts {
658         list,
659         filter,
660         filter_exact: exact,
661         exclude_should_panic,
662         run_ignored,
663         run_tests,
664         bench_benchmarks,
665         logfile,
666         nocapture,
667         color,
668         format,
669         test_threads,
670         skip: matches.opt_strs("skip"),
671         options: Options::new(),
672     };
673
674     Some(Ok(test_opts))
675 }
676
677 #[derive(Clone, PartialEq)]
678 pub struct BenchSamples {
679     ns_iter_summ: stats::Summary,
680     mb_s: usize,
681 }
682
683 #[derive(Clone, PartialEq)]
684 pub enum TestResult {
685     TrOk,
686     TrFailed,
687     TrFailedMsg(String),
688     TrIgnored,
689     TrAllowedFail,
690     TrBench(BenchSamples),
691 }
692
693 unsafe impl Send for TestResult {}
694
695 enum OutputLocation<T> {
696     Pretty(Box<term::StdoutTerminal>),
697     Raw(T),
698 }
699
700 impl<T: Write> Write for OutputLocation<T> {
701     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
702         match *self {
703             Pretty(ref mut term) => term.write(buf),
704             Raw(ref mut stdout) => stdout.write(buf),
705         }
706     }
707
708     fn flush(&mut self) -> io::Result<()> {
709         match *self {
710             Pretty(ref mut term) => term.flush(),
711             Raw(ref mut stdout) => stdout.flush(),
712         }
713     }
714 }
715
716 struct ConsoleTestState {
717     log_out: Option<File>,
718     total: usize,
719     passed: usize,
720     failed: usize,
721     ignored: usize,
722     allowed_fail: usize,
723     filtered_out: usize,
724     measured: usize,
725     metrics: MetricMap,
726     failures: Vec<(TestDesc, Vec<u8>)>,
727     not_failures: Vec<(TestDesc, Vec<u8>)>,
728     options: Options,
729 }
730
731 impl ConsoleTestState {
732     pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
733         let log_out = match opts.logfile {
734             Some(ref path) => Some(File::create(path)?),
735             None => None,
736         };
737
738         Ok(ConsoleTestState {
739             log_out,
740             total: 0,
741             passed: 0,
742             failed: 0,
743             ignored: 0,
744             allowed_fail: 0,
745             filtered_out: 0,
746             measured: 0,
747             metrics: MetricMap::new(),
748             failures: Vec::new(),
749             not_failures: Vec::new(),
750             options: opts.options,
751         })
752     }
753
754     pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
755         let msg = msg.as_ref();
756         match self.log_out {
757             None => Ok(()),
758             Some(ref mut o) => o.write_all(msg.as_bytes()),
759         }
760     }
761
762     pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
763         self.write_log(format!(
764             "{} {}\n",
765             match *result {
766                 TrOk => "ok".to_owned(),
767                 TrFailed => "failed".to_owned(),
768                 TrFailedMsg(ref msg) => format!("failed: {}", msg),
769                 TrIgnored => "ignored".to_owned(),
770                 TrAllowedFail => "failed (allowed)".to_owned(),
771                 TrBench(ref bs) => fmt_bench_samples(bs),
772             },
773             test.name
774         ))
775     }
776
777     fn current_test_count(&self) -> usize {
778         self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
779     }
780 }
781
782 // Format a number with thousands separators
783 fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
784     use std::fmt::Write;
785     let mut output = String::new();
786     let mut trailing = false;
787     for &pow in &[9, 6, 3, 0] {
788         let base = 10_usize.pow(pow);
789         if pow == 0 || trailing || n / base != 0 {
790             if !trailing {
791                 output.write_fmt(format_args!("{}", n / base)).unwrap();
792             } else {
793                 output.write_fmt(format_args!("{:03}", n / base)).unwrap();
794             }
795             if pow != 0 {
796                 output.push(sep);
797             }
798             trailing = true;
799         }
800         n %= base;
801     }
802
803     output
804 }
805
806 pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
807     use std::fmt::Write;
808     let mut output = String::new();
809
810     let median = bs.ns_iter_summ.median as usize;
811     let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
812
813     output
814         .write_fmt(format_args!(
815             "{:>11} ns/iter (+/- {})",
816             fmt_thousands_sep(median, ','),
817             fmt_thousands_sep(deviation, ',')
818         ))
819         .unwrap();
820     if bs.mb_s != 0 {
821         output
822             .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
823             .unwrap();
824     }
825     output
826 }
827
828 // List the tests to console, and optionally to logfile. Filters are honored.
829 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
830     let mut output = match term::stdout() {
831         None => Raw(io::stdout()),
832         Some(t) => Pretty(t),
833     };
834
835     let quiet = opts.format == OutputFormat::Terse;
836     let mut st = ConsoleTestState::new(opts)?;
837
838     let mut ntest = 0;
839     let mut nbench = 0;
840
841     for test in filter_tests(&opts, tests) {
842         use crate::TestFn::*;
843
844         let TestDescAndFn {
845             desc: TestDesc { name, .. },
846             testfn,
847         } = test;
848
849         let fntype = match testfn {
850             StaticTestFn(..) | DynTestFn(..) => {
851                 ntest += 1;
852                 "test"
853             }
854             StaticBenchFn(..) | DynBenchFn(..) => {
855                 nbench += 1;
856                 "benchmark"
857             }
858         };
859
860         writeln!(output, "{}: {}", name, fntype)?;
861         st.write_log(format!("{} {}\n", fntype, name))?;
862     }
863
864     fn plural(count: u32, s: &str) -> String {
865         match count {
866             1 => format!("{} {}", 1, s),
867             n => format!("{} {}s", n, s),
868         }
869     }
870
871     if !quiet {
872         if ntest != 0 || nbench != 0 {
873             writeln!(output, "")?;
874         }
875
876         writeln!(
877             output,
878             "{}, {}",
879             plural(ntest, "test"),
880             plural(nbench, "benchmark")
881         )?;
882     }
883
884     Ok(())
885 }
886
887 // A simple console test runner
888 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
889     fn callback(
890         event: &TestEvent,
891         st: &mut ConsoleTestState,
892         out: &mut dyn OutputFormatter,
893     ) -> io::Result<()> {
894         match (*event).clone() {
895             TeFiltered(ref filtered_tests) => {
896                 st.total = filtered_tests.len();
897                 out.write_run_start(filtered_tests.len())
898             }
899             TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out),
900             TeWait(ref test) => out.write_test_start(test),
901             TeTimeout(ref test) => out.write_timeout(test),
902             TeResult(test, result, stdout) => {
903                 st.write_log_result(&test, &result)?;
904                 out.write_result(&test, &result, &*stdout)?;
905                 match result {
906                     TrOk => {
907                         st.passed += 1;
908                         st.not_failures.push((test, stdout));
909                     }
910                     TrIgnored => st.ignored += 1,
911                     TrAllowedFail => st.allowed_fail += 1,
912                     TrBench(bs) => {
913                         st.metrics.insert_metric(
914                             test.name.as_slice(),
915                             bs.ns_iter_summ.median,
916                             bs.ns_iter_summ.max - bs.ns_iter_summ.min,
917                         );
918                         st.measured += 1
919                     }
920                     TrFailed => {
921                         st.failed += 1;
922                         st.failures.push((test, stdout));
923                     }
924                     TrFailedMsg(msg) => {
925                         st.failed += 1;
926                         let mut stdout = stdout;
927                         stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
928                         st.failures.push((test, stdout));
929                     }
930                 }
931                 Ok(())
932             }
933         }
934     }
935
936     let output = match term::stdout() {
937         None => Raw(io::stdout()),
938         Some(t) => Pretty(t),
939     };
940
941     let max_name_len = tests
942         .iter()
943         .max_by_key(|t| len_if_padded(*t))
944         .map(|t| t.desc.name.as_slice().len())
945         .unwrap_or(0);
946
947     let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
948
949     let mut out: Box<dyn OutputFormatter> = match opts.format {
950         OutputFormat::Pretty => Box::new(PrettyFormatter::new(
951             output,
952             use_color(opts),
953             max_name_len,
954             is_multithreaded,
955         )),
956         OutputFormat::Terse => Box::new(TerseFormatter::new(
957             output,
958             use_color(opts),
959             max_name_len,
960             is_multithreaded,
961         )),
962         OutputFormat::Json => Box::new(JsonFormatter::new(output)),
963     };
964     let mut st = ConsoleTestState::new(opts)?;
965     fn len_if_padded(t: &TestDescAndFn) -> usize {
966         match t.testfn.padding() {
967             PadNone => 0,
968             PadOnRight => t.desc.name.as_slice().len(),
969         }
970     }
971
972     run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?;
973
974     assert!(st.current_test_count() == st.total);
975
976     return out.write_run_finish(&st);
977 }
978
979 #[test]
980 fn should_sort_failures_before_printing_them() {
981     let test_a = TestDesc {
982         name: StaticTestName("a"),
983         ignore: false,
984         should_panic: ShouldPanic::No,
985         allow_fail: false,
986     };
987
988     let test_b = TestDesc {
989         name: StaticTestName("b"),
990         ignore: false,
991         should_panic: ShouldPanic::No,
992         allow_fail: false,
993     };
994
995     let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false);
996
997     let st = ConsoleTestState {
998         log_out: None,
999         total: 0,
1000         passed: 0,
1001         failed: 0,
1002         ignored: 0,
1003         allowed_fail: 0,
1004         filtered_out: 0,
1005         measured: 0,
1006         metrics: MetricMap::new(),
1007         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
1008         options: Options::new(),
1009         not_failures: Vec::new(),
1010     };
1011
1012     out.write_failures(&st).unwrap();
1013     let s = match out.output_location() {
1014         &Raw(ref m) => String::from_utf8_lossy(&m[..]),
1015         &Pretty(_) => unreachable!(),
1016     };
1017
1018     let apos = s.find("a").unwrap();
1019     let bpos = s.find("b").unwrap();
1020     assert!(apos < bpos);
1021 }
1022
1023 fn use_color(opts: &TestOpts) -> bool {
1024     match opts.color {
1025         AutoColor => !opts.nocapture && stdout_isatty(),
1026         AlwaysColor => true,
1027         NeverColor => false,
1028     }
1029 }
1030
1031 #[cfg(any(
1032     target_os = "cloudabi",
1033     target_os = "redox",
1034     all(target_arch = "wasm32", not(target_os = "emscripten")),
1035     all(target_vendor = "fortanix", target_env = "sgx")
1036 ))]
1037 fn stdout_isatty() -> bool {
1038     // FIXME: Implement isatty on Redox and SGX
1039     false
1040 }
1041 #[cfg(unix)]
1042 fn stdout_isatty() -> bool {
1043     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
1044 }
1045 #[cfg(windows)]
1046 fn stdout_isatty() -> bool {
1047     type DWORD = u32;
1048     type BOOL = i32;
1049     type HANDLE = *mut u8;
1050     type LPDWORD = *mut u32;
1051     const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
1052     extern "system" {
1053         fn GetStdHandle(which: DWORD) -> HANDLE;
1054         fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
1055     }
1056     unsafe {
1057         let handle = GetStdHandle(STD_OUTPUT_HANDLE);
1058         let mut out = 0;
1059         GetConsoleMode(handle, &mut out) != 0
1060     }
1061 }
1062
1063 #[derive(Clone)]
1064 pub enum TestEvent {
1065     TeFiltered(Vec<TestDesc>),
1066     TeWait(TestDesc),
1067     TeResult(TestDesc, TestResult, Vec<u8>),
1068     TeTimeout(TestDesc),
1069     TeFilteredOut(usize),
1070 }
1071
1072 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
1073
1074 struct Sink(Arc<Mutex<Vec<u8>>>);
1075 impl Write for Sink {
1076     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1077         Write::write(&mut *self.0.lock().unwrap(), data)
1078     }
1079     fn flush(&mut self) -> io::Result<()> {
1080         Ok(())
1081     }
1082 }
1083
1084 pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
1085 where
1086     F: FnMut(TestEvent) -> io::Result<()>,
1087 {
1088     use std::collections::{self, HashMap};
1089     use std::hash::BuildHasherDefault;
1090     use std::sync::mpsc::RecvTimeoutError;
1091     // Use a deterministic hasher
1092     type TestMap =
1093         HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
1094
1095     let tests_len = tests.len();
1096
1097     let mut filtered_tests = filter_tests(opts, tests);
1098     if !opts.bench_benchmarks {
1099         filtered_tests = convert_benchmarks_to_tests(filtered_tests);
1100     }
1101
1102     let filtered_tests = {
1103         let mut filtered_tests = filtered_tests;
1104         for test in filtered_tests.iter_mut() {
1105             test.desc.name = test.desc.name.with_padding(test.testfn.padding());
1106         }
1107
1108         filtered_tests
1109     };
1110
1111     let filtered_out = tests_len - filtered_tests.len();
1112     callback(TeFilteredOut(filtered_out))?;
1113
1114     let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
1115
1116     callback(TeFiltered(filtered_descs))?;
1117
1118     let (filtered_tests, filtered_benchs): (Vec<_>, _) =
1119         filtered_tests.into_iter().partition(|e| match e.testfn {
1120             StaticTestFn(_) | DynTestFn(_) => true,
1121             _ => false,
1122         });
1123
1124     let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
1125
1126     let mut remaining = filtered_tests;
1127     remaining.reverse();
1128     let mut pending = 0;
1129
1130     let (tx, rx) = channel::<MonitorMsg>();
1131
1132     let mut running_tests: TestMap = HashMap::default();
1133
1134     fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> {
1135         let now = Instant::now();
1136         let timed_out = running_tests
1137             .iter()
1138             .filter_map(|(desc, timeout)| {
1139                 if &now >= timeout {
1140                     Some(desc.clone())
1141                 } else {
1142                     None
1143                 }
1144             })
1145             .collect();
1146         for test in &timed_out {
1147             running_tests.remove(test);
1148         }
1149         timed_out
1150     };
1151
1152     fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
1153         running_tests.values().min().map(|next_timeout| {
1154             let now = Instant::now();
1155             if *next_timeout >= now {
1156                 *next_timeout - now
1157             } else {
1158                 Duration::new(0, 0)
1159             }
1160         })
1161     };
1162
1163     if concurrency == 1 {
1164         while !remaining.is_empty() {
1165             let test = remaining.pop().unwrap();
1166             callback(TeWait(test.desc.clone()))?;
1167             run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No);
1168             let (test, result, stdout) = rx.recv().unwrap();
1169             callback(TeResult(test, result, stdout))?;
1170         }
1171     } else {
1172         while pending > 0 || !remaining.is_empty() {
1173             while pending < concurrency && !remaining.is_empty() {
1174                 let test = remaining.pop().unwrap();
1175                 let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
1176                 running_tests.insert(test.desc.clone(), timeout);
1177                 callback(TeWait(test.desc.clone()))?; //here no pad
1178                 run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes);
1179                 pending += 1;
1180             }
1181
1182             let mut res;
1183             loop {
1184                 if let Some(timeout) = calc_timeout(&running_tests) {
1185                     res = rx.recv_timeout(timeout);
1186                     for test in get_timed_out_tests(&mut running_tests) {
1187                         callback(TeTimeout(test))?;
1188                     }
1189                     if res != Err(RecvTimeoutError::Timeout) {
1190                         break;
1191                     }
1192                 } else {
1193                     res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
1194                     break;
1195                 }
1196             }
1197
1198             let (desc, result, stdout) = res.unwrap();
1199             running_tests.remove(&desc);
1200
1201             callback(TeResult(desc, result, stdout))?;
1202             pending -= 1;
1203         }
1204     }
1205
1206     if opts.bench_benchmarks {
1207         // All benchmarks run at the end, in serial.
1208         for b in filtered_benchs {
1209             callback(TeWait(b.desc.clone()))?;
1210             run_test(opts, false, b, tx.clone(), Concurrent::No);
1211             let (test, result, stdout) = rx.recv().unwrap();
1212             callback(TeResult(test, result, stdout))?;
1213         }
1214     }
1215     Ok(())
1216 }
1217
1218 #[allow(deprecated)]
1219 fn get_concurrency() -> usize {
1220     return match env::var("RUST_TEST_THREADS") {
1221         Ok(s) => {
1222             let opt_n: Option<usize> = s.parse().ok();
1223             match opt_n {
1224                 Some(n) if n > 0 => n,
1225                 _ => panic!(
1226                     "RUST_TEST_THREADS is `{}`, should be a positive integer.",
1227                     s
1228                 ),
1229             }
1230         }
1231         Err(..) => num_cpus(),
1232     };
1233
1234     #[cfg(windows)]
1235     #[allow(nonstandard_style)]
1236     fn num_cpus() -> usize {
1237         #[repr(C)]
1238         struct SYSTEM_INFO {
1239             wProcessorArchitecture: u16,
1240             wReserved: u16,
1241             dwPageSize: u32,
1242             lpMinimumApplicationAddress: *mut u8,
1243             lpMaximumApplicationAddress: *mut u8,
1244             dwActiveProcessorMask: *mut u8,
1245             dwNumberOfProcessors: u32,
1246             dwProcessorType: u32,
1247             dwAllocationGranularity: u32,
1248             wProcessorLevel: u16,
1249             wProcessorRevision: u16,
1250         }
1251         extern "system" {
1252             fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
1253         }
1254         unsafe {
1255             let mut sysinfo = std::mem::zeroed();
1256             GetSystemInfo(&mut sysinfo);
1257             sysinfo.dwNumberOfProcessors as usize
1258         }
1259     }
1260
1261     #[cfg(target_os = "redox")]
1262     fn num_cpus() -> usize {
1263         // FIXME: Implement num_cpus on Redox
1264         1
1265     }
1266
1267     #[cfg(any(
1268         all(target_arch = "wasm32", not(target_os = "emscripten")),
1269         all(target_vendor = "fortanix", target_env = "sgx")
1270     ))]
1271     fn num_cpus() -> usize {
1272         1
1273     }
1274
1275     #[cfg(any(
1276         target_os = "android",
1277         target_os = "cloudabi",
1278         target_os = "emscripten",
1279         target_os = "fuchsia",
1280         target_os = "ios",
1281         target_os = "linux",
1282         target_os = "macos",
1283         target_os = "solaris"
1284     ))]
1285     fn num_cpus() -> usize {
1286         unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
1287     }
1288
1289     #[cfg(any(
1290         target_os = "freebsd",
1291         target_os = "dragonfly",
1292         target_os = "bitrig",
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 }