about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-07-14 11:29:54 -0700
committerBrian Anderson <banderson@mozilla.com>2011-07-14 13:51:30 -0700
commitb3dee955144a722da50e17dde62cb36cbcccf73f (patch)
treec4fe653b9eaf9be74f48fac73406f77a427768e9
parent49da7da441716da2ae99b893907f0fbd1655d813 (diff)
downloadrust-b3dee955144a722da50e17dde62cb36cbcccf73f.tar.gz
rust-b3dee955144a722da50e17dde62cb36cbcccf73f.zip
Add a facility for ignoring tests. Issue #428
Adding the #[ignore] attribute will cause the test not to be run, though it
will still show up in the list of tests.
-rw-r--r--src/comp/front/test.rs39
-rw-r--r--src/lib/test.rs69
-rw-r--r--src/test/stdtest/stdtest.rc1
-rw-r--r--src/test/stdtest/test.rs36
4 files changed, 120 insertions, 25 deletions
diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs
index 939d2c717da..a0d1118bdd0 100644
--- a/src/comp/front/test.rs
+++ b/src/comp/front/test.rs
@@ -11,9 +11,12 @@ export modify_for_testing;
 
 type node_id_gen = @fn() -> ast::node_id;
 
+type test = rec(ast::ident[] path,
+                bool ignore);
+
 type test_ctxt = @rec(node_id_gen next_node_id,
                       mutable ast::ident[] path,
-                      mutable ast::ident[][] testfns);
+                      mutable test[] testfns);
 
 // Traverse the crate, collecting all the test functions, eliding any
 // existing main functions, and synthesizing a main test harness
