|
|
@ -2,7 +2,9 @@ |
|
|
|
|
|
|
|
|
|
|
|
extern crate test; |
|
|
|
extern crate test; |
|
|
|
|
|
|
|
|
|
|
|
use test::TestFn; |
|
|
|
use std::io; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use test::{ColorConfig, Options, OutputFormat, RunIgnored, TestDescAndFn, TestFn, TestOpts}; |
|
|
|
|
|
|
|
|
|
|
|
use crate::console::Console; |
|
|
|
use crate::console::Console; |
|
|
|
use crate::gfx::Gfx; |
|
|
|
use crate::gfx::Gfx; |
|
|
@ -11,31 +13,57 @@ use crate::services::hid::{Hid, KeyPad}; |
|
|
|
/// A custom runner to be used with `#[test_runner]`. This simple implementation
|
|
|
|
/// A custom runner to be used with `#[test_runner]`. This simple implementation
|
|
|
|
/// runs all tests in series, "failing" on the first one to panic (really, the
|
|
|
|
/// runs all tests in series, "failing" on the first one to panic (really, the
|
|
|
|
/// panic is just treated the same as any normal application panic).
|
|
|
|
/// panic is just treated the same as any normal application panic).
|
|
|
|
pub(crate) fn test_runner(test_cases: &[&test::TestDescAndFn]) { |
|
|
|
pub(crate) fn test_runner(tests: &[&TestDescAndFn]) { |
|
|
|
crate::init(); |
|
|
|
crate::init(); |
|
|
|
|
|
|
|
|
|
|
|
let gfx = Gfx::default(); |
|
|
|
let gfx = Gfx::default(); |
|
|
|
let hid = Hid::init().expect("Couldn't obtain HID controller"); |
|
|
|
let hid = Hid::init().unwrap(); |
|
|
|
let _console = Console::init(gfx.top_screen.borrow_mut()); |
|
|
|
|
|
|
|
|
|
|
|
let mut top_screen = gfx.top_screen.borrow_mut(); |
|
|
|
// TODO: may want to use some more features of standard testing framework,
|
|
|
|
top_screen.set_wide_mode(true); |
|
|
|
// like output capture, filtering, panic handling, etc.
|
|
|
|
let _console = Console::init(top_screen); |
|
|
|
// For now this is works without too much setup.
|
|
|
|
|
|
|
|
for test_info in test_cases { |
|
|
|
// Start printing from the top left
|
|
|
|
if let TestFn::StaticTestFn(testfn) = test_info.testfn { |
|
|
|
print!("\x1b[1;1H"); |
|
|
|
println!("Running test {}", test_info.desc.name); |
|
|
|
|
|
|
|
testfn(); |
|
|
|
// TODO: it would be nice to have a way of specifying argv to make these
|
|
|
|
} else { |
|
|
|
// configurable at runtime, but I can't figure out how to do it easily,
|
|
|
|
println!( |
|
|
|
// so for now, just hardcode everything.
|
|
|
|
"unsupported test type for {}: {:?}", |
|
|
|
let opts = TestOpts { |
|
|
|
test_info.desc.name, test_info.testfn |
|
|
|
list: false, |
|
|
|
); |
|
|
|
filters: Vec::new(), |
|
|
|
} |
|
|
|
filter_exact: false, |
|
|
|
} |
|
|
|
// Forking is not supported
|
|
|
|
|
|
|
|
force_run_in_process: true, |
|
|
|
|
|
|
|
exclude_should_panic: false, |
|
|
|
|
|
|
|
run_ignored: RunIgnored::No, |
|
|
|
|
|
|
|
run_tests: true, |
|
|
|
|
|
|
|
// Benchmarks are not supported
|
|
|
|
|
|
|
|
bench_benchmarks: false, |
|
|
|
|
|
|
|
logfile: None, |
|
|
|
|
|
|
|
nocapture: false, |
|
|
|
|
|
|
|
// TODO: color doesn't work because of TERM/TERMINFO.
|
|
|
|
|
|
|
|
// With RomFS we might be able to fake this out nicely...
|
|
|
|
|
|
|
|
color: ColorConfig::AlwaysColor, |
|
|
|
|
|
|
|
format: OutputFormat::Pretty, |
|
|
|
|
|
|
|
shuffle: false, |
|
|
|
|
|
|
|
shuffle_seed: None, |
|
|
|
|
|
|
|
// tweak values? This seems to work out of the box
|
|
|
|
|
|
|
|
test_threads: Some(3), |
|
|
|
|
|
|
|
skip: Vec::new(), |
|
|
|
|
|
|
|
time_options: None, |
|
|
|
|
|
|
|
options: Options::new(), |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
println!("All tests passed! Press START to exit."); |
|
|
|
// Use the default test implementation with our hardcoded options
|
|
|
|
|
|
|
|
let _success = run_static_tests(&opts, tests).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure the user can actually see the results before we exit
|
|
|
|
|
|
|
|
println!("Press START to exit."); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gfx.flush_buffers(); |
|
|
|
|
|
|
|
gfx.swap_buffers(); |
|
|
|
|
|
|
|
|
|
|
|
// TODO: do we need apt.main_loop() here?
|
|
|
|
|
|
|
|
loop { |
|
|
|
loop { |
|
|
|
hid.scan_input(); |
|
|
|
hid.scan_input(); |
|
|
|
|
|
|
|
|
|
|
@ -44,3 +72,64 @@ pub(crate) fn test_runner(test_cases: &[&test::TestDescAndFn]) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Adapted from [`test::test_main_static`], along with [`make_owned_test`].
|
|
|
|
|
|
|
|
fn run_static_tests(opts: &TestOpts, tests: &[&TestDescAndFn]) -> io::Result<bool> { |
|
|
|
|
|
|
|
let tests = tests.iter().map(make_owned_test).collect(); |
|
|
|
|
|
|
|
test::run_tests_console(opts, tests) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Clones static values for putting into a dynamic vector, which test_main()
|
|
|
|
|
|
|
|
/// needs to hand out ownership of tests to parallel test runners.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This will panic when fed any dynamic tests, because they cannot be cloned.
|
|
|
|
|
|
|
|
fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { |
|
|
|
|
|
|
|
match test.testfn { |
|
|
|
|
|
|
|
TestFn::StaticTestFn(f) => TestDescAndFn { |
|
|
|
|
|
|
|
testfn: TestFn::StaticTestFn(f), |
|
|
|
|
|
|
|
desc: test.desc.clone(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
TestFn::StaticBenchFn(f) => TestDescAndFn { |
|
|
|
|
|
|
|
testfn: TestFn::StaticBenchFn(f), |
|
|
|
|
|
|
|
desc: test.desc.clone(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
_ => panic!("non-static tests passed to test::test_main_static"), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// The following functions are stubs needed to link the test library,
|
|
|
|
|
|
|
|
/// but do nothing because we don't actually need them for it to work (hopefully).
|
|
|
|
|
|
|
|
// TODO: move to linker-fix-3ds ?
|
|
|
|
|
|
|
|
mod link_fix { |
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
|
|
|
|
extern "C" fn execvp( |
|
|
|
|
|
|
|
_argc: *const libc::c_char, |
|
|
|
|
|
|
|
_argv: *mut *const libc::c_char, |
|
|
|
|
|
|
|
) -> libc::c_int { |
|
|
|
|
|
|
|
-1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
|
|
|
|
extern "C" fn pipe(_fildes: *mut libc::c_int) -> libc::c_int { |
|
|
|
|
|
|
|
-1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
|
|
|
|
extern "C" fn pthread_sigmask( |
|
|
|
|
|
|
|
_how: ::libc::c_int, |
|
|
|
|
|
|
|
_set: *const libc::sigset_t, |
|
|
|
|
|
|
|
_oldset: *mut libc::sigset_t, |
|
|
|
|
|
|
|
) -> ::libc::c_int { |
|
|
|
|
|
|
|
-1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
|
|
|
|
extern "C" fn sigemptyset(_arg1: *mut libc::sigset_t) -> ::libc::c_int { |
|
|
|
|
|
|
|
-1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
|
|
|
|
extern "C" fn sysconf(_name: libc::c_int) -> libc::c_long { |
|
|
|
|
|
|
|
-1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|