Документация и тестване

18 октомври 2018

Административни неща

Административни неща

Административни неща

Административни неща

Преговор

Enums and pattern matching

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
enum Message {
    Quit,
    Move { x: i64, y: i64 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

let message = Message::Move { x: 1, y: 3 };

match message {
    Message::Quit => println!("What a quitter!"),
    Message::Move { x, y } => println!("Going to ({}, {})!", x, y),
    Message::Write(_) => println!("Pfff.. whatevs"),
    Message::ChangeColor(_, _, b) if b > 200 => println!("So much blue!"),
    _ => println!("Don't care."),
}
Going to (1, 3)!

Преговор

A long time ago….

1 2 3 4 5 6 7 8 9
let mut token = Token::Text(String::from("Отговора е 42"));

match &mut token {
    &mut Token::Text(ref mut text) => {
        *text = String::from("Може би");
        println!("Токена е Text('{}')", text)
    },
    &mut Token::Number(n) => println!("Токена е Number({})", n),
}
Токена е Text('Може би')

Преговор

Today

1 2 3 4 5 6 7 8 9
let mut token = Token::Text(String::from("Отговора е 42"));

match &mut token {
    Token::Text(text) => {
        *text = String::from("Може би");
        println!("Токена е Text('{}')", text)
    },
    Token::Number(n) => println!("Токена е Number({})", n),
}
Токена е Text('Може би')

Преговор

Refutable/Irrefutable patterns

1 2 3 4 5
let (a, b) = (1, 2); // -> Irrefutable pattern

if let Some(val) = Some(5) { // -> Refutable pattern
    println!("Okay!");
}
Okay!

Преговор

Refutable/Irrefutable patterns

1 2 3 4 5
if let (a, b) = (1, 2) {
    println!("Boom!");
}

let Some(val) = Some(5);
error[E0162]: irrefutable if-let pattern
 --> /src/main_4.rs:3:8
  |
3 | if let (a, b) = (1, 2) {
  |        ^^^^^^ irrefutable pattern

error[E0005]: refutable pattern in local binding: `None` not covered
 --> /src/main_4.rs:7:5
  |
7 | let Some(val) = Some(5);
  |     ^^^^^^^^^ pattern `None` not covered

Низове

Низове

Низове

Документация

Документация

Документация

Документация

Документация

Документация

Kоментари

Документация

Kоментари

Документация

Kоментари

Документация

Kоментари

Документация

Kоментари

Документация

Структури

1 2 3 4 5 6 7 8
/// A (half-open) range bounded inclusively below and exclusively above (start..end).
///
/// The `Range` `start..end` contains all values with `x >= start` and `x < end`.
/// It is empty unless `start < end`.
pub struct Range<Idx> {
    pub start: Idx,
    pub end: Idx,
}

Документация

Полета

1 2 3 4 5 6 7 8 9 10
/// A (half-open) range bounded inclusively below and exclusively above (start..end).
///
/// The `Range` `start..end` contains all values with `x >= start` and `x < end`.
/// It is empty unless `start < end`.
pub struct Range<Idx> {
    /// The lower bound of the range (inclusive).
    pub start: Idx,
    /// The upper bound of the range (exclusive).
    pub end: Idx,
}

Документация

Функции и Методи

1 2 3 4 5 6 7 8 9 10 11 12 13 14
impl String {
    /// Appends a given string slice onto the end of this `String`.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// \`\`\`
    /// let mut s = String::from("foo");
    /// s.push_str("bar");
    /// assert_eq!("foobar", s);
    /// \`\`\`
    pub fn push_str(&mut self, string: &str) {}
}

Документация

Модули

1 2 3 4 5 6 7 8
/// Filesystem manipulation operations.
///
/// This module contains basic methods to manipulate the
/// contents of the local filesystem. All methods in this
/// module represent cross-platform filesystem operations.
mod fs {
    /* ... */
}

Документация

Модули

1 2 3 4 5 6 7 8 9
mod fs {
    //! Filesystem manipulation operations.
    //!
    //! This module contains basic methods to manipulate the
    //! contents of the local filesystem. All methods in this
    //! module represent cross-platform filesystem operations.

    /* ... */
}

Документация

Модули

1 2 3 4 5 6 7 8 9
mod fs {
    //! Filesystem manipulation operations.
    //!
    //! This module contains basic methods to manipulate the
    //! contents of the local filesystem. All methods in this
    //! module represent cross-platform filesystem operations.

    /* ... */
}

Коментари, които започват с //!, документират елемента, в който се намират (parent item).

Атрибути

Атрибути

Атрибути

Атрибути

Атрибути

Пример

1 2 3 4 5
#[derive(Debug)]
struct User {
    name: String,
    age: i32,
}

Атрибути

Пример

1 2 3 4 5 6 7 8
#[derive(Debug)]
struct User {
    name: String,
    age: i32,
}

let user = User { name: "Пешо".to_string(), age: 14 };
println!("{:?}", user);
User { name: "Пешо", age: 14 }

Тестове

Тестове

1
cargo new --lib example
1 2 3 4 5 6 7 8 9
// src/lib.rs

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

Тестове

Тестовете са функции, анотирани с #[test]

1 2 3 4 5 6 7 8
fn add_two(x: i32) -> i32 {
    x + 2
}

#[test]
fn it_works() {
    assert_eq!(add_two(2), 4);
}

Тестове

С cargo test се изпълняват всички тестове

     Running target/debug/deps/example-1359d134fea57abe

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests example

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Тестове

Asserts

Тестове

Asserts

Тестове

Asserts

Тестове

Asserts

Тестове

Asserts

Тестове

Asserts

1 2 3
fn main() {
    assert!(add_two(2) == 5);
}
thread 'main' panicked at 'assertion failed: add_two(2) == 5', /src/main_14.rs:3:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Тестове

Asserts

assert_eq! и assert_ne! показват и какви са стойностите, които сравняваме

1 2 3
fn main() {
    assert_eq!(add_two(2), 5);
}
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `4`,
 right: `5`', /src/main_15.rs:3:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Тестове

Panics

За да тестваме, че при определен вход функция спира програмата, има допълнителен атрибут #[should_panic]

1 2 3 4 5 6 7 8 9 10
fn connect(addr: String) {
    // no error handling, will panic if it can't parse `addr`
    let ip_addr: Ipv4Addr = addr.parse().unwrap();
}

#[test]
#[should_panic]
fn cant_connect_to_invalid_ip() {
    connect("10.20.30.1234".to_string());
}

Тестове

Стандартно е тестовете да стоят в отеделен модул

1 2 3 4 5 6 7 8 9 10
fn add_two(x: i32) -> i32 {
    x + 2
}

mod tests {
    #[test]
    fn it_works() {
        assert_eq!(add_two(2), 4);
    }
}

Тестове

С #[cfg(test)] тестовете се компилират само при cargo test

1 2 3 4 5 6 7 8 9 10 11
fn add_two(x: i32) -> i32 {
    x + 2
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(add_two(2), 4);
    }
}

Тестове на документацията

1 2 3 4 5 6
/**
 * Always returns true.
 */
public boolean isAvailable() {
    return false;
}

Тестове на документацията

Тестове на документацията

Тестове на документацията

Тестове на документацията

Пример

1 2 3 4 5 6 7 8 9
/// Converts a `char` to a digit in the given radix.
///
///
/// # Examples
///
/// \`\`\`
/// assert_eq!('1'.to_digit(10), Some(1));
/// assert_eq!('f'.to_digit(16), Some(15));
/// \`\`\`

Тестове на документацията

Пример

1 2 3 4 5 6 7 8 9
/// Converts a `char` to a digit in the given radix.
///
///
/// # Examples
///
/// \`\`\`
/// assert_eq!('1'.to_digit(10), Some(1));
/// assert_eq!('f'.to_digit(16), Some(15));
/// \`\`\`
   Doc-tests example

running 1 test
test src/lib.rs - to_digit (line 8) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Тестове на документацията

Понякога искаме примерите да се компилират, но да не се изпълняват, защото имат странични ефекти.
Тогава може да подадем no_run като език.

Тестове на документацията

Понякога искаме примерите да се компилират, но да не се изпълняват, защото имат странични ефекти.
Тогава може да подадем no_run като език.

1 2 3 4 5 6 7 8 9 10 11 12
/// Create a new file and write bytes to it:
///
/// \`\`\`no_run
/// use std::fs::File;
/// use std::io::prelude::*;
///
/// fn main() -> std::io::Result<()> {
///     let mut file = File::create("foo.txt")?;
///     file.write_all(b"Hello, world!")?;
///     Ok(())
/// }
/// \`\`\`

Тестове на документацията

Ако не искаме дори да се компилират, се използва ignore.

Тестове на документацията

Ако не искаме дори да се компилират, се използва ignore.

Има и други специфики, които може да намерите в Rustdoc книгата:

Организация на тестовете

Unit tests

Организация на тестовете

Unit tests

Организация на тестовете

Unit tests

Организация на тестовете

Unit tests

1 2 3 4 5 6 7 8 9 10 11
fn add_two(x: i32) -> i32 {
    x + 2
}

#[cfg(test)]
mod tests {
    #[test]
    fn adder_adds() {
        assert_eq!(add_two(2), 4);
    }
}

Организация на тестовете

Unit tests

Като подмодул тестовете имат достъп до private функционалността на модула

1 2 3 4 5 6 7 8 9 10 11 12 13
pub fn add_two(x: i32) -> i32 { internal_adder(x) }

fn internal_adder(x: i32) -> i32 { x + 2 }

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn adder_adds() {
        assert_eq!(internal_adder(2), 4);
    }
}

Организация на тестовете

Integration tests

Организация на тестовете

Integration tests

Организация на тестовете

Integration tests

1 2 3 4 5 6 7
adder
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── tests
    └── adder.rs

Организация на тестовете

Integration tests

1 2 3 4 5 6 7
adder
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── tests
    └── adder.rs

Организация на тестовете

Integration tests

1 2 3 4 5 6 7 8
// tests//adder.rs

extern crate adder;

#[test]
fn adder_adds() {
    assert_eq!(adder::add_two(2), 4);
}

Организация на тестовете

Integration tests

1 2 3 4 5 6 7 8
// tests//adder.rs

extern crate adder;

#[test]
fn adder_adds() {
    assert_eq!(adder::add_two(2), 4);
}

Организация на тестовете

Integration tests

1 2 3 4 5 6 7 8
// tests//adder.rs

extern crate adder;

#[test]
fn adder_adds() {
    assert_eq!(adder::add_two(2), 4);
}

Организация на тестовете

Integration tests

1 2 3 4 5 6 7 8
// tests//adder.rs

extern crate adder;

#[test]
fn adder_adds() {
    assert_eq!(adder::add_two(2), 4);
}

Организация на тестовете

Integration tests

1 2 3 4 5 6 7 8
// tests//adder.rs

extern crate adder;

#[test]
fn adder_adds() {
    assert_eq!(adder::add_two(2), 4);
}

Въпроси