The Rust Programming Language › Validating References with Lifetimes › Lifetime Elision

The third rule is that, if there are multiple input lifetime parameters, but
one of them is `&self` or `&mut self` because this is a method, the lifetime of
`self` is assigned to all output lifetime parameters. This third rule makes
methods much nicer to read and write because fewer symbols are necessary.
Let’s pretend we’re the compiler. We’ll apply these rules to figure out the
lifetimes of the references in the signature of the `first_word` function in
Listing 10-25. The signature starts without any lifetimes associated with the
references:
```rust,ignore
fn first_word(s: &str) -> &str {
```
Then, the compiler applies the first rule, which specifies that each parameter
gets its own lifetime. We’ll call it `'a` as usual, so now the signature is
this:
```rust,ignore
fn first_word<'a>(s: &'a str) -> &str {
```
The second rule applies because there is exactly one input lifetime. The second
rule specifies that the lifetime of the one input parameter gets assigned to
the output lifetime, so the signature is now this:
```rust,ignore
fn first_word<'a>(s: &'a str) -> &'a str {
```
Now all the references in this function signature have lifetimes, and the
compiler can continue its analysis without needing the programmer to annotate
the lifetimes in this function signature.
Let’s look at another example, this time using the `longest` function that had
no lifetime parameters when we started working with it in Listing 10-20:
```rust,ignore
fn longest(x: &str, y: &str) -> &str {
```
Let’s apply the first rule: Each parameter gets its own lifetime. This time we
have two parameters instead of one, so we have two lifetimes:


The Rust Programming Language › Validating References with Lifetimes › Lifetime Elision

```rust,ignore
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
```
You can see that the second rule doesn’t apply, because there is more than one
input lifetime. The third rule doesn’t apply either, because `longest` is a
function rather than a method, so none of the parameters are `self`. After
working through all three rules, we still haven’t figured out what the return
type’s lifetime is. This is why we got an error trying to compile the code in
Listing 10-20: The compiler worked through the lifetime elision rules but still
couldn’t figure out all the lifetimes of the references in the signature.
Because the third rule really only applies in method signatures, we’ll look at
lifetimes in that context next to see why the third rule means we don’t have to
annotate lifetimes in method signatures very often.

Validating References with Lifetimes
Lifetime Elision


The Rust Programming Language › Validating References with Lifetimes › In Method Definitions

When we implement methods on a struct with lifetimes, we use the same syntax as
that of generic type parameters, as shown in Listing 10-11. Where we declare
and use the lifetime parameters depends on whether they’re related to the
struct fields or the method parameters and return values.
Lifetime names for struct fields always need to be declared after the `impl`
keyword and then used after the struct’s name because those lifetimes are part
of the struct’s type.
In method signatures inside the `impl` block, references might be tied to the
lifetime of references in the struct’s fields, or they might be independent. In
addition, the lifetime elision rules often make it so that lifetime annotations
aren’t necessary in method signatures. Let’s look at some examples using the
struct named `ImportantExcerpt` that we defined in Listing 10-24.
First, we’ll use a method named `level` whose only parameter is a reference to
`self` and whose return value is an `i32`, which is not a reference to anything:
```rust
impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }
}
```
The lifetime parameter declaration after `impl` and its use after the type name
are required, but because of the first elision rule, we’re not required to
annotate the lifetime of the reference to `self`.
Here is an example where the third lifetime elision rule applies:
```rust
impl<'a> ImportantExcerpt<'a> {
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {announcement}");
        self.part
    }
}
```

Validating References with Lifetimes
In Method Definitions


The Rust Programming Language › Validating References with Lifetimes › In Method Definitions

There are two input lifetimes, so Rust applies the first lifetime elision rule
and gives both `&self` and `announcement` their own lifetimes. Then, because
one of the parameters is `&self`, the return type gets the lifetime of `&self`,
and all lifetimes have been accounted for.


The Rust Programming Language › Validating References with Lifetimes › The Static Lifetime

One special lifetime we need to discuss is `'static`, which denotes that the
affected reference _can_ live for the entire duration of the program. All
string literals have the `'static` lifetime, which we can annotate as follows:
```rust
let s: &'static str = "I have a static lifetime.";
```
The text of this string is stored directly in the program’s binary, which is
always available. Therefore, the lifetime of all string literals is `'static`.
You might see suggestions in error messages to use the `'static` lifetime. But
before specifying `'static` as the lifetime for a reference, think about
whether or not the reference you have actually lives the entire lifetime of
your program, and whether you want it to. Most of the time, an error message
suggesting the `'static` lifetime results from attempting to create a dangling
reference or a mismatch of the available lifetimes. In such cases, the solution
is to fix those problems, not to specify the `'static` lifetime.

Validating References with Lifetimes
The Static Lifetime


The Rust Programming Language › Generic Type Parameters, Trait Bounds, and Lifetimes

Let’s briefly look at the syntax of specifying generic type parameters, trait
bounds, and lifetimes all in one function!
```rust
use std::fmt::Display;

fn longest_with_an_announcement<'a, T>(
    x: &'a str,
    y: &'a str,
    ann: T,
) -> &'a str
where
    T: Display,
{
    println!("Announcement! {ann}");
    if x.len() > y.len() { x } else { y }
}
```
This is the `longest` function from Listing 10-21 that returns the longer of
two string slices. But now it has an extra parameter named `ann` of the generic
type `T`, which can be filled in by any type that implements the `Display`
trait as specified by the `where` clause. This extra parameter will be printed
using `{}`, which is why the `Display` trait bound is necessary. Because
lifetimes are a type of generic, the declarations of the lifetime parameter
`'a` and the generic type parameter `T` go in the same list inside the angle
brackets after the function name.


The Rust Programming Language › Summary

We covered a lot in this chapter! Now that you know about generic type
parameters, traits and trait bounds, and generic lifetime parameters, you’re
ready to write code without repetition that works in many different situations.
Generic type parameters let you apply the code to different types. Traits and
trait bounds ensure that even though the types are generic, they’ll have the
behavior the code needs. You learned how to use lifetime annotations to ensure
that this flexible code won’t have any dangling references. And all of this
analysis happens at compile time, which doesn’t affect runtime performance!
Believe it or not, there is much more to learn on the topics we discussed in
this chapter: Chapter 18 discusses trait objects, which are another way to use
traits. There are also more complex scenarios involving lifetime annotations
that you will only need in very advanced scenarios; for those, you should read
the Rust Reference. But next, you’ll learn how to write tests in
Rust so that you can make sure your code is working the way it should.


The Rust Programming Language › Writing Automated Tests

In his 1972 essay “The Humble Programmer,” Edsger W. Dijkstra said that “program
testing can be a very effective way to show the presence of bugs, but it is
hopelessly inadequate for showing their absence.” That doesn’t mean we shouldn’t
try to test as much as we can!
_Correctness_ in our programs is the extent to which our code does what we
intend it to do. Rust is designed with a high degree of concern about the
correctness of programs, but correctness is complex and not easy to prove.
Rust’s type system shoulders a huge part of this burden, but the type system
cannot catch everything. As such, Rust includes support for writing automated
software tests.
Say we write a function `add_two` that adds 2 to whatever number is passed to
it. This function’s signature accepts an integer as a parameter and returns an
integer as a result. When we implement and compile that function, Rust does all
the type checking and borrow checking that you’ve learned so far to ensure
that, for instance, we aren’t passing a `String` value or an invalid reference
to this function. But Rust _can’t_ check that this function will do precisely
what we intend, which is return the parameter plus 2 rather than, say, the
parameter plus 10 or the parameter minus 50! That’s where tests come in.
We can write tests that assert, for example, that when we pass `3` to the
`add_two` function, the returned value is `5`. We can run these tests whenever
we make changes to our code to make sure any existing correct behavior has not
changed.


The Rust Programming Language › Writing Automated Tests

Testing is a complex skill: Although we can’t cover in one chapter every detail
about how to write good tests, in this chapter we will discuss the mechanics of
Rust’s testing facilities. We’ll talk about the annotations and macros
available to you when writing your tests, the default behavior and options
provided for running your tests, and how to organize tests into unit tests and
integration tests.


The Rust Programming Language › How to Write Tests

_Tests_ are Rust functions that verify that the non-test code is functioning in
the expected manner. The bodies of test functions typically perform these three
actions:
- Set up any needed data or state.
- Run the code you want to test.
- Assert that the results are what you expect.
Let’s look at the features Rust provides specifically for writing tests that
take these actions, which include the `test` attribute, a few macros, and the
`should_panic` attribute.


The Rust Programming Language › How to Write Tests › Structuring Test Functions

