Hi,
Cargo test for my embedded (no_std) library fails as cargo test uses std library. I came across this post . Curious to know if any newer update than using defmt-test.
Hi,
Cargo test for my embedded (no_std) library fails as cargo test uses std library. I came across this post . Curious to know if any newer update than using defmt-test.
for a lib
crate-type, if your tests can run on the host (i.e. you are not testing hardware specific functionalities), you can use the default libtest
harness without problem. you'll need defmt-test
only if you need to run the test on a target architecture. one possible alternative is cargo-nextest runner
together with an emulator (such as qemu
) or debug probe (such as probe-rs
)
no_std
crates can use std
(and alloc
, for that matter) just fine, you just need to explicitly declare an extern crate std
dependency, surely you most likely want the dependency on std
be conditional (e.g. #[cfg(feature = "some_feature_name"]
or #[cfg(test)]
).
for example. suppose you want to use std::dbg!()
macro when running unit tests, you can do something like:
// lib.rs
#![no_std]
// import the `dbg!()` macro only for test builds
#[cfg(test)]
#[macro_use]
extern crate std;
/// communication protocol command
#[derive(Debug)]
pub enum Cmd {
GetStatus,
ReadByte { address: u32 },
WriteByte { address: u32, value: u8 },
}
/// parse byte sequence to [`Cmd`]
pub fn parse_cmd(input: &[u8]) -> Option<Cmd> {
// the dbg!() macro only exists when `cargo test`
// it will not be there when `cargo build`, even for debug profile
#[cfg(test)]
dbg!(input);
match input {
&[0x01, ..] => Some(Cmd::GetStatus),
&[0x02, a0, a1, a2, a3, ..] => Some(Cmd::ReadByte {
address: u32::from_le_bytes([a0, a1, a2, a3]),
}),
&[0x03, a0, a1, a2, a3, d0, ..] => Some(Cmd::WriteByte {
address: u32::from_le_bytes([a0, a1, a2, a3]),
value: d0,
}),
_ => None,
}
}
you can also use a #[cfg(test)]
gated submodule like this:
#[cfg(test)]
mod tests {
use super::*;
extern crate std;
use std::eprintln;
#[test]
fn empty_intput() {
let result = parse_cmd(&[]);
assert!(result.is_none());
eprintln!("empty input parsed into: {:?}", result);
}
}
I tested as below;
#![no_std]
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
extern crate std;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
But it throws the following error
error[E0463]****: can't find crate for std
--> drivers/src/lib.rs:10:5
10 | extern crate std;
| ^^^^^^^^^^^^^^^^^ can't find crate
= note: the riscv32imac-unknown-none-elf
target may not support the standard library
do you have to run the test under the target platform, i.e. risc-v
? if so, you'll have to use other test harness because the default libtest
requires std
.
if, however, you're writing architecture independent portable code, then the test can run on the host, you need to use the --target
command line option if you have your default target configured (e.g. via .cargo/config.toml
).
for example. for a 64bit linux host, it should be cargo test --target x86_64-unknown-linux-gnu
.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.