about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-07-29 19:54:05 -0700
committerBrian Anderson <banderson@mozilla.com>2011-07-29 19:54:05 -0700
commitb8c209cba1038c64dea98d46b35b4bde30316dff (patch)
tree68db00e92eb55c4aaed0cc37a68cc654925312c6 /src/lib
parent4e6bb137fe89674e8f41f85a56e63444a8608231 (diff)
Refactor std::test
Separate the console output from the running of tests
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/test.rs178
1 files changed, 108 insertions, 70 deletions
diff --git a/src/lib/test.rs b/src/lib/test.rs
index 7fc6ad4da13..d751cceb265 100644
--- a/src/lib/test.rs
+++ b/src/lib/test.rs
@@ -99,105 +99,143 @@ fn run_tests_console(opts: &test_opts, tests: &test_desc[]) -> bool {
 fn run_tests_console_(opts: &test_opts, tests: &test_desc[],
                       to_task: &test_to_task) -> bool {
 
-    let filtered_tests = filter_tests(opts, tests);
-
-    let out = io::stdout();
-
-    let total = ivec::len(filtered_tests);
-    out.write_line(#fmt("\nrunning %u tests", total));
-
-    let futures = ~[];
-
-    let passed = 0u;
-    let failed = 0u;
-    let ignored = 0u;
-
-    let failures = ~[];
-
-    // It's tempting to just spawn all the tests at once but that doesn't
-    // provide a great user experience because you might sit waiting for the
-    // result of a particular test for an unusually long amount of time.
-    let concurrency = get_concurrency();
-    log #fmt("using %u test tasks", concurrency);
-    let run_idx = 0u;
-    let wait_idx = 0u;
-
-    while wait_idx < total {
-        while ivec::len(futures) < concurrency && run_idx < total {
-            futures += ~[run_test(filtered_tests.(run_idx), to_task)];
-            run_idx += 1u;
-        }
-
-        let future = futures.(0);
-        out.write_str(#fmt("running %s ... ", future.test.name));
-        let result = future.wait();
-        alt result {
-          tr_ok. {
-            passed += 1u;
-            write_ok(out, concurrency);
-            out.write_line("");
-          }
-          tr_failed. {
-            failed += 1u;
-            write_failed(out, concurrency);
-            out.write_line("");
-            failures += ~[future.test];
+    type test_state = @{
+        out: io::writer,
+        use_color: bool,
+        mutable total: uint,
+        mutable passed: uint,
+        mutable failed: uint,
+        mutable ignored: uint,
+        mutable failures: test_desc[]
+    };
+
+    fn callback(event: testevent, st: test_state) {
+        alt event {
+          te_filtered(filtered_tests) {
+            st.total = ivec::len(filtered_tests);
+            st.out.write_line(#fmt("\nrunning %u tests", st.total));
           }
-          tr_ignored. {
-            ignored += 1u;
-            write_ignored(out, concurrency);
-            out.write_line("");
+          te_result(test, result) {
+            st.out.write_str(#fmt("test %s ... ", test.name));
+            alt result {
+              tr_ok. {
+                st.passed += 1u;
+                write_ok(st.out, st.use_color);
+                st.out.write_line("");
+              }
+              tr_failed. {
+                st.failed += 1u;
+                write_failed(st.out, st.use_color);
+                st.out.write_line("");
+                st.failures += ~[test];
+              }
+              tr_ignored. {
+                st.ignored += 1u;
+                write_ignored(st.out, st.use_color);
+                st.out.write_line("");
+              }
+            }
           }
         }
-        futures = ivec::slice(futures, 1u, ivec::len(futures));
-        wait_idx += 1u;
     }
 
-    assert (passed + failed + ignored == total);
-    let success = failed == 0u;
+    let st = @{
+        out: io::stdout(),
+        use_color: use_color(),
+        mutable total: 0u,
+        mutable passed: 0u,
+        mutable failed: 0u,
+        mutable ignored: 0u,
+        mutable failures: ~[]
+    };
+
+    run_tests(opts, tests, to_task,
+              bind callback(_, st));
+
+    assert st.passed + st.failed + st.ignored == st.total;
+    let success = st.failed == 0u;
 
     if !success {
-        out.write_line("\nfailures:");
-        for test: test_desc  in failures {
-            out.write_line(#fmt("    %s", test.name));
+        st.out.write_line("\nfailures:");
+        for test: test_desc in st.failures {
+            let testname = test.name; // Satisfy alias analysis
+            st.out.write_line(#fmt("    %s", testname));
         }
     }
 
-    out.write_str(#fmt("\nresult: "));
+    st.out.write_str(#fmt("\nresult: "));
     if success {
-        write_ok(out, concurrency);
-    } else { write_failed(out, concurrency); }
-    out.write_str(#fmt(". %u passed; %u failed; %u ignored\n\n", passed,
-                       failed, ignored));
+        write_ok(st.out, st.use_color);
+    } else { write_failed(st.out, st.use_color); }
+    st.out.write_str(#fmt(". %u passed; %u failed; %u ignored\n\n",
+                       st.passed, st.failed, st.ignored));
 
     ret success;
 
-    fn write_ok(out: &io::writer, concurrency: uint) {
-        write_pretty(out, "ok", term::color_green, concurrency);
+    fn write_ok(out: &io::writer, use_color: bool) {
+        write_pretty(out, "ok", term::color_green, use_color);
     }
 
-    fn write_failed(out: &io::writer, concurrency: uint) {
-        write_pretty(out, "FAILED", term::color_red, concurrency);
+    fn write_failed(out: &io::writer, use_color: bool) {
+        write_pretty(out, "FAILED", term::color_red, use_color);
     }
 
-    fn write_ignored(out: &io::writer, concurrency: uint) {
-        write_pretty(out, "ignored", term::color_yellow, concurrency);
+    fn write_ignored(out: &io::writer, use_color: bool) {
+        write_pretty(out, "ignored", term::color_yellow, use_color);
     }
 
     fn write_pretty(out: &io::writer, word: &str, color: u8,
-                    concurrency: uint) {
-        // In the presence of concurrency, outputing control characters
-        // can cause some crazy artifacting
-        if concurrency == 1u && term::color_supported() {
+                    use_color: bool) {
+        if use_color && term::color_supported() {
             term::fg(out.get_buf_writer(), color);
         }
         out.write_str(word);
-        if concurrency == 1u && term::color_supported() {
+        if use_color && term::color_supported() {
             term::reset(out.get_buf_writer());
         }
     }
 }
 
+fn use_color() -> bool {
+    ret get_concurrency() == 1u;
+}
+
+tag testevent {
+    te_filtered(test_desc[]);
+    te_result(test_desc, test_result);
+}
+
+fn run_tests(opts: &test_opts, tests: &test_desc[],
+             to_task: &test_to_task, callback: fn(testevent)) {
+
+    let filtered_tests = filter_tests(opts, tests);
+
+    callback(te_filtered(filtered_tests));
+
+    // It's tempting to just spawn all the tests at once but that doesn't
+    // provide a great user experience because you might sit waiting for the
+    // result of a particular test for an unusually long amount of time.
+    let concurrency = get_concurrency();
+    log #fmt("using %u test tasks", concurrency);
+    let total = ivec::len(filtered_tests);
+    let run_idx = 0u;
+    let wait_idx = 0u;
+    let futures = ~[];
+
+    while wait_idx < total {
+        while ivec::len(futures) < concurrency && run_idx < total {
+            futures += ~[run_test(filtered_tests.(run_idx), to_task)];
+            run_idx += 1u;
+        }
+
+        let future = futures.(0);
+        let result = future.wait();
+        callback(te_result(future.test, result));
+        futures = ivec::slice(futures, 1u, ivec::len(futures));
+        wait_idx += 1u;
+    }
+}
+
 fn get_concurrency() -> uint {
     alt getenv("RUST_THREADS") {
       option::some(t) {