@@ -88,7 +91,9 @@ fn fold_item(&test_ctxt cx, &@ast::item i,
 
     if (is_test_fn(i)) {
         log "this is a test function";
-        cx.testfns += ~[cx.path];
+        auto test = rec(path = cx.path,
+                        ignore = is_ignored(i));
+        cx.testfns += ~[test];
         log #fmt("have %u test functions", ivec::len(cx.testfns));
     }
 
@@ -116,6 +121,10 @@ fn is_test_fn(&@ast::item i) -> bool {
     ret has_test_attr && has_test_signature(i);
 }
 
+fn is_ignored(&@ast::item i) -> bool {
+    attr::contains_name(attr::attr_metas(i.attrs), "ignore")
+}
+
 fn add_test_module(&test_ctxt cx, &ast::_mod m) -> ast::_mod {
     auto testmod = mk_test_module(cx);
     ret rec(items=m.items + ~[testmod] with m);
@@ -225,10 +234,9 @@ fn mk_test_desc_vec(&test_ctxt cx) -> @ast::expr {
     log #fmt("building test vector from %u tests",
              ivec::len(cx.testfns));
     auto descs = ~[];
-    for (ast::ident[] testpath in cx.testfns) {
-        log #fmt("encoding %s", ast::path_name_i(testpath));
-        auto path = testpath;
-        descs += ~[mk_test_desc_rec(cx, path)];
+    for (test test in cx.testfns) {
+        auto test_ = test; // Satisfy alias analysis
+        descs += ~[mk_test_desc_rec(cx, test_)];
     }
 
     ret @rec(id = cx.next_node_id(),
@@ -236,7 +244,10 @@ fn mk_test_desc_vec(&test_ctxt cx) -> @ast::expr {
              span = rec(lo=0u,hi=0u));
 }
 
-fn mk_test_desc_rec(&test_ctxt cx, ast::ident[] path) -> @ast::expr {
+fn mk_test_desc_rec(&test_ctxt cx, test test) -> @ast::expr {
+    auto path = test.path;
+
+    log #fmt("encoding %s", ast::path_name_i(path));
 
     let ast::lit name_lit = nospan(ast::lit_str(ast::path_name_i(path),
                                                 ast::sk_rc));
@@ -260,7 +271,19 @@ fn mk_test_desc_rec(&test_ctxt cx, ast::ident[] path) -> @ast::expr {
                                          ident = "fn",
                                          expr = @fn_expr));
 
-    let ast::expr_ desc_rec_ = ast::expr_rec(~[name_field, fn_field],
+    let ast::lit ignore_lit = nospan(ast::lit_bool(test.ignore));
+
+    let ast::expr ignore_expr = rec(id = cx.next_node_id(),
+                                    node = ast::expr_lit(@ignore_lit),
+                                    span = rec(lo=0u, hi=0u));
+
+    let ast::field ignore_field = nospan(rec(mut = ast::imm,
+                                             ident = "ignore",
+                                             expr = @ignore_expr));
+
+    let ast::expr_ desc_rec_ = ast::expr_rec(~[name_field,
+                                               fn_field,
+                                               ignore_field],
                                              option::none);
     let ast::expr desc_rec = rec(id = cx.next_node_id(),
                                  node = desc_rec_,
diff --git a/src/lib/test.rs b/src/lib/test.rs
index ebf82b14d03..037206b39f3 100644
--- a/src/lib/test.rs
+++ b/src/lib/test.rs
@@ -7,6 +7,11 @@ export test_name;
 export test_fn;
 export test_desc;
 export test_main;
+export test_result;
+export tr_ok;
+export tr_failed;
+export tr_ignored;
+export run_test;
 
 // The name of a test. By convention this follows the rules for rust
 // paths, i.e it should be a series of identifiers seperated by double
@@ -23,7 +28,8 @@ type test_fn = fn();
 // The definition of a single test. A test runner will run a list of
 // these.
 type test_desc = rec(test_name name,
-                     test_fn fn);
+                     test_fn fn,
+                     bool ignore);
 
 // The default console test runner. It accepts the command line
 // arguments and a vector of test_descs (generated at compile time).
@@ -43,6 +49,12 @@ fn parse_opts(&vec[str] args) -> test_opts {
         })
 }
 
+tag test_result {
+    tr_ok;
+    tr_failed;
+    tr_ignored;
+}
+
 // A simple console test runner
 fn run_tests(&test_opts opts, &test_desc[] tests) -> bool {
 
@@ -55,21 +67,30 @@ fn run_tests(&test_opts opts, &test_desc[] tests) -> bool {
 
     auto passed = 0u;
     auto failed = 0u;
+    auto ignored = 0u;
 
     for (test_desc test in filtered_tests) {
         out.write_str(#fmt("running %s ... ", test.name));
-        if (run_test(test)) {
-            passed += 1u;
-            write_ok(out);
-            out.write_line("");
-        } else {
-            failed += 1u;
-            write_failed(out);
-            out.write_line("");
+        alt (run_test(test)) {
+            tr_ok {
+                passed += 1u;
+                write_ok(out);
+                out.write_line("");
+            }
+            tr_failed {
+                failed += 1u;
+                write_failed(out);
+                out.write_line("");
+            }
+            tr_ignored {
+                ignored += 1u;
+                write_ignored(out);
+                out.write_line("");
+            }
         }
     }
 
-    assert passed + failed == total;
+    assert passed + failed + ignored == total;
 
     out.write_str(#fmt("\nresult: "));
     if (failed == 0u) {
@@ -77,16 +98,11 @@ fn run_tests(&test_opts opts, &test_desc[] tests) -> bool {
     } else {
         write_failed(out);
     }
-    out.write_str(#fmt(". %u passed; %u failed\n\n",
-                       passed, failed));
+    out.write_str(#fmt(". %u passed; %u failed; %u ignored\n\n",
+                       passed, failed, ignored));
 
     ret true;
 
-    fn run_test(&test_desc test) -> bool {
-        test.fn();
-        ret true;
-    }
-
     fn write_ok(&io::writer out) {
         if (term::color_supported()) {
             term::fg(out.get_buf_writer(), term::color_green);
@@ -106,6 +122,16 @@ fn run_tests(&test_opts opts, &test_desc[] tests) -> bool {
             term::reset(out.get_buf_writer());
         }
     }
+
+    fn write_ignored(&io::writer out) {
+        if (term::color_supported()) {
+            term::fg(out.get_buf_writer(), term::color_yellow);
+        }
+        out.write_str("ignored");
+        if (term::color_supported()) {
+            term::reset(out.get_buf_writer());
+        }
+    }
 }
 
 fn filter_tests(&test_opts opts, &test_desc[] tests) -> test_desc[] {
@@ -128,6 +154,15 @@ fn filter_tests(&test_opts opts, &test_desc[] tests) -> test_desc[] {
     ret ivec::filter_map(filter, tests);
 }
 
+fn run_test(&test_desc test) -> test_result {
+    if (!test.ignore) {
+        test.fn();
+        ret tr_ok;
+    } else {
+        ret tr_ignored;
+    }
+}
+
 
 // Local Variables:
 // mode: rust;
diff --git a/src/test/stdtest/stdtest.rc b/src/test/stdtest/stdtest.rc
index ab455001b61..5bce1659179 100644
--- a/src/test/stdtest/stdtest.rc
+++ b/src/test/stdtest/stdtest.rc
@@ -2,6 +2,7 @@ use std;
 
 mod sha1;
 mod int;
+mod test;
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/test/stdtest/test.rs b/src/test/stdtest/test.rs
new file mode 100644
index 00000000000..17f18a5151e
--- /dev/null
+++ b/src/test/stdtest/test.rs
@@ -0,0 +1,36 @@
+import std::test;
+
+#[test]
+fn do_not_run_ignored_tests() {
+    auto ran = @mutable false;
+    auto f = bind fn(@mutable bool ran) {
+        *ran = true;
+    } (ran);
+
+    auto desc = rec(name = "whatever",
+                    fn = f,
+                    ignore = true);
+
+    auto res = test::run_test(desc);
+
+    assert ran == false;
+}
+
+#[test]
+fn ignored_tests_result_in_ignored() {
+    fn f() { }
+    auto desc = rec(name = "whatever",
+                    fn = f,
+                    ignore = true);
+    auto res = test::run_test(desc);
+    assert res == test::tr_ignored;
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End: