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