At its simplest, a test in Rust is a function that’s annotated with the `test`
attribute. Attributes are metadata about pieces of Rust code; one example is
the `derive` attribute we used with structs in Chapter 5. To change a function
into a test function, add `#[test]` on the line before `fn`. When you run your
tests with the `cargo test` command, Rust builds a test runner binary that runs
the annotated functions and reports on whether each test function passes or
fails.
Whenever we make a new library project with Cargo, a test module with a test
function in it is automatically generated for us. This module gives you a
template for writing your tests so that you don’t have to look up the exact
structure and syntax every time you start a new project. You can add as many
additional test functions and as many test modules as you want!
We’ll explore some aspects of how tests work by experimenting with the template
test before we actually test any code. Then, we’ll write some real-world tests
that call some code that we’ve written and assert that its behavior is correct.
Let’s create a new library project called `adder` that will add two numbers:
```console
$ cargo new adder --lib
     Created library `adder` project
$ cd adder
```
The contents of the _src/lib.rs_ file in your `adder` library should look like
Listing 11-1.
Listing 11-1: The code generated automatically by `cargo new` (src/lib.rs)
```rust,noplayground
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

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

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}
```

How to Write Tests
Structuring Test Functions


The Rust Programming Language › How to Write Tests › Structuring Test Functions

The file starts with an example `add` function so that we have something to
test.
For now, let’s focus solely on the `it_works` function. Note the `#[test]`
annotation: This attribute indicates this is a test function, so the test
runner knows to treat this function as a test. We might also have non-test
functions in the `tests` module to help set up common scenarios or perform
common operations, so we always need to indicate which functions are tests.
The example function body uses the `assert_eq!` macro to assert that `result`,
which contains the result of calling `add` with 2 and 2, equals 4. This
assertion serves as an example of the format for a typical test. Let’s run it
to see that this test passes.
The `cargo test` command runs all tests in our project, as shown in Listing
11-2.
Listing 11-2: The output from running the automatically generated test
```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57s
     Running unittests src/lib.rs (target/debug/deps/adder-01ad14159ff659ab)

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```


The Rust Programming Language › How to Write Tests › Structuring Test Functions

Cargo compiled and ran the test. We see the line `running 1 test`. The next
line shows the name of the generated test function, called `tests::it_works`,
and that the result of running that test is `ok`. The overall summary `test
result: ok.` means that all the tests passed, and the portion that reads `1
passed; 0 failed` totals the number of tests that passed or failed.
It’s possible to mark a test as ignored so that it doesn’t run in a particular
instance; we’ll cover that in the “Ignoring Tests Unless Specifically
Requested” section later in this chapter. Because we
haven’t done that here, the summary shows `0 ignored`. We can also pass an
argument to the `cargo test` command to run only tests whose name matches a
string; this is called _filtering_, and we’ll cover it in the “Running a
Subset of Tests by Name” section. Here, we haven’t
filtered the tests being run, so the end of the summary shows `0 filtered out`.
The `0 measured` statistic is for benchmark tests that measure performance.
Benchmark tests are, as of this writing, only available in nightly Rust. See
the documentation about benchmark tests to learn more.
The next part of the test output starting at `Doc-tests adder` is for the
results of any documentation tests. We don’t have any documentation tests yet,
but Rust can compile any code examples that appear in our API documentation.
This feature helps keep your docs and your code in sync! We’ll discuss how to
write documentation tests in the “Documentation Comments as
Tests” section of Chapter 14. For now, we’ll
ignore the `Doc-tests` output.


The Rust Programming Language › How to Write Tests › Structuring Test Functions

Let’s start to customize the test to our own needs. First, change the name of
the `it_works` function to a different name, such as `exploration`, like so:
Filename: src/lib.rs
```rust,noplayground
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

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

    #[test]
    fn exploration() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}
```
Then, run `cargo test` again. The output now shows `exploration` instead of
`it_works`:
```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.59s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::exploration ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```


The Rust Programming Language › How to Write Tests › Structuring Test Functions

Now we’ll add another test, but this time we’ll make a test that fails! Tests
fail when something in the test function panics. Each test is run in a new
thread, and when the main thread sees that a test thread has died, the test is
marked as failed. In Chapter 9, we talked about how the simplest way to panic
is to call the `panic!` macro. Enter the new test as a function named
`another`, so your _src/lib.rs_ file looks like Listing 11-3.
Listing 11-3: Adding a second test that will fail because we call the `panic!` macro (src/lib.rs)
```rust,panics,noplayground
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

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

    #[test]
    fn exploration() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    fn another() {
        panic!("Make this test fail");
    }
}
```
Run the tests again using `cargo test`. The output should look like Listing
11-4, which shows that our `exploration` test passed and `another` failed.
Listing 11-4: Test results when one test passes and one test fails


The Rust Programming Language › How to Write Tests › Structuring Test Functions

```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.72s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::another ... FAILED
test tests::exploration ... ok

failures:

---- tests::another stdout ----

thread 'tests::another' (6019162) panicked at src/lib.rs:17:9:
Make this test fail
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::another

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
Instead of `ok`, the line `test tests::another` shows `FAILED`. Two new
sections appear between the individual results and the summary: The first
displays the detailed reason for each test failure. In this case, we get the
details that `tests::another` failed because it panicked with the message `Make
this test fail` on line 17 in the _src/lib.rs_ file. The next section lists
just the names of all the failing tests, which is useful when there are lots of
tests and lots of detailed failing test output. We can use the name of a
failing test to run just that test to debug it more easily; we’ll talk more
about ways to run tests in the “Controlling How Tests Are
Run” section.
The summary line displays at the end: Overall, our test result is `FAILED`. We
had one test pass and one test fail.


The Rust Programming Language › How to Write Tests › Structuring Test Functions

Now that you’ve seen what the test results look like in different scenarios,
let’s look at some macros other than `panic!` that are useful in tests.


The Rust Programming Language › How to Write Tests › Checking Results with `assert!`

The `assert!` macro, provided by the standard library, is useful when you want
to ensure that some condition in a test evaluates to `true`. We give the
`assert!` macro an argument that evaluates to a Boolean. If the value is
`true`, nothing happens and the test passes. If the value is `false`, the
`assert!` macro calls `panic!` to cause the test to fail. Using the `assert!`
macro helps us check that our code is functioning in the way we intend.
In Chapter 5, Listing 5-15, we used a `Rectangle` struct and a `can_hold`
method, which are repeated here in Listing 11-5. Let’s put this code in the
_src/lib.rs_ file, then write some tests for it using the `assert!` macro.
Listing 11-5: The `Rectangle` struct and its `can_hold` method from Chapter 5 (src/lib.rs)
```rust,noplayground
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}
```
The `can_hold` method returns a Boolean, which means it’s a perfect use case
for the `assert!` macro. In Listing 11-6, we write a test that exercises the
`can_hold` method by creating a `Rectangle` instance that has a width of 8 and
a height of 7 and asserting that it can hold another `Rectangle` instance that
has a width of 5 and a height of 1.
Listing 11-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle (src/lib.rs)

How to Write Tests
Checking Results with `assert!`


The Rust Programming Language › How to Write Tests › Checking Results with `assert!`

```rust,noplayground
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle {
            width: 8,
            height: 7,
        };
        let smaller = Rectangle {
            width: 5,
            height: 1,
        };

        assert!(larger.can_hold(&smaller));
    }
}
```
Note the `use super::*;` line inside the `tests` module. The `tests` module is
a regular module that follows the usual visibility rules we covered in Chapter
7 in the “Paths for Referring to an Item in the Module
Tree”
section. Because the `tests` module is an inner module, we need to bring the
code under test in the outer module into the scope of the inner module. We use
a glob here, so anything we define in the outer module is available to this
`tests` module.
We’ve named our test `larger_can_hold_smaller`, and we’ve created the two
`Rectangle` instances that we need. Then, we called the `assert!` macro and
passed it the result of calling `larger.can_hold(&smaller)`. This expression is
supposed to return `true`, so our test should pass. Let’s find out!


The Rust Programming Language › How to Write Tests › Checking Results with `assert!`

```console
$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 1 test
test tests::larger_can_hold_smaller ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests rectangle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
It does pass! Let’s add another test, this time asserting that a smaller
rectangle cannot hold a larger rectangle:
Filename: src/lib.rs
```rust,noplayground
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn larger_can_hold_smaller() {
        // --snip--
    }

    #[test]
    fn smaller_cannot_hold_larger() {
        let larger = Rectangle {
            width: 8,
            height: 7,
        };
        let smaller = Rectangle {
            width: 5,
            height: 1,
        };

        assert!(!smaller.can_hold(&larger));
    }
}
```
Because the correct result of the `can_hold` function in this case is `false`,
we need to negate that result before we pass it to the `assert!` macro. As a
result, our test will pass if `can_hold` returns `false`:


