diff --git a/integration-tests/build.rs b/integration-tests/build.rs index 5182784b3..e1c5c2fbe 100644 --- a/integration-tests/build.rs +++ b/integration-tests/build.rs @@ -18,6 +18,11 @@ fn build_libtaskchampion(suites: &[&'static str]) { build.object(libtaskchampion); build.include("../lib"); build.include("src/bindings_tests/unity"); + build.define("UNITY_OUTPUT_CHAR", "test_output"); + build.define( + "UNITY_OUTPUT_CHAR_HEADER_DECLARATION", + "test_output(char c)", + ); build.file("src/bindings_tests/unity/unity.c"); let mut files = vec!["src/bindings_tests/test.c".to_string()]; diff --git a/integration-tests/src/bindings_tests/mod.rs b/integration-tests/src/bindings_tests/mod.rs index 4eba5b421..327ca83fe 100644 --- a/integration-tests/src/bindings_tests/mod.rs +++ b/integration-tests/src/bindings_tests/mod.rs @@ -1,14 +1,28 @@ +use std::fs; + +extern "C" { + // set up to send test output to TEST-OUTPUT + fn setup_output(); + // close the output file + fn finish_output(); +} + // Each suite is represented by a _tests C function in .c. // All of these C files are built into a library that is linked to the crate -- but not to test // crates. So, this macro produces a "glue function" that calls the C function, and that can be // called from test crates. macro_rules! suite( { $s:ident } => { - pub fn $s() -> i32 { + pub fn $s() -> (i32, String) { extern "C" { fn $s() -> i32; } - unsafe { $s() } + unsafe { setup_output() }; + let res = unsafe { $s() }; + unsafe { finish_output() }; + let output = fs::read_to_string("TEST-OUTPUT") + .unwrap_or_else(|e| format!("could not open TEST-OUTPUT: {}", e)); + (res, output) } }; ); diff --git a/integration-tests/src/bindings_tests/replica.c b/integration-tests/src/bindings_tests/replica.c index bd15adfa9..282d2948b 100644 --- a/integration-tests/src/bindings_tests/replica.c +++ b/integration-tests/src/bindings_tests/replica.c @@ -1,8 +1,8 @@ #include #include #include -#include "unity.h" #include "taskchampion.h" +#include "unity.h" // creating an in-memory replica does not crash static void test_replica_creation(void) { diff --git a/integration-tests/src/bindings_tests/test.c b/integration-tests/src/bindings_tests/test.c index 609943fc4..5afa236ca 100644 --- a/integration-tests/src/bindings_tests/test.c +++ b/integration-tests/src/bindings_tests/test.c @@ -1,6 +1,30 @@ +#include #include "unity.h" // these functions are shared between all test "suites" // and cannot be customized per-suite. void setUp(void) { } void tearDown(void) { } + +static FILE *output = NULL; + +// Set up for test_output, writing output to "TEST-OUTPUT" in the +// current directory. The Rust test harness reads this file to get +// the output and display it only on failure. This is called by +// the Rust test harness +void setup_output(void) { + output = fopen("TEST-OUTPUT", "w"); +} + +// Close the output file. Called by the Rust test harness. +void finish_output(void) { + fclose(output); + output = NULL; +} + +// this replaces UNITY_OUTPUT_CHAR, and writes output to +// TEST-OUTPUT in the current directory; the Rust test harness +// will read this data if the test fails. +void test_output(char c) { + fputc(c, output); +} diff --git a/integration-tests/tests/bindings.rs b/integration-tests/tests/bindings.rs index 9f14ec47f..a121dd721 100644 --- a/integration-tests/tests/bindings.rs +++ b/integration-tests/tests/bindings.rs @@ -1,5 +1,6 @@ use lazy_static::lazy_static; use std::sync::Mutex; +use tempfile::TempDir; lazy_static! { // the C library running the tests is not reentrant, so we use a mutex to ensure that only one @@ -11,8 +12,18 @@ macro_rules! suite( { $s:ident } => { #[test] fn $s() { - let _guard = MUTEX.lock().unwrap(); - assert_eq!(integration_tests::bindings_tests::$s(), 0); + let tmp_dir = TempDir::new().expect("TempDir failed"); + let (res, output) = { + let _guard = MUTEX.lock().unwrap(); + // run the tests in the temp dir (NOTE: this must be inside + // the mutex guard!) + std::env::set_current_dir(tmp_dir.as_ref()).unwrap(); + integration_tests::bindings_tests::$s() + }; + println!("{}", output); + if res != 0 { + assert!(false, "test failed"); + } } }; );