I'm working on a crate that gets compiled as a C dynamic library and imported by an another binary (Neovim in this case).
I'd like to leverage cargo test
to test it, but I'm unsure what the less inconvenient option might be.
My current solution involves a 2-step process (code is here):
- compile the code snippet I'd like to test, producing a
.so
file. The code looks something like:
use nvim_oxi::lua::lua_State;
#[no_mangle]
extern "C" fn luaopen_liboxi_tests(_state: *mut lua_State) -> std::os::raw::c_int {
let result = std::panic::catch_unwind(|| {
// Code I want to test.
});
std::process::exit(match result {
Ok(_) => 0,
Err(err) => {
eprintln!("{err:?}");
1
},
})
}
- write a regular test that starts Neovim with the appropriate cli flags and asserts that stderr is empty:
#[test]
fn () {
let out = std::process::Command::new("nvim")
.args(["-u", "NONE", "--headless"])
.args(["-c", "set rtp+=/Users/noib3/Dropbox/projects/nvim-oxi"])
.args(["-c", "lua require(\"liboxi_tests\")"])
.args(["+quit"])
.output()
.expect("Couldn't find `nvim` binary in $PATH!");
let stderr = String::from_utf8_lossy(&out.stderr);
assert_eq!(stderr, String::new());
}
This is obviously not ideal for a variety of reasons:
a) very verbose, everything apart from the the // Code I want to test.
line is noise. Could be avoided by writing a proc macro that extends #[test]
;
b) stderr output are nested in the event of an unsuccessful test, for example
---- api::buffer::get_changedtick stdout ----
thread 'api::buffer::get_changedtick' panicked at 'assertion failed: `(left == right)`
left: `"thread '<unnamed>' panicked at 'assertion failed: buf.get_changedtick().is_er
r()', oxi-tests/src/api/buffer.rs:43:9\nnote: run with `RUST_BACKTRACE=1` environment v
ariable to display a backtrace\nAny { .. }\n"`,
right: `""`', oxi-tests/src/api/buffer.rs:32:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
notice the two thread <x> panicked at <y>
. I'd like to only see the inner one;
c) it's a 2 step process, I have to do a cargo build
before every cargo test *
. Could be avoided with a simple shell alias;
d) since every test has to compiled into a separate crate, if I have 100 integration tests I'll have to wait for 100 cargo build
s before getting all the results. This is probably the worst part and I don't think there's a lot one can do to avoid it
I'd appreciate some input on the various points. Is there a better way that I'm not seeing?