]> git.lizzy.rs Git - rust.git/blob - src/libtest/lib.rs
fix line length
[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 = "bitrig",
1294         target_os = "netbsd"
1295     ))]
1296     fn num_cpus() -> usize {
1297         use std::ptr;
1298
1299         let mut cpus: libc::c_uint = 0;
1300         let mut cpus_size = std::mem::size_of_val(&cpus);
1301
1302         unsafe {
1303             cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
1304         }
1305         if cpus < 1 {
1306             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1307             unsafe {
1308                 libc::sysctl(
1309                     mib.as_mut_ptr(),
1310                     2,
1311                     &mut cpus as *mut _ as *mut _,
1312                     &mut cpus_size as *mut _ as *mut _,
1313                     ptr::null_mut(),
1314                     0,
1315                 );
1316             }
1317             if cpus < 1 {
1318                 cpus = 1;
1319             }
1320         }
1321         cpus as usize
1322     }
1323
1324     #[cfg(target_os = "openbsd")]
1325     fn num_cpus() -> usize {
1326         use std::ptr;
1327
1328         let mut cpus: libc::c_uint = 0;
1329         let mut cpus_size = std::mem::size_of_val(&cpus);
1330         let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1331
1332         unsafe {
1333             libc::sysctl(
1334                 mib.as_mut_ptr(),
1335                 2,
1336                 &mut cpus as *mut _ as *mut _,
1337                 &mut cpus_size as *mut _ as *mut _,
1338                 ptr::null_mut(),
1339                 0,
1340             );
1341         }
1342         if cpus < 1 {
1343             cpus = 1;
1344         }
1345         cpus as usize
1346     }
1347
1348     #[cfg(target_os = "haiku")]
1349     fn num_cpus() -> usize {
1350         // FIXME: implement
1351         1
1352     }
1353
1354     #[cfg(target_os = "l4re")]
1355     fn num_cpus() -> usize {
1356         // FIXME: implement
1357         1
1358     }
1359 }
1360
1361 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1362     let mut filtered = tests;
1363     let matches_filter = |test: &TestDescAndFn, filter: &str| {
1364         let test_name = test.desc.name.as_slice();
1365
1366         match opts.filter_exact {
1367             true => test_name == filter,
1368             false => test_name.contains(filter),
1369         }
1370     };
1371
1372     // Remove tests that don't match the test filter
1373     if let Some(ref filter) = opts.filter {
1374         filtered.retain(|test| matches_filter(test, filter));
1375     }
1376
1377     // Skip tests that match any of the skip filters
1378     filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
1379
1380     // Excludes #[should_panic] tests
1381     if opts.exclude_should_panic {
1382         filtered.retain(|test| test.desc.should_panic == ShouldPanic::No);
1383     }
1384
1385     // maybe unignore tests
1386     match opts.run_ignored {
1387         RunIgnored::Yes => {
1388             filtered
1389                 .iter_mut()
1390                 .for_each(|test| test.desc.ignore = false);
1391         }
1392         RunIgnored::Only => {
1393             filtered.retain(|test| test.desc.ignore);
1394             filtered
1395                 .iter_mut()
1396                 .for_each(|test| test.desc.ignore = false);
1397         }
1398         RunIgnored::No => {}
1399     }
1400
1401     // Sort the tests alphabetically
1402     filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
1403
1404     filtered
1405 }
1406
1407 pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1408     // convert benchmarks to tests, if we're not benchmarking them
1409     tests
1410         .into_iter()
1411         .map(|x| {
1412             let testfn = match x.testfn {
1413                 DynBenchFn(bench) => DynTestFn(Box::new(move || {
1414                     bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b)))
1415                 })),
1416                 StaticBenchFn(benchfn) => DynTestFn(Box::new(move || {
1417                     bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
1418                 })),
1419                 f => f,
1420             };
1421             TestDescAndFn {
1422                 desc: x.desc,
1423                 testfn,
1424             }
1425         })
1426         .collect()
1427 }
1428
1429 pub fn run_test(
1430     opts: &TestOpts,
1431     force_ignore: bool,
1432     test: TestDescAndFn,
1433     monitor_ch: Sender<MonitorMsg>,
1434     concurrency: Concurrent,
1435 ) {
1436     let TestDescAndFn { desc, testfn } = test;
1437
1438     let ignore_because_panic_abort = cfg!(target_arch = "wasm32")
1439         && !cfg!(target_os = "emscripten")
1440         && desc.should_panic != ShouldPanic::No;
1441
1442     if force_ignore || desc.ignore || ignore_because_panic_abort {
1443         monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap();
1444         return;
1445     }
1446
1447     fn run_test_inner(
1448         desc: TestDesc,
1449         monitor_ch: Sender<MonitorMsg>,
1450         nocapture: bool,
1451         testfn: Box<dyn FnBox() + Send>,
1452         concurrency: Concurrent,
1453     ) {
1454         // Buffer for capturing standard I/O
1455         let data = Arc::new(Mutex::new(Vec::new()));
1456         let data2 = data.clone();
1457
1458         let name = desc.name.clone();
1459         let runtest = move || {
1460             let oldio = if !nocapture {
1461                 Some((
1462                     io::set_print(Some(Box::new(Sink(data2.clone())))),
1463                     io::set_panic(Some(Box::new(Sink(data2)))),
1464                 ))
1465             } else {
1466                 None
1467             };
1468
1469             let result = catch_unwind(AssertUnwindSafe(testfn));
1470
1471             if let Some((printio, panicio)) = oldio {
1472                 io::set_print(printio);
1473                 io::set_panic(panicio);
1474             };
1475
1476             let test_result = calc_result(&desc, result);
1477             let stdout = data.lock().unwrap().to_vec();
1478             monitor_ch
1479                 .send((desc.clone(), test_result, stdout))
1480                 .unwrap();
1481         };
1482
1483         // If the platform is single-threaded we're just going to run
1484         // the test synchronously, regardless of the concurrency
1485         // level.
1486         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
1487         if concurrency == Concurrent::Yes && supports_threads {
1488             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
1489             cfg.spawn(runtest).unwrap();
1490         } else {
1491             runtest();
1492         }
1493     }
1494
1495     match testfn {
1496         DynBenchFn(bencher) => {
1497             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1498                 bencher.run(harness)
1499             });
1500         }
1501         StaticBenchFn(benchfn) => {
1502             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1503                 (benchfn.clone())(harness)
1504             });
1505         }
1506         DynTestFn(f) => {
1507             let cb = move || __rust_begin_short_backtrace(f);
1508             run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency)
1509         }
1510         StaticTestFn(f) => run_test_inner(
1511             desc,
1512             monitor_ch,
1513             opts.nocapture,
1514             Box::new(move || __rust_begin_short_backtrace(f)),
1515             concurrency,
1516         ),
1517     }
1518 }
1519
1520 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
1521 #[inline(never)]
1522 fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
1523     f()
1524 }
1525
1526 fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) -> TestResult {
1527     match (&desc.should_panic, task_result) {
1528         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
1529         (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
1530             if err
1531                 .downcast_ref::<String>()
1532                 .map(|e| &**e)
1533                 .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
1534                 .map(|e| e.contains(msg))
1535                 .unwrap_or(false)
1536             {
1537                 TrOk
1538             } else {
1539                 if desc.allow_fail {
1540                     TrAllowedFail
1541                 } else {
1542                     TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
1543                 }
1544             }
1545         }
1546         _ if desc.allow_fail => TrAllowedFail,
1547         _ => TrFailed,
1548     }
1549 }
1550
1551 #[derive(Clone, PartialEq)]
1552 pub struct MetricMap(BTreeMap<String, Metric>);
1553
1554 impl MetricMap {
1555     pub fn new() -> MetricMap {
1556         MetricMap(BTreeMap::new())
1557     }
1558
1559     /// Insert a named `value` (+/- `noise`) metric into the map. The value
1560     /// must be non-negative. The `noise` indicates the uncertainty of the
1561     /// metric, which doubles as the "noise range" of acceptable
1562     /// pairwise-regressions on this named value, when comparing from one
1563     /// metric to the next using `compare_to_old`.
1564     ///
1565     /// If `noise` is positive, then it means this metric is of a value
1566     /// you want to see grow smaller, so a change larger than `noise` in the
1567     /// positive direction represents a regression.
1568     ///
1569     /// If `noise` is negative, then it means this metric is of a value
1570     /// you want to see grow larger, so a change larger than `noise` in the
1571     /// negative direction represents a regression.
1572     pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
1573         let m = Metric { value, noise };
1574         self.0.insert(name.to_owned(), m);
1575     }
1576
1577     pub fn fmt_metrics(&self) -> String {
1578         let v = self
1579             .0
1580             .iter()
1581             .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
1582             .collect::<Vec<_>>();
1583         v.join(", ")
1584     }
1585 }
1586
1587 // Benchmarking
1588
1589 pub use std::hint::black_box;
1590
1591 impl Bencher {
1592     /// Callback for benchmark functions to run in their body.
1593     pub fn iter<T, F>(&mut self, mut inner: F)
1594     where
1595         F: FnMut() -> T,
1596     {
1597         if self.mode == BenchMode::Single {
1598             ns_iter_inner(&mut inner, 1);
1599             return;
1600         }
1601
1602         self.summary = Some(iter(&mut inner));
1603     }
1604
1605     pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
1606     where
1607         F: FnMut(&mut Bencher),
1608     {
1609         f(self);
1610         return self.summary;
1611     }
1612 }
1613
1614 fn ns_from_dur(dur: Duration) -> u64 {
1615     dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64)
1616 }
1617
1618 fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
1619 where
1620     F: FnMut() -> T,
1621 {
1622     let start = Instant::now();
1623     for _ in 0..k {
1624         black_box(inner());
1625     }
1626     return ns_from_dur(start.elapsed());
1627 }
1628
1629 pub fn iter<T, F>(inner: &mut F) -> stats::Summary
1630 where
1631     F: FnMut() -> T,
1632 {
1633     // Initial bench run to get ballpark figure.
1634     let ns_single = ns_iter_inner(inner, 1);
1635
1636     // Try to estimate iter count for 1ms falling back to 1m
1637     // iterations if first run took < 1ns.
1638     let ns_target_total = 1_000_000; // 1ms
1639     let mut n = ns_target_total / cmp::max(1, ns_single);
1640
1641     // if the first run took more than 1ms we don't want to just
1642     // be left doing 0 iterations on every loop. The unfortunate
1643     // side effect of not being able to do as many runs is
1644     // automatically handled by the statistical analysis below
1645     // (i.e., larger error bars).
1646     n = cmp::max(1, n);
1647
1648     let mut total_run = Duration::new(0, 0);
1649     let samples: &mut [f64] = &mut [0.0_f64; 50];
1650     loop {
1651         let loop_start = Instant::now();
1652
1653         for p in &mut *samples {
1654             *p = ns_iter_inner(inner, n) as f64 / n as f64;
1655         }
1656
1657         stats::winsorize(samples, 5.0);
1658         let summ = stats::Summary::new(samples);
1659
1660         for p in &mut *samples {
1661             let ns = ns_iter_inner(inner, 5 * n);
1662             *p = ns as f64 / (5 * n) as f64;
1663         }
1664
1665         stats::winsorize(samples, 5.0);
1666         let summ5 = stats::Summary::new(samples);
1667
1668         let loop_run = loop_start.elapsed();
1669
1670         // If we've run for 100ms and seem to have converged to a
1671         // stable median.
1672         if loop_run > Duration::from_millis(100)
1673             && summ.median_abs_dev_pct < 1.0
1674             && summ.median - summ5.median < summ5.median_abs_dev
1675         {
1676             return summ5;
1677         }
1678
1679         total_run = total_run + loop_run;
1680         // Longest we ever run for is 3s.
1681         if total_run > Duration::from_secs(3) {
1682             return summ5;
1683         }
1684
1685         // If we overflow here just return the results so far. We check a
1686         // multiplier of 10 because we're about to multiply by 2 and the
1687         // next iteration of the loop will also multiply by 5 (to calculate
1688         // the summ5 result)
1689         n = match n.checked_mul(10) {
1690             Some(_) => n * 2,
1691             None => {
1692                 return summ5;
1693             }
1694         };
1695     }
1696 }
1697
1698 pub mod bench {
1699     use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult};
1700     use crate::stats;
1701     use std::cmp;
1702     use std::io;
1703     use std::panic::{catch_unwind, AssertUnwindSafe};
1704     use std::sync::{Arc, Mutex};
1705
1706     pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F)
1707     where
1708         F: FnMut(&mut Bencher),
1709     {
1710         let mut bs = Bencher {
1711             mode: BenchMode::Auto,
1712             summary: None,
1713             bytes: 0,
1714         };
1715
1716         let data = Arc::new(Mutex::new(Vec::new()));
1717         let data2 = data.clone();
1718
1719         let oldio = if !nocapture {
1720             Some((
1721                 io::set_print(Some(Box::new(Sink(data2.clone())))),
1722                 io::set_panic(Some(Box::new(Sink(data2)))),
1723             ))
1724         } else {
1725             None
1726         };
1727
1728         let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
1729
1730         if let Some((printio, panicio)) = oldio {
1731             io::set_print(printio);
1732             io::set_panic(panicio);
1733         };
1734
1735         let test_result = match result {
1736             //bs.bench(f) {
1737             Ok(Some(ns_iter_summ)) => {
1738                 let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
1739                 let mb_s = bs.bytes * 1000 / ns_iter;
1740
1741                 let bs = BenchSamples {
1742                     ns_iter_summ,
1743                     mb_s: mb_s as usize,
1744                 };
1745                 TestResult::TrBench(bs)
1746             }
1747             Ok(None) => {
1748                 // iter not called, so no data.
1749                 // FIXME: error in this case?
1750                 let samples: &mut [f64] = &mut [0.0_f64; 1];
1751                 let bs = BenchSamples {
1752                     ns_iter_summ: stats::Summary::new(samples),
1753                     mb_s: 0,
1754                 };
1755                 TestResult::TrBench(bs)
1756             }
1757             Err(_) => TestResult::TrFailed,
1758         };
1759
1760         let stdout = data.lock().unwrap().to_vec();
1761         monitor_ch.send((desc, test_result, stdout)).unwrap();
1762     }
1763
1764     pub fn run_once<F>(f: F)
1765     where
1766         F: FnMut(&mut Bencher),
1767     {
1768         let mut bs = Bencher {
1769             mode: BenchMode::Single,
1770             summary: None,
1771             bytes: 0,
1772         };
1773         bs.bench(f);
1774     }
1775 }
1776
1777 #[cfg(test)]
1778 mod tests {
1779     use crate::bench;
1780     use crate::test::{
1781         filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
1782         ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
1783         TrIgnored, TrOk,
1784     };
1785     use crate::Bencher;
1786     use crate::Concurrent;
1787     use std::sync::mpsc::channel;
1788
1789     fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
1790         vec![
1791             TestDescAndFn {
1792                 desc: TestDesc {
1793                     name: StaticTestName("1"),
1794                     ignore: true,
1795                     should_panic: ShouldPanic::No,
1796                     allow_fail: false,
1797                 },
1798                 testfn: DynTestFn(Box::new(move || {})),
1799             },
1800             TestDescAndFn {
1801                 desc: TestDesc {
1802                     name: StaticTestName("2"),
1803                     ignore: false,
1804                     should_panic: ShouldPanic::No,
1805                     allow_fail: false,
1806                 },
1807                 testfn: DynTestFn(Box::new(move || {})),
1808             },
1809         ]
1810     }
1811
1812     #[test]
1813     pub fn do_not_run_ignored_tests() {
1814         fn f() {
1815             panic!();
1816         }
1817         let desc = TestDescAndFn {
1818             desc: TestDesc {
1819                 name: StaticTestName("whatever"),
1820                 ignore: true,
1821                 should_panic: ShouldPanic::No,
1822                 allow_fail: false,
1823             },
1824             testfn: DynTestFn(Box::new(f)),
1825         };
1826         let (tx, rx) = channel();
1827         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1828         let (_, res, _) = rx.recv().unwrap();
1829         assert!(res != TrOk);
1830     }
1831
1832     #[test]
1833     pub fn ignored_tests_result_in_ignored() {
1834         fn f() {}
1835         let desc = TestDescAndFn {
1836             desc: TestDesc {
1837                 name: StaticTestName("whatever"),
1838                 ignore: true,
1839                 should_panic: ShouldPanic::No,
1840                 allow_fail: false,
1841             },
1842             testfn: DynTestFn(Box::new(f)),
1843         };
1844         let (tx, rx) = channel();
1845         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1846         let (_, res, _) = rx.recv().unwrap();
1847         assert!(res == TrIgnored);
1848     }
1849
1850     #[test]
1851     fn test_should_panic() {
1852         fn f() {
1853             panic!();
1854         }
1855         let desc = TestDescAndFn {
1856             desc: TestDesc {
1857                 name: StaticTestName("whatever"),
1858                 ignore: false,
1859                 should_panic: ShouldPanic::Yes,
1860                 allow_fail: false,
1861             },
1862             testfn: DynTestFn(Box::new(f)),
1863         };
1864         let (tx, rx) = channel();
1865         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1866         let (_, res, _) = rx.recv().unwrap();
1867         assert!(res == TrOk);
1868     }
1869
1870     #[test]
1871     fn test_should_panic_good_message() {
1872         fn f() {
1873             panic!("an error message");
1874         }
1875         let desc = TestDescAndFn {
1876             desc: TestDesc {
1877                 name: StaticTestName("whatever"),
1878                 ignore: false,
1879                 should_panic: ShouldPanic::YesWithMessage("error message"),
1880                 allow_fail: false,
1881             },
1882             testfn: DynTestFn(Box::new(f)),
1883         };
1884         let (tx, rx) = channel();
1885         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1886         let (_, res, _) = rx.recv().unwrap();
1887         assert!(res == TrOk);
1888     }
1889
1890     #[test]
1891     fn test_should_panic_bad_message() {
1892         fn f() {
1893             panic!("an error message");
1894         }
1895         let expected = "foobar";
1896         let failed_msg = "Panic did not include expected string";
1897         let desc = TestDescAndFn {
1898             desc: TestDesc {
1899                 name: StaticTestName("whatever"),
1900                 ignore: false,
1901                 should_panic: ShouldPanic::YesWithMessage(expected),
1902                 allow_fail: false,
1903             },
1904             testfn: DynTestFn(Box::new(f)),
1905         };
1906         let (tx, rx) = channel();
1907         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1908         let (_, res, _) = rx.recv().unwrap();
1909         assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
1910     }
1911
1912     #[test]
1913     fn test_should_panic_but_succeeds() {
1914         fn f() {}
1915         let desc = TestDescAndFn {
1916             desc: TestDesc {
1917                 name: StaticTestName("whatever"),
1918                 ignore: false,
1919                 should_panic: ShouldPanic::Yes,
1920                 allow_fail: false,
1921             },
1922             testfn: DynTestFn(Box::new(f)),
1923         };
1924         let (tx, rx) = channel();
1925         run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
1926         let (_, res, _) = rx.recv().unwrap();
1927         assert!(res == TrFailed);
1928     }
1929
1930     #[test]
1931     fn parse_ignored_flag() {
1932         let args = vec![
1933             "progname".to_string(),
1934             "filter".to_string(),
1935             "--ignored".to_string(),
1936         ];
1937         let opts = parse_opts(&args).unwrap().unwrap();
1938         assert_eq!(opts.run_ignored, RunIgnored::Only);
1939     }
1940
1941     #[test]
1942     fn parse_include_ignored_flag() {
1943         let args = vec![
1944             "progname".to_string(),
1945             "filter".to_string(),
1946             "-Zunstable-options".to_string(),
1947             "--include-ignored".to_string(),
1948         ];
1949         let opts = parse_opts(&args).unwrap().unwrap();
1950         assert_eq!(opts.run_ignored, RunIgnored::Yes);
1951     }
1952
1953     #[test]
1954     pub fn filter_for_ignored_option() {
1955         // When we run ignored tests the test filter should filter out all the
1956         // unignored tests and flip the ignore flag on the rest to false
1957
1958         let mut opts = TestOpts::new();
1959         opts.run_tests = true;
1960         opts.run_ignored = RunIgnored::Only;
1961
1962         let tests = one_ignored_one_unignored_test();
1963         let filtered = filter_tests(&opts, tests);
1964
1965         assert_eq!(filtered.len(), 1);
1966         assert_eq!(filtered[0].desc.name.to_string(), "1");
1967         assert!(!filtered[0].desc.ignore);
1968     }
1969
1970     #[test]
1971     pub fn run_include_ignored_option() {
1972         // When we "--include-ignored" tests, the ignore flag should be set to false on
1973         // all tests and no test filtered out
1974
1975         let mut opts = TestOpts::new();
1976         opts.run_tests = true;
1977         opts.run_ignored = RunIgnored::Yes;
1978
1979         let tests = one_ignored_one_unignored_test();
1980         let filtered = filter_tests(&opts, tests);
1981
1982         assert_eq!(filtered.len(), 2);
1983         assert!(!filtered[0].desc.ignore);
1984         assert!(!filtered[1].desc.ignore);
1985     }
1986
1987     #[test]
1988     pub fn exclude_should_panic_option() {
1989         let mut opts = TestOpts::new();
1990         opts.run_tests = true;
1991         opts.exclude_should_panic = true;
1992
1993         let mut tests = one_ignored_one_unignored_test();
1994         tests.push(TestDescAndFn {
1995             desc: TestDesc {
1996                 name: StaticTestName("3"),
1997                 ignore: false,
1998                 should_panic: ShouldPanic::Yes,
1999                 allow_fail: false,
2000             },
2001             testfn: DynTestFn(Box::new(move || {})),
2002         });
2003
2004         let filtered = filter_tests(&opts, tests);
2005
2006         assert_eq!(filtered.len(), 2);
2007         assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
2008     }
2009
2010     #[test]
2011     pub fn exact_filter_match() {
2012         fn tests() -> Vec<TestDescAndFn> {
2013             vec!["base", "base::test", "base::test1", "base::test2"]
2014                 .into_iter()
2015                 .map(|name| TestDescAndFn {
2016                     desc: TestDesc {
2017                         name: StaticTestName(name),
2018                         ignore: false,
2019                         should_panic: ShouldPanic::No,
2020                         allow_fail: false,
2021                     },
2022                     testfn: DynTestFn(Box::new(move || {})),
2023                 })
2024                 .collect()
2025         }
2026
2027         let substr = filter_tests(
2028             &TestOpts {
2029                 filter: Some("base".into()),
2030                 ..TestOpts::new()
2031             },
2032             tests(),
2033         );
2034         assert_eq!(substr.len(), 4);
2035
2036         let substr = filter_tests(
2037             &TestOpts {
2038                 filter: Some("bas".into()),
2039                 ..TestOpts::new()
2040             },
2041             tests(),
2042         );
2043         assert_eq!(substr.len(), 4);
2044
2045         let substr = filter_tests(
2046             &TestOpts {
2047                 filter: Some("::test".into()),
2048                 ..TestOpts::new()
2049             },
2050             tests(),
2051         );
2052         assert_eq!(substr.len(), 3);
2053
2054         let substr = filter_tests(
2055             &TestOpts {
2056                 filter: Some("base::test".into()),
2057                 ..TestOpts::new()
2058             },
2059             tests(),
2060         );
2061         assert_eq!(substr.len(), 3);
2062
2063         let exact = filter_tests(
2064             &TestOpts {
2065                 filter: Some("base".into()),
2066                 filter_exact: true,
2067                 ..TestOpts::new()
2068             },
2069             tests(),
2070         );
2071         assert_eq!(exact.len(), 1);
2072
2073         let exact = filter_tests(
2074             &TestOpts {
2075                 filter: Some("bas".into()),
2076                 filter_exact: true,
2077                 ..TestOpts::new()
2078             },
2079             tests(),
2080         );
2081         assert_eq!(exact.len(), 0);
2082
2083         let exact = filter_tests(
2084             &TestOpts {
2085                 filter: Some("::test".into()),
2086                 filter_exact: true,
2087                 ..TestOpts::new()
2088             },
2089             tests(),
2090         );
2091         assert_eq!(exact.len(), 0);
2092
2093         let exact = filter_tests(
2094             &TestOpts {
2095                 filter: Some("base::test".into()),
2096                 filter_exact: true,
2097                 ..TestOpts::new()
2098             },
2099             tests(),
2100         );
2101         assert_eq!(exact.len(), 1);
2102     }
2103
2104     #[test]
2105     pub fn sort_tests() {
2106         let mut opts = TestOpts::new();
2107         opts.run_tests = true;
2108
2109         let names = vec![
2110             "sha1::test".to_string(),
2111             "isize::test_to_str".to_string(),
2112             "isize::test_pow".to_string(),
2113             "test::do_not_run_ignored_tests".to_string(),
2114             "test::ignored_tests_result_in_ignored".to_string(),
2115             "test::first_free_arg_should_be_a_filter".to_string(),
2116             "test::parse_ignored_flag".to_string(),
2117             "test::parse_include_ignored_flag".to_string(),
2118             "test::filter_for_ignored_option".to_string(),
2119             "test::run_include_ignored_option".to_string(),
2120             "test::sort_tests".to_string(),
2121         ];
2122         let tests = {
2123             fn testfn() {}
2124             let mut tests = Vec::new();
2125             for name in &names {
2126                 let test = TestDescAndFn {
2127                     desc: TestDesc {
2128                         name: DynTestName((*name).clone()),
2129                         ignore: false,
2130                         should_panic: ShouldPanic::No,
2131                         allow_fail: false,
2132                     },
2133                     testfn: DynTestFn(Box::new(testfn)),
2134                 };
2135                 tests.push(test);
2136             }
2137             tests
2138         };
2139         let filtered = filter_tests(&opts, tests);
2140
2141         let expected = vec![
2142             "isize::test_pow".to_string(),
2143             "isize::test_to_str".to_string(),
2144             "sha1::test".to_string(),
2145             "test::do_not_run_ignored_tests".to_string(),
2146             "test::filter_for_ignored_option".to_string(),
2147             "test::first_free_arg_should_be_a_filter".to_string(),
2148             "test::ignored_tests_result_in_ignored".to_string(),
2149             "test::parse_ignored_flag".to_string(),
2150             "test::parse_include_ignored_flag".to_string(),
2151             "test::run_include_ignored_option".to_string(),
2152             "test::sort_tests".to_string(),
2153         ];
2154
2155         for (a, b) in expected.iter().zip(filtered) {
2156             assert!(*a == b.desc.name.to_string());
2157         }
2158     }
2159
2160     #[test]
2161     pub fn test_metricmap_compare() {
2162         let mut m1 = MetricMap::new();
2163         let mut m2 = MetricMap::new();
2164         m1.insert_metric("in-both-noise", 1000.0, 200.0);
2165         m2.insert_metric("in-both-noise", 1100.0, 200.0);
2166
2167         m1.insert_metric("in-first-noise", 1000.0, 2.0);
2168         m2.insert_metric("in-second-noise", 1000.0, 2.0);
2169
2170         m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
2171         m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
2172
2173         m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
2174         m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
2175
2176         m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
2177         m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
2178
2179         m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
2180         m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
2181     }
2182
2183     #[test]
2184     pub fn test_bench_once_no_iter() {
2185         fn f(_: &mut Bencher) {}
2186         bench::run_once(f);
2187     }
2188
2189     #[test]
2190     pub fn test_bench_once_iter() {
2191         fn f(b: &mut Bencher) {
2192             b.iter(|| {})
2193         }
2194         bench::run_once(f);
2195     }
2196
2197     #[test]
2198     pub fn test_bench_no_iter() {
2199         fn f(_: &mut Bencher) {}
2200
2201         let (tx, rx) = channel();
2202
2203         let desc = TestDesc {
2204             name: StaticTestName("f"),
2205             ignore: false,
2206             should_panic: ShouldPanic::No,
2207             allow_fail: false,
2208         };
2209
2210         crate::bench::benchmark(desc, tx, true, f);
2211         rx.recv().unwrap();
2212     }
2213
2214     #[test]
2215     pub fn test_bench_iter() {
2216         fn f(b: &mut Bencher) {
2217             b.iter(|| {})
2218         }
2219
2220         let (tx, rx) = channel();
2221
2222         let desc = TestDesc {
2223             name: StaticTestName("f"),
2224             ignore: false,
2225             should_panic: ShouldPanic::No,
2226             allow_fail: false,
2227         };
2228
2229         crate::bench::benchmark(desc, tx, true, f);
2230         rx.recv().unwrap();
2231     }
2232 }