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