I'm currently working on a Rust project that has a library target as well as a binary target.
The library defines two panic handlers, one for production use and one for testing, which are conditionally compiled using the #[cfg(test)] attribute. This works fine for unit testing src/lib.rs, but as soon as integration tests in tests/ (or src/main.rs for that matter), the "production" panic handler is linked in, i.e. in those circumstances, lib.rs gets compiled with test=false.
Is there some way to prevent/configure that?
This is pretty minimally reproducible with the following directory structure:
Cargo.toml
src/lib.rs
src/main.rs
The manifest looks like this:
# Cargo.toml
...
[lib]
name = "kernel"
[[bin]]
path = "src/main.rs"
name = "titanium"
Code for the binary:
// main.rs
fn main() {
println!("Hello, world!");
}
#[test]
fn it_works() {
assert_eq!(kernel::hello(), "Hello!".to_string());
}
... and for the library:
// lib.rs
#[cfg(test)]
pub fn hello() -> String {
"Hello!".to_string()
}
#[cfg(not(test))]
pub fn hello() -> String {
"Goodbye!".to_string()
}
#[test]
fn it_works() {
assert_eq!(hello(), "Hello!".to_string())
}
Answer Above behaviour is in fact desirable for probably 99% of use cases, however, mine isn't one of them.
For my use case (testsuite for toy OS running in a VM "headless", i.e. with output only to stdout of the host machine) I ended up defining a feature to switch panic handlers. Adapted to above example it now looks like this:
# Cargo.toml
...
[features]
test_qemu_headless = []
The binary then remains unchanged, and in the library I do
// lib.rs
#[cfg(feature = "test_qemu_headless")]
pub fn hello() -> String {
"Hello!".to_string()
}
#[cfg(not(feature = "test_qemu_headless"))]
pub fn hello() -> String {
"Goodbye!".to_string()
}
#[test]
fn it_works() {
assert_eq!(hello(), "Hello!".to_string())
}
The tests are then run with
cargo test --features test_qemu_headless