I'm having problem on a specific function of a test of a specific file:
mod test {
//...
#[test]
#[cfg(feature = "proto-igmp")]
fn test_handle_igmp() {
I've found here https://github.com/rust-lang/cargo/issues/1407 that I can test specific tests by passing its name as an argument to the test binary. But where's such binary? And can I make println work inside tests?
I want to run test_handle_igmp to print some things and see why the error is happening.
You can find it in target/$MODE/$NAME-$hash, e.g. target/debug/example-3beac917983bc7e3.exe. Note that there might be multiple ones, some for doc tests, some for #[test] functions.
That being said if you just want to run test_handle_igmp, you can just use
cargo test test_handle_igmp -- --nocapture
to run your test and see the println outputs. See cargo test --help or the online documentation.
Related
I have a number of tests defined inside some of my modules with:
#[cfg(test)]
mod tests {
...
and a number of tests found inside my /tests directory. All of these happen to need a common function called get_local() that I have put inside a utils module
+src
|-lib.rs
|-utils.rs
|-...
+tests
|_common.rs
Now since this function is only used in case I run tests I thought I should add a #[cfg(test)] above it.
#[cfg(test)]
pub fn get_local() -> SomeResult { ... }
and then I make sure it is inside lib.rs:
pub mod utils;
When I try using the function in tests/common.rs though:
use my_crate::utils::get_local;
and run the tests with the test command I get the error: no get_local in utils. This error only goes away if I remove #[cfg(test)] from the declaration of get_local. Why does this happen?
Why does this happen?
#[cfg(test)] is only active when the crate is being compiled into a test binary (instead of a library or normal binary) — the same condition under which #[test] functions are compiled to be run rather than ignored. But for a tests/ test, the crate being compiled in test mode is not your library — it's a separate binary crate for the test, which Cargo sets up to depend on your library compiled normally.
Thus, tests/ tests may only test the "public API" of your library — they see it no differently than a dependent crate outside your library.
As a workaround, you can use #[doc(hidden)] instead of #cfg(test)] so that the function is always available but undocumented, or you can put it in a module which is compiled into the test as well as the main library (but it's tricky to write code that works in both cases).
As for the "why does this happen?", Kevin Reid already answered: code in tests/ are "Integration Tests" and, therefore, uses the regular version of your lib (not the test-compiled one). See Integration Testing.
You may use the approach bellow to have a common test module for a single crate. Note that, for Integration Tests, each file inside tests/ is compiled as an individual crate. You may still create modules there.
With that said, my approach to having common test code is to put them inside a "test_commons" module and use:
lib.rs:
#[cfg(test)]
mod test_commons;
The contents of test_commons.rs has nothing special -- functions are defined without any #[cfg(test)] annotation.
Then, to use it:
#[cfg(test)]
mod tests {
use super::*;
use crate::test_commons::{self,ContainerKind,Blocking};
...
For Integration Tests inside tests/ to share that same code, simply use:
#[path = "../../src/test_commons.rs"] mod test_commons;
The Rust language supports conditional compilation using attributes like #[cfg(test)].
Rust also supports build scripts using a build.rs file to run code as part of the build process to prepare for compilation.
I would like to use conditional compilation in Rust code to conditionally compile depending on whether we're compiling for a build script, similar to how that is possible for test builds.
Imagine the following:
#[cfg(build)]
fn main() {
// Part of build script
}
#[cfg(not(build))]
fn main() {
// Not part of build script, probably regular build
}
This does not work, because build is not a valid identifier here.
Is it possible to do this using a different attribute, or could some other trick be used to achieve something similar?
For some context on this issue:
My goal is to generate shell completion scripts through clap at compile time. I've quite a comprehensive App definition across multiple files in the application. I'd like to use this in build.rs by including these parts using the include!(...) macro (as suggested by clap), so I don't have to define App a second time. This pulls some dependencies with it, which I'd like to exclude when used by the build.rs file as they aren't needed in that case. This is what I'm trying to make available in my build.rs script.
You can just put the build code in build.rs (or presumably have build.rs declare a mod xyz to pull in another file).
I wonder if the question you are trying to ask is whether you can reference the same code from build.rs and main.rs, and if so can that code tell if it's being called by one or the other. It seems you could switch on an environment variable set when using build.rs (using something like option_env, but possibly a nicer way might be to enable a feature in the main code from within build.rs.
(Have a read of the documentation for build scripts if you haven't already.)
This is what works for me:
fn main() {
if std::env::var("PROFILE").unwrap() == "debug" {
// Here I do something that is needed for tests
// only, not for 'release'
}
}
I'm writing a program in Rust and I have some tests for it. I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used:
warning: function is never used: ... #[warn(dead_code)] on by default
How I can mark this function as used so as not to get the warnings?
Specific question
How I can mark this function as used so as not to get the warnings?
The Rust compiler runs many lints to warn you about possible issues in your code and the dead_code lint is one of them. It can be very useful in pointing out mistakes when code is complete, but may also be a nuisance at earlier stages. Often, this can be solved by either deleting unused code, or by marking a public method. However, all lints can be turned off by allowing them, and your error message (#[warn(dead_code)] on by default) contains the name of the lint you could disable.
#[allow(dead_code)]
fn my_unused_function() {}
Alternative for testing
I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used.
This happens to be a special case, which is that code that is only used for testing isn't needed in the real executable and should probably not be included.
In order to optionally disable compilation of test code, you can mark it accordingly using the cfg attribute with the test profile.
#[cfg(test)]
fn my_test_specific_function() {}
When marked in this way, the compiler knows to ignore the method during compilation. This is similar to commonly used ifdef usage in other languages like C or C++, where you are telling a preprocessor to ignore the enclosed code unless TESTING is defined.
#ifdef TESTING
...
#endif
For people getting this warning while making a rust library, you may get this if you don't have your modules set to pub in your lib.rs.
pub mod foo;
If something is only used in tests, it should be omitted altogether. This can be done with the #[cfg(test)] attribute.
dead_code is a lint, which means you can allow it on the thing that's causing it to trigger.
#[allow(dead_code)]
fn dummy() {}
fn main() {}
There is another situation where this can occur. If you have several helper functions in a module, e.g. in tests/utils/mod.rs and then several integration tests (tests/a.rs, tests/b.rs) each of which does
mod utils;
use utils::...;
then you will get dead code warnings if you do not use all of the code from all of the tests. For example if test a.rs only uses utils::foo and b.rs only uses utils::bar then you will get dead code warnings for both.
That is because each test is compiled as an independent crate. Here is the bug report for it. It looks difficult to solve so I wouldn't hold my breath.
You can disable specific lints for a whole project in Rust by going into your main.rs file and adding the following at the very top of the file:
#![allow(
dead_code,
unused_imports
)]
You max prefix the unused function name with an underscore:
fn _dummy() {}
fn main() {}
See: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code
For some reason I found that setting the main function to public:
pub fn main()
and then copying my main.rs file to lib.rs
cp src/main.rs src/lib.rs
then recompiling fixed this.
No need to use a macro for it, although the macro should work for non main functions.
I use a method that appeared in Rust 1.10 for my tests but I want my crate to also work with version 1.7.
Is there a way (something like attribute #[cfg(min_version="1.10")]) to specify code that should only run in Rust 1.10 or newer?
I could use a build script, but I don't want a more complicated build just because I wanted to test my crate on an older Rust version.
While there is no way except build scripts (and in the future procedural macros) to check compiler versions, you can use feature flags to manually enable and disable code.
Usually you want to use some new compiler feature to provide new functionality which you could not do with the old compiler. In that case you use the cfg attribute with feature flags which you define to enable code. E.g.
#[cfg(feature = "foo")]
pub fn foo() {
cool_new_compiler_function();
}
And in your Cargo.toml:
[features]
foo = []
Hiding code behind feature flags like this also works in test code. In your specific case you could alternately introduce a legacy feature and disable tests using modern code like this:
#[test]
#[cfg(not(feature = "legacy"))]
fn test_foo() {
Foo::foo();
}
And then to run tests in legacy mode you run:
cargo test --features "legacy"
Note that doing it the latter way means that your tests will not compile by default on older compilers. For normal (non-test) code, adding such a legacy flag would be a very bad, breaking change.
I'm writing a Rust library and I want to provide examples in my documentation that
compile as part of running cargo test
do not run.
Is this possible?
I'm writing a database client library, and the examples make use of a hypothetical, non-existing database server. As such, the examples always fail when run, but it's important that the examples be valid syntactically. Hence my requirements above.
If there's no way to do what I want, then how does one opt out of having cargo test run a specific doc test? I.e., have cargo run compile-and-run some doc tests but completely ignore some others?
This is documented in The rustdoc book, specifically the chapter about attributes.
Your opening codeblock delimiter should look like:
/// ```no_run
From the book:
/// ```no_run
/// loop {
/// println!("Hello, world");
/// }
/// ```
The no_run attribute will compile your code, but not run it. This is
important for examples such as "Here's how to retrieve a web page,"
which you would want to ensure compiles, but might be run in a test
environment that has no network access.
To omit build completely use ignore instead of no_run.
Put this in Cargo.toml:
[lib]
doctest = false
Found it here: https://doc.rust-lang.org/cargo/commands/cargo-test.html