]> git.lizzy.rs Git - rust.git/blob - src/libtest/lib.rs
Ensure `record_layout_for_printing()` is inlined.
[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 run_ignored: RunIgnored,
370     pub run_tests: bool,
371     pub bench_benchmarks: bool,
372     pub logfile: Option<PathBuf>,
373     pub nocapture: bool,
374     pub color: ColorConfig,
375     pub format: OutputFormat,
376     pub test_threads: Option<usize>,
377     pub skip: Vec<String>,
378     pub options: Options,
379 }
380
381 impl TestOpts {
382     #[cfg(test)]
383     fn new() -> TestOpts {
384         TestOpts {
385             list: false,
386             filter: None,
387             filter_exact: false,
388             run_ignored: RunIgnored::No,
389             run_tests: false,
390             bench_benchmarks: false,
391             logfile: None,
392             nocapture: false,
393             color: AutoColor,
394             format: OutputFormat::Pretty,
395             test_threads: None,
396             skip: vec![],
397             options: Options::new(),
398         }
399     }
400 }
401
402 /// Result of parsing the options.
403 pub type OptRes = Result<TestOpts, String>;
404
405 fn optgroups() -> getopts::Options {
406     let mut opts = getopts::Options::new();
407     opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
408         .optflag("", "ignored", "Run only ignored tests")
409         .optflag("", "test", "Run tests and not benchmarks")
410         .optflag("", "bench", "Run benchmarks instead of tests")
411         .optflag("", "list", "List all tests and benchmarks")
412         .optflag("h", "help", "Display this message (longer with --help)")
413         .optopt(
414             "",
415             "logfile",
416             "Write logs to the specified file instead \
417              of stdout",
418             "PATH",
419         )
420         .optflag(
421             "",
422             "nocapture",
423             "don't capture stdout/stderr of each \
424              task, allow printing directly",
425         )
426         .optopt(
427             "",
428             "test-threads",
429             "Number of threads used for running tests \
430              in parallel",
431             "n_threads",
432         )
433         .optmulti(
434             "",
435             "skip",
436             "Skip tests whose names contain FILTER (this flag can \
437              be used multiple times)",
438             "FILTER",
439         )
440         .optflag(
441             "q",
442             "quiet",
443             "Display one character per test instead of one line. \
444              Alias to --format=terse",
445         )
446         .optflag(
447             "",
448             "exact",
449             "Exactly match filters rather than by substring",
450         )
451         .optopt(
452             "",
453             "color",
454             "Configure coloring of output:
455             auto   = colorize if stdout is a tty and tests are run on serially (default);
456             always = always colorize output;
457             never  = never colorize output;",
458             "auto|always|never",
459         )
460         .optopt(
461             "",
462             "format",
463             "Configure formatting of output:
464             pretty = Print verbose output;
465             terse  = Display one character per test;
466             json   = Output a json document",
467             "pretty|terse|json",
468         )
469         .optopt(
470             "Z",
471             "",
472             "Enable nightly-only flags:
473             unstable-options = Allow use of experimental features",
474             "unstable-options",
475         );
476     return opts;
477 }
478
479 fn usage(binary: &str, options: &getopts::Options) {
480     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
481     println!(
482         r#"{usage}
483
484 The FILTER string is tested against the name of all tests, and only those
485 tests whose names contain the filter are run.
486
487 By default, all tests are run in parallel. This can be altered with the
488 --test-threads flag or the RUST_TEST_THREADS environment variable when running
489 tests (set it to 1).
490
491 All tests have their standard output and standard error captured by default.
492 This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
493 environment variable to a value other than "0". Logging is not captured by default.
494
495 Test Attributes:
496
497     #[test]        - Indicates a function is a test to be run. This function
498                      takes no arguments.
499     #[bench]       - Indicates a function is a benchmark to be run. This
500                      function takes one argument (test::Bencher).
501     #[should_panic] - This function (also labeled with #[test]) will only pass if
502                      the code causes a panic (an assertion failure or panic!)
503                      A message may be provided, which the failure string must
504                      contain: #[should_panic(expected = "foo")].
505     #[ignore]      - When applied to a function which is already attributed as a
506                      test, then the test runner will ignore these tests during
507                      normal test runs. Running with --ignored or --include-ignored will run
508                      these tests."#,
509         usage = options.usage(&message)
510     );
511 }
512
513 // FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
514 fn is_nightly() -> bool {
515     // Whether this is a feature-staged build, i.e., on the beta or stable channel
516     let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
517     // Whether we should enable unstable features for bootstrapping
518     let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
519
520     bootstrap || !disable_unstable_features
521 }
522
523 // Parses command line arguments into test options
524 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
525     let mut allow_unstable = false;
526     let opts = optgroups();
527     let args = args.get(1..).unwrap_or(args);
528     let matches = match opts.parse(args) {
529         Ok(m) => m,
530         Err(f) => return Some(Err(f.to_string())),
531     };
532
533     if let Some(opt) = matches.opt_str("Z") {
534         if !is_nightly() {
535             return Some(Err(
536                 "the option `Z` is only accepted on the nightly compiler".into(),
537             ));
538         }
539
540         match &*opt {
541             "unstable-options" => {
542                 allow_unstable = true;
543             }
544             _ => {
545                 return Some(Err("Unrecognized option to `Z`".into()));
546             }
547         }
548     };
549
550     if matches.opt_present("h") {
551         usage(&args[0], &opts);
552         return None;
553     }
554
555     let filter = if !matches.free.is_empty() {
556         Some(matches.free[0].clone())
557     } else {
558         None
559     };
560
561     let include_ignored = matches.opt_present("include-ignored");
562     if !allow_unstable && include_ignored {
563         return Some(Err(
564             "The \"include-ignored\" flag is only accepted on the nightly compiler".into(),
565         ));
566     }
567
568     let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
569         (true, true) => {
570             return Some(Err(
571                 "the options --include-ignored and --ignored are mutually exclusive".into(),
572             ));
573         }
574         (true, false) => RunIgnored::Yes,
575         (false, true) => RunIgnored::Only,
576         (false, false) => RunIgnored::No,
577     };
578     let quiet = matches.opt_present("quiet");
579     let exact = matches.opt_present("exact");
580     let list = matches.opt_present("list");
581
582     let logfile = matches.opt_str("logfile");
583     let logfile = logfile.map(|s| PathBuf::from(&s));
584
585     let bench_benchmarks = matches.opt_present("bench");
586     let run_tests = !bench_benchmarks || matches.opt_present("test");
587
588     let mut nocapture = matches.opt_present("nocapture");
589     if !nocapture {
590         nocapture = match env::var("RUST_TEST_NOCAPTURE") {
591             Ok(val) => &val != "0",
592             Err(_) => false,
593         };
594     }
595
596     let test_threads = match matches.opt_str("test-threads") {
597         Some(n_str) => match n_str.parse::<usize>() {
598             Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
599             Ok(n) => Some(n),
600             Err(e) => {
601                 return Some(Err(format!(
602                     "argument for --test-threads must be a number > 0 \
603                      (error: {})",
604                     e
605                 )));
606             }
607         },
608         None => None,
609     };
610
611     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
612         Some("auto") | None => AutoColor,
613         Some("always") => AlwaysColor,
614         Some("never") => NeverColor,
615
616         Some(v) => {
617             return Some(Err(format!(
618                 "argument for --color must be auto, always, or never (was \
619                  {})",
620                 v
621             )));
622         }
623     };
624
625     let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
626         None if quiet => OutputFormat::Terse,
627         Some("pretty") | None => OutputFormat::Pretty,
628         Some("terse") => OutputFormat::Terse,
629         Some("json") => {
630             if !allow_unstable {
631                 return Some(Err(
632                     "The \"json\" format is only accepted on the nightly compiler".into(),
633                 ));
634             }
635             OutputFormat::Json
636         }
637
638         Some(v) => {
639             return Some(Err(format!(
640                 "argument for --format must be pretty, terse, or json (was \
641                  {})",
642                 v
643             )));
644         }
645     };
646
647     let test_opts = TestOpts {
648         list,
649         filter,
650         filter_exact: exact,
651         run_ignored,
652         run_tests,
653         bench_benchmarks,
654         logfile,
655         nocapture,
656         color,
657         format,
658         test_threads,
659         skip: matches.opt_strs("skip"),
660         options: Options::new(),
661     };
662
663     Some(Ok(test_opts))
664 }
665
666 #[derive(Clone, PartialEq)]
667 pub struct BenchSamples {
668     ns_iter_summ: stats::Summary,
669     mb_s: usize,
670 }
671
672 #[derive(Clone, PartialEq)]
673 pub enum TestResult {
674     TrOk,
675     TrFailed,
676     TrFailedMsg(String),
677     TrIgnored,
678     TrAllowedFail,
679     TrBench(BenchSamples),
680 }
681
682 unsafe impl Send for TestResult {}
683
684 enum OutputLocation<T> {
685     Pretty(Box<term::StdoutTerminal>),
686     Raw(T),
687 }
688
689 impl<T: Write> Write for OutputLocation<T> {
690     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
691         match *self {
692             Pretty(ref mut term) => term.write(buf),
693             Raw(ref mut stdout) => stdout.write(buf),
694         }
695     }
696
697     fn flush(&mut self) -> io::Result<()> {
698         match *self {
699             Pretty(ref mut term) => term.flush(),
700             Raw(ref mut stdout) => stdout.flush(),
701         }
702     }
703 }
704
705 struct ConsoleTestState {
706     log_out: Option<File>,
707     total: usize,
708     passed: usize,
709     failed: usize,
710     ignored: usize,
711     allowed_fail: usize,
712     filtered_out: usize,
713     measured: usize,
714     metrics: MetricMap,
715     failures: Vec<(TestDesc, Vec<u8>)>,
716     not_failures: Vec<(TestDesc, Vec<u8>)>,
717     options: Options,
718 }
719
720 impl ConsoleTestState {
721     pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
722         let log_out = match opts.logfile {
723             Some(ref path) => Some(File::create(path)?),
724             None => None,
725         };
726
727         Ok(ConsoleTestState {
728             log_out,
729             total: 0,
730             passed: 0,
731             failed: 0,
732             ignored: 0,
733             allowed_fail: 0,
734             filtered_out: 0,
735             measured: 0,
736             metrics: MetricMap::new(),
737             failures: Vec::new(),
738             not_failures: Vec::new(),
739             options: opts.options,
740         })
741     }
742
743     pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
744         let msg = msg.as_ref();
745         match self.log_out {
746             None => Ok(()),
747             Some(ref mut o) => o.write_all(msg.as_bytes()),
748         }
749     }
750
751     pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
752         self.write_log(format!(
753             "{} {}\n",
754             match *result {
755                 TrOk => "ok".to_owned(),
756                 TrFailed => "failed".to_owned(),
757                 TrFailedMsg(ref msg) => format!("failed: {}", msg),
758                 TrIgnored => "ignored".to_owned(),
759                 TrAllowedFail => "failed (allowed)".to_owned(),
760                 TrBench(ref bs) => fmt_bench_samples(bs),
761             },
762             test.name
763         ))
764     }
765
766     fn current_test_count(&self) -> usize {
767         self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
768     }
769 }
770
771 // Format a number with thousands separators
772 fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
773     use std::fmt::Write;
774     let mut output = String::new();
775     let mut trailing = false;
776     for &pow in &[9, 6, 3, 0] {
777         let base = 10_usize.pow(pow);
778         if pow == 0 || trailing || n / base != 0 {
779             if !trailing {
780                 output.write_fmt(format_args!("{}", n / base)).unwrap();
781             } else {
782                 output.write_fmt(format_args!("{:03}", n / base)).unwrap();
783             }
784             if pow != 0 {
785                 output.push(sep);
786             }
787             trailing = true;
788         }
789         n %= base;
790     }
791
792     output
793 }
794
795 pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
796     use std::fmt::Write;
797     let mut output = String::new();
798
799     let median = bs.ns_iter_summ.median as usize;
800     let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
801
802     output
803         .write_fmt(format_args!(
804             "{:>11} ns/iter (+/- {})",
805             fmt_thousands_sep(median, ','),
806             fmt_thousands_sep(deviation, ',')
807         ))
808         .unwrap();
809     if bs.mb_s != 0 {
810         output
811             .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
812             .unwrap();
813     }
814     output
815 }
816
817 // List the tests to console, and optionally to logfile. Filters are honored.
818 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
819     let mut output = match term::stdout() {
820         None => Raw(io::stdout()),
821         Some(t) => Pretty(t),
822     };
823
824     let quiet = opts.format == OutputFormat::Terse;
825     let mut st = ConsoleTestState::new(opts)?;
826
827     let mut ntest = 0;
828     let mut nbench = 0;
829
830     for test in filter_tests(&opts, tests) {
831         use crate::TestFn::*;
832
833         let TestDescAndFn {
834             desc: TestDesc { name, .. },
835             testfn,
836         } = test;
837
838         let fntype = match testfn {
839             StaticTestFn(..) | DynTestFn(..) => {
840                 ntest += 1;
841                 "test"
842             }
843             StaticBenchFn(..) | DynBenchFn(..) => {
844                 nbench += 1;
845                 "benchmark"
846             }
847         };
848
849         writeln!(output, "{}: {}", name, fntype)?;
850         st.write_log(format!("{} {}\n", fntype, name))?;
851     }
852
853     fn plural(count: u32, s: &str) -> String {
854         match count {
855             1 => format!("{} {}", 1, s),
856             n => format!("{} {}s", n, s),
857         }
858     }
859
860     if !quiet {
861         if ntest != 0 || nbench != 0 {
862             writeln!(output, "")?;
863         }
864
865         writeln!(
866             output,
867             "{}, {}",
868             plural(ntest, "test"),
869             plural(nbench, "benchmark")
870         )?;
871     }
872
873     Ok(())
874 }
875
876 // A simple console test runner
877 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
878     fn callback(
879         event: &TestEvent,
880         st: &mut ConsoleTestState,
881         out: &mut dyn OutputFormatter,
882     ) -> io::Result<()> {
883         match (*event).clone() {
884             TeFiltered(ref filtered_tests) => {
885                 st.total = filtered_tests.len();
886                 out.write_run_start(filtered_tests.len())
887             }
888             TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out),
889             TeWait(ref test) => out.write_test_start(test),
890             TeTimeout(ref test) => out.write_timeout(test),
891             TeResult(test, result, stdout) => {
892                 st.write_log_result(&test, &result)?;
893                 out.write_result(&test, &result, &*stdout)?;
894                 match result {
895                     TrOk => {
896                         st.passed += 1;
897                         st.not_failures.push((test, stdout));
898                     }
899                     TrIgnored => st.ignored += 1,
900                     TrAllowedFail => st.allowed_fail += 1,
901                     TrBench(bs) => {
902                         st.metrics.insert_metric(
903                             test.name.as_slice(),
904                             bs.ns_iter_summ.median,
905                             bs.ns_iter_summ.max - bs.ns_iter_summ.min,
906                         );
907                         st.measured += 1
908                     }
909                     TrFailed => {
910                         st.failed += 1;
911                         st.failures.push((test, stdout));
912                     }
913                     TrFailedMsg(msg) => {
914                         st.failed += 1;
915                         let mut stdout = stdout;
916                         stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
917                         st.failures.push((test, stdout));
918                     }
919                 }
920                 Ok(())
921             }
922         }
923     }
924
925     let output = match term::stdout() {
926         None => Raw(io::stdout()),
927         Some(t) => Pretty(t),
928     };
929
930     let max_name_len = tests
931         .iter()
932         .max_by_key(|t| len_if_padded(*t))
933         .map(|t| t.desc.name.as_slice().len())
934         .unwrap_or(0);
935
936     let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
937
938     let mut out: Box<dyn OutputFormatter> = match opts.format {
939         OutputFormat::Pretty => Box::new(PrettyFormatter::new(
940             output,
941             use_color(opts),
942             max_name_len,
943             is_multithreaded,
944         )),
945         OutputFormat::Terse => Box::new(TerseFormatter::new(
946             output,
947             use_color(opts),
948             max_name_len,
949             is_multithreaded,
950         )),
951         OutputFormat::Json => Box::new(JsonFormatter::new(output)),
952     };
953     let mut st = ConsoleTestState::new(opts)?;
954     fn len_if_padded(t: &TestDescAndFn) -> usize {
955         match t.testfn.padding() {
956             PadNone => 0,
957             PadOnRight => t.desc.name.as_slice().len(),
958         }
959     }
960
961     run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?;
962
963     assert!(st.current_test_count() == st.total);
964
965     return out.write_run_finish(&st);
966 }
967
968 #[test]
969 fn should_sort_failures_before_printing_them() {
970     let test_a = TestDesc {
971         name: StaticTestName("a"),
972         ignore: false,
973         should_panic: ShouldPanic::No,
974         allow_fail: false,
975     };
976
977     let test_b = TestDesc {
978         name: StaticTestName("b"),
979         ignore: false,
980         should_panic: ShouldPanic::No,
981         allow_fail: false,
982     };
983
984     let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false);
985
986     let st = ConsoleTestState {
987         log_out: None,
988         total: 0,
989         passed: 0,
990         failed: 0,
991         ignored: 0,
992         allowed_fail: 0,
993         filtered_out: 0,
994         measured: 0,
995         metrics: MetricMap::new(),
996         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
997         options: Options::new(),
998         not_failures: Vec::new(),
999     };
1000
1001     out.write_failures(&st).unwrap();
1002     let s = match out.output_location() {
1003         &Raw(ref m) => String::from_utf8_lossy(&m[..]),
1004         &Pretty(_) => unreachable!(),
1005     };
1006
1007     let apos = s.find("a").unwrap();
1008     let bpos = s.find("b").unwrap();
1009     assert!(apos < bpos);
1010 }
1011
1012 fn use_color(opts: &TestOpts) -> bool {
1013     match opts.color {
1014         AutoColor => !opts.nocapture && stdout_isatty(),
1015         AlwaysColor => true,
1016         NeverColor => false,
1017     }
1018 }
1019
1020 #[cfg(any(
1021     target_os = "cloudabi",
1022     target_os = "redox",
1023     all(target_arch = "wasm32", not(target_os = "emscripten")),
1024     all(target_vendor = "fortanix", target_env = "sgx")
1025 ))]
1026 fn stdout_isatty() -> bool {
1027     // FIXME: Implement isatty on Redox and SGX
1028     false
1029 }
1030 #[cfg(unix)]
1031 fn stdout_isatty() -> bool {
1032     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
1033 }
1034 #[cfg(windows)]
1035 fn stdout_isatty() -> bool {
1036     type DWORD = u32;
1037     type BOOL = i32;
1038     type HANDLE = *mut u8;
1039     type LPDWORD = *mut u32;
1040     const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
1041     extern "system" {
1042         fn GetStdHandle(which: DWORD) -> HANDLE;
1043         fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
1044     }
1045     unsafe {
1046         let handle = GetStdHandle(STD_OUTPUT_HANDLE);
1047         let mut out = 0;
1048         GetConsoleMode(handle, &mut out) != 0
1049     }
1050 }
1051
1052 #[derive(Clone)]
1053 pub enum TestEvent {
1054     TeFiltered(Vec<TestDesc>),
1055     TeWait(TestDesc),
1056     TeResult(TestDesc, TestResult, Vec<u8>),
1057     TeTimeout(TestDesc),
1058     TeFilteredOut(usize),
1059 }
1060
1061 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
1062
1063 struct Sink(Arc<Mutex<Vec<u8>>>);
1064 impl Write for Sink {
1065     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1066         Write::write(&mut *self.0.lock().unwrap(), data)
1067     }
1068     fn flush(&mut self) -> io::Result<()> {
1069         Ok(())
1070     }
1071 }
1072
1073 pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
1074 where
1075     F: FnMut(TestEvent) -> io::Result<()>,
1076 {
1077     use std::collections::{self, HashMap};
1078     use std::hash::BuildHasherDefault;
1079     use std::sync::mpsc::RecvTimeoutError;
1080     // Use a deterministic hasher
1081     type TestMap =
1082         HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
1083
1084     let tests_len = tests.len();
1085
1086     let mut filtered_tests = filter_tests(opts, tests);
1087     if !opts.bench_benchmarks {
1088         filtered_tests = convert_benchmarks_to_tests(filtered_tests);
1089     }
1090
1091     let filtered_tests = {
1092         let mut filtered_tests = filtered_tests;
1093         for test in filtered_tests.iter_mut() {
1094             test.desc.name = test.desc.name.with_padding(test.testfn.padding());
1095         }
1096
1097         filtered_tests
1098     };
1099
1100     let filtered_out = tests_len - filtered_tests.len();
1101     callback(TeFilteredOut(filtered_out))?;
1102
1103     let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
1104
1105     callback(TeFiltered(filtered_descs))?;
1106
1107     let (filtered_tests, filtered_benchs): (Vec<_>, _) =
1108         filtered_tests.into_iter().partition(|e| match e.testfn {
1109             StaticTestFn(_) | DynTestFn(_) => true,
1110             _ => false,
1111         });
1112
1113     let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
1114
1115     let mut remaining = filtered_tests;
1116     remaining.reverse();
1117     let mut pending = 0;
1118
1119     let (tx, rx) = channel::<MonitorMsg>();
1120
1121     let mut running_tests: TestMap = HashMap::default();
1122
1123     fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> {
1124         let now = Instant::now();
1125         let timed_out = running_tests
1126             .iter()
1127             .filter_map(|(desc, timeout)| {
1128                 if &now >= timeout {
1129                     Some(desc.clone())
1130                 } else {
1131                     None
1132                 }
1133             })
1134             .collect();
1135         for test in &timed_out {
1136             running_tests.remove(test);
1137         }
1138         timed_out
1139     };
1140
1141     fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
1142         running_tests.values().min().map(|next_timeout| {
1143             let now = Instant::now();
1144             if *next_timeout >= now {
1145                 *next_timeout - now
1146             } else {
1147                 Duration::new(0, 0)
1148             }
1149         })
1150     };
1151
1152     if concurrency == 1 {
1153         while !remaining.is_empty() {
1154             let test = remaining.pop().unwrap();
1155             callback(TeWait(test.desc.clone()))?;
1156             run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No);
1157             let (test, result, stdout) = rx.recv().unwrap();
1158             callback(TeResult(test, result, stdout))?;
1159         }
1160     } else {
1161         while pending > 0 || !remaining.is_empty() {
1162             while pending < concurrency && !remaining.is_empty() {
1163                 let test = remaining.pop().unwrap();
1164                 let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
1165                 running_tests.insert(test.desc.clone(), timeout);
1166                 callback(TeWait(test.desc.clone()))?; //here no pad
1167                 run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes);
1168                 pending += 1;
1169             }
1170
1171             let mut res;
1172             loop {
1173                 if let Some(timeout) = calc_timeout(&running_tests) {
1174                     res = rx.recv_timeout(timeout);
1175                     for test in get_timed_out_tests(&mut running_tests) {
1176                         callback(TeTimeout(test))?;
1177                     }
1178                     if res != Err(RecvTimeoutError::Timeout) {
1179                         break;
1180                     }
1181                 } else {
1182                     res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
1183                     break;
1184                 }
1185             }
1186
1187             let (desc, result, stdout) = res.unwrap();
1188             running_tests.remove(&desc);
1189
1190             callback(TeResult(desc, result, stdout))?;
1191             pending -= 1;
1192         }
1193     }
1194
1195     if opts.bench_benchmarks {
1196         // All benchmarks run at the end, in serial.
1197         for b in filtered_benchs {
1198             callback(TeWait(b.desc.clone()))?;
1199             run_test(opts, false, b, tx.clone(), Concurrent::No);
1200             let (test, result, stdout) = rx.recv().unwrap();
1201             callback(TeResult(test, result, stdout))?;
1202         }
1203     }
1204     Ok(())
1205 }
1206
1207 #[allow(deprecated)]
1208 fn get_concurrency() -> usize {
1209     return match env::var("RUST_TEST_THREADS") {
1210         Ok(s) => {
1211             let opt_n: Option<usize> = s.parse().ok();
1212             match opt_n {
1213                 Some(n) if n > 0 => n,
1214                 _ => panic!(
1215                     "RUST_TEST_THREADS is `{}`, should be a positive integer.",
1216                     s
1217                 ),
1218             }
1219         }
1220         Err(..) => num_cpus(),
1221     };
1222
1223     #[cfg(windows)]
1224     #[allow(nonstandard_style)]
1225     fn num_cpus() -> usize {
1226         #[repr(C)]
1227         struct SYSTEM_INFO {
1228             wProcessorArchitecture: u16,
1229             wReserved: u16,
1230             dwPageSize: u32,
1231             lpMinimumApplicationAddress: *mut u8,
1232             lpMaximumApplicationAddress: *mut u8,
1233             dwActiveProcessorMask: *mut u8,
1234             dwNumberOfProcessors: u32,
1235             dwProcessorType: u32,
1236             dwAllocationGranularity: u32,
1237             wProcessorLevel: u16,
1238             wProcessorRevision: u16,
1239         }
1240         extern "system" {
1241             fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
1242         }
1243         unsafe {
1244             let mut sysinfo = std::mem::zeroed();
1245             GetSystemInfo(&mut sysinfo);
1246             sysinfo.dwNumberOfProcessors as usize
1247         }
1248     }
1249
1250     #[cfg(target_os = "redox")]
1251     fn num_cpus() -> usize {
1252         // FIXME: Implement num_cpus on Redox
1253         1
1254     }
1255
1256     #[cfg(any(
1257         all(target_arch = "wasm32", not(target_os = "emscripten")),
1258         all(target_vendor = "fortanix", target_env = "sgx")
1259     ))]
1260     fn num_cpus() -> usize {
1261         1
1262     }
1263
1264     #[cfg(any(
1265         target_os = "android",
1266         target_os = "cloudabi",
1267         target_os = "emscripten",
1268         target_os = "fuchsia",
1269         target_os = "ios",
1270         target_os = "linux",
1271         target_os = "macos",
1272         target_os = "solaris"
1273     ))]
1274     fn num_cpus() -> usize {
1275         unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
1276     }
1277
1278     #[cfg(any(
1279         target_os = "freebsd",
1280         target_os = "dragonfly",
1281         target_os = "bitrig",
1282         target_os = "netbsd"
1283     ))]
1284     fn num_cpus() -> usize {
1285         use std::ptr;
1286
1287         let mut cpus: libc::c_uint = 0;
1288         let mut cpus_size = std::mem::size_of_val(&cpus);
1289
1290         unsafe {
1291             cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
1292         }
1293         if cpus < 1 {
1294             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1295             unsafe {
1296                 libc::sysctl(
1297                     mib.as_mut_ptr(),
1298                     2,
1299                     &mut cpus as *mut _ as *mut _,
1300                     &mut cpus_size as *mut _ as *mut _,
1301                     ptr::null_mut(),
1302                     0,
1303                 );
1304             }
1305             if cpus < 1 {
1306                 cpus = 1;
1307             }
1308         }
1309         cpus as usize
1310     }
1311
1312     #[cfg(target_os = "openbsd")]
1313     fn num_cpus() -> usize {
1314         use std::ptr;
1315
1316         let mut cpus: libc::c_uint = 0;
1317         let mut cpus_size = std::mem::size_of_val(&cpus);
1318         let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
1319
1320         unsafe {
1321             libc::sysctl(
1322                 mib.as_mut_ptr(),
1323                 2,
1324                 &mut cpus as *mut _ as *mut _,
1325                 &mut cpus_size as *mut _ as *mut _,
1326                 ptr::null_mut(),
1327                 0,
1328             );
1329         }
1330         if cpus < 1 {
1331             cpus = 1;
1332         }
1333         cpus as usize
1334     }
1335
1336     #[cfg(target_os = "haiku")]
1337     fn num_cpus() -> usize {
1338         // FIXME: implement
1339         1
1340     }
1341
1342     #[cfg(target_os = "l4re")]
1343     fn num_cpus() -> usize {
1344         // FIXME: implement
1345         1
1346     }
1347 }
1348
1349 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1350     let mut filtered = tests;
1351     let matches_filter = |test: &TestDescAndFn, filter: &str| {
1352         let test_name = test.desc.name.as_slice();
1353
1354         match opts.filter_exact {
1355             true => test_name == filter,
1356             false => test_name.contains(filter),
1357         }
1358     };
1359
1360     // Remove tests that don't match the test filter
1361     if let Some(ref filter) = opts.filter {
1362         filtered.retain(|test| matches_filter(test, filter));
1363     }
1364
1365     // Skip tests that match any of the skip filters
1366     filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
1367
1368     // maybe unignore tests
1369     match opts.run_ignored {
1370         RunIgnored::Yes => {
1371             filtered
1372                 .iter_mut()
1373                 .for_each(|test| test.desc.ignore = false);
1374         }
1375         RunIgnored::Only => {
1376             filtered.retain(|test| test.desc.ignore);
1377             filtered
1378                 .iter_mut()
1379                 .for_each(|test| test.desc.ignore = false);
1380         }
1381         RunIgnored::No => {}
1382     }
1383
1384     // Sort the tests alphabetically
1385     filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
1386
1387     filtered
1388 }
1389
1390 pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
1391     // convert benchmarks to tests, if we're not benchmarking them
1392     tests
1393         .into_iter()
1394         .map(|x| {
1395             let testfn = match x.testfn {
1396                 DynBenchFn(bench) => DynTestFn(Box::new(move || {
1397                     bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b)))
1398                 })),
1399                 StaticBenchFn(benchfn) => DynTestFn(Box::new(move || {
1400                     bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
1401                 })),
1402                 f => f,
1403             };
1404             TestDescAndFn {
1405                 desc: x.desc,
1406                 testfn,
1407             }
1408         })
1409         .collect()
1410 }
1411
1412 pub fn run_test(
1413     opts: &TestOpts,
1414     force_ignore: bool,
1415     test: TestDescAndFn,
1416     monitor_ch: Sender<MonitorMsg>,
1417     concurrency: Concurrent,
1418 ) {
1419     let TestDescAndFn { desc, testfn } = test;
1420
1421     let ignore_because_panic_abort = cfg!(target_arch = "wasm32")
1422         && !cfg!(target_os = "emscripten")
1423         && desc.should_panic != ShouldPanic::No;
1424
1425     if force_ignore || desc.ignore || ignore_because_panic_abort {
1426         monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap();
1427         return;
1428     }
1429
1430     fn run_test_inner(
1431         desc: TestDesc,
1432         monitor_ch: Sender<MonitorMsg>,
1433         nocapture: bool,
1434         testfn: Box<dyn FnBox() + Send>,
1435         concurrency: Concurrent,
1436     ) {
1437         // Buffer for capturing standard I/O
1438         let data = Arc::new(Mutex::new(Vec::new()));
1439         let data2 = data.clone();
1440
1441         let name = desc.name.clone();
1442         let runtest = move || {
1443             let oldio = if !nocapture {
1444                 Some((
1445                     io::set_print(Some(Box::new(Sink(data2.clone())))),
1446                     io::set_panic(Some(Box::new(Sink(data2)))),
1447                 ))
1448             } else {
1449                 None
1450             };
1451
1452             let result = catch_unwind(AssertUnwindSafe(testfn));
1453
1454             if let Some((printio, panicio)) = oldio {
1455                 io::set_print(printio);
1456                 io::set_panic(panicio);
1457             };
1458
1459             let test_result = calc_result(&desc, result);
1460             let stdout = data.lock().unwrap().to_vec();
1461             monitor_ch
1462                 .send((desc.clone(), test_result, stdout))
1463                 .unwrap();
1464         };
1465
1466         // If the platform is single-threaded we're just going to run
1467         // the test synchronously, regardless of the concurrency
1468         // level.
1469         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
1470         if concurrency == Concurrent::Yes && supports_threads {
1471             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
1472             cfg.spawn(runtest).unwrap();
1473         } else {
1474             runtest();
1475         }
1476     }
1477
1478     match testfn {
1479         DynBenchFn(bencher) => {
1480             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1481                 bencher.run(harness)
1482             });
1483         }
1484         StaticBenchFn(benchfn) => {
1485             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
1486                 (benchfn.clone())(harness)
1487             });
1488         }
1489         DynTestFn(f) => {
1490             let cb = move || __rust_begin_short_backtrace(f);
1491             run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency)
1492         }
1493         StaticTestFn(f) => run_test_inner(
1494             desc,
1495             monitor_ch,
1496             opts.nocapture,
1497             Box::new(move || __rust_begin_short_backtrace(f)),
1498             concurrency,
1499         ),
1500     }
1501 }
1502
1503 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
1504 #[inline(never)]
1505 fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
1506     f()
1507 }
1508
1509 fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) -> TestResult {
1510     match (&desc.should_panic, task_result) {
1511         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
1512         (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
1513             if err
1514                 .downcast_ref::<String>()
1515                 .map(|e| &**e)
1516                 .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
1517                 .map(|e| e.contains(msg))
1518                 .unwrap_or(false)
1519             {
1520                 TrOk
1521             } else {
1522                 if desc.allow_fail {
1523                     TrAllowedFail
1524                 } else {
1525                     TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
1526                 }
1527             }
1528         }
1529         _ if desc.allow_fail => TrAllowedFail,
1530         _ => TrFailed,
1531     }
1532 }
1533
1534 #[derive(Clone, PartialEq)]
1535 pub struct MetricMap(BTreeMap<String, Metric>);
1536
1537 impl MetricMap {
1538     pub fn new() -> MetricMap {
1539         MetricMap(BTreeMap::new())
1540     }
1541
1542     /// Insert a named `value` (+/- `noise`) metric into the map. The value
1543     /// must be non-negative. The `noise` indicates the uncertainty of the
1544     /// metric, which doubles as the "noise range" of acceptable
1545     /// pairwise-regressions on this named value, when comparing from one
1546     /// metric to the next using `compare_to_old`.
1547     ///
1548     /// If `noise` is positive, then it means this metric is of a value
1549     /// you want to see grow smaller, so a change larger than `noise` in the
1550     /// positive direction represents a regression.
1551     ///
1552     /// If `noise` is negative, then it means this metric is of a value
1553     /// you want to see grow larger, so a change larger than `noise` in the
1554     /// negative direction represents a regression.
1555     pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
1556         let m = Metric { value, noise };
1557         self.0.insert(name.to_owned(), m);
1558     }
1559
1560     pub fn fmt_metrics(&self) -> String {
1561         let v = self
1562             .0
1563             .iter()
1564             .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
1565             .collect::<Vec<_>>();
1566         v.join(", ")
1567     }
1568 }
1569
1570 // Benchmarking
1571
1572 /// A function that is opaque to the optimizer, to allow benchmarks to
1573 /// pretend to use outputs to assist in avoiding dead-code
1574 /// elimination.
1575 ///
1576 /// This function is a no-op, and does not even read from `dummy`.
1577 #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
1578 pub fn black_box<T>(dummy: T) -> T {
1579     // we need to "use" the argument in some way LLVM can't
1580     // introspect.
1581     unsafe { asm!("" : : "r"(&dummy)) }
1582     dummy
1583 }
1584 #[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
1585 #[inline(never)]
1586 pub fn black_box<T>(dummy: T) -> T {
1587     dummy
1588 }
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 exact_filter_match() {
1988         fn tests() -> Vec<TestDescAndFn> {
1989             vec!["base", "base::test", "base::test1", "base::test2"]
1990                 .into_iter()
1991                 .map(|name| TestDescAndFn {
1992                     desc: TestDesc {
1993                         name: StaticTestName(name),
1994                         ignore: false,
1995                         should_panic: ShouldPanic::No,
1996                         allow_fail: false,
1997                     },
1998                     testfn: DynTestFn(Box::new(move || {})),
1999                 })
2000                 .collect()
2001         }
2002
2003         let substr = filter_tests(
2004             &TestOpts {
2005                 filter: Some("base".into()),
2006                 ..TestOpts::new()
2007             },
2008             tests(),
2009         );
2010         assert_eq!(substr.len(), 4);
2011
2012         let substr = filter_tests(
2013             &TestOpts {
2014                 filter: Some("bas".into()),
2015                 ..TestOpts::new()
2016             },
2017             tests(),
2018         );
2019         assert_eq!(substr.len(), 4);
2020
2021         let substr = filter_tests(
2022             &TestOpts {
2023                 filter: Some("::test".into()),
2024                 ..TestOpts::new()
2025             },
2026             tests(),
2027         );
2028         assert_eq!(substr.len(), 3);
2029
2030         let substr = filter_tests(
2031             &TestOpts {
2032                 filter: Some("base::test".into()),
2033                 ..TestOpts::new()
2034             },
2035             tests(),
2036         );
2037         assert_eq!(substr.len(), 3);
2038
2039         let exact = filter_tests(
2040             &TestOpts {
2041                 filter: Some("base".into()),
2042                 filter_exact: true,
2043                 ..TestOpts::new()
2044             },
2045             tests(),
2046         );
2047         assert_eq!(exact.len(), 1);
2048
2049         let exact = filter_tests(
2050             &TestOpts {
2051                 filter: Some("bas".into()),
2052                 filter_exact: true,
2053                 ..TestOpts::new()
2054             },
2055             tests(),
2056         );
2057         assert_eq!(exact.len(), 0);
2058
2059         let exact = filter_tests(
2060             &TestOpts {
2061                 filter: Some("::test".into()),
2062                 filter_exact: true,
2063                 ..TestOpts::new()
2064             },
2065             tests(),
2066         );
2067         assert_eq!(exact.len(), 0);
2068
2069         let exact = filter_tests(
2070             &TestOpts {
2071                 filter: Some("base::test".into()),
2072                 filter_exact: true,
2073                 ..TestOpts::new()
2074             },
2075             tests(),
2076         );
2077         assert_eq!(exact.len(), 1);
2078     }
2079
2080     #[test]
2081     pub fn sort_tests() {
2082         let mut opts = TestOpts::new();
2083         opts.run_tests = true;
2084
2085         let names = vec![
2086             "sha1::test".to_string(),
2087             "isize::test_to_str".to_string(),
2088             "isize::test_pow".to_string(),
2089             "test::do_not_run_ignored_tests".to_string(),
2090             "test::ignored_tests_result_in_ignored".to_string(),
2091             "test::first_free_arg_should_be_a_filter".to_string(),
2092             "test::parse_ignored_flag".to_string(),
2093             "test::parse_include_ignored_flag".to_string(),
2094             "test::filter_for_ignored_option".to_string(),
2095             "test::run_include_ignored_option".to_string(),
2096             "test::sort_tests".to_string(),
2097         ];
2098         let tests = {
2099             fn testfn() {}
2100             let mut tests = Vec::new();
2101             for name in &names {
2102                 let test = TestDescAndFn {
2103                     desc: TestDesc {
2104                         name: DynTestName((*name).clone()),
2105                         ignore: false,
2106                         should_panic: ShouldPanic::No,
2107                         allow_fail: false,
2108                     },
2109                     testfn: DynTestFn(Box::new(testfn)),
2110                 };
2111                 tests.push(test);
2112             }
2113             tests
2114         };
2115         let filtered = filter_tests(&opts, tests);
2116
2117         let expected = vec![
2118             "isize::test_pow".to_string(),
2119             "isize::test_to_str".to_string(),
2120             "sha1::test".to_string(),
2121             "test::do_not_run_ignored_tests".to_string(),
2122             "test::filter_for_ignored_option".to_string(),
2123             "test::first_free_arg_should_be_a_filter".to_string(),
2124             "test::ignored_tests_result_in_ignored".to_string(),
2125             "test::parse_ignored_flag".to_string(),
2126             "test::parse_include_ignored_flag".to_string(),
2127             "test::run_include_ignored_option".to_string(),
2128             "test::sort_tests".to_string(),
2129         ];
2130
2131         for (a, b) in expected.iter().zip(filtered) {
2132             assert!(*a == b.desc.name.to_string());
2133         }
2134     }
2135
2136     #[test]
2137     pub fn test_metricmap_compare() {
2138         let mut m1 = MetricMap::new();
2139         let mut m2 = MetricMap::new();
2140         m1.insert_metric("in-both-noise", 1000.0, 200.0);
2141         m2.insert_metric("in-both-noise", 1100.0, 200.0);
2142
2143         m1.insert_metric("in-first-noise", 1000.0, 2.0);
2144         m2.insert_metric("in-second-noise", 1000.0, 2.0);
2145
2146         m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
2147         m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
2148
2149         m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
2150         m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
2151
2152         m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
2153         m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
2154
2155         m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
2156         m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
2157     }
2158
2159     #[test]
2160     pub fn test_bench_once_no_iter() {
2161         fn f(_: &mut Bencher) {}
2162         bench::run_once(f);
2163     }
2164
2165     #[test]
2166     pub fn test_bench_once_iter() {
2167         fn f(b: &mut Bencher) {
2168             b.iter(|| {})
2169         }
2170         bench::run_once(f);
2171     }
2172
2173     #[test]
2174     pub fn test_bench_no_iter() {
2175         fn f(_: &mut Bencher) {}
2176
2177         let (tx, rx) = channel();
2178
2179         let desc = TestDesc {
2180             name: StaticTestName("f"),
2181             ignore: false,
2182             should_panic: ShouldPanic::No,
2183             allow_fail: false,
2184         };
2185
2186         crate::bench::benchmark(desc, tx, true, f);
2187         rx.recv().unwrap();
2188     }
2189
2190     #[test]
2191     pub fn test_bench_iter() {
2192         fn f(b: &mut Bencher) {
2193             b.iter(|| {})
2194         }
2195
2196         let (tx, rx) = channel();
2197
2198         let desc = TestDesc {
2199             name: StaticTestName("f"),
2200             ignore: false,
2201             should_panic: ShouldPanic::No,
2202             allow_fail: false,
2203         };
2204
2205         crate::bench::benchmark(desc, tx, true, f);
2206         rx.recv().unwrap();
2207     }
2208 }