Use same struct across multiple test files [duplicate] - testing

I have Rust project with both integration tests (in the /tests dir) and benchmarks (in the /benches dir). There are a couple of utility functions that I need in tests and benches, but they aren't related to my crate itself, so I can't just put them in the /utils dir.
What is idiomatic way to handle this situation?

Create a shared crate (preferred)
As stated in the comments, create a new crate. You don't have to publish the crate to crates.io. Just keep it as a local unpublished crate inside your project and mark it as a development-only dependency.
This is best used with version 2 of the Cargo resolver. For better performance, consider using a Cargo workspace.
.
├── Cargo.toml
├── src
│   └── lib.rs
├── tests
│   └── integration.rs
└── utilities
├── Cargo.toml
└── src
└── lib.rs
Cargo.toml
# ...
[dev-dependencies]
utilities = { path = "utilities" }
utilities/src/lib.rs
pub fn shared_code() {
println!("I am shared code");
}
tests/integration.rs
extern crate utilities;
#[test]
fn a_test() {
utilities::shared_code();
}
A test-only module
You could place a module inside your crate that is only compiled when a specific feature is passed. This is the same concept used for unit tests. This has the advantage that it can access internals of your library code. It has the disadvantage that you need to pass the flag each time you run the code.
This is best used with version 2 of the Cargo resolver.
Cargo.toml
# ...
[features]
test-utilities = []
src/lib.rs
#[cfg(feature = "test-utilities")]
pub mod test_utilities {
pub fn shared_code() {
println!("I'm inside the library")
}
}
tests/integration.rs
extern crate the_library;
#[test]
fn a_test() {
the_library::test_utilities::shared_code();
}
execution
cargo test --features=test-utilities
This is best used with version 2 of the Cargo resolver.
Use a module from an arbitrary file path
This is just ugly to me, and really goes out of the normal path.
utilities.rs
pub fn shared_code() {
println!("This is just sitting out there");
}
tests/integration.rs
#[path = "../utilities.rs"]
mod utilities;
#[test]
fn a_test() {
utilities::shared_code();
}
See also:
Where should I put test utility functions in Rust?

You could add those utility-functions to a pub-module inside your main crate and use the #[doc(hidden)] or #![doc(hidden)] attribute to hide them from the docs-generator. Extra comments will guide the reader to why they are there.

Whilst this doesn't help for benchmarks, I came here looking for a way to do this with multiple integration tests, and later found that you can do the following for integration tests:
Modules with common code follow the ordinary modules rules, so it's ok to create common module as tests/common/mod.rs.
Source: https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html

Related

Cross-module function call in Rust

I'm trying to call a function belonging to some module from another module (for code factoring, organization, etc).
Here is my crate structure:
➜ mod_test git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
├── bin
│ └── one.rs
├── lib
│ └── two.rs
└── main.rs
3 directories, 5 files
In main I declare:
pub mod bin {
pub mod one;
}
pub mod lib {
pub mod two;
}
and all these files simply contain a trivial pub fn main() {println!("hello");}.
At this point, everything is okay.
Now, is it possible to call lib::two::main from bin/one.rs?
None of use crate::lib::two;, use super::lib::two;, use self::super::lib::two; added in bin/one.rs work.
edit: I have: rustc 1.42.0 (b8cedc004 2020-03-09) installed on Linux 5.3.0-45-generic, for what it's worth.
edit 2: whenever using the super keyword, I get this mysterious error from rustc:
error[E0433]: failed to resolve: there are too many leading `super` keywords
and I can't find any troubleshooting about this anywhere.
edit 3: adding a lib.rs file in src declaring the lib module structure, and writing use mod_test::lib::two; in one.rs works, but:
1) it defeats the idea of not multiplying "dumb module declaration files" in my crate.
2) I have to literally copy the exact same information at two different places (in main.rs and in lib.rs)
3) use mod_test::lib::two; is the only working syntax, using crate or super keywords still result in arcane compiler errors
src/bin is a special directory name to Cargo. Files in this directory are compiled as standalone binaries when you run cargo build. When compiled as binaries, they aren't part of the crate structure defined in main.rs or lib.rs.
If you just want to use bin::one as a module inside main.rs, what you have works already! You're getting error messages from compiling one.rs as a standalone binary, not from compiling main.rs with bin::one as a module. If you run cargo run --bin <name-of-project>, compilation will succeed and it will run the program in main.rs.
To tell Cargo not to compile one.rs by itself, I would suggest renaming the bin directory. This not only solves the technical problem, but also is less likely to confuse other programmers reading the project, who will expect bin to contain binaries. There may be some way to prevent Cargo from treating bin specially in this way; however, renaming it is probably the best option.
If you do want one.rs to be compiled to a separate executable that uses two, you must create a lib.rs file in the same directory as main.rs. This is also a special file to Cargo and it defines the module structure for the library crate.
// lib.rs
pub mod lib { /* note: this lib is not related to lib.rs; just unfortunately named */
pub mod two;
}
Then inside one.rs, write use <crate-name>::lib::two;
// bin/one.rs
use mod_test::lib::two;
crate::lib::two does not work, as files inside the bin directory are compiled as standalone binaries, not as crate members; therefore, you have to call the crate by its "external" name.
adding a lib.rs file in src declaring the lib module structure, and writing use mod_test::lib::two; in one.rs works, but:
1) it defeats the idea of not multiplying "dumb module declaration files" in my crate.
2) I have to literally copy the exact same information at two different places (in main.rs and in lib.rs)
main.rs and lib.rs are two different crate roots. They are allowed to have different structure. You don't need both unless you want to generate both the binary and the library. If you want to use the library crate from inside any binary (including main.rs), it's just a use away:
use mod_test;
See also
Rust modules confusion when there is main.rs and lib.rs
Rust package with both a library and a binary?