The Rust Programming Language › How to Write Tests › Checking Results with `assert!`

```console
$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 2 tests
test tests::larger_can_hold_smaller ... ok
test tests::smaller_cannot_hold_larger ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests rectangle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
Two tests that pass! Now let’s see what happens to our test results when we
introduce a bug in our code. We’ll change the implementation of the `can_hold`
method by replacing the greater-than sign (`>`) with a less-than sign (`<`)
when it compares the widths:
```rust,not_desired_behavior,noplayground
// --snip--
impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width < other.width && self.height > other.height
    }
}
```
Running the tests now produces the following:


The Rust Programming Language › How to Write Tests › Checking Results with `assert!`

```console
$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 2 tests
test tests::larger_can_hold_smaller ... FAILED
test tests::smaller_cannot_hold_larger ... ok

failures:

---- tests::larger_can_hold_smaller stdout ----

thread 'tests::larger_can_hold_smaller' (6020788) panicked at src/lib.rs:28:9:
assertion failed: larger.can_hold(&smaller)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::larger_can_hold_smaller

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
Our tests caught the bug! Because `larger.width` is `8` and `smaller.width` is
`5`, the comparison of the widths in `can_hold` now returns `false`: 8 is not
less than 5.


The Rust Programming Language › How to Write Tests › Testing Equality with `assert_eq!` and `assert_ne!`

A common way to verify functionality is to test for equality between the result
of the code under test and the value you expect the code to return. You could
do this by using the `assert!` macro and passing it an expression using the
`==` operator. However, this is such a common test that the standard library
provides a pair of macros—`assert_eq!` and `assert_ne!`—to perform this test
more conveniently. These macros compare two arguments for equality or
inequality, respectively. They’ll also print the two values if the assertion
fails, which makes it easier to see _why_ the test failed; conversely, the
`assert!` macro only indicates that it got a `false` value for the `==`
expression, without printing the values that led to the `false` value.
In Listing 11-7, we write a function named `add_two` that adds `2` to its
parameter, and then we test this function using the `assert_eq!` macro.
Listing 11-7: Testing the function `add_two` using the `assert_eq!` macro (src/lib.rs)
```rust,noplayground
pub fn add_two(a: u64) -> u64 {
    a + 2
}

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

    #[test]
    fn it_adds_two() {
        let result = add_two(2);
        assert_eq!(result, 4);
    }
}
```
Let’s check that it passes!


The Rust Programming Language › How to Write Tests › Testing Equality with `assert_eq!` and `assert_ne!`

```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
We create a variable named `result` that holds the result of calling
`add_two(2)`. Then, we pass `result` and `4` as the arguments to the
`assert_eq!` macro. The output line for this test is `test tests::it_adds_two
... ok`, and the `ok` text indicates that our test passed!
Let’s introduce a bug into our code to see what `assert_eq!` looks like when it
fails. Change the implementation of the `add_two` function to instead add `3`:
```rust,not_desired_behavior,noplayground
pub fn add_two(a: u64) -> u64 {
    a + 3
}
```
Run the tests again:


The Rust Programming Language › How to Write Tests › Testing Equality with `assert_eq!` and `assert_ne!`

```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::it_adds_two ... FAILED

failures:

---- tests::it_adds_two stdout ----

thread 'tests::it_adds_two' (6020955) panicked at src/lib.rs:12:9:
assertion `left == right` failed
  left: 5
 right: 4
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::it_adds_two

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
Our test caught the bug! The `tests::it_adds_two` test failed, and the message
tells us that the assertion that failed was `left == right` and what the `left`
and `right` values are. This message helps us start debugging: The `left`
argument, where we had the result of calling `add_two(2)`, was `5`, but the
`right` argument was `4`. You can imagine that this would be especially helpful
when we have a lot of tests going on.


The Rust Programming Language › How to Write Tests › Testing Equality with `assert_eq!` and `assert_ne!`

Note that in some languages and test frameworks, the parameters to equality
assertion functions are called `expected` and `actual`, and the order in which
we specify the arguments matters. However, in Rust, they’re called `left` and
`right`, and the order in which we specify the value we expect and the value
the code produces doesn’t matter. We could write the assertion in this test as
`assert_eq!(4, result)`, which would result in the same failure message that
displays `` assertion `left == right` failed ``.
The `assert_ne!` macro will pass if the two values we give it are not equal and
will fail if they are equal. This macro is most useful for cases when we’re not
sure what a value _will_ be, but we know what the value definitely _shouldn’t_
be. For example, if we’re testing a function that is guaranteed to change its
input in some way, but the way in which the input is changed depends on the day
of the week that we run our tests, the best thing to assert might be that the
output of the function is not equal to the input.


The Rust Programming Language › How to Write Tests › Testing Equality with `assert_eq!` and `assert_ne!`

Under the surface, the `assert_eq!` and `assert_ne!` macros use the operators
`==` and `!=`, respectively. When the assertions fail, these macros print their
arguments using debug formatting, which means the values being compared must
implement the `PartialEq` and `Debug` traits. All primitive types and most of
the standard library types implement these traits. For structs and enums that
you define yourself, you’ll need to implement `PartialEq` to assert equality of
those types. You’ll also need to implement `Debug` to print the values when the
assertion fails. Because both traits are derivable traits, as mentioned in
Listing 5-12 in Chapter 5, this is usually as straightforward as adding the
`#[derive(PartialEq, Debug)]` annotation to your struct or enum definition. See
Appendix C, “Derivable Traits,” for more
details about these and other derivable traits.


The Rust Programming Language › How to Write Tests › Adding Custom Failure Messages

You can also add a custom message to be printed with the failure message as
optional arguments to the `assert!`, `assert_eq!`, and `assert_ne!` macros. Any
arguments specified after the required arguments are passed along to the
`format!` macro (discussed in “Concatenating with `+` or
`format!`”
 in Chapter 8), so you can pass a format string that contains `{}`
placeholders and values to go in those placeholders. Custom messages are useful
for documenting what an assertion means; when a test fails, you’ll have a better
idea of what the problem is with the code.
For example, let’s say we have a function that greets people by name and we
want to test that the name we pass into the function appears in the output:
Filename: src/lib.rs
```rust,noplayground
pub fn greeting(name: &str) -> String {
    format!("Hello {name}!")
}

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

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(result.contains("Carol"));
    }
}
```
The requirements for this program haven’t been agreed upon yet, and we’re
pretty sure the `Hello` text at the beginning of the greeting will change. We
decided we don’t want to have to update the test when the requirements change,
so instead of checking for exact equality to the value returned from the
`greeting` function, we’ll just assert that the output contains the text of the
input parameter.
Now let’s introduce a bug into this code by changing `greeting` to exclude
`name` to see what the default test failure looks like:
```rust,not_desired_behavior,noplayground
pub fn greeting(name: &str) -> String {
    String::from("Hello!")
}
```
Running this test produces the following:

How to Write Tests
Adding Custom Failure Messages


The Rust Programming Language › How to Write Tests › Adding Custom Failure Messages

```console
$ cargo test
   Compiling greeter v0.1.0 (file:///projects/greeter)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.91s
     Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)

running 1 test
test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----

thread 'tests::greeting_contains_name' (6021143) panicked at src/lib.rs:12:9:
assertion failed: result.contains("Carol")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::greeting_contains_name

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
This result just indicates that the assertion failed and which line the
assertion is on. A more useful failure message would print the value from the
`greeting` function. Let’s add a custom failure message composed of a format
string with a placeholder filled in with the actual value we got from the
`greeting` function:
```rust,ignore
    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{result}`"
        );
    }
```
Now when we run the test, we’ll get a more informative error message:


The Rust Programming Language › How to Write Tests › Adding Custom Failure Messages

```console
$ cargo test
   Compiling greeter v0.1.0 (file:///projects/greeter)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.93s
     Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)

running 1 test
test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----

thread 'tests::greeting_contains_name' (6021333) panicked at src/lib.rs:12:9:
Greeting did not contain name, value was `Hello!`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::greeting_contains_name

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
We can see the value we actually got in the test output, which would help us
debug what happened instead of what we were expecting to happen.


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

In addition to checking return values, it’s important to check that our code
handles error conditions as we expect. For example, consider the `Guess` type
that we created in Chapter 9, Listing 9-13. Other code that uses `Guess`
depends on the guarantee that `Guess` instances will contain only values
between 1 and 100. We can write a test that ensures that attempting to create a
`Guess` instance with a value outside that range panics.
We do this by adding the attribute `should_panic` to our test function. The
test passes if the code inside the function panics; the test fails if the code
inside the function doesn’t panic.
Listing 11-8 shows a test that checks that the error conditions of `Guess::new`
happen when we expect them to.
Listing 11-8: Testing that a condition will cause a `panic!` (src/lib.rs)
```rust,noplayground
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {value}.");
        }

        Guess { value }
    }
}

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

    #[test]
    #[should_panic]
    fn greater_than_100() {
        Guess::new(200);
    }
}
```
We place the `#[should_panic]` attribute after the `#[test]` attribute and
before the test function it applies to. Let’s look at the result when this test
passes:

