Skip to content

Commit 20e94de

Browse files
committed
Add a flag to run ignored tests. Issue #428
1 parent 81acf69 commit 20e94de

File tree

3 files changed

+119
-22
lines changed

3 files changed

+119
-22
lines changed

src/lib/getopts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export optflag;
1717
export optflagopt;
1818
export optmulti;
1919
export getopts;
20+
export getopts_ivec;
2021
export result;
2122
export success;
2223
export failure;

src/lib/test.rs

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ export test_fn;
88
export test_desc;
99
export test_main;
1010
export test_result;
11+
export test_opts;
1112
export tr_ok;
1213
export tr_failed;
1314
export tr_ignored;
1415
export run_test;
16+
export filter_tests;
17+
export parse_opts;
1518

1619
// The name of a test. By convention this follows the rules for rust
1720
// paths, i.e it should be a series of identifiers seperated by double
@@ -34,19 +37,52 @@ type test_desc = rec(test_name name,
3437
// The default console test runner. It accepts the command line
3538
// arguments and a vector of test_descs (generated at compile time).
3639
fn test_main(&vec[str] args, &test_desc[] tests) {
37-
if (!run_tests(parse_opts(args), tests)) {
40+
auto ivec_args = {
41+
auto iargs = ~[];
42+
for (str arg in args) {
43+
iargs += ~[arg]
44+
}
45+
iargs
46+
};
47+
check ivec::is_not_empty(ivec_args);
48+
auto opts = alt (parse_opts(ivec_args)) {
49+
either::left(?o) { o }
50+
either::right(?m) { fail m }
51+
};
52+
if (!run_tests(opts, tests)) {
3853
fail "Some tests failed";
3954
}
4055
}
4156

42-
type test_opts = rec(option::t[str] filter);
57+
type test_opts = rec(option::t[str] filter,
58+
bool run_ignored);
59+
60+
type opt_res = either::t[test_opts, str];
61+
62+
// Parses command line arguments into test options
63+
fn parse_opts(&str[] args) : ivec::is_not_empty(args) -> opt_res {
64+
65+
// FIXME (#649): Shouldn't have to check here
66+
check ivec::is_not_empty(args);
67+
auto args_ = ivec::tail(args);
68+
auto opts = ~[getopts::optflag("ignored")];
69+
auto match = alt (getopts::getopts_ivec(args_, opts)) {
70+
getopts::success(?m) { m }
71+
getopts::failure(?f) { ret either::right(getopts::fail_str(f)) }
72+
};
73+
74+
auto filter = if (vec::len(match.free) > 0u) {
75+
option::some(match.free.(0))
76+
} else {
77+
option::none
78+
};
79+
80+
auto run_ignored = getopts::opt_present(match, "ignored");
81+
82+
auto test_opts = rec(filter = filter,
83+
run_ignored = run_ignored);
4384

44-
fn parse_opts(&vec[str] args) -> test_opts {
45-
rec(filter = if (vec::len(args) > 1u) {
46-
option::some(args.(1))
47-
} else {
48-
option::none
49-
})
85+
ret either::left(test_opts);
5086
}
5187

5288
tag test_result {
@@ -135,23 +171,43 @@ fn run_tests(&test_opts opts, &test_desc[] tests) -> bool {
135171
}
136172

137173
fn filter_tests(&test_opts opts, &test_desc[] tests) -> test_desc[] {
138-
if (option::is_none(opts.filter)) {
139-
ret tests;
140-
}
174+
auto filtered = tests;
141175

142-
auto filter_str = alt opts.filter { option::some(?f) { f }
143-
option::none { "" } };
176+
filtered = if (option::is_none(opts.filter)) {
177+
filtered
178+
} else {
179+
auto filter_str = alt opts.filter { option::some(?f) { f }
180+
option::none { "" } };
181+
182+
auto filter = bind fn(&test_desc test,
183+
str filter_str) -> option::t[test_desc] {
184+
if (str::find(test.name, filter_str) >= 0) {
185+
ret option::some(test);
186+
} else {
187+
ret option::none;
188+
}
189+
} (_, filter_str);
144190

145-
auto filter = bind fn(&test_desc test,
146-
str filter_str) -> option::t[test_desc] {
147-
if (str::find(test.name, filter_str) >= 0) {
148-
ret option::some(test);
149-
} else {
150-
ret option::none;
151-
}
152-
} (_, filter_str);
191+
ivec::filter_map(filter, filtered)
192+
};
193+
194+
filtered = if (!opts.run_ignored) {
195+
filtered
196+
} else {
197+
auto filter = fn(&test_desc test) -> option::t[test_desc] {
198+
if (test.ignore) {
199+
ret option::some(rec(name = test.name,
200+
fn = test.fn,
201+
ignore = false));
202+
} else {
203+
ret option::none;
204+
}
205+
};
206+
207+
ivec::filter_map(filter, filtered)
208+
};
153209

154-
ret ivec::filter_map(filter, tests);
210+
ret filtered;
155211
}
156212

157213
fn run_test(&test_desc test) -> test_result {

src/test/stdtest/test.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import std::test;
2+
import std::str;
3+
import std::option;
4+
import std::either;
5+
import std::ivec;
26

37
#[test]
48
fn do_not_run_ignored_tests() {
@@ -26,6 +30,42 @@ fn ignored_tests_result_in_ignored() {
2630
assert res == test::tr_ignored;
2731
}
2832

33+
#[test]
34+
fn first_free_arg_should_be_a_filter() {
35+
auto args = ~["progname", "filter"];
36+
check ivec::is_not_empty(args);
37+
auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
38+
assert str::eq("filter", option::get(opts.filter));
39+
}
40+
41+
#[test]
42+
fn parse_ignored_flag() {
43+
auto args = ~["progname", "filter", "--ignored"];
44+
check ivec::is_not_empty(args);
45+
auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
46+
assert opts.run_ignored;
47+
}
48+
49+
#[test]
50+
fn filter_for_ignored_option() {
51+
// When we run ignored tests the test filter should filter out all the
52+
// unignored tests and flip the ignore flag on the rest to false
53+
54+
auto opts = rec(filter = option::none,
55+
run_ignored = true);
56+
auto tests = ~[rec(name = "1",
57+
fn = fn() {},
58+
ignore = true),
59+
rec(name = "2",
60+
fn = fn() {},
61+
ignore = false)];
62+
auto filtered = test::filter_tests(opts, tests);
63+
64+
assert ivec::len(filtered) == 1u;
65+
assert filtered.(0).name == "1";
66+
assert filtered.(0).ignore == false;
67+
}
68+
2969
// Local Variables:
3070
// mode: rust;
3171
// fill-column: 78;

0 commit comments

Comments
 (0)