Use module from parent directory in rust

Is it possible to structure a rust project in this way?
Directory structure:
src
├── a
│   └── bin1.rs
├── b
│   ├── bin2.rs
└── common
├── mod.rs
from Cargo.toml:
[[bin]]
name = "bin1"
path = "src/a/bin1.rs"
[[bin]]
name = "bin2"
path = "src/b/bin2.rs"
I would like to be able to use the common module in bin1.rs and bin2.rs. It's possible by adding the path attribute before the import:
#[path="../common/mod.rs"]
mod code;
Is there a way for bin1.rs and bin2.rs to use common without having to hardcode the path?
The recommended method to share code between binaries is to have a src/lib.rs file. Both binaries automatically have access to anything accessible through this lib.rs file as a separate crate.
Then you would simply define a mod common; in the src/lib.rs file. If your crate is called my_crate, your binaries would be able to use it with
use my_crate::common::Foo;

How to import a module from a directory outside of the `src` directory?

I'm stuck when learning how to access a module. I'm trying to insert a folder other than src into src. It's not working and it gives me an error. Here this is my project tree.
$ Project1
.
|-- src
| |-- main.rs
| |--FolderinSrcFolder
| |--folderinsrcmodule.rs
|
|--anothersrc
| |--mod.rs
|
|-- rootmodule.rs
|-- Cargo.toml
|-- Cargo.lock
How can I access anothersrc/mod.rs src/main.rs? How can I access rootmodule.rs from src/main.rs?
I already read the Rust documentation.
Idiomatic solution
Don't. Put all of your source code into the src directory. You could also create another crate with its own src directory. Don't fight these idioms and conventions, it's simply not worth it.
See also:
Rust package with both a library and a binary?
Literal solution
This directly answers your question, but I strongly recommend that you don't actually use this!
Layout
.
├── Cargo.toml
├── bad_location.rs
└── src
   └── main.rs
src/main.rs
#[path = "../bad_location.rs"]
mod bad_location;
fn main() {
println!("Was this a bad idea? {}", bad_location::dont_do_this());
}
badlocation.rs
pub fn dont_do_this() -> bool {
true
}
The key is the #[path] annotation.
See also:
How can I use a module from outside the src folder in a binary project, such as for integration tests or benchmarks?
How do I tell Cargo to run files from a directory other than "src"?
How do I import from a sibling module?

How to include types from the main module in other files from the same crate?

I'm writing a Rust library called my_new_lib and have the following file structure:
├── my_new_lib
├── src
├── lib.rs
└── file1.rs
├── tests
In lib.rs I defined a struct:
/// content of lib.rs
pub struct my_struct {}
In file1.rs I want to use my_struct, for example:
/// content of file1.rs
use ????
pub struct my_second_struct {
member1: my_struct
}
what should I put in the use clause in file1.rs to make it work?
You must use the crate keyword to access to the root of your crate:
use crate::MyStruct;

What is an idiomatic way to have shared utility functions for integration tests and benchmarks?

I have Rust project with both integration tests (in the /tests dir) and benchmarks (in the /benches dir). There are a couple of utility functions that I need in tests and benches, but they aren't related to my crate itself, so I can't just put them in the /utils dir.
What is idiomatic way to handle this situation?
Create a shared crate (preferred)
As stated in the comments, create a new crate. You don't have to publish the crate to crates.io. Just keep it as a local unpublished crate inside your project and mark it as a development-only dependency.
This is best used with version 2 of the Cargo resolver. For better performance, consider using a Cargo workspace.
.
├── Cargo.toml
├── src
│   └── lib.rs
├── tests
│   └── integration.rs
└── utilities
├── Cargo.toml
└── src
└── lib.rs
Cargo.toml
# ...
[dev-dependencies]
utilities = { path = "utilities" }
utilities/src/lib.rs
pub fn shared_code() {
println!("I am shared code");
}
tests/integration.rs
extern crate utilities;
#[test]
fn a_test() {
utilities::shared_code();
}
A test-only module
You could place a module inside your crate that is only compiled when a specific feature is passed. This is the same concept used for unit tests. This has the advantage that it can access internals of your library code. It has the disadvantage that you need to pass the flag each time you run the code.
This is best used with version 2 of the Cargo resolver.
Cargo.toml
# ...
[features]
test-utilities = []
src/lib.rs
#[cfg(feature = "test-utilities")]
pub mod test_utilities {
pub fn shared_code() {
println!("I'm inside the library")
}
}
tests/integration.rs
extern crate the_library;
#[test]
fn a_test() {
the_library::test_utilities::shared_code();
}
execution
cargo test --features=test-utilities
This is best used with version 2 of the Cargo resolver.
Use a module from an arbitrary file path
This is just ugly to me, and really goes out of the normal path.
utilities.rs
pub fn shared_code() {
println!("This is just sitting out there");
}
tests/integration.rs
#[path = "../utilities.rs"]
mod utilities;
#[test]
fn a_test() {
utilities::shared_code();
}
See also:
Where should I put test utility functions in Rust?
You could add those utility-functions to a pub-module inside your main crate and use the #[doc(hidden)] or #![doc(hidden)] attribute to hide them from the docs-generator. Extra comments will guide the reader to why they are there.
Whilst this doesn't help for benchmarks, I came here looking for a way to do this with multiple integration tests, and later found that you can do the following for integration tests:
Modules with common code follow the ordinary modules rules, so it's ok to create common module as tests/common/mod.rs.
Source: https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html