Simplifiy running tests
diff --git a/.travis.yml b/.travis.yml index 162f863..8efe4b7 100644 --- a/.travis.yml +++ b/.travis.yml
@@ -42,7 +42,7 @@ script: - make test # Run a QEMU instance of the HiFive1 app - - PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc + - PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc --features=__internal_disable_gpio_in_integration_test - pushd test-runner - cargo run - popd
diff --git a/Cargo.toml b/Cargo.toml index c1b9714..eb56daa 100644 --- a/Cargo.toml +++ b/Cargo.toml
@@ -9,6 +9,7 @@ alloc = ["libtock-core/alloc"] custom_panic_handler = ["libtock-core/custom_panic_handler"] custom_alloc_error_handler = ["libtock-core/custom_alloc_error_handler"] +__internal_disable_gpio_in_integration_test = [] [dependencies] core = { package = "async-support", path = "async-support" }
diff --git a/examples-features/libtock_test.rs b/examples-features/libtock_test.rs index 26cccb4..5fe9e59 100644 --- a/examples-features/libtock_test.rs +++ b/examples-features/libtock_test.rs
@@ -2,7 +2,6 @@ // Requires P0.03 and P0.04 to be connected (on a nRF52 DK). #![no_std] - extern crate alloc; use alloc::string::String; @@ -36,6 +35,10 @@ } } +#[cfg_attr( + feature = "__internal_disable_gpio_in_integration_test", + allow(unused_variables) +)] async fn libtock_test( test: &mut LibtockTest, timer: &mut DriverContext, @@ -48,6 +51,7 @@ test.heap()?; test.drivers_only_instantiable_once()?; test.callbacks(timer).await?; + #[cfg(not(feature = "__internal_disable_gpio_in_integration_test"))] test.gpio(gpio)?; Ok(()) } @@ -113,7 +117,7 @@ let mut with_callback = timer_context.with_callback(|_, _| callback_hit = true); let mut timer = with_callback.init()?; - timer.set_alarm(Duration::from_ms(50))?; + timer.set_alarm(Duration::from_ms(1000))?; AlternatingFuture { yielded: false }.await; @@ -122,6 +126,10 @@ self.check_if_true(callback_hit, "Callbacks") } + #[cfg_attr( + feature = "__internal_disable_gpio_in_integration_test", + allow(dead_code) + )] fn gpio(&mut self, gpio: &mut GpioDriverFactory) -> TockResult<()> { let mut gpio_driver = gpio.init_driver().ok().unwrap();
diff --git a/test-runner/src/main.rs b/test-runner/src/main.rs index e8c7dcb..0ee3455 100644 --- a/test-runner/src/main.rs +++ b/test-runner/src/main.rs
@@ -1,25 +1,19 @@ -use std::collections::HashMap; +use std::fmt; use std::process::Stdio; use std::time::Duration; -use structopt::StructOpt; use tokio::io::AsyncBufReadExt; use tokio::io::BufReader; use tokio::process::Command; use tokio::time::timeout; -#[derive(Debug, StructOpt)] -#[structopt(name = "libtock test runner", about = "run libtock tests")] -struct Arguments { - #[structopt(short, long)] - timeout_ms: usize, -} - #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { timeout(Duration::from_secs(10), perform_tests()).await? } async fn perform_tests() -> Result<(), Box<dyn std::error::Error>> { + let mut failed_tests = Vec::new(); + let tests = Command::new("qemu-system-riscv32") .arg("-M") .arg("sifive_e") @@ -36,70 +30,100 @@ let stdout_reader = BufReader::new(stdout); let mut stdout_lines = stdout_reader.lines(); - let mut result_map = HashMap::<TockTest, bool>::new(); while let Some(line) = stdout_lines.next_line().await? { println!("UART: {}", line); - if let Some(entry) = parse_line(line) { - result_map.insert(entry.0, entry.1); + let test_result = test_succeeded(line, &mut failed_tests); + if let Some(true) = test_result { + return Ok(()); } - if result_map.keys().len() >= NUMBER_OF_TESTS { - if result_map.values().all(|x| *x) { - return Ok(()); - } else { - panic!(); - } + if let Some(false) = test_result { + return Err(Box::new(TestError::TestFailure(failed_tests))); } } - panic!("qemu exited unexpectedly") + Err(Box::new(TestError::QemuExit)) } -fn parse_line(input: String) -> Option<(TockTest, bool)> { - let result = input.find("[ OK ]").is_some(); +fn test_succeeded(input: String, failed_tests: &mut Vec<String>) -> Option<bool> { + let success = input.find("[ OK ]").is_some(); + let failure = input.find("[ FAILURE ]").is_some(); let input = input.replace("[ OK ]", ""); let input = input.replace("[ FAILURE ]", ""); let input = input.trim(); - let tock_test = label_to_tocktest(input.to_string()); - tock_test.map(|test| (test, result)) + if input == "Test suite finished with state SUCCESS" && success { + return Some(true); + } else if input == "Test suite finished with state FAILURE" && !success { + return Some(false); + } else if failure { + failed_tests.push(input.to_string()); + } + None } -const NUMBER_OF_TESTS: usize = 6; -#[derive(PartialEq, Debug, Hash, Eq)] -enum TockTest { - Console, - StaticMut, - DynamicDispatch, - Formatting, - Heap, - DriversOnlyInstantiableOnce, +#[derive(Debug)] +enum TestError { + TestFailure(Vec<String>), + QemuExit, } -fn label_to_tocktest(label: String) -> Option<TockTest> { - match label.as_str() { - "Console" => Some(TockTest::Console), - "static mut" => Some(TockTest::StaticMut), - "Dynamic dispatch" => Some(TockTest::DynamicDispatch), - "Formatting" => Some(TockTest::Formatting), - "Heap" => Some(TockTest::Heap), - "Drivers only instantiable once" => Some(TockTest::DriversOnlyInstantiableOnce), - _ => None, +impl fmt::Display for TestError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TestError::TestFailure(failures) => { + writeln!(f, "A test failure occured. Failed Tests")?; + for test in failures { + writeln!(f, "Test failed\"{}\"", test)?; + } + Ok(()) + } + TestError::QemuExit => write!(f, "Qemu exited unexpectedly."), + } } } +impl std::error::Error for TestError {} + #[cfg(test)] mod test { use super::*; #[test] - pub fn works() { + pub fn detects_success_of_test_suite() { + let mut test_results = Vec::new(); assert_eq!( - parse_line("[ OK ] Console".into()), - Some((TockTest::Console, true)) + test_succeeded( + "[ OK ] Test suite finished with state SUCCESS".into(), + &mut test_results + ), + Some(true) ); } #[test] - pub fn fails() { - assert_eq!(parse_line("[ OK ] No Console".into()), None); + pub fn detects_failure_of_test_suite() { + let mut test_results = Vec::new(); + assert_eq!( + test_succeeded( + "[ FAILURE ] Test suite finished with state FAILURE".into(), + &mut test_results + ), + Some(false) + ); + } + + #[test] + pub fn detects_test_failures() { + let mut test_results = Vec::new(); + test_succeeded("[ FAILURE ] Another test".into(), &mut test_results); + assert_eq!(test_results, vec!["Another test"]); + } + + #[test] + pub fn ignores_other_tests() { + let mut test_results = Vec::new(); + assert_eq!( + test_succeeded("[ SUCCESS ] Another test".into(), &mut test_results), + None + ); } }