How to Write Tests
Checking for Panics with `should_panic`


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

```console
$ cargo test
   Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58s
     Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)

running 1 test
test tests::greater_than_100 - should panic ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests guessing_game

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
Looks good! Now let’s introduce a bug in our code by removing the condition
that the `new` function will panic if the value is greater than 100:
```rust,not_desired_behavior,noplayground
// --snip--
impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 {
            panic!("Guess value must be between 1 and 100, got {value}.");
        }

        Guess { value }
    }
}
```
When we run the test in Listing 11-8, it will fail:


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

```console
$ cargo test
   Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
     Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)

running 1 test
test tests::greater_than_100 - should panic ... FAILED

failures:

---- tests::greater_than_100 stdout ----
note: test did not panic as expected at src/lib.rs:21:8

failures:
    tests::greater_than_100

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
We don’t get a very helpful message in this case, but when we look at the test
function, we see that it’s annotated with `#[should_panic]`. The failure we got
means that the code in the test function did not cause a panic.
Tests that use `should_panic` can be imprecise. A `should_panic` test would
pass even if the test panics for a different reason from the one we were
expecting. To make `should_panic` tests more precise, we can add an optional
`expected` parameter to the `should_panic` attribute. The test harness will
make sure that the failure message contains the provided text. For example,
consider the modified code for `Guess` in Listing 11-9 where the `new` function
panics with different messages depending on whether the value is too small or
too large.
Listing 11-9: Testing for a `panic!` with a panic message containing a specified substring (src/lib.rs)


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

```rust,noplayground
// --snip--

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 {
            panic!(
                "Guess value must be greater than or equal to 1, got {value}."
            );
        } else if value > 100 {
            panic!(
                "Guess value must be less than or equal to 100, got {value}."
            );
        }

        Guess { value }
    }
}

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

    #[test]
    #[should_panic(expected = "less than or equal to 100")]
    fn greater_than_100() {
        Guess::new(200);
    }
}
```
This test will pass because the value we put in the `should_panic` attribute’s
`expected` parameter is a substring of the message that the `Guess::new`
function panics with. We could have specified the entire panic message that we
expect, which in this case would be `Guess value must be less than or equal to
100, got 200`. What you choose to specify depends on how much of the panic
message is unique or dynamic and how precise you want your test to be. In this
case, a substring of the panic message is enough to ensure that the code in the
test function executes the `else if value > 100` case.
To see what happens when a `should_panic` test with an `expected` message
fails, let’s again introduce a bug into our code by swapping the bodies of the
`if value < 1` and the `else if value > 100` blocks:


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

```rust,ignore,not_desired_behavior
        if value < 1 {
            panic!(
                "Guess value must be less than or equal to 100, got {value}."
            );
        } else if value > 100 {
            panic!(
                "Guess value must be greater than or equal to 1, got {value}."
            );
        }
```
This time when we run the `should_panic` test, it will fail:
```console
$ cargo test
   Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)

running 1 test
test tests::greater_than_100 - should panic ... FAILED

failures:

---- tests::greater_than_100 stdout ----

thread 'tests::greater_than_100' (6021675) panicked at src/lib.rs:12:13:
Guess value must be greater than or equal to 1, got 200.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: panic did not contain expected string
      panic message: "Guess value must be greater than or equal to 1, got 200."
 expected substring: "less than or equal to 100"

failures:
    tests::greater_than_100

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```


The Rust Programming Language › How to Write Tests › Checking for Panics with `should_panic`

The failure message indicates that this test did indeed panic as we expected,
but the panic message did not include the expected string `less than or equal
to 100`. The panic message that we did get in this case was `Guess value must
be greater than or equal to 1, got 200`. Now we can start figuring out where
our bug is!


The Rust Programming Language › How to Write Tests › Using `Result<T, E>` in Tests

All of our tests so far panic when they fail. We can also write tests that use
`Result<T, E>`! Here’s the test from Listing 11-1, rewritten to use `Result<T,
E>` and return an `Err` instead of panicking:
```rust,noplayground
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() -> Result<(), String> {
        let result = add(2, 2);

        if result == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}
```
The `it_works` function now has the `Result<(), String>` return type. In the
body of the function, rather than calling the `assert_eq!` macro, we return
`Ok(())` when the test passes and an `Err` with a `String` inside when the test
fails.
Writing tests so that they return a `Result<T, E>` enables you to use the
question mark operator in the body of tests, which can be a convenient way to
write tests that should fail if any operation within them returns an `Err`
variant.
You can’t use the `#[should_panic]` annotation on tests that use `Result<T,
E>`. To assert that an operation returns an `Err` variant, _don’t_ use the
question mark operator on the `Result<T, E>` value. Instead, use
`assert!(value.is_err())`.
Now that you know several ways to write tests, let’s look at what is happening
when we run our tests and explore the different options we can use with `cargo
test`.

How to Write Tests
Using `Result<T, E>` in Tests


The Rust Programming Language › Controlling How Tests Are Run

Just as `cargo run` compiles your code and then runs the resultant binary,
`cargo test` compiles your code in test mode and runs the resultant test
binary. The default behavior of the binary produced by `cargo test` is to run
all the tests in parallel and capture output generated during test runs,
preventing the output from being displayed and making it easier to read the
output related to the test results. You can, however, specify command line
options to change this default behavior.
Some command line options go to `cargo test`, and some go to the resultant test
binary. To separate these two types of arguments, you list the arguments that
go to `cargo test` followed by the separator `--` and then the ones that go to
the test binary. Running `cargo test --help` displays the options you can use
with `cargo test`, and running `cargo test -- --help` displays the options you
can use after the separator. These options are also documented in the “Tests”
section of _The `rustc` Book_.


The Rust Programming Language › Controlling How Tests Are Run › Running Tests in Parallel or Consecutively

When you run multiple tests, by default they run in parallel using threads,
meaning they finish running more quickly and you get feedback sooner. Because
the tests are running at the same time, you must make sure your tests don’t
depend on each other or on any shared state, including a shared environment,
such as the current working directory or environment variables.
For example, say each of your tests runs some code that creates a file on disk
named _test-output.txt_ and writes some data to that file. Then, each test
reads the data in that file and asserts that the file contains a particular
value, which is different in each test. Because the tests run at the same time,
one test might overwrite the file in the time between when another test is
writing and reading the file. The second test will then fail, not because the
code is incorrect but because the tests have interfered with each other while
running in parallel. One solution is to make sure each test writes to a
different file; another solution is to run the tests one at a time.
If you don’t want to run the tests in parallel or if you want more fine-grained
control over the number of threads used, you can send the `--test-threads` flag
and the number of threads you want to use to the test binary. Take a look at
the following example:
```console
$ cargo test -- --test-threads=1
```
We set the number of test threads to `1`, telling the program not to use any
parallelism. Running the tests using one thread will take longer than running
them in parallel, but the tests won’t interfere with each other if they share
state.


The Rust Programming Language › Controlling How Tests Are Run › Showing Function Output

By default, if a test passes, Rust’s test library captures anything printed to
standard output. For example, if we call `println!` in a test and the test
passes, we won’t see the `println!` output in the terminal; we’ll see only the
line that indicates the test passed. If a test fails, we’ll see whatever was
printed to standard output with the rest of the failure message.
As an example, Listing 11-10 has a silly function that prints the value of its
parameter and returns 10, as well as a test that passes and a test that fails.
Listing 11-10: Tests for a function that calls `println!` (src/lib.rs)
```rust,panics,noplayground
fn prints_and_returns_10(a: i32) -> i32 {
    println!("I got the value {a}");
    10
}

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

    #[test]
    fn this_test_will_pass() {
        let value = prints_and_returns_10(4);
        assert_eq!(value, 10);
    }

    #[test]
    fn this_test_will_fail() {
        let value = prints_and_returns_10(8);
        assert_eq!(value, 5);
    }
}
```
When we run these tests with `cargo test`, we’ll see the following output:

Controlling How Tests Are Run
Showing Function Output


The Rust Programming Language › Controlling How Tests Are Run › Showing Function Output

