minigrep-tool-cli 0.1.1

A simple command-line search tool
Documentation
use crate::CaseMode::CaseSensitive;
use CaseMode::CaseInsensitive;
use std::error::Error;
use std::{env, fs};

pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
    let content = fs::read_to_string(&config.file_path)?;

    search(&config.query, &content, &config.case_mode)
        .iter()
        .for_each(|matching_string| println!("Found {matching_string}"));

    Ok(())
}

fn search<'a>(query: &str, content: &'a str, case_mode: &CaseMode) -> Vec<&'a str> {
    content
        .lines()
        .filter(|l| match case_mode {
            CaseSensitive => l.contains(query),
            CaseInsensitive => l.to_lowercase().contains(&query.to_lowercase()),
        })
        .collect::<Vec<_>>()
}

enum CaseMode {
    CaseInsensitive,
    CaseSensitive,
}

pub struct Config {
    pub query: String,
    pub file_path: String,
    pub(crate) case_mode: CaseMode,
}
impl Config {
    pub fn build(mut arguments: impl Iterator<Item = String>) -> Result<Self, &'static str> {
        arguments.next();

        let query = arguments.next().ok_or("query string not supplied")?;
        let file_path = arguments.next().ok_or("file path not supplied")?;
        let case_mode = Self::case_mode()?;

        Ok(Config {
            query,
            file_path,
            case_mode,
        })
    }

    fn case_mode() -> Result<CaseMode, &'static str> {
        let case_mode = match env::var("CASE_MODE").as_deref().unwrap_or("sensitive") {
            "sensitive" => CaseSensitive,
            "insensitive" => CaseInsensitive,
            _ => return Err("Invalid case mode"),
        };
        Ok(case_mode)
    }
}

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

    #[test]
    fn finds_a_case_sensitive_matching_result() {
        let query = "duct";
        let content = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";

        let results = search(query, content, &CaseSensitive);

        assert_eq!(vec!["safe, fast, productive."], results)
    }

    #[test]
    fn finds_case_sensitive_matching_result() {
        let query = "RuSt";
        let content = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
        let results = search(query, content, &CaseInsensitive);

        assert_eq!(vec!["Rust:"], results);
    }
}