Each Rust source file in tests directory is compiled as a separate crate. One way of sharing some code between integration tests is making module with public functions, importing and using it within tests.
File tests/common.rs:
pub fn setup() {
}
File with test: tests/integration_test.rs
mod common;
#[test]
fn test_add() {
common::setup();
assert_eq!(adder::add(3, 2), 5);
}
Modules with common code follow the ordinary modules rules, so it's ok to create common module as tests/common/mod.rs.
Sometimes there is a need to have dependencies for tests (or examples, or benchmarks) only. Such dependencies are added to Cargo.toml in the [dev-dependencies] section. These dependencies are not propagated to other packages which depend on this package.
One such example is using a crate that extends standard assert! macros. File Cargo.toml:
[dev-dependencies]
pretty_assertions = "0.4.0"
File src/lib.rs:
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}
Cargo docs on specifying dependencies.
As an introduction to this section, to borrow from the official docs, "one should try to minimize the amount of unsafe code in a code base." With that in mind, let's get started! Unsafe annotations in Rust are used to bypass protections put in place by the compiler; specifically, there are four primary things that unsafe is used for:
• dereferencing raw pointers
• calling functions or methods which are unsafe (including calling a function over FFI, see a previous chapter of the book)
• accessing or modifying static mutable variables
• implementing unsafe traits
Raw pointers * and references &T function similarly, but references are always safe because they are guaranteed to point to valid data due to the borrow checker. Dereferencing a raw pointer can only be done through an unsafe block.
fn main() {
let raw_p: *const u32 = &10;
unsafe {
assert!(*raw_p == 10);
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Some functions can be declared as unsafe, meaning it is the programmer's responsibility to ensure correctness instead of the compiler's. One example of this is std::slice::from_raw_parts which will create a slice given a pointer to the first element and a length.
use std::slice;
fn main() {
let some_vector = vec![1, 2, 3, 4];
let pointer = some_vector.as_ptr();
let length = some_vector.len();
unsafe {
let my_slice: &[u32] = slice::from_raw_parts(pointer, length);
assert_eq!(some_vector.as_slice(), my_slice);
}
}