» Make grep CLI App in Rust » 2. Development » 2.4 Add Tests

Add Tests

Rust provides robust support for writing tests. The built-in testing framework is part of the standard library and is easy to use.

Rust uses the #[test] attribute to define test functions. These functions are identified by the attribute, and the test runner executes them when running tests.

Test files are typically named after the module they are testing, with the addition of the tests suffix. For example, if you have a module named my_module, the corresponding test file would be my_module_tests.rs.

Test functions are named with the test_ prefix, followed by a descriptive name indicating what is being tested. Use snake_case for function names.

The assert! macro and related macros like assert_eq! and assert_ne! are used for making assertions in test functions. Assertions help validate that the actual results match the expected results.

tests/lib_tests.rs:

use tempfile::tempdir;

use lr_grustep::{grep, grep_count, grep_recursive, GrepOptions, MatchItem, MatchResult};

#[test]
fn test_grep() {
    let pattern = "fn grep";
    let file_content = "This is a test line with fn grep in it.";
    let temp_dir = tempdir().expect("Failed to create temporary directory");
    let file_path = temp_dir.path().join("test_file.txt");

    std::fs::write(&file_path, file_content).expect("Failed to write to temporary file");

    let options = GrepOptions {
        ignore_case: false,
        invert_match: false,
    };

    let result = grep(pattern, &file_path, &options).unwrap();
    let matched_lines = result.get(file_path.to_string_lossy().as_ref()).unwrap();
    assert_eq!(matched_lines.len(), 1);

    // Check the content of the matched line
    assert_eq!(matched_lines[0].line, file_content.trim());
}

#[test]
fn test_grep_count() {
    let mut result = MatchResult::new();
    let item = MatchItem {
        line_number: 1,
        line: String::from("Test line"),
    };
    result.insert(String::from("test_file.txt"), vec![item]);

    let count = grep_count(&result);
    assert_eq!(count, 1);
}

#[test]
fn test_grep_recursive() {
    let pattern = "TODO";
    let temp_dir = tempdir().expect("Failed to create temporary directory");
    let nested_dir = temp_dir.path().join("nested");
    std::fs::create_dir(&nested_dir).expect("Failed to create nested directory");

    let file_content = "TODO: Implement this feature.";
    let file_path = temp_dir.path().join("test_file.txt");
    let nested_file_path = nested_dir.join("nested_file.txt");

    std::fs::write(&file_path, file_content).expect("Failed to write to temporary file");
    std::fs::write(&nested_file_path, file_content).expect("Failed to write to nested file");

    let options = GrepOptions {
        ignore_case: false,
        invert_match: false,
    };

    let result = grep_recursive(pattern, temp_dir.path(), &options).unwrap();
    let matched_lines = result.get(file_path.to_string_lossy().as_ref()).unwrap();
    assert_eq!(matched_lines.len(), 1);

    // Check the content of the matched line
    assert_eq!(matched_lines[0].line, file_content.trim());

    // Similarly, check the content for the nested file
    let nested_matched_lines = result
        .get(nested_file_path.to_string_lossy().as_ref())
        .unwrap();
    assert_eq!(nested_matched_lines.len(), 1);
    assert_eq!(nested_matched_lines[0].line, file_content.trim());
}

Tests are run using the cargo test command:

cargo test

You should get test results as below:

     Running tests/lib_tests.rs (target/debug/deps/lib_tests-a90b7c416c14752c)

running 3 tests
test test_grep_count ... ok
test test_grep ... ok
test test_grep_recursive ... ok

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

If there's something wrong, you will get a detailed error messge like this:

     Running tests/lib_tests.rs (target/debug/deps/lib_tests-a90b7c416c14752c)

running 3 tests
test test_grep_count ... ok
test test_grep ... FAILED
test test_grep_recursive ... ok

failures:

---- test_grep stdout ----
thread 'test_grep' panicked at tests/lib_tests.rs:21:5:
assertion `left == right` failed
  left: 0
 right: 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test_grep

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

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

Then, you can fix your code based on this error message.

PrevNext