Cargo test for embedded target fails

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);
	}
}
1 Like

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.

1 Like

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.