let opts = test_opts(config);
let cx = {config: config, procsrv: procsrv::mk()};
let tests = make_tests(cx);
- let res = test::run_tests_console_(opts, tests.tests, tests.to_task);
+ let res = test::run_tests_console(opts, tests);
procsrv::close(cx.procsrv);
if !res { fail "Some tests failed"; }
}
run_ignored: config.run_ignored}
}
-type tests_and_conv_fn = {
- tests: [test::test_desc<fn@()>],
- to_task: fn@(fn@()) -> test::joinable
-};
-
-fn make_tests(cx: cx) -> tests_and_conv_fn {
+fn make_tests(cx: cx) -> [test::test_desc] {
#debug("making tests from %s", cx.config.src_base);
- let configport = port::<[u8]>();
let tests = [];
for file: str in fs::list_dir(cx.config.src_base) {
let file = file;
#debug("inspecting file %s", file);
if is_test(cx.config, file) {
- tests += [make_test(cx, file, configport)];
+ tests += [make_test(cx, file)]
}
}
- ret {tests: tests, to_task: bind closure_to_task(cx, configport, _)};
+ ret tests;
}
fn is_test(config: config, testfile: str) -> bool {
ret valid;
}
-fn make_test(cx: cx, testfile: str, configport: port<[u8]>) ->
- test::test_desc<fn@()> {
- {name: make_test_name(cx.config, testfile),
- fn: make_test_closure(testfile, chan(configport)),
- ignore: header::is_test_ignored(cx.config, testfile),
- should_fail: false}
+fn make_test(cx: cx, testfile: str) ->
+ test::test_desc {
+ {
+ name: make_test_name(cx.config, testfile),
+ fn: make_test_closure(cx, testfile),
+ ignore: header::is_test_ignored(cx.config, testfile),
+ should_fail: false
+ }
}
fn make_test_name(config: config, testfile: str) -> str {
#fmt["[%s] %s", mode_str(config.mode), testfile]
}
-fn make_test_closure(testfile: str,
- configchan: chan<[u8]>) -> test::test_fn<fn@()> {
- bind send_config(testfile, configchan)
-}
-
-fn send_config(testfile: str, configchan: chan<[u8]>) {
- send(configchan, str::bytes(testfile));
-}
-
-fn closure_to_task(cx: cx, configport: port<[u8]>, testfn: fn@()) ->
- test::joinable {
- testfn();
- let testfile = recv(configport);
- let (config, chan) = (cx.config, cx.procsrv.chan);
- ret task::spawn_joinable {||
+fn make_test_closure(cx: cx, testfile: str) -> test::test_fn {
+ let config = cx.config;
+ let chan = cx.procsrv.chan;
+ ret {||
run_test_task(config, chan, testfile);
};
}
fn run_test_task(config: common::config,
procsrv_chan: procsrv::reqchan,
- testfile: [u8]) {
+ testfile: str) {
test::configure_test_task();
let procsrv = procsrv::from_chan(procsrv_chan);
export test_name;
export test_fn;
-export default_test_fn;
export test_desc;
export test_main;
export test_result;
export tr_failed;
export tr_ignored;
export run_tests_console;
-export run_tests_console_;
-export run_test;
-export filter_tests;
-export parse_opts;
-export test_to_task;
-export default_test_to_task;
export configure_test_task;
-export joinable;
#[abi = "cdecl"]
native mod rustrt {
// the test succeeds; if the function fails then the test fails. We
// may need to come up with a more clever definition of test in order
// to support isolation of tests into tasks.
-type test_fn<T> = T;
-
-type default_test_fn = test_fn<fn~()>;
+type test_fn = fn~();
// The definition of a single test. A test runner will run a list of
// these.
-type test_desc<T> = {
+type test_desc = {
name: test_name,
- fn: test_fn<T>,
+ fn: test_fn,
ignore: bool,
should_fail: bool
};
// The default console test runner. It accepts the command line
// arguments and a vector of test_descs (generated at compile time).
-fn test_main(args: [str], tests: [test_desc<default_test_fn>]) {
+fn test_main(args: [str], tests: [test_desc]) {
check (vec::is_not_empty(args));
let opts =
alt parse_opts(args) {
tag test_result { tr_ok; tr_failed; tr_ignored; }
-type joinable = (task::task, comm::port<task::task_notification>);
-
-// To get isolation and concurrency tests have to be run in their own tasks.
-// In cases where test functions are closures it is not ok to just dump them
-// into a task and run them, so this transformation gives the caller a chance
-// to create the test task.
-type test_to_task<T> = fn@(test_fn<T>) -> joinable;
-
// A simple console test runner
fn run_tests_console(opts: test_opts,
- tests: [test_desc<default_test_fn>]) -> bool {
- run_tests_console_(opts, tests, default_test_to_task)
-}
-
-fn run_tests_console_<T: copy>(opts: test_opts, tests: [test_desc<T>],
- to_task: test_to_task<T>) -> bool {
+ tests: [test_desc]) -> bool {
type test_state =
@{out: io::writer,
mutable passed: uint,
mutable failed: uint,
mutable ignored: uint,
- mutable failures: [test_desc<T>]};
+ mutable failures: [test_desc]};
- fn callback<T: copy>(event: testevent<T>, st: test_state) {
+ fn callback(event: testevent, st: test_state) {
alt event {
te_filtered(filtered_tests) {
st.total = vec::len(filtered_tests);
mutable ignored: 0u,
mutable failures: []};
- run_tests(opts, tests, to_task, bind callback(_, st));
+ run_tests(opts, tests, bind callback(_, st));
assert (st.passed + st.failed + st.ignored == st.total);
let success = st.failed == 0u;
if !success {
st.out.write_line("\nfailures:");
- for test: test_desc<T> in st.failures {
+ for test: test_desc in st.failures {
let testname = test.name; // Satisfy alias analysis
st.out.write_line(#fmt[" %s", testname]);
}
fn use_color() -> bool { ret get_concurrency() == 1u; }
-tag testevent<T> {
- te_filtered([test_desc<T>]);
- te_wait(test_desc<T>);
- te_result(test_desc<T>, test_result);
+tag testevent {
+ te_filtered([test_desc]);
+ te_wait(test_desc);
+ te_result(test_desc, test_result);
}
-fn run_tests<T: copy>(opts: test_opts, tests: [test_desc<T>],
- to_task: test_to_task<T>,
- callback: fn@(testevent<T>)) {
+fn run_tests(opts: test_opts, tests: [test_desc],
+ 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.
+ // It's tempting to just spawn all the tests at once, but since we have many
+ // tests that run in other processes we would be making a big mess.
let concurrency = get_concurrency();
#debug("using %u test tasks", concurrency);
let total = vec::len(filtered_tests);
while wait_idx < total {
while vec::len(futures) < concurrency && run_idx < total {
- futures += [run_test(filtered_tests[run_idx], to_task)];
+ futures += [run_test(filtered_tests[run_idx])];
run_idx += 1u;
}
fn get_concurrency() -> uint { rustrt::sched_threads() }
-fn filter_tests<T: copy>(opts: test_opts,
- tests: [test_desc<T>]) -> [test_desc<T>] {
+fn filter_tests(opts: test_opts,
+ tests: [test_desc]) -> [test_desc] {
let filtered = tests;
// Remove tests that don't match the test filter
option::none { "" }
};
- fn filter_fn<T: copy>(test: test_desc<T>, filter_str: str) ->
- option::t<test_desc<T>> {
+ fn filter_fn(test: test_desc, filter_str: str) ->
+ option::t<test_desc> {
if str::find(test.name, filter_str) >= 0 {
ret option::some(test);
} else { ret option::none; }
filtered = if !opts.run_ignored {
filtered
} else {
- fn filter<T: copy>(test: test_desc<T>) -> option::t<test_desc<T>> {
+ fn filter(test: test_desc) -> option::t<test_desc> {
if test.ignore {
ret option::some({name: test.name,
fn: test.fn,
// Sort the tests alphabetically
filtered =
{
- fn lteq<T>(t1: test_desc<T>, t2: test_desc<T>) -> bool {
+ fn lteq(t1: test_desc, t2: test_desc) -> bool {
str::lteq(t1.name, t2.name)
}
sort::merge_sort(bind lteq(_, _), filtered)
ret filtered;
}
-type test_future<T> = {test: test_desc<T>, wait: fn@() -> test_result};
+type test_future = {test: test_desc, wait: fn@() -> test_result};
-fn run_test<T: copy>(test: test_desc<T>,
- to_task: test_to_task<T>) -> test_future<T> {
+fn run_test(test: test_desc) -> test_future {
if test.ignore {
ret {test: test, wait: fn@() -> test_result { tr_ignored }};
}
- let test_task = to_task(test.fn);
+ let test_task = test_to_task(test.fn);
ret {test: test,
wait: fn@() -> test_result {
alt task::join(test_task) {
// We need to run our tests in another task in order to trap test failures.
// This function only works with functions that don't contain closures.
-fn default_test_to_task(&&f: default_test_fn) -> joinable {
+fn test_to_task(&&f: test_fn) -> task::joinable_task {
ret task::spawn_joinable(fn~[copy f]() {
configure_test_task();
f();
ignore: true,
should_fail: false
};
- let future = test::run_test(desc, test::default_test_to_task);
+ let future = run_test(desc);
let result = future.wait();
- assert result != test::tr_ok;
+ assert result != tr_ok;
}
#[test]
ignore: true,
should_fail: false
};
- let res = test::run_test(desc, test::default_test_to_task).wait();
- assert (res == test::tr_ignored);
+ let res = run_test(desc).wait();
+ assert (res == tr_ignored);
}
#[test]
ignore: false,
should_fail: true
};
- let res = test::run_test(desc, test::default_test_to_task).wait();
- assert res == test::tr_ok;
+ let res = run_test(desc).wait();
+ assert res == tr_ok;
}
#[test]
ignore: false,
should_fail: true
};
- let res = test::run_test(desc, test::default_test_to_task).wait();
- assert res == test::tr_failed;
+ let res = run_test(desc).wait();
+ assert res == tr_failed;
}
#[test]
fn first_free_arg_should_be_a_filter() {
let args = ["progname", "filter"];
check (vec::is_not_empty(args));
- let opts = alt test::parse_opts(args) { either::left(o) { o } };
+ let opts = alt parse_opts(args) { either::left(o) { o } };
assert (str::eq("filter", option::get(opts.filter)));
}
fn parse_ignored_flag() {
let args = ["progname", "filter", "--ignored"];
check (vec::is_not_empty(args));
- let opts = alt test::parse_opts(args) { either::left(o) { o } };
+ let opts = alt parse_opts(args) { either::left(o) { o } };
assert (opts.run_ignored);
}
let opts = {filter: option::none, run_ignored: true};
let tests =
- [{name: "1", fn: fn@() { }, ignore: true, should_fail: false},
- {name: "2", fn: fn@() { }, ignore: false, should_fail: false}];
- let filtered = test::filter_tests(opts, tests);
+ [{name: "1", fn: fn~() { }, ignore: true, should_fail: false},
+ {name: "2", fn: fn~() { }, ignore: false, should_fail: false}];
+ let filtered = filter_tests(opts, tests);
assert (vec::len(filtered) == 1u);
assert (filtered[0].name == "1");
"test::sort_tests"];
let tests =
{
- let testfn = fn@() { };
+ let testfn = fn~() { };
let tests = [];
for name: str in names {
let test = {name: name, fn: testfn, ignore: false,
}
tests
};
- let filtered = test::filter_tests(opts, tests);
+ let filtered = filter_tests(opts, tests);
let expected =
["int::test_pow", "int::test_to_str", "sha1::test",
for (a, b) in pairs { assert (a == b.name); }
-}
+ }
}