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