```console
$ cargo test
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::this_test_will_fail ... FAILED
test tests::this_test_will_pass ... ok

failures:

---- tests::this_test_will_fail stdout ----
I got the value 8

thread 'tests::this_test_will_fail' (6019863) panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::this_test_will_fail

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
Note that nowhere in this output do we see `I got the value 4`, which is
printed when the test that passes runs. That output has been captured. The
output from the test that failed, `I got the value 8`, appears in the section
of the test summary output, which also shows the cause of the test failure.
If we want to see printed values for passing tests as well, we can tell Rust to
also show the output of successful tests with `--show-output`:
```console
$ cargo test -- --show-output
```
When we run the tests in Listing 11-10 again with the `--show-output` flag, we
see the following output:


The Rust Programming Language › Controlling How Tests Are Run › Showing Function Output

```console
$ cargo test -- --show-output
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::this_test_will_fail ... FAILED
test tests::this_test_will_pass ... ok

successes:

---- tests::this_test_will_pass stdout ----
I got the value 4

successes:
    tests::this_test_will_pass

failures:

---- tests::this_test_will_fail stdout ----
I got the value 8

thread 'tests::this_test_will_fail' (6022313) panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::this_test_will_fail

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```


The Rust Programming Language › Controlling How Tests Are Run › Running a Subset of Tests by Name

Running a full test suite can sometimes take a long time. If you’re working on
code in a particular area, you might want to run only the tests pertaining to
that code. You can choose which tests to run by passing `cargo test` the name
or names of the test(s) you want to run as an argument.
To demonstrate how to run a subset of tests, we’ll first create three tests for
our `add_two` function, as shown in Listing 11-11, and choose which ones to run.
Listing 11-11: Three tests with three different names (src/lib.rs)
```rust,noplayground
pub fn add_two(a: u64) -> u64 {
    a + 2
}

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

    #[test]
    fn add_two_and_two() {
        let result = add_two(2);
        assert_eq!(result, 4);
    }

    #[test]
    fn add_three_and_two() {
        let result = add_two(3);
        assert_eq!(result, 5);
    }

    #[test]
    fn one_hundred() {
        let result = add_two(100);
        assert_eq!(result, 102);
    }
}
```
If we run the tests without passing any arguments, as we saw earlier, all the
tests will run in parallel:

Controlling How Tests Are Run
Running a Subset of Tests by Name


The Rust Programming Language › Controlling How Tests Are Run › Running a Subset of Tests by Name › Running Single Tests

```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 3 tests
test tests::add_three_and_two ... ok
test tests::add_two_and_two ... ok
test tests::one_hundred ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
We can pass the name of any test function to `cargo test` to run only that test:
```console
$ cargo test one_hundred
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.69s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::one_hundred ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s

```
Only the test with the name `one_hundred` ran; the other two tests didn’t match
that name. The test output lets us know we had more tests that didn’t run by
displaying `2 filtered out` at the end.

Controlling How Tests Are Run
Running a Subset of Tests by Name
Running Single Tests


The Rust Programming Language › Controlling How Tests Are Run › Running a Subset of Tests by Name › Filtering to Run Multiple Tests

We can’t specify the names of multiple tests in this way; only the first value
given to `cargo test` will be used. But there is a way to run multiple tests.
We can specify part of a test name, and any test whose name matches that value
will be run. For example, because two of our tests’ names contain `add`, we can
run those two by running `cargo test add`:
```console
$ cargo test add
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::add_three_and_two ... ok
test tests::add_two_and_two ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s

```
This command ran all tests with `add` in the name and filtered out the test
named `one_hundred`. Also note that the module in which a test appears becomes
part of the test’s name, so we can run all the tests in a module by filtering
on the module’s name.

Controlling How Tests Are Run
Running a Subset of Tests by Name
Filtering to Run Multiple Tests


The Rust Programming Language › Controlling How Tests Are Run › Ignoring Tests Unless Specifically Requested

Sometimes a few specific tests can be very time-consuming to execute, so you
might want to exclude them during most runs of `cargo test`. Rather than
listing as arguments all tests you do want to run, you can instead annotate the
time-consuming tests using the `ignore` attribute to exclude them, as shown
here:
Filename: src/lib.rs
```rust,noplayground
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    #[ignore]
    fn expensive_test() {
        // code that takes an hour to run
    }
}
```
After `#[test]`, we add the `#[ignore]` line to the test we want to exclude.
Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t:
```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::expensive_test ... ignored
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```


The Rust Programming Language › Controlling How Tests Are Run › Ignoring Tests Unless Specifically Requested

The `expensive_test` function is listed as `ignored`. If we want to run only
the ignored tests, we can use `cargo test -- --ignored`:
```console
$ cargo test -- --ignored
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::expensive_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
By controlling which tests run, you can make sure your `cargo test` results
will be returned quickly. When you’re at a point where it makes sense to check
the results of the `ignored` tests and you have time to wait for the results,
you can run `cargo test -- --ignored` instead. If you want to run all tests
whether they’re ignored or not, you can run `cargo test -- --include-ignored`.


The Rust Programming Language › Test Organization

As mentioned at the start of the chapter, testing is a complex discipline, and
different people use different terminology and organization. The Rust community
thinks about tests in terms of two main categories: unit tests and integration
tests. _Unit tests_ are small and more focused, testing one module in isolation
at a time, and can test private interfaces. _Integration tests_ are entirely
external to your library and use your code in the same way any other external
code would, using only the public interface and potentially exercising multiple
modules per test.
Writing both kinds of tests is important to ensure that the pieces of your
library are doing what you expect them to, separately and together.


The Rust Programming Language › Test Organization › Unit Tests › The `tests` Module and `#[cfg(test)]`

The purpose of unit tests is to test each unit of code in isolation from the
rest of the code to quickly pinpoint where code is and isn’t working as
expected. You’ll put unit tests in the _src_ directory in each file with the
code that they’re testing. The convention is to create a module named `tests`
in each file to contain the test functions and to annotate the module with
`cfg(test)`.
The `#[cfg(test)]` annotation on the `tests` module tells Rust to compile and
run the test code only when you run `cargo test`, not when you run `cargo
build`. This saves compile time when you only want to build the library and
saves space in the resultant compiled artifact because the tests are not
included. You’ll see that because integration tests go in a different
directory, they don’t need the `#[cfg(test)]` annotation. However, because unit
tests go in the same files as the code, you’ll use `#[cfg(test)]` to specify
that they shouldn’t be included in the compiled result.
Recall that when we generated the new `adder` project in the first section of
this chapter, Cargo generated this code for us:
Filename: src/lib.rs
```rust,noplayground
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

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

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}
```

Test Organization
Unit Tests
The `tests` Module and `#[cfg(test)]`


The Rust Programming Language › Test Organization › Unit Tests › Private Function Tests

On the automatically generated `tests` module, the attribute `cfg` stands for
_configuration_ and tells Rust that the following item should only be included
given a certain configuration option. In this case, the configuration option is
`test`, which is provided by Rust for compiling and running tests. By using the
`cfg` attribute, Cargo compiles our test code only if we actively run the tests
with `cargo test`. This includes any helper functions that might be within this
module, in addition to the functions annotated with `#[test]`.
There’s debate within the testing community about whether or not private
functions should be tested directly, and other languages make it difficult or
impossible to test private functions. Regardless of which testing ideology you
adhere to, Rust’s privacy rules do allow you to test private functions.
Consider the code in Listing 11-12 with the private function `internal_adder`.
Listing 11-12: Testing a private function (src/lib.rs)
```rust,noplayground
pub fn add_two(a: u64) -> u64 {
    internal_adder(a, 2)
}

fn internal_adder(left: u64, right: u64) -> u64 {
    left + right
}

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

    #[test]
    fn internal() {
        let result = internal_adder(2, 2);
        assert_eq!(result, 4);
    }
}
```

Test Organization
Unit Tests
Private Function Tests


The Rust Programming Language › Test Organization › Unit Tests › Private Function Tests

Note that the `internal_adder` function is not marked as `pub`. Tests are just
Rust code, and the `tests` module is just another module. As we discussed in
“Paths for Referring to an Item in the Module Tree”,
items in child modules can use the items in their ancestor modules. In this
test, we bring all of the items belonging to the `tests` module’s parent into
scope with `use super::*`, and then the test can call `internal_adder`. If you
don’t think private functions should be tested, there’s nothing in Rust that
will compel you to do so.


The Rust Programming Language › Test Organization › Integration Tests › The tests Directory

