<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>Testing the Library's Functionality - The Rust Programming Language</title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <base href=""> <link rel="stylesheet" href="book.css"> <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'> <link rel="shortcut icon" href="favicon.png"> <!-- Font Awesome --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> <link rel="stylesheet" href="highlight.css"> <link rel="stylesheet" href="tomorrow-night.css"> <style> .page-wrapper.has-warning > .nav-chapters { /* add height for warning content & margin */ top: 120px; } p.warning { background-color: rgb(242, 222, 222); border-bottom-color: rgb(238, 211, 215); border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-bottom-style: solid; border-bottom-width: 0.666667px; border-image-outset: 0 0 0 0; border-image-repeat: stretch stretch; border-image-slice: 100% 100% 100% 100%; border-image-source: none; border-image-width: 1 1 1 1; border-left-color: rgb(238, 211, 215); border-left-style: solid; border-left-width: 0.666667px; border-right-color: rgb(238, 211, 215); border-right-style: solid; border-right-width: 0.666667px; border-top-color: rgb(238, 211, 215); border-top-left-radius: 4px; border-top-right-radius: 4px; border-top-style: solid; border-top-width: 0.666667px; color: rgb(185, 74, 72); margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 30px; padding-bottom: 8px; padding-left: 14px; padding-right: 35px; padding-top: 8px; } p.warning strong { color: rgb(185, 74, 72) } p.warning a { color: rgb(0, 136, 204) } </style> <!-- MathJax --> <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> <!-- Fetch JQuery from CDN but have a local fallback --> <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> <script> if (typeof jQuery == 'undefined') { document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E")); } </script> </head> <body class="light"> <!-- Set the theme before any content is loaded, prevents flash --> <script type="text/javascript"> var theme = localStorage.getItem('theme'); if (theme == null) { theme = 'light'; } $('body').removeClass().addClass(theme); </script> <!-- Hide / unhide sidebar before it is displayed --> <script type="text/javascript"> var sidebar = localStorage.getItem('sidebar'); if (sidebar === "hidden") { $("html").addClass("sidebar-hidden") } else if (sidebar === "visible") { $("html").addClass("sidebar-visible") } </script> <div id="sidebar" class="sidebar"> <ul class="chapter"><li><a href="ch01-00-introduction.html"><strong>1.</strong> Introduction</a></li><li><ul class="section"><li><a href="ch01-01-installation.html"><strong>1.1.</strong> Installation</a></li><li><a href="ch01-02-hello-world.html"><strong>1.2.</strong> Hello, World!</a></li></ul></li><li><a href="ch02-00-guessing-game-tutorial.html"><strong>2.</strong> Guessing Game Tutorial</a></li><li><a href="ch03-00-common-programming-concepts.html"><strong>3.</strong> Common Programming Concepts</a></li><li><ul class="section"><li><a href="ch03-01-variables-and-mutability.html"><strong>3.1.</strong> Variables and Mutability</a></li><li><a href="ch03-02-data-types.html"><strong>3.2.</strong> Data Types</a></li><li><a href="ch03-03-how-functions-work.html"><strong>3.3.</strong> How Functions Work</a></li><li><a href="ch03-04-comments.html"><strong>3.4.</strong> Comments</a></li><li><a href="ch03-05-control-flow.html"><strong>3.5.</strong> Control Flow</a></li></ul></li><li><a href="ch04-00-understanding-ownership.html"><strong>4.</strong> Understanding Ownership</a></li><li><ul class="section"><li><a href="ch04-01-what-is-ownership.html"><strong>4.1.</strong> What is Ownership?</a></li><li><a href="ch04-02-references-and-borrowing.html"><strong>4.2.</strong> References & Borrowing</a></li><li><a href="ch04-03-slices.html"><strong>4.3.</strong> Slices</a></li></ul></li><li><a href="ch05-00-structs.html"><strong>5.</strong> Using Structs to Structure Related Data</a></li><li><ul class="section"><li><a href="ch05-01-defining-structs.html"><strong>5.1.</strong> Defining and Instantiating Structs</a></li><li><a href="ch05-02-example-structs.html"><strong>5.2.</strong> An Example Program Using Structs</a></li><li><a href="ch05-03-method-syntax.html"><strong>5.3.</strong> Method Syntax</a></li></ul></li><li><a href="ch06-00-enums.html"><strong>6.</strong> Enums and Pattern Matching</a></li><li><ul class="section"><li><a href="ch06-01-defining-an-enum.html"><strong>6.1.</strong> Defining an Enum</a></li><li><a href="ch06-02-match.html"><strong>6.2.</strong> The <code>match</code> Control Flow Operator</a></li><li><a href="ch06-03-if-let.html"><strong>6.3.</strong> Concise Control Flow with <code>if let</code></a></li></ul></li><li><a href="ch07-00-modules.html"><strong>7.</strong> Modules</a></li><li><ul class="section"><li><a href="ch07-01-mod-and-the-filesystem.html"><strong>7.1.</strong> <code>mod</code> and the Filesystem</a></li><li><a href="ch07-02-controlling-visibility-with-pub.html"><strong>7.2.</strong> Controlling Visibility with <code>pub</code></a></li><li><a href="ch07-03-importing-names-with-use.html"><strong>7.3.</strong> Importing Names with <code>use</code></a></li></ul></li><li><a href="ch08-00-common-collections.html"><strong>8.</strong> Common Collections</a></li><li><ul class="section"><li><a href="ch08-01-vectors.html"><strong>8.1.</strong> Vectors</a></li><li><a href="ch08-02-strings.html"><strong>8.2.</strong> Strings</a></li><li><a href="ch08-03-hash-maps.html"><strong>8.3.</strong> Hash Maps</a></li></ul></li><li><a href="ch09-00-error-handling.html"><strong>9.</strong> Error Handling</a></li><li><ul class="section"><li><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong>9.1.</strong> Unrecoverable Errors with <code>panic!</code></a></li><li><a href="ch09-02-recoverable-errors-with-result.html"><strong>9.2.</strong> Recoverable Errors with <code>Result</code></a></li><li><a href="ch09-03-to-panic-or-not-to-panic.html"><strong>9.3.</strong> To <code>panic!</code> or Not To <code>panic!</code></a></li></ul></li><li><a href="ch10-00-generics.html"><strong>10.</strong> Generic Types, Traits, and Lifetimes</a></li><li><ul class="section"><li><a href="ch10-01-syntax.html"><strong>10.1.</strong> Generic Data Types</a></li><li><a href="ch10-02-traits.html"><strong>10.2.</strong> Traits: Defining Shared Behavior</a></li><li><a href="ch10-03-lifetime-syntax.html"><strong>10.3.</strong> Validating References with Lifetimes</a></li></ul></li><li><a href="ch11-00-testing.html"><strong>11.</strong> Testing</a></li><li><ul class="section"><li><a href="ch11-01-writing-tests.html"><strong>11.1.</strong> Writing tests</a></li><li><a href="ch11-02-running-tests.html"><strong>11.2.</strong> Running tests</a></li><li><a href="ch11-03-test-organization.html"><strong>11.3.</strong> Test Organization</a></li></ul></li><li><a href="ch12-00-an-io-project.html"><strong>12.</strong> An I/O Project</a></li><li><ul class="section"><li><a href="ch12-01-accepting-command-line-arguments.html"><strong>12.1.</strong> Accepting Command Line Arguments</a></li><li><a href="ch12-02-reading-a-file.html"><strong>12.2.</strong> Reading a File</a></li><li><a href="ch12-03-improving-error-handling-and-modularity.html"><strong>12.3.</strong> Improving Error Handling and Modularity</a></li><li><a href="ch12-04-testing-the-librarys-functionality.html" class="active"><strong>12.4.</strong> Testing the Library's Functionality</a></li><li><a href="ch12-05-working-with-environment-variables.html"><strong>12.5.</strong> Working with Environment Variables</a></li><li><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong>12.6.</strong> Writing to <code>stderr</code> instead of <code>stdout</code></a></li></ul></li><li><a href="ch13-00-functional-features.html"><strong>13.</strong> Functional Language Features in Rust</a></li><li><ul class="section"><li><a href="ch13-01-closures.html"><strong>13.1.</strong> Closures</a></li><li><a href="ch13-02-iterators.html"><strong>13.2.</strong> Iterators</a></li><li><a href="ch13-03-improving-our-io-project.html"><strong>13.3.</strong> Improving our I/O Project</a></li><li><a href="ch13-04-performance.html"><strong>13.4.</strong> Performance</a></li></ul></li><li><a href="ch14-00-more-about-cargo.html"><strong>14.</strong> More about Cargo and Crates.io</a></li><li><ul class="section"><li><a href="ch14-01-release-profiles.html"><strong>14.1.</strong> Release Profiles</a></li><li><a href="ch14-02-publishing-to-crates-io.html"><strong>14.2.</strong> Publishing a Crate to Crates.io</a></li><li><a href="ch14-03-cargo-workspaces.html"><strong>14.3.</strong> Cargo Workspaces</a></li><li><a href="ch14-04-installing-binaries.html"><strong>14.4.</strong> Installing Binaries from Crates.io with <code>cargo install</code></a></li><li><a href="ch14-05-extending-cargo.html"><strong>14.5.</strong> Extending Cargo with Custom Commands</a></li></ul></li><li><a href="ch15-00-smart-pointers.html"><strong>15.</strong> Smart Pointers</a></li><li><ul class="section"><li><a href="ch15-01-box.html"><strong>15.1.</strong> <code>Box<T></code> Points to Data on the Heap and Has a Known Size</a></li><li><a href="ch15-02-deref.html"><strong>15.2.</strong> The <code>Deref</code> Trait Allows Access to the Data Through a Reference</a></li><li><a href="ch15-03-drop.html"><strong>15.3.</strong> The <code>Drop</code> Trait Runs Code on Cleanup</a></li><li><a href="ch15-04-rc.html"><strong>15.4.</strong> <code>Rc<T></code>, the Reference Counted Smart Pointer</a></li><li><a href="ch15-05-interior-mutability.html"><strong>15.5.</strong> <code>RefCell<T></code> and the Interior Mutability Pattern</a></li><li><a href="ch15-06-reference-cycles.html"><strong>15.6.</strong> Creating Reference Cycles and Leaking Memory is Safe</a></li></ul></li><li><a href="ch16-00-concurrency.html"><strong>16.</strong> Fearless Concurrency</a></li><li><ul class="section"><li><a href="ch16-01-threads.html"><strong>16.1.</strong> Threads</a></li><li><a href="ch16-02-message-passing.html"><strong>16.2.</strong> Message Passing</a></li><li><a href="ch16-03-shared-state.html"><strong>16.3.</strong> Shared State</a></li><li><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong>16.4.</strong> Extensible Concurrency: <code>Sync</code> and <code>Send</code></a></li></ul></li><li><a href="ch17-00-oop.html"><strong>17.</strong> Is Rust an Object-Oriented Programming Language?</a></li><li><ul class="section"><li><a href="ch17-01-what-is-oo.html"><strong>17.1.</strong> What Does Object-Oriented Mean?</a></li><li><a href="ch17-02-trait-objects.html"><strong>17.2.</strong> Trait Objects for Using Values of Different Types</a></li><li><a href="ch17-03-oo-design-patterns.html"><strong>17.3.</strong> Object-Oriented Design Pattern Implementations</a></li></ul></li><li><a href="ch18-00-patterns.html"><strong>18.</strong> Patterns Match the Structure of Values</a></li><li><ul class="section"><li><a href="ch18-01-all-the-places-for-patterns.html"><strong>18.1.</strong> All the Places Patterns May be Used</a></li><li><a href="ch18-02-refutability.html"><strong>18.2.</strong> Refutability: Whether a Pattern Might Fail to Match</a></li><li><a href="ch18-03-pattern-syntax.html"><strong>18.3.</strong> All the Pattern Syntax</a></li></ul></li><li><a href="ch19-00-advanced-features.html"><strong>19.</strong> Advanced Features</a></li><li><ul class="section"><li><a href="ch19-01-unsafe-rust.html"><strong>19.1.</strong> Unsafe Rust</a></li><li><a href="ch19-02-advanced-lifetimes.html"><strong>19.2.</strong> Advanced Lifetimes</a></li><li><a href="ch19-03-advanced-traits.html"><strong>19.3.</strong> Advanced Traits</a></li><li><a href="ch19-04-advanced-types.html"><strong>19.4.</strong> Advanced Types</a></li><li><a href="ch19-05-advanced-functions-and-closures.html"><strong>19.5.</strong> Advanced Functions & Closures</a></li></ul></li><li><a href="ch20-00-final-project-a-web-server.html"><strong>20.</strong> Final Project: Building a Multithreaded Web Server</a></li><li><ul class="section"><li><a href="ch20-01-single-threaded.html"><strong>20.1.</strong> A Single Threaded Web Server</a></li><li><a href="ch20-02-slow-requests.html"><strong>20.2.</strong> How Slow Requests Affect Throughput</a></li><li><a href="ch20-03-designing-the-interface.html"><strong>20.3.</strong> Designing the Thread Pool Interface</a></li><li><a href="ch20-04-storing-threads.html"><strong>20.4.</strong> Creating the Thread Pool and Storing Threads</a></li><li><a href="ch20-05-sending-requests-via-channels.html"><strong>20.5.</strong> Sending Requests to Threads Via Channels</a></li><li><a href="ch20-06-graceful-shutdown-and-cleanup.html"><strong>20.6.</strong> Graceful Shutdown and Cleanup</a></li></ul></li><li><a href="appendix-00.html"><strong>21.</strong> Appendix</a></li><li><ul class="section"><li><a href="appendix-01-keywords.html"><strong>21.1.</strong> A - Keywords</a></li><li><a href="appendix-02-operators.html"><strong>21.2.</strong> B - Operators</a></li><li><strong>21.3.</strong> C - Derivable Traits</li><li><strong>21.4.</strong> D - Nightly Rust</li><li><strong>21.5.</strong> E - Macros</li><li><strong>21.6.</strong> F - Translations</li><li><a href="appendix-07-newest-features.html"><strong>21.7.</strong> G - Newest Features</a></li></ul></li></ul> </div> <div id="page-wrapper" class="page-wrapper has-warning"> <div class="page"> <header><p class="warning">You are reading a <strong>draft</strong> of the next edition of TRPL. For more, go <a href="../index.html">here</a>.</p></header> <div id="menu-bar" class="menu-bar"> <div class="left-buttons"> <i id="sidebar-toggle" class="fa fa-bars"></i> <i id="theme-toggle" class="fa fa-paint-brush"></i> </div> <h1 class="menu-title">The Rust Programming Language</h1> <div class="right-buttons"> <i id="print-button" class="fa fa-print" title="Print this book"></i> </div> </div> <div id="content" class="content"> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#testing-the-librarys-functionality" id="testing-the-librarys-functionality"><h2>Testing the Library's Functionality</h2></a> <p>Now that we've extracted the logic into <em>src/lib.rs</em> and left all the argument parsing and error handling in <em>src/main.rs</em>, it's much easier for us to write tests for the core functionality of our code. We can call our functions directly with various arguments and check return values without having to call our binary from the command line.</p> <p>In this section, we're going to follow the Test Driven Development (TDD) process. This is a software development technique that follows this set of steps:</p> <ol> <li>Write a test that fails, and run it to make sure it fails for the reason you expected.</li> <li>Write or modify just enough code to make the new test pass.</li> <li>Refactor the code you just added or changed, and make sure the tests continue to pass.</li> <li>Repeat!</li> </ol> <p>This is just one of many ways to write software, but TDD can help drive the design of code. Writing the test before writing the code that makes the test pass helps to maintain high test coverage throughout the process.</p> <p>We're going to test drive the implementation of the part of our <code>greprs</code> program that will actually do the searching for the query string in the file contents and produce a list of lines that match the query. We're going to add this functionality in a function called <code>search</code>.</p> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#writing-a-failing-test" id="writing-a-failing-test"><h3>Writing a Failing Test</h3></a> <p>First, since we don't really need them any more, let's remove the <code>println!</code> statements from both <em>src/lib.rs</em> and <em>src/main.rs</em>. Then we'll add a <code>test</code> module with a test function, like we did in Chapter 11. The test function specifies the behavior we'd like the <code>search</code> function to have: it will take a query and the text to search for the query in, and will return only the lines from the text that contain the query. Listing 12-15 shows this test:</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><pre class="playpen"><code class="language-rust"># #![allow(unused_variables)] #fn main() { # fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { # vec![] # } # #[cfg(test)] mod test { use super::*; #[test] fn one_result() { let query = "duct"; let contents = "\ Rust: safe, fast, productive. Pick three."; assert_eq!( vec!["safe, fast, productive."], search(query, contents) ); } } #}</code></pre></pre> <p><span class="caption">Listing 12-15: Creating a failing test for the <code>search</code> function we wish we had</span></p> <p>We've chosen to use "duct" as the string we're looking for in this test. The text we're searching in is three lines, only one of which contains "duct". We assert that the value returned from the <code>search</code> function contains only the one line we expect.</p> <p>We aren't able to run this test and watch it fail though, since this test doesn't even compile yet! We're going to add just enough code to get it to compile: a definition of the <code>search</code> function that always returns an empty vector, as shown in Listing 12-16. Once we have this, the test should compile and fail because an empty vector doesn't match a vector containing the one line <code>"safe, fast, productive."</code>.</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><pre class="playpen"><code class="language-rust"># #![allow(unused_variables)] #fn main() { fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { vec![] } #}</code></pre></pre> <p><span class="caption">Listing 12-16: Defining just enough of the <code>search</code> function that our test will compile</span></p> <!-- Will add ghosting and wingdings in libreoffice /Carol --> <p>Notice that we need an explicit lifetime <code>'a</code> defined in the signature of <code>search</code> and used with the <code>contents</code> argument and the return value. Remember from Chapter 10 that the lifetime parameters specify which argument lifetime is connected to the lifetime of the return value. In this case, we're indicating that the returned vector should contain string slices that reference slices of the argument <code>contents</code> (rather than the argument <code>query</code>).</p> <p>In other words, we're telling Rust that the data returned by the <code>search</code> function will live as long as the data passed into the <code>search</code> function in the <code>contents</code> argument. This is important! The data referenced <em>by</em> a slice needs to be valid in order for the reference to be valid; if the compiler assumed we were making string slices of <code>query</code> rather than <code>contents</code>, it would do its safety checking incorrectly.</p> <p>If we tried to compile this function without lifetimes, we would get this error:</p> <pre><code class="language-text">error[E0106]: missing lifetime specifier --> src/lib.rs:5:47 | 5 | fn search(query: &str, contents: &str) -> Vec<&str> { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `query` or `contents` </code></pre> <p>Rust can't possibly know which of the two arguments we need, so we need to tell it. Because <code>contents</code> is the argument that contains all of our text and we want to return the parts of that text that match, we know <code>contents</code> is the argument that should be connected to the return value using the lifetime syntax.</p> <p>Other programming languages don't require you to connect arguments to return values in the signature, so this may still feel strange, but will get easier over time. You may want to compare this example with the Lifetime Syntax section in Chapter 10.</p> <p>Now let's try running our test:</p> <pre><code class="language-text">$ cargo test ...warnings... Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs Running target/debug/deps/greprs-abcabcabc running 1 test test test::one_result ... FAILED failures: ---- test::one_result stdout ---- thread 'test::one_result' panicked at 'assertion failed: `(left == right)` (left: `["safe, fast, productive."]`, right: `[]`)', src/lib.rs:16 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: test::one_result test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured error: test failed </code></pre> <p>Great, our test fails, exactly as we expected. Let's get the test to pass!</p> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#writing-code-that-gets-the-test-to-pass" id="writing-code-that-gets-the-test-to-pass"><h3>Writing Code that Gets the Test to Pass</h3></a> <p>Currently, our test is failing because we always return an empty vector. To fix that and implement <code>search</code>, our program needs to follow these steps:</p> <ol> <li>Iterate through each line of the contents.</li> <li>Check if the line contains our query string. <ul> <li>If it does, add it to the list of values we're returning.</li> <li>If it doesn't, do nothing.</li> </ul> </li> <li>Return the list of results that match.</li> </ol> <p>Let's take each step at a time, starting with iterating through lines.</p> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#iterating-through-lines-with-the-lines-method" id="iterating-through-lines-with-the-lines-method"><h4>Iterating Through Lines with the <code>lines</code> method</h4></a> <p>Rust has a helpful method to handle line-by-line iteration of strings, conveniently named <code>lines</code>, that works as shown in Listing 12-17:</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><code class="language-rust ignore">fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { // do something with line } } </code></pre> <p><span class="caption">Listing 12-17: Iterating through each line in <code>contents</code></span></p> <!-- Will add wingdings in libreoffice /Carol --> <p>The <code>lines</code> method returns an iterator. We'll be talking about iterators in depth in Chapter 13, but we've already seen this way of using an iterator in Listing 3-6, where we used a <code>for</code> loop with an iterator to run some code on each item in a collection.</p> <!-- so what does `lines` do on its own, if we need to use it in a for loop to work? --> <!-- It does nothing on its own, it returns an iterator for you to do something with. Here, the thing we're doing with it is using it with a `for` loop. I'm not sure exactly what you're asking or how to make the text clearer, but I added a reference to where we've done this in the book previously. /Carol --> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#searching-each-line-for-the-query" id="searching-each-line-for-the-query"><h4>Searching Each Line for the Query</h4></a> <p>Next, we'll add functionality to check if the current line contains the query string. Luckily, strings have another helpful method named <code>contains</code> that does this for us! Add the <code>contains</code> method to the <code>search</code> function as shown in Listing 12-18:</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><code class="language-rust ignore">fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { if line.contains(query) { // do something with line } } } </code></pre> <p><span class="caption">Listing 12-18: Adding functionality to see if the line contains the string in <code>query</code></span></p> <!-- Will add ghosting and wingdings in libreoffice /Carol --> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#storing-matching-lines" id="storing-matching-lines"><h4>Storing Matching Lines</h4></a> <p>Finally, we need a way to store the lines that contain our query string. For that, we can make a mutable vector before the <code>for</code> loop and call the <code>push</code> method to store a <code>line</code> in the vector. After the <code>for</code> loop, we return the vector, as shown in Listing 12-19:</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><code class="language-rust ignore">fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results } </code></pre> <p><span class="caption">Listing 12-19: Storing the lines that match so that we can return them</span></p> <!-- Will add ghosting and wingdings in libreoffice /Carol --> <p>Now the <code>search</code> function should be returning only the lines that contain <code>query</code>, and our test should pass. Let's run the tests:</p> <pre><code class="language-text">$ cargo test running 1 test test test::one_result ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured Running target/debug/greprs-2f55ee8cd1721808 running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured Doc-tests greprs running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured </code></pre> <p>Our test passed, great, it works!</p> <p>Now that our test is passing, we could consider opportunities for refactoring the implementation of the <code>search</code> function while keeping the tests passing in order to maintain the same functionality while we do so. This code isn't bad, but it isn't taking advantage of some useful features of iterators. We'll be coming back to this example in Chapter 13 where we'll explore iterators in detail and see how to improve it.</p> <!-- If we aren't going into this here, maybe just keep it focused, there's a lot going on here as is --> <!-- The reason we mention refactoring here is that it's a key step in the TDD method that we were implicitly using before. Now that we've added text to the beginning of this section to explicitly mention that we're doing TDD and what the steps are, we want to address the "refactor" step. People who have some experience with Rust might also look at this example and wonder why we're not doing this in a different way, and be concerned that we're not teaching the best way possible. This paragraph reassures them that we know what we're doing and we're getting to the better way in Chapter 13. /Carol --> <a class="header" href="ch12-04-testing-the-librarys-functionality.html#using-the-search-function-in-the-run-function" id="using-the-search-function-in-the-run-function"><h4>Using the <code>search</code> Function in the <code>run</code> Function</h4></a> <p>Now that we have the <code>search</code> function working and tested, we need to actually call <code>search</code> from our <code>run</code> function. We need to pass the <code>config.query</code> value and the <code>contents</code> that <code>run</code> read from the file to the <code>search</code> function. Then <code>run</code> will print out each line returned from <code>search</code>:</p> <p><span class="filename">Filename: src/lib.rs</span></p> <pre><code class="language-rust ignore">pub fn run(config: Config) -> Result<(), Box<Error>> { let mut f = File::open(config.filename)?; let mut contents = String::new(); f.read_to_string(&mut contents)?; for line in search(&config.query, &contents) { println!("{}", line); } Ok(()) } </code></pre> <!-- Will add ghosting and wingdings in libreoffice /Carol --> <p>We're again using a <code>for</code> loop to get each line returned from <code>search</code>, and the code that we run for each line prints it out.</p> <p>Now our whole program should be working! Let's try it out, first with a word that should return exactly one line from the Emily Dickinson poem, "frog":</p> <pre><code class="language-text">$ cargo run frog poem.txt Compiling greprs v0.1.0 (file:///projects/greprs) Finished dev [unoptimized + debuginfo] target(s) in 0.38 secs Running `target/debug/greprs frog poem.txt` How public, like a frog </code></pre> <p>Cool! Next, how about a word that will match multiple lines, like "the":</p> <pre><code class="language-text">$ cargo run the poem.txt Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/greprs the poem.txt` Then there's a pair of us — don't tell! To tell your name the livelong day </code></pre> <p>And finally, let's make sure that we don't get any lines when we search for a word that isn't anywhere in the poem, like "monomorphization":</p> <pre><code class="language-text">$ cargo run monomorphization poem.txt Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/greprs monomorphization poem.txt` </code></pre> <p>Excellent! We've built our own version of a classic tool, and learned a lot about how to structure applications. We've also learned a bit about file input and output, lifetimes, testing, and command line parsing.</p> <p>Feel free to move on to Chapter 13 if you'd like at this point. To round out this project chapter, though, we're going to briefly demonstrate how to work with environment variables and printing to standard error, both of which are useful when writing command line programs.</p> </div> <!-- Mobile navigation buttons --> <a href="ch12-03-improving-error-handling-and-modularity.html" class="mobile-nav-chapters previous"> <i class="fa fa-angle-left"></i> </a> <a href="ch12-05-working-with-environment-variables.html" class="mobile-nav-chapters next"> <i class="fa fa-angle-right"></i> </a> </div> <a href="ch12-03-improving-error-handling-and-modularity.html" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys"> <i class="fa fa-angle-left"></i> </a> <a href="ch12-05-working-with-environment-variables.html" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys"> <i class="fa fa-angle-right"></i> </a> </div> <!-- Local fallback for Font Awesome --> <script> if ($(".fa").css("font-family") !== "FontAwesome") { $('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head'); } </script> <!-- Livereload script (if served using the cli tool) --> <script src="highlight.js"></script> <script src="book.js"></script> </body> </html>