]> git.lizzy.rs Git - rust.git/blob - src/libtest/lib.rs
Change some instances of .connect() to .join()
[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 // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
27 #![cfg_attr(stage0, feature(custom_attribute))]
28 #![crate_name = "test"]
29 #![unstable(feature = "test")]
30 #![staged_api]
31 #![crate_type = "rlib"]
32 #![crate_type = "dylib"]
33 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
34        html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
35        html_root_url = "http://doc.rust-lang.org/nightly/")]
36
37 #![feature(asm)]
38 #![feature(box_syntax)]
39 #![feature(duration)]
40 #![feature(duration_span)]
41 #![feature(fnbox)]
42 #![feature(iter_cmp)]
43 #![feature(libc)]
44 #![feature(rt)]
45 #![feature(rustc_private)]
46 #![feature(set_stdio)]
47 #![feature(slice_extras)]
48 #![feature(staged_api)]
49
50 extern crate getopts;
51 extern crate serialize;
52 extern crate serialize as rustc_serialize;
53 extern crate term;
54 extern crate libc;
55
56 pub use self::TestFn::*;
57 pub use self::ColorConfig::*;
58 pub use self::TestResult::*;
59 pub use self::TestName::*;
60 use self::TestEvent::*;
61 use self::NamePadding::*;
62 use self::OutputLocation::*;
63
64 use stats::Stats;
65 use getopts::{OptGroup, optflag, optopt};
66 use serialize::Encodable;
67 use std::boxed::FnBox;
68 use term::Terminal;
69 use term::color::{Color, RED, YELLOW, GREEN, CYAN};
70
71 use std::any::Any;
72 use std::cmp;
73 use std::collections::BTreeMap;
74 use std::env;
75 use std::fmt;
76 use std::fs::File;
77 use std::io::prelude::*;
78 use std::io;
79 use std::iter::repeat;
80 use std::path::PathBuf;
81 use std::sync::mpsc::{channel, Sender};
82 use std::sync::{Arc, Mutex};
83 use std::thread;
84 use std::time::Duration;
85
86 // to be used by rustc to compile tests in libtest
87 pub mod test {
88     pub use {Bencher, TestName, TestResult, TestDesc,
89              TestDescAndFn, TestOpts, TrFailed, TrIgnored, TrOk,
90              Metric, MetricMap,
91              StaticTestFn, StaticTestName, DynTestName, DynTestFn,
92              run_test, test_main, test_main_static, filter_tests,
93              parse_opts, StaticBenchFn, ShouldPanic};
94 }
95
96 pub mod stats;
97
98 // The name of a test. By convention this follows the rules for rust
99 // paths; i.e. it should be a series of identifiers separated by double
100 // colons. This way if some test runner wants to arrange the tests
101 // hierarchically it may.
102
103 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
104 pub enum TestName {
105     StaticTestName(&'static str),
106     DynTestName(String)
107 }
108 impl TestName {
109     fn as_slice<'a>(&'a self) -> &'a str {
110         match *self {
111             StaticTestName(s) => s,
112             DynTestName(ref s) => s
113         }
114     }
115 }
116 impl fmt::Display for TestName {
117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         fmt::Display::fmt(self.as_slice(), f)
119     }
120 }
121
122 #[derive(Clone, Copy)]
123 enum NamePadding {
124     PadNone,
125     PadOnRight,
126 }
127
128 impl TestDesc {
129     fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
130         let mut name = String::from(self.name.as_slice());
131         let fill = column_count.saturating_sub(name.len());
132         let pad = repeat(" ").take(fill).collect::<String>();
133         match align {
134             PadNone => name,
135             PadOnRight => {
136                 name.push_str(&pad);
137                 name
138             }
139         }
140     }
141 }
142
143 /// Represents a benchmark function.
144 pub trait TDynBenchFn: Send {
145     fn run(&self, harness: &mut Bencher);
146 }
147
148 // A function that runs a test. If the function returns successfully,
149 // the test succeeds; if the function panics then the test fails. We
150 // may need to come up with a more clever definition of test in order
151 // to support isolation of tests into threads.
152 pub enum TestFn {
153     StaticTestFn(fn()),
154     StaticBenchFn(fn(&mut Bencher)),
155     StaticMetricFn(fn(&mut MetricMap)),
156     DynTestFn(Box<FnBox() + Send>),
157     DynMetricFn(Box<FnBox(&mut MetricMap)+Send>),
158     DynBenchFn(Box<TDynBenchFn+'static>)
159 }
160
161 impl TestFn {
162     fn padding(&self) -> NamePadding {
163         match self {
164             &StaticTestFn(..)   => PadNone,
165             &StaticBenchFn(..)  => PadOnRight,
166             &StaticMetricFn(..) => PadOnRight,
167             &DynTestFn(..)      => PadNone,
168             &DynMetricFn(..)    => PadOnRight,
169             &DynBenchFn(..)     => PadOnRight,
170         }
171     }
172 }
173
174 impl fmt::Debug for TestFn {
175     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176         f.write_str(match *self {
177             StaticTestFn(..) => "StaticTestFn(..)",
178             StaticBenchFn(..) => "StaticBenchFn(..)",
179             StaticMetricFn(..) => "StaticMetricFn(..)",
180             DynTestFn(..) => "DynTestFn(..)",
181             DynMetricFn(..) => "DynMetricFn(..)",
182             DynBenchFn(..) => "DynBenchFn(..)"
183         })
184     }
185 }
186
187 /// Manager of the benchmarking runs.
188 ///
189 /// This is fed into functions marked with `#[bench]` to allow for
190 /// set-up & tear-down before running a piece of code repeatedly via a
191 /// call to `iter`.
192 #[derive(Copy, Clone)]
193 pub struct Bencher {
194     iterations: u64,
195     dur: Duration,
196     pub bytes: u64,
197 }
198
199 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
200 pub enum ShouldPanic {
201     No,
202     Yes(Option<&'static str>)
203 }
204
205 // The definition of a single test. A test runner will run a list of
206 // these.
207 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
208 pub struct TestDesc {
209     pub name: TestName,
210     pub ignore: bool,
211     pub should_panic: ShouldPanic,
212 }
213
214 unsafe impl Send for TestDesc {}
215
216 #[derive(Debug)]
217 pub struct TestDescAndFn {
218     pub desc: TestDesc,
219     pub testfn: TestFn,
220 }
221
222 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Copy)]
223 pub struct Metric {
224     value: f64,
225     noise: f64
226 }
227
228 impl Metric {
229     pub fn new(value: f64, noise: f64) -> Metric {
230         Metric {value: value, noise: noise}
231     }
232 }
233
234 #[derive(PartialEq)]
235 pub struct MetricMap(BTreeMap<String,Metric>);
236
237 impl Clone for MetricMap {
238     fn clone(&self) -> MetricMap {
239         let MetricMap(ref map) = *self;
240         MetricMap(map.clone())
241     }
242 }
243
244 // The default console test runner. It accepts the command line
245 // arguments and a vector of test_descs.
246 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn> ) {
247     let opts =
248         match parse_opts(args) {
249             Some(Ok(o)) => o,
250             Some(Err(msg)) => panic!("{:?}", msg),
251             None => return
252         };
253     match run_tests_console(&opts, tests) {
254         Ok(true) => {}
255         Ok(false) => panic!("Some tests failed"),
256         Err(e) => panic!("io error when running tests: {:?}", e),
257     }
258 }
259
260 // A variant optimized for invocation with a static test vector.
261 // This will panic (intentionally) when fed any dynamic tests, because
262 // it is copying the static values out into a dynamic vector and cannot
263 // copy dynamic values. It is doing this because from this point on
264 // a Vec<TestDescAndFn> is used in order to effect ownership-transfer
265 // semantics into parallel test runners, which in turn requires a Vec<>
266 // rather than a &[].
267 pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) {
268     let args = args.collect::<Vec<_>>();
269     let owned_tests = tests.iter().map(|t| {
270         match t.testfn {
271             StaticTestFn(f) => TestDescAndFn { testfn: StaticTestFn(f), desc: t.desc.clone() },
272             StaticBenchFn(f) => TestDescAndFn { testfn: StaticBenchFn(f), desc: t.desc.clone() },
273             _ => panic!("non-static tests passed to test::test_main_static")
274         }
275     }).collect();
276     test_main(&args, owned_tests)
277 }
278
279 #[derive(Copy, Clone)]
280 pub enum ColorConfig {
281     AutoColor,
282     AlwaysColor,
283     NeverColor,
284 }
285
286 pub struct TestOpts {
287     pub filter: Option<String>,
288     pub run_ignored: bool,
289     pub run_tests: bool,
290     pub bench_benchmarks: bool,
291     pub logfile: Option<PathBuf>,
292     pub nocapture: bool,
293     pub color: ColorConfig,
294 }
295
296 impl TestOpts {
297     #[cfg(test)]
298     fn new() -> TestOpts {
299         TestOpts {
300             filter: None,
301             run_ignored: false,
302             run_tests: false,
303             bench_benchmarks: false,
304             logfile: None,
305             nocapture: false,
306             color: AutoColor,
307         }
308     }
309 }
310
311 /// Result of parsing the options.
312 pub type OptRes = Result<TestOpts, String>;
313
314 fn optgroups() -> Vec<getopts::OptGroup> {
315     vec!(getopts::optflag("", "ignored", "Run ignored tests"),
316       getopts::optflag("", "test", "Run tests and not benchmarks"),
317       getopts::optflag("", "bench", "Run benchmarks instead of tests"),
318       getopts::optflag("h", "help", "Display this message (longer with --help)"),
319       getopts::optopt("", "logfile", "Write logs to the specified file instead \
320                           of stdout", "PATH"),
321       getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \
322                                          task, allow printing directly"),
323       getopts::optopt("", "color", "Configure coloring of output:
324             auto   = colorize if stdout is a tty and tests are run on serially (default);
325             always = always colorize output;
326             never  = never colorize output;", "auto|always|never"))
327 }
328
329 fn usage(binary: &str) {
330     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
331     println!(r#"{usage}
332
333 The FILTER regex is tested against the name of all tests to run, and
334 only those tests that match are run.
335
336 By default, all tests are run in parallel. This can be altered with the
337 RUST_TEST_THREADS environment variable when running tests (set it to 1).
338
339 All tests have their standard output and standard error captured by default.
340 This can be overridden with the --nocapture flag or the RUST_TEST_NOCAPTURE=1
341 environment variable. Logging is not captured by default.
342
343 Test Attributes:
344
345     #[test]        - Indicates a function is a test to be run. This function
346                      takes no arguments.
347     #[bench]       - Indicates a function is a benchmark to be run. This
348                      function takes one argument (test::Bencher).
349     #[should_panic] - This function (also labeled with #[test]) will only pass if
350                      the code causes a panic (an assertion failure or panic!)
351                      A message may be provided, which the failure string must
352                      contain: #[should_panic(expected = "foo")].
353     #[ignore]      - When applied to a function which is already attributed as a
354                      test, then the test runner will ignore these tests during
355                      normal test runs. Running with --ignored will run these
356                      tests."#,
357              usage = getopts::usage(&message, &optgroups()));
358 }
359
360 // Parses command line arguments into test options
361 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
362     let args_ = args.tail();
363     let matches =
364         match getopts::getopts(args_, &optgroups()) {
365           Ok(m) => m,
366           Err(f) => return Some(Err(f.to_string()))
367         };
368
369     if matches.opt_present("h") { usage(&args[0]); return None; }
370
371     let filter = if !matches.free.is_empty() {
372         Some(matches.free[0].clone())
373     } else {
374         None
375     };
376
377     let run_ignored = matches.opt_present("ignored");
378
379     let logfile = matches.opt_str("logfile");
380     let logfile = logfile.map(|s| PathBuf::from(&s));
381
382     let bench_benchmarks = matches.opt_present("bench");
383     let run_tests = ! bench_benchmarks ||
384         matches.opt_present("test");
385
386     let mut nocapture = matches.opt_present("nocapture");
387     if !nocapture {
388         nocapture = env::var("RUST_TEST_NOCAPTURE").is_ok();
389     }
390
391     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
392         Some("auto") | None => AutoColor,
393         Some("always") => AlwaysColor,
394         Some("never") => NeverColor,
395
396         Some(v) => return Some(Err(format!("argument for --color must be \
397                                             auto, always, or never (was {})",
398                                             v))),
399     };
400
401     let test_opts = TestOpts {
402         filter: filter,
403         run_ignored: run_ignored,
404         run_tests: run_tests,
405         bench_benchmarks: bench_benchmarks,
406         logfile: logfile,
407         nocapture: nocapture,
408         color: color,
409     };
410
411     Some(Ok(test_opts))
412 }
413
414 #[derive(Clone, PartialEq)]
415 pub struct BenchSamples {
416     ns_iter_summ: stats::Summary,
417     mb_s: usize,
418 }
419
420 #[derive(Clone, PartialEq)]
421 pub enum TestResult {
422     TrOk,
423     TrFailed,
424     TrIgnored,
425     TrMetrics(MetricMap),
426     TrBench(BenchSamples),
427 }
428
429 unsafe impl Send for TestResult {}
430
431 enum OutputLocation<T> {
432     Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
433     Raw(T),
434 }
435
436 struct ConsoleTestState<T> {
437     log_out: Option<File>,
438     out: OutputLocation<T>,
439     use_color: bool,
440     total: usize,
441     passed: usize,
442     failed: usize,
443     ignored: usize,
444     measured: usize,
445     metrics: MetricMap,
446     failures: Vec<(TestDesc, Vec<u8> )> ,
447     max_name_len: usize, // number of columns to fill when aligning names
448 }
449
450 impl<T: Write> ConsoleTestState<T> {
451     pub fn new(opts: &TestOpts,
452                _: Option<T>) -> io::Result<ConsoleTestState<io::Stdout>> {
453         let log_out = match opts.logfile {
454             Some(ref path) => Some(try!(File::create(path))),
455             None => None
456         };
457         let out = match term::stdout() {
458             None => Raw(io::stdout()),
459             Some(t) => Pretty(t)
460         };
461
462         Ok(ConsoleTestState {
463             out: out,
464             log_out: log_out,
465             use_color: use_color(opts),
466             total: 0,
467             passed: 0,
468             failed: 0,
469             ignored: 0,
470             measured: 0,
471             metrics: MetricMap::new(),
472             failures: Vec::new(),
473             max_name_len: 0,
474         })
475     }
476
477     pub fn write_ok(&mut self) -> io::Result<()> {
478         self.write_pretty("ok", term::color::GREEN)
479     }
480
481     pub fn write_failed(&mut self) -> io::Result<()> {
482         self.write_pretty("FAILED", term::color::RED)
483     }
484
485     pub fn write_ignored(&mut self) -> io::Result<()> {
486         self.write_pretty("ignored", term::color::YELLOW)
487     }
488
489     pub fn write_metric(&mut self) -> io::Result<()> {
490         self.write_pretty("metric", term::color::CYAN)
491     }
492
493     pub fn write_bench(&mut self) -> io::Result<()> {
494         self.write_pretty("bench", term::color::CYAN)
495     }
496
497     pub fn write_pretty(&mut self,
498                         word: &str,
499                         color: term::color::Color) -> io::Result<()> {
500         match self.out {
501             Pretty(ref mut term) => {
502                 if self.use_color {
503                     try!(term.fg(color));
504                 }
505                 try!(term.write_all(word.as_bytes()));
506                 if self.use_color {
507                     try!(term.reset());
508                 }
509                 term.flush()
510             }
511             Raw(ref mut stdout) => {
512                 try!(stdout.write_all(word.as_bytes()));
513                 stdout.flush()
514             }
515         }
516     }
517
518     pub fn write_plain(&mut self, s: &str) -> io::Result<()> {
519         match self.out {
520             Pretty(ref mut term) => {
521                 try!(term.write_all(s.as_bytes()));
522                 term.flush()
523             },
524             Raw(ref mut stdout) => {
525                 try!(stdout.write_all(s.as_bytes()));
526                 stdout.flush()
527             },
528         }
529     }
530
531     pub fn write_run_start(&mut self, len: usize) -> io::Result<()> {
532         self.total = len;
533         let noun = if len != 1 { "tests" } else { "test" };
534         self.write_plain(&format!("\nrunning {} {}\n", len, noun))
535     }
536
537     pub fn write_test_start(&mut self, test: &TestDesc,
538                             align: NamePadding) -> io::Result<()> {
539         let name = test.padded_name(self.max_name_len, align);
540         self.write_plain(&format!("test {} ... ", name))
541     }
542
543     pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> {
544         try!(match *result {
545             TrOk => self.write_ok(),
546             TrFailed => self.write_failed(),
547             TrIgnored => self.write_ignored(),
548             TrMetrics(ref mm) => {
549                 try!(self.write_metric());
550                 self.write_plain(&format!(": {}", mm.fmt_metrics()))
551             }
552             TrBench(ref bs) => {
553                 try!(self.write_bench());
554
555                 try!(self.write_plain(&format!(": {}", fmt_bench_samples(bs))));
556
557                 Ok(())
558             }
559         });
560         self.write_plain("\n")
561     }
562
563     pub fn write_log(&mut self, test: &TestDesc,
564                      result: &TestResult) -> io::Result<()> {
565         match self.log_out {
566             None => Ok(()),
567             Some(ref mut o) => {
568                 let s = format!("{} {}\n", match *result {
569                         TrOk => "ok".to_string(),
570                         TrFailed => "failed".to_string(),
571                         TrIgnored => "ignored".to_string(),
572                         TrMetrics(ref mm) => mm.fmt_metrics(),
573                         TrBench(ref bs) => fmt_bench_samples(bs)
574                     }, test.name);
575                 o.write_all(s.as_bytes())
576             }
577         }
578     }
579
580     pub fn write_failures(&mut self) -> io::Result<()> {
581         try!(self.write_plain("\nfailures:\n"));
582         let mut failures = Vec::new();
583         let mut fail_out = String::new();
584         for &(ref f, ref stdout) in &self.failures {
585             failures.push(f.name.to_string());
586             if !stdout.is_empty() {
587                 fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
588                 let output = String::from_utf8_lossy(stdout);
589                 fail_out.push_str(&output);
590                 fail_out.push_str("\n");
591             }
592         }
593         if !fail_out.is_empty() {
594             try!(self.write_plain("\n"));
595             try!(self.write_plain(&fail_out));
596         }
597
598         try!(self.write_plain("\nfailures:\n"));
599         failures.sort();
600         for name in &failures {
601             try!(self.write_plain(&format!("    {}\n", name)));
602         }
603         Ok(())
604     }
605
606     pub fn write_run_finish(&mut self) -> io::Result<bool> {
607         assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
608
609         let success = self.failed == 0;
610         if !success {
611             try!(self.write_failures());
612         }
613
614         try!(self.write_plain("\ntest result: "));
615         if success {
616             // There's no parallelism at this point so it's safe to use color
617             try!(self.write_ok());
618         } else {
619             try!(self.write_failed());
620         }
621         let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
622                         self.passed, self.failed, self.ignored, self.measured);
623         try!(self.write_plain(&s));
624         return Ok(success);
625     }
626 }
627
628 // Format a number with thousands separators
629 fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
630     use std::fmt::Write;
631     let mut output = String::new();
632     let mut trailing = false;
633     for &pow in &[9, 6, 3, 0] {
634         let base = 10_usize.pow(pow);
635         if pow == 0 || trailing || n / base != 0 {
636             if !trailing {
637                 output.write_fmt(format_args!("{}", n / base)).unwrap();
638             } else {
639                 output.write_fmt(format_args!("{:03}", n / base)).unwrap();
640             }
641             if pow != 0 {
642                 output.push(sep);
643             }
644             trailing = true;
645         }
646         n %= base;
647     }
648
649     output
650 }
651
652 pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
653     use std::fmt::Write;
654     let mut output = String::new();
655
656     let median = bs.ns_iter_summ.median as usize;
657     let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
658
659     output.write_fmt(format_args!("{:>11} ns/iter (+/- {})",
660                      fmt_thousands_sep(median, ','),
661                      fmt_thousands_sep(deviation, ','))).unwrap();
662     if bs.mb_s != 0 {
663         output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap();
664     }
665     output
666 }
667
668 // A simple console test runner
669 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn> ) -> io::Result<bool> {
670
671     fn callback<T: Write>(event: &TestEvent,
672                           st: &mut ConsoleTestState<T>) -> io::Result<()> {
673         match (*event).clone() {
674             TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
675             TeWait(ref test, padding) => st.write_test_start(test, padding),
676             TeResult(test, result, stdout) => {
677                 try!(st.write_log(&test, &result));
678                 try!(st.write_result(&result));
679                 match result {
680                     TrOk => st.passed += 1,
681                     TrIgnored => st.ignored += 1,
682                     TrMetrics(mm) => {
683                         let tname = test.name;
684                         let MetricMap(mm) = mm;
685                         for (k,v) in &mm {
686                             st.metrics
687                               .insert_metric(&format!("{}.{}",
688                                                       tname,
689                                                       k),
690                                              v.value,
691                                              v.noise);
692                         }
693                         st.measured += 1
694                     }
695                     TrBench(bs) => {
696                         st.metrics.insert_metric(test.name.as_slice(),
697                                                  bs.ns_iter_summ.median,
698                                                  bs.ns_iter_summ.max - bs.ns_iter_summ.min);
699                         st.measured += 1
700                     }
701                     TrFailed => {
702                         st.failed += 1;
703                         st.failures.push((test, stdout));
704                     }
705                 }
706                 Ok(())
707             }
708         }
709     }
710
711     let mut st = try!(ConsoleTestState::new(opts, None::<io::Stdout>));
712     fn len_if_padded(t: &TestDescAndFn) -> usize {
713         match t.testfn.padding() {
714             PadNone => 0,
715             PadOnRight => t.desc.name.as_slice().len(),
716         }
717     }
718     match tests.iter().max_by(|t|len_if_padded(*t)) {
719         Some(t) => {
720             let n = t.desc.name.as_slice();
721             st.max_name_len = n.len();
722         },
723         None => {}
724     }
725     try!(run_tests(opts, tests, |x| callback(&x, &mut st)));
726     return st.write_run_finish();
727 }
728
729 #[test]
730 fn should_sort_failures_before_printing_them() {
731     let test_a = TestDesc {
732         name: StaticTestName("a"),
733         ignore: false,
734         should_panic: ShouldPanic::No
735     };
736
737     let test_b = TestDesc {
738         name: StaticTestName("b"),
739         ignore: false,
740         should_panic: ShouldPanic::No
741     };
742
743     let mut st = ConsoleTestState {
744         log_out: None,
745         out: Raw(Vec::new()),
746         use_color: false,
747         total: 0,
748         passed: 0,
749         failed: 0,
750         ignored: 0,
751         measured: 0,
752         max_name_len: 10,
753         metrics: MetricMap::new(),
754         failures: vec!((test_b, Vec::new()), (test_a, Vec::new()))
755     };
756
757     st.write_failures().unwrap();
758     let s = match st.out {
759         Raw(ref m) => String::from_utf8_lossy(&m[..]),
760         Pretty(_) => unreachable!()
761     };
762
763     let apos = s.find("a").unwrap();
764     let bpos = s.find("b").unwrap();
765     assert!(apos < bpos);
766 }
767
768 fn use_color(opts: &TestOpts) -> bool {
769     match opts.color {
770         AutoColor => !opts.nocapture && stdout_isatty(),
771         AlwaysColor => true,
772         NeverColor => false,
773     }
774 }
775
776 #[cfg(unix)]
777 fn stdout_isatty() -> bool {
778     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
779 }
780 #[cfg(windows)]
781 fn stdout_isatty() -> bool {
782     const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
783     extern "system" {
784         fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
785         fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
786                           lpMode: libc::LPDWORD) -> libc::BOOL;
787     }
788     unsafe {
789         let handle = GetStdHandle(STD_OUTPUT_HANDLE);
790         let mut out = 0;
791         GetConsoleMode(handle, &mut out) != 0
792     }
793 }
794
795 #[derive(Clone)]
796 enum TestEvent {
797     TeFiltered(Vec<TestDesc> ),
798     TeWait(TestDesc, NamePadding),
799     TeResult(TestDesc, TestResult, Vec<u8> ),
800 }
801
802 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
803
804
805 fn run_tests<F>(opts: &TestOpts,
806                 tests: Vec<TestDescAndFn> ,
807                 mut callback: F) -> io::Result<()> where
808     F: FnMut(TestEvent) -> io::Result<()>,
809 {
810     let mut filtered_tests = filter_tests(opts, tests);
811     if !opts.bench_benchmarks {
812         filtered_tests = convert_benchmarks_to_tests(filtered_tests);
813     }
814
815     let filtered_descs = filtered_tests.iter()
816                                        .map(|t| t.desc.clone())
817                                        .collect();
818
819     try!(callback(TeFiltered(filtered_descs)));
820
821     let (filtered_tests, filtered_benchs_and_metrics): (Vec<_>, _) =
822         filtered_tests.into_iter().partition(|e| {
823             match e.testfn {
824                 StaticTestFn(_) | DynTestFn(_) => true,
825                 _ => false
826             }
827         });
828
829     // It's tempting to just spawn all the tests at once, but since we have
830     // many tests that run in other processes we would be making a big mess.
831     let concurrency = get_concurrency();
832
833     let mut remaining = filtered_tests;
834     remaining.reverse();
835     let mut pending = 0;
836
837     let (tx, rx) = channel::<MonitorMsg>();
838
839     while pending > 0 || !remaining.is_empty() {
840         while pending < concurrency && !remaining.is_empty() {
841             let test = remaining.pop().unwrap();
842             if concurrency == 1 {
843                 // We are doing one test at a time so we can print the name
844                 // of the test before we run it. Useful for debugging tests
845                 // that hang forever.
846                 try!(callback(TeWait(test.desc.clone(), test.testfn.padding())));
847             }
848             run_test(opts, !opts.run_tests, test, tx.clone());
849             pending += 1;
850         }
851
852         let (desc, result, stdout) = rx.recv().unwrap();
853         if concurrency != 1 {
854             try!(callback(TeWait(desc.clone(), PadNone)));
855         }
856         try!(callback(TeResult(desc, result, stdout)));
857         pending -= 1;
858     }
859
860     if opts.bench_benchmarks {
861         // All benchmarks run at the end, in serial.
862         // (this includes metric fns)
863         for b in filtered_benchs_and_metrics {
864             try!(callback(TeWait(b.desc.clone(), b.testfn.padding())));
865             run_test(opts, false, b, tx.clone());
866             let (test, result, stdout) = rx.recv().unwrap();
867             try!(callback(TeResult(test, result, stdout)));
868         }
869     }
870     Ok(())
871 }
872
873 #[allow(deprecated)]
874 fn get_concurrency() -> usize {
875     return match env::var("RUST_TEST_THREADS") {
876         Ok(s) => {
877             let opt_n: Option<usize> = s.parse().ok();
878             match opt_n {
879                 Some(n) if n > 0 => n,
880                 _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s)
881             }
882         }
883         Err(..) => {
884             if std::rt::util::limit_thread_creation_due_to_osx_and_valgrind() {
885                 1
886             } else {
887                 num_cpus()
888             }
889         }
890     };
891
892     #[cfg(windows)]
893     fn num_cpus() -> usize {
894         unsafe {
895             let mut sysinfo = std::mem::zeroed();
896             libc::GetSystemInfo(&mut sysinfo);
897             sysinfo.dwNumberOfProcessors as usize
898         }
899     }
900
901     #[cfg(unix)]
902     fn num_cpus() -> usize {
903         extern { fn rust_get_num_cpus() -> libc::uintptr_t; }
904         unsafe { rust_get_num_cpus() as usize }
905     }
906 }
907
908 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
909     let mut filtered = tests;
910
911     // Remove tests that don't match the test filter
912     filtered = match opts.filter {
913         None => filtered,
914         Some(ref filter) => {
915             filtered.into_iter().filter(|test| {
916                 test.desc.name.as_slice().contains(&filter[..])
917             }).collect()
918         }
919     };
920
921     // Maybe pull out the ignored test and unignore them
922     filtered = if !opts.run_ignored {
923         filtered
924     } else {
925         fn filter(test: TestDescAndFn) -> Option<TestDescAndFn> {
926             if test.desc.ignore {
927                 let TestDescAndFn {desc, testfn} = test;
928                 Some(TestDescAndFn {
929                     desc: TestDesc {ignore: false, ..desc},
930                     testfn: testfn
931                 })
932             } else {
933                 None
934             }
935         };
936         filtered.into_iter().filter_map(|x| filter(x)).collect()
937     };
938
939     // Sort the tests alphabetically
940     filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
941
942     filtered
943 }
944
945 pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
946     // convert benchmarks to tests, if we're not benchmarking them
947     tests.into_iter().map(|x| {
948         let testfn = match x.testfn {
949             DynBenchFn(bench) => {
950                 DynTestFn(Box::new(move || bench::run_once(|b| bench.run(b))))
951             }
952             StaticBenchFn(benchfn) => {
953                 DynTestFn(Box::new(move || bench::run_once(|b| benchfn(b))))
954             }
955             f => f
956         };
957         TestDescAndFn { desc: x.desc, testfn: testfn }
958     }).collect()
959 }
960
961 pub fn run_test(opts: &TestOpts,
962                 force_ignore: bool,
963                 test: TestDescAndFn,
964                 monitor_ch: Sender<MonitorMsg>) {
965
966     let TestDescAndFn {desc, testfn} = test;
967
968     if force_ignore || desc.ignore {
969         monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap();
970         return;
971     }
972
973     fn run_test_inner(desc: TestDesc,
974                       monitor_ch: Sender<MonitorMsg>,
975                       nocapture: bool,
976                       testfn: Box<FnBox() + Send>) {
977         struct Sink(Arc<Mutex<Vec<u8>>>);
978         impl Write for Sink {
979             fn write(&mut self, data: &[u8]) -> io::Result<usize> {
980                 Write::write(&mut *self.0.lock().unwrap(), data)
981             }
982             fn flush(&mut self) -> io::Result<()> { Ok(()) }
983         }
984
985         thread::spawn(move || {
986             let data = Arc::new(Mutex::new(Vec::new()));
987             let data2 = data.clone();
988             let cfg = thread::Builder::new().name(match desc.name {
989                 DynTestName(ref name) => name.clone().to_string(),
990                 StaticTestName(name) => name.to_string(),
991             });
992
993             let result_guard = cfg.spawn(move || {
994                 if !nocapture {
995                     io::set_print(box Sink(data2.clone()));
996                     io::set_panic(box Sink(data2));
997                 }
998                 testfn()
999             }).unwrap();
1000             let test_result = calc_result(&desc, result_guard.join());
1001             let stdout = data.lock().unwrap().to_vec();
1002             monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
1003         });
1004     }
1005
1006     match testfn {
1007         DynBenchFn(bencher) => {
1008             let bs = ::bench::benchmark(|harness| bencher.run(harness));
1009             monitor_ch.send((desc, TrBench(bs), Vec::new())).unwrap();
1010             return;
1011         }
1012         StaticBenchFn(benchfn) => {
1013             let bs = ::bench::benchmark(|harness| (benchfn.clone())(harness));
1014             monitor_ch.send((desc, TrBench(bs), Vec::new())).unwrap();
1015             return;
1016         }
1017         DynMetricFn(f) => {
1018             let mut mm = MetricMap::new();
1019             f.call_box((&mut mm,));
1020             monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap();
1021             return;
1022         }
1023         StaticMetricFn(f) => {
1024             let mut mm = MetricMap::new();
1025             f(&mut mm);
1026             monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap();
1027             return;
1028         }
1029         DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f),
1030         StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture,
1031                                           Box::new(move|| f()))
1032     }
1033 }
1034
1035 fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any+Send>>) -> TestResult {
1036     match (&desc.should_panic, task_result) {
1037         (&ShouldPanic::No, Ok(())) |
1038         (&ShouldPanic::Yes(None), Err(_)) => TrOk,
1039         (&ShouldPanic::Yes(Some(msg)), Err(ref err))
1040             if err.downcast_ref::<String>()
1041                 .map(|e| &**e)
1042                 .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
1043                 .map(|e| e.contains(msg))
1044                 .unwrap_or(false) => TrOk,
1045         _ => TrFailed,
1046     }
1047 }
1048
1049 impl MetricMap {
1050
1051     pub fn new() -> MetricMap {
1052         MetricMap(BTreeMap::new())
1053     }
1054
1055     /// Insert a named `value` (+/- `noise`) metric into the map. The value
1056     /// must be non-negative. The `noise` indicates the uncertainty of the
1057     /// metric, which doubles as the "noise range" of acceptable
1058     /// pairwise-regressions on this named value, when comparing from one
1059     /// metric to the next using `compare_to_old`.
1060     ///
1061     /// If `noise` is positive, then it means this metric is of a value
1062     /// you want to see grow smaller, so a change larger than `noise` in the
1063     /// positive direction represents a regression.
1064     ///
1065     /// If `noise` is negative, then it means this metric is of a value
1066     /// you want to see grow larger, so a change larger than `noise` in the
1067     /// negative direction represents a regression.
1068     pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
1069         let m = Metric {
1070             value: value,
1071             noise: noise
1072         };
1073         let MetricMap(ref mut map) = *self;
1074         map.insert(name.to_string(), m);
1075     }
1076
1077     pub fn fmt_metrics(&self) -> String {
1078         let MetricMap(ref mm) = *self;
1079         let v : Vec<String> = mm.iter()
1080             .map(|(k,v)| format!("{}: {} (+/- {})", *k,
1081                                  v.value, v.noise))
1082             .collect();
1083         v.join(", ")
1084     }
1085 }
1086
1087
1088 // Benchmarking
1089
1090 /// A function that is opaque to the optimizer, to allow benchmarks to
1091 /// pretend to use outputs to assist in avoiding dead-code
1092 /// elimination.
1093 ///
1094 /// This function is a no-op, and does not even read from `dummy`.
1095 pub fn black_box<T>(dummy: T) -> T {
1096     // we need to "use" the argument in some way LLVM can't
1097     // introspect.
1098     unsafe {asm!("" : : "r"(&dummy))}
1099     dummy
1100 }
1101
1102
1103 impl Bencher {
1104     /// Callback for benchmark functions to run in their body.
1105     pub fn iter<T, F>(&mut self, mut inner: F) where F: FnMut() -> T {
1106         self.dur = Duration::span(|| {
1107             let k = self.iterations;
1108             for _ in 0..k {
1109                 black_box(inner());
1110             }
1111         });
1112     }
1113
1114     pub fn ns_elapsed(&mut self) -> u64 {
1115         self.dur.secs() * 1_000_000_000 + (self.dur.extra_nanos() as u64)
1116     }
1117
1118     pub fn ns_per_iter(&mut self) -> u64 {
1119         if self.iterations == 0 {
1120             0
1121         } else {
1122             self.ns_elapsed() / cmp::max(self.iterations, 1)
1123         }
1124     }
1125
1126     pub fn bench_n<F>(&mut self, n: u64, f: F) where F: FnOnce(&mut Bencher) {
1127         self.iterations = n;
1128         f(self);
1129     }
1130
1131     // This is a more statistics-driven benchmark algorithm
1132     pub fn auto_bench<F>(&mut self, mut f: F) -> stats::Summary where F: FnMut(&mut Bencher) {
1133         // Initial bench run to get ballpark figure.
1134         let mut n = 1;
1135         self.bench_n(n, |x| f(x));
1136
1137         // Try to estimate iter count for 1ms falling back to 1m
1138         // iterations if first run took < 1ns.
1139         if self.ns_per_iter() == 0 {
1140             n = 1_000_000;
1141         } else {
1142             n = 1_000_000 / cmp::max(self.ns_per_iter(), 1);
1143         }
1144         // if the first run took more than 1ms we don't want to just
1145         // be left doing 0 iterations on every loop. The unfortunate
1146         // side effect of not being able to do as many runs is
1147         // automatically handled by the statistical analysis below
1148         // (i.e. larger error bars).
1149         if n == 0 { n = 1; }
1150
1151         let mut total_run = Duration::new(0, 0);
1152         let samples : &mut [f64] = &mut [0.0_f64; 50];
1153         loop {
1154             let mut summ = None;
1155             let mut summ5 = None;
1156
1157             let loop_run = Duration::span(|| {
1158
1159                 for p in &mut *samples {
1160                     self.bench_n(n, |x| f(x));
1161                     *p = self.ns_per_iter() as f64;
1162                 };
1163
1164                 stats::winsorize(samples, 5.0);
1165                 summ = Some(stats::Summary::new(samples));
1166
1167                 for p in &mut *samples {
1168                     self.bench_n(5 * n, |x| f(x));
1169                     *p = self.ns_per_iter() as f64;
1170                 };
1171
1172                 stats::winsorize(samples, 5.0);
1173                 summ5 = Some(stats::Summary::new(samples));
1174             });
1175             let summ = summ.unwrap();
1176             let summ5 = summ5.unwrap();
1177
1178             // If we've run for 100ms and seem to have converged to a
1179             // stable median.
1180             if loop_run > Duration::from_millis(100) &&
1181                 summ.median_abs_dev_pct < 1.0 &&
1182                 summ.median - summ5.median < summ5.median_abs_dev {
1183                 return summ5;
1184             }
1185
1186             total_run = total_run + loop_run;
1187             // Longest we ever run for is 3s.
1188             if total_run > Duration::from_secs(3) {
1189                 return summ5;
1190             }
1191
1192             // If we overflow here just return the results so far. We check a
1193             // multiplier of 10 because we're about to multiply by 2 and the
1194             // next iteration of the loop will also multiply by 5 (to calculate
1195             // the summ5 result)
1196             n = match n.checked_mul(10) {
1197                 Some(_) => n * 2,
1198                 None => return summ5,
1199             };
1200         }
1201     }
1202 }
1203
1204 pub mod bench {
1205     use std::cmp;
1206     use std::time::Duration;
1207     use super::{Bencher, BenchSamples};
1208
1209     pub fn benchmark<F>(f: F) -> BenchSamples where F: FnMut(&mut Bencher) {
1210         let mut bs = Bencher {
1211             iterations: 0,
1212             dur: Duration::new(0, 0),
1213             bytes: 0
1214         };
1215
1216         let ns_iter_summ = bs.auto_bench(f);
1217
1218         let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
1219         let iter_s = 1_000_000_000 / ns_iter;
1220         let mb_s = (bs.bytes * iter_s) / 1_000_000;
1221
1222         BenchSamples {
1223             ns_iter_summ: ns_iter_summ,
1224             mb_s: mb_s as usize
1225         }
1226     }
1227
1228     pub fn run_once<F>(f: F) where F: FnOnce(&mut Bencher) {
1229         let mut bs = Bencher {
1230             iterations: 0,
1231             dur: Duration::new(0, 0),
1232             bytes: 0
1233         };
1234         bs.bench_n(1, f);
1235     }
1236 }
1237
1238 #[cfg(test)]
1239 mod tests {
1240     use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts,
1241                TestDesc, TestDescAndFn, TestOpts, run_test,
1242                MetricMap,
1243                StaticTestName, DynTestName, DynTestFn, ShouldPanic};
1244     use std::sync::mpsc::channel;
1245
1246     #[test]
1247     pub fn do_not_run_ignored_tests() {
1248         fn f() { panic!(); }
1249         let desc = TestDescAndFn {
1250             desc: TestDesc {
1251                 name: StaticTestName("whatever"),
1252                 ignore: true,
1253                 should_panic: ShouldPanic::No,
1254             },
1255             testfn: DynTestFn(Box::new(move|| f())),
1256         };
1257         let (tx, rx) = channel();
1258         run_test(&TestOpts::new(), false, desc, tx);
1259         let (_, res, _) = rx.recv().unwrap();
1260         assert!(res != TrOk);
1261     }
1262
1263     #[test]
1264     pub fn ignored_tests_result_in_ignored() {
1265         fn f() { }
1266         let desc = TestDescAndFn {
1267             desc: TestDesc {
1268                 name: StaticTestName("whatever"),
1269                 ignore: true,
1270                 should_panic: ShouldPanic::No,
1271             },
1272             testfn: DynTestFn(Box::new(move|| f())),
1273         };
1274         let (tx, rx) = channel();
1275         run_test(&TestOpts::new(), false, desc, tx);
1276         let (_, res, _) = rx.recv().unwrap();
1277         assert!(res == TrIgnored);
1278     }
1279
1280     #[test]
1281     fn test_should_panic() {
1282         fn f() { panic!(); }
1283         let desc = TestDescAndFn {
1284             desc: TestDesc {
1285                 name: StaticTestName("whatever"),
1286                 ignore: false,
1287                 should_panic: ShouldPanic::Yes(None)
1288             },
1289             testfn: DynTestFn(Box::new(move|| f())),
1290         };
1291         let (tx, rx) = channel();
1292         run_test(&TestOpts::new(), false, desc, tx);
1293         let (_, res, _) = rx.recv().unwrap();
1294         assert!(res == TrOk);
1295     }
1296
1297     #[test]
1298     fn test_should_panic_good_message() {
1299         fn f() { panic!("an error message"); }
1300         let desc = TestDescAndFn {
1301             desc: TestDesc {
1302                 name: StaticTestName("whatever"),
1303                 ignore: false,
1304                 should_panic: ShouldPanic::Yes(Some("error message"))
1305             },
1306             testfn: DynTestFn(Box::new(move|| f())),
1307         };
1308         let (tx, rx) = channel();
1309         run_test(&TestOpts::new(), false, desc, tx);
1310         let (_, res, _) = rx.recv().unwrap();
1311         assert!(res == TrOk);
1312     }
1313
1314     #[test]
1315     fn test_should_panic_bad_message() {
1316         fn f() { panic!("an error message"); }
1317         let desc = TestDescAndFn {
1318             desc: TestDesc {
1319                 name: StaticTestName("whatever"),
1320                 ignore: false,
1321                 should_panic: ShouldPanic::Yes(Some("foobar"))
1322             },
1323             testfn: DynTestFn(Box::new(move|| f())),
1324         };
1325         let (tx, rx) = channel();
1326         run_test(&TestOpts::new(), false, desc, tx);
1327         let (_, res, _) = rx.recv().unwrap();
1328         assert!(res == TrFailed);
1329     }
1330
1331     #[test]
1332     fn test_should_panic_but_succeeds() {
1333         fn f() { }
1334         let desc = TestDescAndFn {
1335             desc: TestDesc {
1336                 name: StaticTestName("whatever"),
1337                 ignore: false,
1338                 should_panic: ShouldPanic::Yes(None)
1339             },
1340             testfn: DynTestFn(Box::new(move|| f())),
1341         };
1342         let (tx, rx) = channel();
1343         run_test(&TestOpts::new(), false, desc, tx);
1344         let (_, res, _) = rx.recv().unwrap();
1345         assert!(res == TrFailed);
1346     }
1347
1348     #[test]
1349     fn parse_ignored_flag() {
1350         let args = vec!("progname".to_string(),
1351                         "filter".to_string(),
1352                         "--ignored".to_string());
1353         let opts = match parse_opts(&args) {
1354             Some(Ok(o)) => o,
1355             _ => panic!("Malformed arg in parse_ignored_flag")
1356         };
1357         assert!((opts.run_ignored));
1358     }
1359
1360     #[test]
1361     pub fn filter_for_ignored_option() {
1362         // When we run ignored tests the test filter should filter out all the
1363         // unignored tests and flip the ignore flag on the rest to false
1364
1365         let mut opts = TestOpts::new();
1366         opts.run_tests = true;
1367         opts.run_ignored = true;
1368
1369         let tests = vec!(
1370             TestDescAndFn {
1371                 desc: TestDesc {
1372                     name: StaticTestName("1"),
1373                     ignore: true,
1374                     should_panic: ShouldPanic::No,
1375                 },
1376                 testfn: DynTestFn(Box::new(move|| {})),
1377             },
1378             TestDescAndFn {
1379                 desc: TestDesc {
1380                     name: StaticTestName("2"),
1381                     ignore: false,
1382                     should_panic: ShouldPanic::No,
1383                 },
1384                 testfn: DynTestFn(Box::new(move|| {})),
1385             });
1386         let filtered = filter_tests(&opts, tests);
1387
1388         assert_eq!(filtered.len(), 1);
1389         assert_eq!(filtered[0].desc.name.to_string(),
1390                    "1");
1391         assert!(filtered[0].desc.ignore == false);
1392     }
1393
1394     #[test]
1395     pub fn sort_tests() {
1396         let mut opts = TestOpts::new();
1397         opts.run_tests = true;
1398
1399         let names =
1400             vec!("sha1::test".to_string(),
1401                  "isize::test_to_str".to_string(),
1402                  "isize::test_pow".to_string(),
1403                  "test::do_not_run_ignored_tests".to_string(),
1404                  "test::ignored_tests_result_in_ignored".to_string(),
1405                  "test::first_free_arg_should_be_a_filter".to_string(),
1406                  "test::parse_ignored_flag".to_string(),
1407                  "test::filter_for_ignored_option".to_string(),
1408                  "test::sort_tests".to_string());
1409         let tests =
1410         {
1411             fn testfn() { }
1412             let mut tests = Vec::new();
1413             for name in &names {
1414                 let test = TestDescAndFn {
1415                     desc: TestDesc {
1416                         name: DynTestName((*name).clone()),
1417                         ignore: false,
1418                         should_panic: ShouldPanic::No,
1419                     },
1420                     testfn: DynTestFn(Box::new(testfn)),
1421                 };
1422                 tests.push(test);
1423             }
1424             tests
1425         };
1426         let filtered = filter_tests(&opts, tests);
1427
1428         let expected =
1429             vec!("isize::test_pow".to_string(),
1430                  "isize::test_to_str".to_string(),
1431                  "sha1::test".to_string(),
1432                  "test::do_not_run_ignored_tests".to_string(),
1433                  "test::filter_for_ignored_option".to_string(),
1434                  "test::first_free_arg_should_be_a_filter".to_string(),
1435                  "test::ignored_tests_result_in_ignored".to_string(),
1436                  "test::parse_ignored_flag".to_string(),
1437                  "test::sort_tests".to_string());
1438
1439         for (a, b) in expected.iter().zip(filtered) {
1440             assert!(*a == b.desc.name.to_string());
1441         }
1442     }
1443
1444     #[test]
1445     pub fn test_metricmap_compare() {
1446         let mut m1 = MetricMap::new();
1447         let mut m2 = MetricMap::new();
1448         m1.insert_metric("in-both-noise", 1000.0, 200.0);
1449         m2.insert_metric("in-both-noise", 1100.0, 200.0);
1450
1451         m1.insert_metric("in-first-noise", 1000.0, 2.0);
1452         m2.insert_metric("in-second-noise", 1000.0, 2.0);
1453
1454         m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
1455         m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
1456
1457         m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
1458         m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
1459
1460         m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
1461         m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
1462
1463         m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
1464         m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
1465     }
1466 }