Читаем Rust by Example полностью

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() {

// some setup code, like creating required files/directories, starting

// servers, etc.

}

File with test: tests/integration_test.rs

// importing common module.

mod common;

#[test]

fn test_add() {

// using common code.

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.

<p id="development_dependencies"><strong><a l:href="#development_dependencies">Development dependencies</a></strong></p>

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:

# standard crate data is left out

[dev-dependencies]

pretty_assertions = "0.4.0"

File src/lib.rs:

// externing crate for test-only use

#[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);

}

}

<p id="see_also_74"><strong><a l:href="#see_also_74">See Also</a></strong></p>

Cargo docs on specifying dependencies.

<p id="unsafe_operations"><strong><a l:href="#unsafe_operations">Unsafe Operations</a></strong></p>

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

<p id="raw_pointers"><strong><a l:href="#raw_pointers">Raw Pointers</a></strong></p>

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

<p id="calling_unsafe_functions"><strong><a l:href="#calling_unsafe_functions">Calling Unsafe Functions</a></strong></p>

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);

}

}

Перейти на страницу:

Похожие книги