In Rust, integration tests are entirely external to your library. They use your
library in the same way any other code would, which means they can only call
functions that are part of your library’s public API. Their purpose is to test
whether many parts of your library work together correctly. Units of code that
work correctly on their own could have problems when integrated, so test
coverage of the integrated code is important as well. To create integration
tests, you first need a _tests_ directory.
We create a _tests_ directory at the top level of our project directory, next
to _src_. Cargo knows to look for integration test files in this directory. We
can then make as many test files as we want, and Cargo will compile each of the
files as an individual crate.
Let’s create an integration test. With the code in Listing 11-12 still in the
_src/lib.rs_ file, make a _tests_ directory, and create a new file named
_tests/integration_test.rs_. Your directory structure should look like this:
```text
adder
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── tests
    └── integration_test.rs
```
Enter the code in Listing 11-13 into the _tests/integration_test.rs_ file.
Listing 11-13: An integration test of a function in the `adder` crate (tests/integration_test.rs)
```rust,ignore
use adder::add_two;

#[test]
fn it_adds_two() {
    let result = add_two(2);
    assert_eq!(result, 4);
}
```
Each file in the _tests_ directory is a separate crate, so we need to bring our
library into each test crate’s scope. For that reason, we add `use
adder::add_two;` at the top of the code, which we didn’t need in the unit tests.

Test Organization
Integration Tests
The tests Directory


The Rust Programming Language › Test Organization › Integration Tests › The tests Directory

We don’t need to annotate any code in _tests/integration_test.rs_ with
`#[cfg(test)]`. Cargo treats the _tests_ directory specially and compiles files
in this directory only when we run `cargo test`. Run `cargo test` now:
```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1.31s
     Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)

running 1 test
test tests::internal ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
The three sections of output include the unit tests, the integration test, and
the doc tests. Note that if any test in a section fails, the following sections
will not be run. For example, if a unit test fails, there won’t be any output
for integration and doc tests, because those tests will only be run if all unit
tests are passing.


The Rust Programming Language › Test Organization › Integration Tests › Submodules in Integration Tests

The first section for the unit tests is the same as we’ve been seeing: one line
for each unit test (one named `internal` that we added in Listing 11-12) and
then a summary line for the unit tests.
The integration tests section starts with the line `Running
tests/integration_test.rs`. Next, there is a line for each test function in
that integration test and a summary line for the results of the integration
test just before the `Doc-tests adder` section starts.
Each integration test file has its own section, so if we add more files in the
_tests_ directory, there will be more integration test sections.
We can still run a particular integration test function by specifying the test
function’s name as an argument to `cargo test`. To run all the tests in a
particular integration test file, use the `--test` argument of `cargo test`
followed by the name of the file:
```console
$ cargo test --test integration_test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.64s
     Running tests/integration_test.rs (target/debug/deps/integration_test-82e7799c1bc62298)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
This command runs only the tests in the _tests/integration_test.rs_ file.

Test Organization
Integration Tests
Submodules in Integration Tests


The Rust Programming Language › Test Organization › Integration Tests › Submodules in Integration Tests

As you add more integration tests, you might want to make more files in the
_tests_ directory to help organize them; for example, you can group the test
functions by the functionality they’re testing. As mentioned earlier, each file
in the _tests_ directory is compiled as its own separate crate, which is useful
for creating separate scopes to more closely imitate the way end users will be
using your crate. However, this means files in the _tests_ directory don’t
share the same behavior as files in _src_ do, as you learned in Chapter 7
regarding how to separate code into modules and files.
The different behavior of _tests_ directory files is most noticeable when you
have a set of helper functions to use in multiple integration test files, and
you try to follow the steps in the “Separating Modules into Different
Files” section of Chapter 7 to
extract them into a common module. For example, if we create _tests/common.rs_
and place a function named `setup` in it, we can add some code to `setup` that
we want to call from multiple test functions in multiple test files:
Filename: tests/common.rs
```rust,noplayground
pub fn setup() {
    // setup code specific to your library's tests would go here
}
```
When we run the tests again, we’ll see a new section in the test output for the
_common.rs_ file, even though this file doesn’t contain any test functions nor
did we call the `setup` function from anywhere:


The Rust Programming Language › Test Organization › Integration Tests › Submodules in Integration Tests

```console
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.89s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::internal ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/common.rs (target/debug/deps/common-92948b65e88960b4)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/integration_test.rs (target/debug/deps/integration_test-92948b65e88960b4)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```
Having `common` appear in the test results with `running 0 tests` displayed for
it is not what we wanted. We just wanted to share some code with the other
integration test files. To avoid having `common` appear in the test output,
instead of creating _tests/common.rs_, we’ll create _tests/common/mod.rs_. The
project directory now looks like this:


The Rust Programming Language › Test Organization › Integration Tests › Integration Tests for Binary Crates

```text
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── tests
    ├── common
    │   └── mod.rs
    └── integration_test.rs
```
This is the older naming convention that Rust also understands that we mentioned
in “Alternate File Paths” in Chapter 7. Naming the
file this way tells Rust not to treat the `common` module as an integration test
file. When we move the `setup` function code into _tests/common/mod.rs_ and
delete the _tests/common.rs_ file, the section in the test output will no longer
appear. Files in subdirectories of the _tests_ directory don’t get compiled as
separate crates or have sections in the test output.
After we’ve created _tests/common/mod.rs_, we can use it from any of the
integration test files as a module. Here’s an example of calling the `setup`
function from the `it_adds_two` test in _tests/integration_test.rs_:
Filename: tests/integration_test.rs
```rust,ignore
use adder::add_two;

mod common;

#[test]
fn it_adds_two() {
    common::setup();

    let result = add_two(2);
    assert_eq!(result, 4);
}
```
Note that the `mod common;` declaration is the same as the module declaration
we demonstrated in Listing 7-21. Then, in the test function, we can call the
`common::setup()` function.

Test Organization
Integration Tests
Integration Tests for Binary Crates


The Rust Programming Language › Test Organization › Integration Tests › Integration Tests for Binary Crates

If our project is a binary crate that only contains a _src/main.rs_ file and
doesn’t have a _src/lib.rs_ file, we can’t create integration tests in the
_tests_ directory and bring functions defined in the _src/main.rs_ file into
scope with a `use` statement. Only library crates expose functions that other
crates can use; binary crates are meant to be run on their own.
This is one of the reasons Rust projects that provide a binary have a
straightforward _src/main.rs_ file that calls logic that lives in the
_src/lib.rs_ file. Using that structure, integration tests _can_ test the
library crate with `use` to make the important functionality available. If the
important functionality works, the small amount of code in the _src/main.rs_
file will work as well, and that small amount of code doesn’t need to be tested.


The Rust Programming Language › Summary

Rust’s testing features provide a way to specify how code should function to
ensure that it continues to work as you expect, even as you make changes. Unit
tests exercise different parts of a library separately and can test private
implementation details. Integration tests check that many parts of the library
work together correctly, and they use the library’s public API to test the code
in the same way external code will use it. Even though Rust’s type system and
ownership rules help prevent some kinds of bugs, tests are still important to
reduce logic bugs having to do with how your code is expected to behave.
Let’s combine the knowledge you learned in this chapter and in previous
chapters to work on a project!


The Rust Programming Language › An I/O Project: Building a Command Line Program

This chapter is a recap of the many skills you’ve learned so far and an
exploration of a few more standard library features. We’ll build a command line
tool that interacts with file and command line input/output to practice some of
the Rust concepts you now have under your belt.
Rust’s speed, safety, single binary output, and cross-platform support make it
an ideal language for creating command line tools, so for our project, we’ll
make our own version of the classic command line search tool `grep`
(**g**lobally search a **r**egular **e**xpression and **p**rint). In the
simplest use case, `grep` searches a specified file for a specified string. To
do so, `grep` takes as its arguments a file path and a string. Then, it reads
the file, finds lines in that file that contain the string argument, and prints
those lines.
Along the way, we’ll show how to make our command line tool use the terminal
features that many other command line tools use. We’ll read the value of an
environment variable to allow the user to configure the behavior of our tool.
We’ll also print error messages to the standard error console stream (`stderr`)
instead of standard output (`stdout`) so that, for example, the user can
redirect successful output to a file while still seeing error messages onscreen.
One Rust community member, Andrew Gallant, has already created a fully
featured, very fast version of `grep`, called `ripgrep`. By comparison, our
version will be fairly simple, but this chapter will give you some of the
background knowledge you need to understand a real-world project such as
`ripgrep`.
Our `grep` project will combine a number of concepts you’ve learned so far:


The Rust Programming Language › An I/O Project: Building a Command Line Program

- Organizing code (Chapter 7)
- Using vectors and strings (Chapter 8)
- Handling errors (Chapter 9)
- Using traits and lifetimes where appropriate (Chapter 10)
- Writing tests (Chapter 11)
We’ll also briefly introduce closures, iterators, and trait objects, which
Chapter 13 and Chapter 18 will
cover in detail.


