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.
This commit is contained in:
parent
49da7da441
commit
b3dee95514
@ -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_,
|
||||
|
@ -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;
|
||||
|
@ -2,6 +2,7 @@ use std;
|
||||
|
||||
mod sha1;
|
||||
mod int;
|
||||
mod test;
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
36
src/test/stdtest/test.rs
Normal file
36
src/test/stdtest/test.rs
Normal file
@ -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:
|
Loading…
Reference in New Issue
Block a user