about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2013-07-09 17:18:02 -0700
committerGraydon Hoare <graydon@mozilla.com>2013-07-11 13:15:52 -0700
commit8614d1694cda26118c2f44a2acd986f137935816 (patch)
tree8849549fa24bf5f9253d14b8068f17561ec0b1dd
parentbf1f69c1565acfb33ea02389e2c6d6c87ee63e3a (diff)
downloadrust-8614d1694cda26118c2f44a2acd986f137935816.tar.gz
rust-8614d1694cda26118c2f44a2acd986f137935816.zip
extra: factor ConsoleTestState methods into an impl, fix perf bug.
It was re-reading terminfo on each line of output.
-rw-r--r--src/libextra/test.rs287
1 files changed, 148 insertions, 139 deletions
diff --git a/src/libextra/test.rs b/src/libextra/test.rs
index 14de7d0c21d..6ef03744366 100644
--- a/src/libextra/test.rs
+++ b/src/libextra/test.rs
@@ -31,7 +31,6 @@ use std::result;
 use std::task;
 use std::to_str::ToStr;
 use std::u64;
-use std::uint;
 
 
 // The name of a test. By convention this follows the rules for rust
@@ -191,6 +190,7 @@ pub enum TestResult { TrOk, TrFailed, TrIgnored, TrBench(BenchSamples) }
 struct ConsoleTestState {
     out: @io::Writer,
     log_out: Option<@io::Writer>,
+    term: Option<term::Terminal>,
     use_color: bool,
     total: uint,
     passed: uint,
@@ -200,171 +200,180 @@ struct ConsoleTestState {
     failures: ~[TestDesc]
 }
 
-// A simple console test runner
-pub fn run_tests_console(opts: &TestOpts,
-                         tests: ~[TestDescAndFn]) -> bool {
-    fn callback(event: &TestEvent, st: &mut ConsoleTestState) {
-        debug!("callback(event=%?)", event);
-        match copy *event {
-          TeFiltered(ref filtered_tests) => {
-            st.total = filtered_tests.len();
-            let noun = if st.total != 1 { ~"tests" } else { ~"test" };
-            st.out.write_line(fmt!("\nrunning %u %s", st.total, noun));
-          }
-          TeWait(ref test) => st.out.write_str(
-              fmt!("test %s ... ", test.name.to_str())),
-          TeResult(test, result) => {
-            match st.log_out {
-                Some(f) => write_log(f, copy result, &test),
-                None => ()
-            }
-            match result {
-              TrOk => {
-                st.passed += 1;
-                write_ok(st.out, st.use_color);
-                st.out.write_line("");
-              }
-              TrFailed => {
-                st.failed += 1;
-                write_failed(st.out, st.use_color);
-                st.out.write_line("");
-                st.failures.push(test);
-              }
-              TrIgnored => {
-                st.ignored += 1;
-                write_ignored(st.out, st.use_color);
-                st.out.write_line("");
-              }
-              TrBench(bs) => {
-                st.benchmarked += 1u;
-                write_bench(st.out, st.use_color);
-                st.out.write_line(fmt!(": %s",
-                                       fmt_bench_samples(&bs)));
-              }
-            }
-          }
+impl ConsoleTestState {
+    pub fn new(opts: &TestOpts) -> ConsoleTestState {
+        let log_out = match opts.logfile {
+            Some(ref path) => match io::file_writer(path,
+                                                    [io::Create,
+                                                     io::Truncate]) {
+                result::Ok(w) => Some(w),
+                result::Err(ref s) => {
+                    fail!("can't open output file: %s", *s)
+                }
+            },
+            None => None
+        };
+        let out = io::stdout();
+        let term = match term::Terminal::new(out) {
+            Err(_) => None,
+            Ok(t) => Some(t)
+        };
+        ConsoleTestState {
+            out: out,
+            log_out: log_out,
+            use_color: use_color(),
+            term: term,
+            total: 0u,
+            passed: 0u,
+            failed: 0u,
+            ignored: 0u,
+            benchmarked: 0u,
+            failures: ~[]
         }
     }
 
-    let log_out = match opts.logfile {
-        Some(ref path) => match io::file_writer(path,
-                                                [io::Create,
-                                                 io::Truncate]) {
-          result::Ok(w) => Some(w),
-          result::Err(ref s) => {
-              fail!("can't open output file: %s", *s)
-          }
-        },
-        None => None
-    };
-
-    let st = @mut ConsoleTestState {
-        out: io::stdout(),
-        log_out: log_out,
-        use_color: use_color(),
-        total: 0u,
-        passed: 0u,
-        failed: 0u,
-        ignored: 0u,
-        benchmarked: 0u,
-        failures: ~[]
-    };
-
-    run_tests(opts, tests, |x| callback(&x, st));
-
-    assert!(st.passed + st.failed +
-                 st.ignored + st.benchmarked == st.total);
-    let success = st.failed == 0u;
+    pub fn write_ok(&self) {
+        self.write_pretty("ok", term::color::GREEN);
+    }
 
-    if !success {
-        print_failures(st);
+    pub fn write_failed(&self) {
+        self.write_pretty("FAILED", term::color::RED);
     }
 
-    {
-      let st: &mut ConsoleTestState = st;
-      st.out.write_str(fmt!("\nresult: "));
-      if success {
-          // There's no parallelism at this point so it's safe to use color
-          write_ok(st.out, true);
-      } else {
-          write_failed(st.out, true);
-      }
-      st.out.write_str(fmt!(". %u passed; %u failed; %u ignored\n\n",
-                            st.passed, st.failed, st.ignored));
+    pub fn write_ignored(&self) {
+        self.write_pretty("ignored", term::color::YELLOW);
     }
 
-    return success;
+    pub fn write_bench(&self) {
+        self.write_pretty("bench", term::color::CYAN);
+    }
 
-    fn fmt_bench_samples(bs: &BenchSamples) -> ~str {
-        if bs.mb_s != 0 {
-            fmt!("%u ns/iter (+/- %u) = %u MB/s",
-                 bs.ns_iter_summ.median as uint,
-                 (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as uint,
-                 bs.mb_s)
-        } else {
-            fmt!("%u ns/iter (+/- %u)",
-                 bs.ns_iter_summ.median as uint,
-                 (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as uint)
+    pub fn write_pretty(&self,
+                        word: &str,
+                        color: term::color::Color) {
+        match self.term {
+            None => self.out.write_str(word),
+            Some(ref t) => {
+                if self.use_color {
+                    t.fg(color);
+                }
+                self.out.write_str(word);
+                if self.use_color {
+                    t.reset();
+                }
+            }
         }
     }
 
-    fn write_log(out: @io::Writer, result: TestResult, test: &TestDesc) {
-        out.write_line(fmt!("%s %s",
-                    match result {
-                        TrOk => ~"ok",
-                        TrFailed => ~"failed",
-                        TrIgnored => ~"ignored",
-                        TrBench(ref bs) => fmt_bench_samples(bs)
-                    }, test.name.to_str()));
+    pub fn write_run_start(&mut self, len: uint) {
+        self.total = len;
+        let noun = if len != 1 { &"tests" } else { &"test" };
+        self.out.write_line(fmt!("\nrunning %u %s", len, noun));
     }
 
-    fn write_ok(out: @io::Writer, use_color: bool) {
-        write_pretty(out, "ok", term::color::GREEN, use_color);
+    pub fn write_test_start(&self, test: &TestDesc) {
+        self.out.write_str(fmt!("test %s ... ", test.name.to_str()));
     }
 
-    fn write_failed(out: @io::Writer, use_color: bool) {
-        write_pretty(out, "FAILED", term::color::RED, use_color);
+    pub fn write_result(&self, result: &TestResult) {
+        match *result {
+            TrOk => self.write_ok(),
+            TrFailed => self.write_failed(),
+            TrIgnored => self.write_ignored(),
+            TrBench(ref bs) => {
+                self.write_bench();
+                self.out.write_str(": " + fmt_bench_samples(bs))
+            }
+        }
+        self.out.write_str(&"\n");
+    }
+
+    pub fn write_log(&self, test: &TestDesc, result: &TestResult) {
+        match self.log_out {
+            None => (),
+            Some(out) => {
+                out.write_line(fmt!("%s %s",
+                                    match *result {
+                                        TrOk => ~"ok",
+                                        TrFailed => ~"failed",
+                                        TrIgnored => ~"ignored",
+                                        TrBench(ref bs) => fmt_bench_samples(bs)
+                                    }, test.name.to_str()));
+            }
+        }
     }
 
-    fn write_ignored(out: @io::Writer, use_color: bool) {
-        write_pretty(out, "ignored", term::color::YELLOW, use_color);
+    pub fn write_failures(&self) {
+        self.out.write_line("\nfailures:");
+        let mut failures = ~[];
+        for self.failures.iter().advance() |f| {
+            failures.push(f.name.to_str());
+        }
+        sort::tim_sort(failures);
+        for failures.iter().advance |name| {
+            self.out.write_line(fmt!("    %s", name.to_str()));
+        }
     }
 
-    fn write_bench(out: @io::Writer, use_color: bool) {
-        write_pretty(out, "bench", term::color::CYAN, use_color);
-    }
+    pub fn write_run_finish(&self) -> bool {
+        assert!(self.passed + self.failed + self.ignored + self.benchmarked == self.total);
+        let success = self.failed == 0u;
+        if !success {
+            self.write_failures();
+        }
 
-    fn write_pretty(out: @io::Writer,
-                    word: &str,
-                    color: term::color::Color,
-                    use_color: bool) {
-        let t = term::Terminal::new(out);
-        match t {
-            Ok(term)  => {
-                if use_color {
-                    term.fg(color);
-                }
-                out.write_str(word);
-                if use_color {
-                    term.reset();
-                }
-            },
-            Err(_) => out.write_str(word)
+        self.out.write_str("\nresult: ");
+        if success {
+            // There's no parallelism at this point so it's safe to use color
+            self.write_ok();
+        } else {
+            self.write_failed();
         }
+        self.out.write_str(fmt!(". %u passed; %u failed; %u ignored, %u benchmarked\n\n",
+                                self.passed, self.failed, self.ignored, self.benchmarked));
+        return success;
     }
 }
 
-fn print_failures(st: &ConsoleTestState) {
-    st.out.write_line("\nfailures:");
-    let mut failures = ~[];
-    for uint::range(0, st.failures.len()) |i| {
-        let name = copy st.failures[i].name;
-        failures.push(name.to_str());
+pub fn fmt_bench_samples(bs: &BenchSamples) -> ~str {
+    if bs.mb_s != 0 {
+        fmt!("%u ns/iter (+/- %u) = %u MB/s",
+             bs.ns_iter_summ.median as uint,
+             (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as uint,
+             bs.mb_s)
+    } else {
+        fmt!("%u ns/iter (+/- %u)",
+             bs.ns_iter_summ.median as uint,
+             (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as uint)
     }
-    sort::tim_sort(failures);
-    for failures.iter().advance |name| {
-        st.out.write_line(fmt!("    %s", name.to_str()));
+}
+
+// A simple console test runner
+pub fn run_tests_console(opts: &TestOpts,
+                         tests: ~[TestDescAndFn]) -> bool {
+    fn callback(event: &TestEvent, st: &mut ConsoleTestState) {
+        debug!("callback(event=%?)", event);
+        match copy *event {
+            TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
+            TeWait(ref test) => st.write_test_start(test),
+            TeResult(test, result) => {
+                st.write_log(&test, &result);
+                st.write_result(&result);
+                match result {
+                    TrOk => st.passed += 1,
+                    TrIgnored => st.ignored += 1,
+                    TrBench(_) => st.benchmarked += 1,
+                    TrFailed => {
+                        st.failed += 1;
+                        st.failures.push(test);
+                    }
+                }
+            }
+        }
     }
+    let st = @mut ConsoleTestState::new(opts);
+    run_tests(opts, tests, |x| callback(&x, st));
+    return st.write_run_finish();
 }
 
 #[test]