The Rust Programming Language › Accepting Command Line Arguments

Let’s create a new project with, as always, `cargo new`. We’ll call our project
`minigrep` to distinguish it from the `grep` tool that you might already have
on your system:
```console
$ cargo new minigrep
     Created binary (application) `minigrep` project
$ cd minigrep
```
The first task is to make `minigrep` accept its two command line arguments: the
file path and a string to search for. That is, we want to be able to run our
program with `cargo run`, two hyphens to indicate the following arguments are
for our program rather than for `cargo`, a string to search for, and a path to
a file to search in, like so:
```console
$ cargo run -- searchstring example-filename.txt
```
Right now, the program generated by `cargo new` cannot process arguments we
give it. Some existing libraries on crates.io can help
with writing a program that accepts command line arguments, but because you’re
just learning this concept, let’s implement this capability ourselves.


The Rust Programming Language › Accepting Command Line Arguments › Reading the Argument Values

To enable `minigrep` to read the values of command line arguments we pass to
it, we’ll need the `std::env::args` function provided in Rust’s standard
library. This function returns an iterator of the command line arguments passed
to `minigrep`. We’ll cover iterators fully in Chapter 13
. For now, you only need to know two details about iterators: Iterators
produce a series of values, and we can call the `collect` method on an iterator
to turn it into a collection, such as a vector, which contains all the elements
the iterator produces.
The code in Listing 12-1 allows your `minigrep` program to read any command
line arguments passed to it and then collect the values into a vector.
Listing 12-1: Collecting the command line arguments into a vector and printing them (src/main.rs)
```rust
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    dbg!(args);
}
```
First, we bring the `std::env` module into scope with a `use` statement so that
we can use its `args` function. Notice that the `std::env::args` function is
nested in two levels of modules. As we discussed in Chapter
7, in cases where the desired function is
nested in more than one module, we’ve chosen to bring the parent module into
scope rather than the function. By doing so, we can easily use other functions
from `std::env`. It’s also less ambiguous than adding `use std::env::args` and
then calling the function with just `args`, because `args` might easily be
mistaken for a function that’s defined in the current module.

Accepting Command Line Arguments
Reading the Argument Values


The Rust Programming Language › Accepting Command Line Arguments › The `args` Function and Invalid Unicode

Note that `std::env::args` will panic if any argument contains invalid
Unicode. If your program needs to accept arguments containing invalid
Unicode, use `std::env::args_os` instead. That function returns an iterator
that produces `OsString` values instead of `String` values. We’ve chosen to
use `std::env::args` here for simplicity because `OsString` values differ per
platform and are more complex to work with than `String` values.
On the first line of `main`, we call `env::args`, and we immediately use
`collect` to turn the iterator into a vector containing all the values produced
by the iterator. We can use the `collect` function to create many kinds of
collections, so we explicitly annotate the type of `args` to specify that we
want a vector of strings. Although you very rarely need to annotate types in
Rust, `collect` is one function you do often need to annotate because Rust
isn’t able to infer the kind of collection you want.
Finally, we print the vector using the debug macro. Let’s try running the code
first with no arguments and then with two arguments:
```console
$ cargo run
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running `target/debug/minigrep`
[src/main.rs:5:5] args = [
    "target/debug/minigrep",
]
```

Accepting Command Line Arguments
The `args` Function and Invalid Unicode


The Rust Programming Language › Accepting Command Line Arguments › The `args` Function and Invalid Unicode

```console
$ cargo run -- needle haystack
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.57s
     Running `target/debug/minigrep needle haystack`
[src/main.rs:5:5] args = [
    "target/debug/minigrep",
    "needle",
    "haystack",
]
```
Notice that the first value in the vector is `"target/debug/minigrep"`, which
is the name of our binary. This matches the behavior of the arguments list in
C, letting programs use the name by which they were invoked in their execution.
It’s often convenient to have access to the program name in case you want to
print it in messages or change the behavior of the program based on what
command line alias was used to invoke the program. But for the purposes of this
chapter, we’ll ignore it and save only the two arguments we need.


The Rust Programming Language › Accepting Command Line Arguments › Saving the Argument Values in Variables

The program is currently able to access the values specified as command line
arguments. Now we need to save the values of the two arguments in variables so
that we can use the values throughout the rest of the program. We do that in
Listing 12-2.
Listing 12-2: Creating variables to hold the query argument and file path argument (src/main.rs)
```rust,should_panic,noplayground
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    let query = &args[1];
    let file_path = &args[2];

    println!("Searching for {query}");
    println!("In file {file_path}");
}
```
As we saw when we printed the vector, the program’s name takes up the first
value in the vector at `args[0]`, so we’re starting arguments at index 1. The
first argument `minigrep` takes is the string we’re searching for, so we put a
reference to the first argument in the variable `query`. The second argument
will be the file path, so we put a reference to the second argument in the
variable `file_path`.
We temporarily print the values of these variables to prove that the code is
working as we intend. Let’s run this program again with the arguments `test`
and `sample.txt`:
```console
$ cargo run -- test sample.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt
```

Accepting Command Line Arguments
Saving the Argument Values in Variables


The Rust Programming Language › Accepting Command Line Arguments › Saving the Argument Values in Variables

Great, the program is working! The values of the arguments we need are being
saved into the right variables. Later we’ll add some error handling to deal
with certain potential erroneous situations, such as when the user provides no
arguments; for now, we’ll ignore that situation and work on adding file-reading
capabilities instead.


The Rust Programming Language › Reading a File

Now we’ll add functionality to read the file specified in the `file_path`
argument. First, we need a sample file to test it with: We’ll use a file with a
small amount of text over multiple lines with some repeated words. Listing 12-3
has an Emily Dickinson poem that will work well! Create a file called
_poem.txt_ at the root level of your project, and enter the poem “I’m Nobody!
Who are you?”
Listing 12-3: A poem by Emily Dickinson makes a good test case. (poem.txt)
```text
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
```
With the text in place, edit _src/main.rs_ and add code to read the file, as
shown in Listing 12-4.
Listing 12-4: Reading the contents of the file specified by the second argument (src/main.rs)
```rust,should_panic,noplayground
use std::env;
use std::fs;

fn main() {
    // --snip--
    println!("In file {file_path}");

    let contents = fs::read_to_string(file_path)
        .expect("Should have been able to read the file");

    println!("With text:\n{contents}");
}
```
First, we bring in a relevant part of the standard library with a `use`
statement: We need `std::fs` to handle files.
In `main`, the new statement `fs::read_to_string` takes the `file_path`, opens
that file, and returns a value of type `std::io::Result<String>` that contains
the file’s contents.


The Rust Programming Language › Reading a File

After that, we again add a temporary `println!` statement that prints the value
of `contents` after the file is read so that we can check that the program is
working so far.
Let’s run this code with any string as the first command line argument (because
we haven’t implemented the searching part yet) and the _poem.txt_ file as the
second argument:
```console
$ cargo run -- the poem.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep the poem.txt`
Searching for the
In file poem.txt
With text:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

