From 20e94de3925af29bd73a0f0f0b0706da72271115 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 14 Jul 2011 16:05:33 -0700 Subject: Add a flag to run ignored tests. Issue #428 --- src/lib/getopts.rs | 1 + src/lib/test.rs | 100 ++++++++++++++++++++++++++++++++++++----------- src/test/stdtest/test.rs | 40 +++++++++++++++++++ 3 files changed, 119 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/lib/getopts.rs b/src/lib/getopts.rs index bdcfbea3b28..7ce3355b205 100644 --- a/src/lib/getopts.rs +++ b/src/lib/getopts.rs @@ -17,6 +17,7 @@ export optflag; export optflagopt; export optmulti; export getopts; +export getopts_ivec; export result; export success; export failure; diff --git a/src/lib/test.rs b/src/lib/test.rs index 037206b39f3..cfca12480a1 100644 --- a/src/lib/test.rs +++ b/src/lib/test.rs @@ -8,10 +8,13 @@ export test_fn; export test_desc; export test_main; export test_result; +export test_opts; export tr_ok; export tr_failed; export tr_ignored; export run_test; +export filter_tests; +export parse_opts; // 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 @@ -34,19 +37,52 @@ type test_desc = rec(test_name name, // The default console test runner. It accepts the command line // arguments and a vector of test_descs (generated at compile time). fn test_main(&vec[str] args, &test_desc[] tests) { - if (!run_tests(parse_opts(args), tests)) { + auto ivec_args = { + auto iargs = ~[]; + for (str arg in args) { + iargs += ~[arg] + } + iargs + }; + check ivec::is_not_empty(ivec_args); + auto opts = alt (parse_opts(ivec_args)) { + either::left(?o) { o } + either::right(?m) { fail m } + }; + if (!run_tests(opts, tests)) { fail "Some tests failed"; } } -type test_opts = rec(option::t[str] filter); +type test_opts = rec(option::t[str] filter, + bool run_ignored); + +type opt_res = either::t[test_opts, str]; + +// Parses command line arguments into test options +fn parse_opts(&str[] args) : ivec::is_not_empty(args) -> opt_res { + + // FIXME (#649): Shouldn't have to check here + check ivec::is_not_empty(args); + auto args_ = ivec::tail(args); + auto opts = ~[getopts::optflag("ignored")]; + auto match = alt (getopts::getopts_ivec(args_, opts)) { + getopts::success(?m) { m } + getopts::failure(?f) { ret either::right(getopts::fail_str(f)) } + }; + + auto filter = if (vec::len(match.free) > 0u) { + option::some(match.free.(0)) + } else { + option::none + }; + + auto run_ignored = getopts::opt_present(match, "ignored"); + + auto test_opts = rec(filter = filter, + run_ignored = run_ignored); -fn parse_opts(&vec[str] args) -> test_opts { - rec(filter = if (vec::len(args) > 1u) { - option::some(args.(1)) - } else { - option::none - }) + ret either::left(test_opts); } tag test_result { @@ -135,23 +171,43 @@ fn run_tests(&test_opts opts, &test_desc[] tests) -> bool { } fn filter_tests(&test_opts opts, &test_desc[] tests) -> test_desc[] { - if (option::is_none(opts.filter)) { - ret tests; - } + auto filtered = tests; - auto filter_str = alt opts.filter { option::some(?f) { f } - option::none { "" } }; + filtered = if (option::is_none(opts.filter)) { + filtered + } else { + auto filter_str = alt opts.filter { option::some(?f) { f } + option::none { "" } }; + + auto filter = bind fn(&test_desc test, + str filter_str) -> option::t[test_desc] { + if (str::find(test.name, filter_str) >= 0) { + ret option::some(test); + } else { + ret option::none; + } + } (_, filter_str); - auto filter = bind fn(&test_desc test, - str filter_str) -> option::t[test_desc] { - if (str::find(test.name, filter_str) >= 0) { - ret option::some(test); - } else { - ret option::none; - } - } (_, filter_str); + ivec::filter_map(filter, filtered) + }; + + filtered = if (!opts.run_ignored) { + filtered + } else { + auto filter = fn(&test_desc test) -> option::t[test_desc] { + if (test.ignore) { + ret option::some(rec(name = test.name, + fn = test.fn, + ignore = false)); + } else { + ret option::none; + } + }; + + ivec::filter_map(filter, filtered) + }; - ret ivec::filter_map(filter, tests); + ret filtered; } fn run_test(&test_desc test) -> test_result { diff --git a/src/test/stdtest/test.rs b/src/test/stdtest/test.rs index 17f18a5151e..0079a94522b 100644 --- a/src/test/stdtest/test.rs +++ b/src/test/stdtest/test.rs @@ -1,4 +1,8 @@ import std::test; +import std::str; +import std::option; +import std::either; +import std::ivec; #[test] fn do_not_run_ignored_tests() { @@ -26,6 +30,42 @@ fn ignored_tests_result_in_ignored() { assert res == test::tr_ignored; } +#[test] +fn first_free_arg_should_be_a_filter() { + auto args = ~["progname", "filter"]; + check ivec::is_not_empty(args); + auto opts = alt test::parse_opts(args) { either::left(?o) { o } }; + assert str::eq("filter", option::get(opts.filter)); +} + +#[test] +fn parse_ignored_flag() { + auto args = ~["progname", "filter", "--ignored"]; + check ivec::is_not_empty(args); + auto opts = alt test::parse_opts(args) { either::left(?o) { o } }; + assert opts.run_ignored; +} + +#[test] +fn filter_for_ignored_option() { + // When we run ignored tests the test filter should filter out all the + // unignored tests and flip the ignore flag on the rest to false + + auto opts = rec(filter = option::none, + run_ignored = true); + auto tests = ~[rec(name = "1", + fn = fn() {}, + ignore = true), + rec(name = "2", + fn = fn() {}, + ignore = false)]; + auto filtered = test::filter_tests(opts, tests); + + assert ivec::len(filtered) == 1u; + assert filtered.(0).name == "1"; + assert filtered.(0).ignore == false; +} + // Local Variables: // mode: rust; // fill-column: 78; -- cgit 1.4.1-3-g733a5