```
Great! The code read and then printed the contents of the file. But the code
has a few flaws. At the moment, the `main` function has multiple
responsibilities: Generally, functions are clearer and easier to maintain if
each function is responsible for only one idea. The other problem is that we’re
not handling errors as well as we could. The program is still small, so these
flaws aren’t a big problem, but as the program grows, it will be harder to fix
them cleanly. It’s a good practice to begin refactoring early on when
developing a program because it’s much easier to refactor smaller amounts of
code. We’ll do that next.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling

To improve our program, we’ll fix four problems that have to do with the
program’s structure and how it’s handling potential errors. First, our `main`
function now performs two tasks: It parses arguments and reads files. As our
program grows, the number of separate tasks the `main` function handles will
increase. As a function gains responsibilities, it becomes more difficult to
reason about, harder to test, and harder to change without breaking one of its
parts. It’s best to separate functionality so that each function is responsible
for one task.
This issue also ties into the second problem: Although `query` and `file_path`
are configuration variables to our program, variables like `contents` are used
to perform the program’s logic. The longer `main` becomes, the more variables
we’ll need to bring into scope; the more variables we have in scope, the harder
it will be to keep track of the purpose of each. It’s best to group the
configuration variables into one structure to make their purpose clear.
The third problem is that we’ve used `expect` to print an error message when
reading the file fails, but the error message just prints `Should have been
able to read the file`. Reading a file can fail in a number of ways: For
example, the file could be missing, or we might not have permission to open it.
Right now, regardless of the situation, we’d print the same error message for
everything, which wouldn’t give the user any information!


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling

Fourth, we use `expect` to handle an error, and if the user runs our program
without specifying enough arguments, they’ll get an `index out of bounds` error
from Rust that doesn’t clearly explain the problem. It would be best if all the
error-handling code were in one place so that future maintainers had only one
place to consult the code if the error-handling logic needed to change. Having
all the error-handling code in one place will also ensure that we’re printing
messages that will be meaningful to our end users.
Let’s address these four problems by refactoring our project.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › Separating Concerns in Binary Projects › Extracting the Argument Parser

The organizational problem of allocating responsibility for multiple tasks to
the `main` function is common to many binary projects. As a result, many Rust
programmers find it useful to split up the separate concerns of a binary
program when the `main` function starts getting large. This process has the
following steps:
- Split your program into a _main.rs_ file and a _lib.rs_ file and move your
  program’s logic to _lib.rs_.
- As long as your command line parsing logic is small, it can remain in
  the `main` function.
- When the command line parsing logic starts getting complicated, extract it
  from the `main` function into other functions or types.
The responsibilities that remain in the `main` function after this process
should be limited to the following:
- Calling the command line parsing logic with the argument values
- Setting up any other configuration
- Calling a `run` function in _lib.rs_
- Handling the error if `run` returns an error
This pattern is about separating concerns: _main.rs_ handles running the
program and _lib.rs_ handles all the logic of the task at hand. Because you
can’t test the `main` function directly, this structure lets you test all of
your program’s logic by moving it out of the `main` function. The code that
remains in the `main` function will be small enough to verify its correctness
by reading it. Let’s rework our program by following this process.
We’ll extract the functionality for parsing arguments into a function that
`main` will call. Listing 12-5 shows the new start of the `main` function that
calls a new function `parse_config`, which we’ll define in _src/main.rs_.
Listing 12-5: Extracting a `parse_config` function from `main` (src/main.rs)


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › Separating Concerns in Binary Projects › Grouping Configuration Values

```rust,ignore
fn main() {
    let args: Vec<String> = env::args().collect();

    let (query, file_path) = parse_config(&args);

    // --snip--
}

fn parse_config(args: &[String]) -> (&str, &str) {
    let query = &args[1];
    let file_path = &args[2];

    (query, file_path)
}
```
We’re still collecting the command line arguments into a vector, but instead of
assigning the argument value at index 1 to the variable `query` and the
argument value at index 2 to the variable `file_path` within the `main`
function, we pass the whole vector to the `parse_config` function. The
`parse_config` function then holds the logic that determines which argument
goes in which variable and passes the values back to `main`. We still create
the `query` and `file_path` variables in `main`, but `main` no longer has the
responsibility of determining how the command line arguments and variables
correspond.
This rework may seem like overkill for our small program, but we’re refactoring
in small, incremental steps. After making this change, run the program again to
verify that the argument parsing still works. It’s good to check your progress
often, to help identify the cause of problems when they occur.
We can take another small step to improve the `parse_config` function further.
At the moment, we’re returning a tuple, but then we immediately break that
tuple into individual parts again. This is a sign that perhaps we don’t have
the right abstraction yet.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › Separating Concerns in Binary Projects › Grouping Configuration Values

Another indicator that shows there’s room for improvement is the `config` part
of `parse_config`, which implies that the two values we return are related and
are both part of one configuration value. We’re not currently conveying this
meaning in the structure of the data other than by grouping the two values into
a tuple; we’ll instead put the two values into one struct and give each of the
struct fields a meaningful name. Doing so will make it easier for future
maintainers of this code to understand how the different values relate to each
other and what their purpose is.
Listing 12-6 shows the improvements to the `parse_config` function.
Listing 12-6: Refactoring `parse_config` to return an instance of a `Config` struct (src/main.rs)
```rust,should_panic,noplayground
fn main() {
    let args: Vec<String> = env::args().collect();

    let config = parse_config(&args);

    println!("Searching for {}", config.query);
    println!("In file {}", config.file_path);

    let contents = fs::read_to_string(config.file_path)
        .expect("Should have been able to read the file");

    // --snip--
}

struct Config {
    query: String,
    file_path: String,
}

fn parse_config(args: &[String]) -> Config {
    let query = args[1].clone();
    let file_path = args[2].clone();

    Config { query, file_path }
}
```


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › Separating Concerns in Binary Projects › Grouping Configuration Values

We’ve added a struct named `Config` defined to have fields named `query` and
`file_path`. The signature of `parse_config` now indicates that it returns a
`Config` value. In the body of `parse_config`, where we used to return
string slices that reference `String` values in `args`, we now define `Config`
to contain owned `String` values. The `args` variable in `main` is the owner of
the argument values and is only letting the `parse_config` function borrow
them, which means we’d violate Rust’s borrowing rules if `Config` tried to take
ownership of the values in `args`.
There are a number of ways we could manage the `String` data; the easiest,
though somewhat inefficient, route is to call the `clone` method on the values.
This will make a full copy of the data for the `Config` instance to own, which
takes more time and memory than storing a reference to the string data.
However, cloning the data also makes our code very straightforward because we
don’t have to manage the lifetimes of the references; in this circumstance,
giving up a little performance to gain simplicity is a worthwhile trade-off.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › The Trade-Offs of Using `clone` › Creating a Constructor for `Config`

There’s a tendency among many Rustaceans to avoid using `clone` to fix
ownership problems because of its runtime cost. In
Chapter 13, you’ll learn how to use more efficient
methods in this type of situation. But for now, it’s okay to copy a few
strings to continue making progress because you’ll make these copies only
once and your file path and query string are very small. It’s better to have
a working program that’s a bit inefficient than to try to hyperoptimize code
on your first pass. As you become more experienced with Rust, it’ll be
easier to start with the most efficient solution, but for now, it’s
perfectly acceptable to call `clone`.
We’ve updated `main` so that it places the instance of `Config` returned by
`parse_config` into a variable named `config`, and we updated the code that
previously used the separate `query` and `file_path` variables so that it now
uses the fields on the `Config` struct instead.
Now our code more clearly conveys that `query` and `file_path` are related and
that their purpose is to configure how the program will work. Any code that
uses these values knows to find them in the `config` instance in the fields
named for their purpose.
So far, we’ve extracted the logic responsible for parsing the command line
arguments from `main` and placed it in the `parse_config` function. Doing so
helped us see that the `query` and `file_path` values were related, and that
relationship should be conveyed in our code. We then added a `Config` struct to
name the related purpose of `query` and `file_path` and to be able to return the
values’ names as struct field names from the `parse_config` function.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › The Trade-Offs of Using `clone` › Creating a Constructor for `Config`

So, now that the purpose of the `parse_config` function is to create a `Config`
instance, we can change `parse_config` from a plain function to a function
named `new` that is associated with the `Config` struct. Making this change
will make the code more idiomatic. We can create instances of types in the
standard library, such as `String`, by calling `String::new`. Similarly, by
changing `parse_config` into a `new` function associated with `Config`, we’ll
be able to create instances of `Config` by calling `Config::new`. Listing 12-7
shows the changes we need to make.
Listing 12-7: Changing `parse_config` into `Config::new` (src/main.rs)
```rust,should_panic,noplayground
fn main() {
    let args: Vec<String> = env::args().collect();

    let config = Config::new(&args);

    // --snip--
}

// --snip--

impl Config {
    fn new(args: &[String]) -> Config {
        let query = args[1].clone();
        let file_path = args[2].clone();

        Config { query, file_path }
    }
}
```
We’ve updated `main` where we were calling `parse_config` to instead call
`Config::new`. We’ve changed the name of `parse_config` to `new` and moved it
within an `impl` block, which associates the `new` function with `Config`. Try
compiling this code again to make sure it works.


The Rust Programming Language › Refactoring to Improve Modularity and Error Handling › Fixing the Error Handling › Improving the Error Message

Now we’ll work on fixing our error handling. Recall that attempting to access
the values in the `args` vector at index 1 or index 2 will cause the program to
panic if the vector contains fewer than three items. Try running the program
without any arguments; it will look like this:
```console
$ cargo run
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep`

thread 'main' (6023615) panicked at src/main.rs:27:21:
index out of bounds: the len is 1 but the index is 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
The line `index out of bounds: the len is 1 but the index is 1` is an error
message intended for programmers. It won’t help our end users understand what
they should do instead. Let’s fix that now.
In Listing 12-8, we add a check in the `new` function that will verify that the
slice is long enough before accessing index 1 and index 2. If the slice isn’t
long enough, the program panics and displays a better error message.
Listing 12-8: Adding a check for the number of arguments (src/main.rs)
```rust,ignore
    // --snip--
    fn new(args: &[String]) -> Config {
        if args.len() < 3 {
            panic!("not enough arguments");
        }
        // --snip--
```