test_lulu/
lib.rs

1use std::fs;
2use std::error::Error;
3
4pub struct Config {
5    pub query: String,
6    pub file_path: String,
7    pub ignore_case: bool,
8}
9
10use std::env;
11
12impl Config {
13    pub fn build(
14        mut args: impl Iterator<Item = String>,
15    ) -> Result<Config, &'static str> {
16        args.next();
17
18        let query = match args.next() {
19            Some(arg) => arg,
20            None => return Err("Didn't get a query string"),
21        };
22
23        let file_path = match args.next() {
24            Some(arg) => arg,
25            None => return Err("Didn't get a file path"),
26        };
27
28        let ignore_case = env::var("IGNORE_CASE").is_ok();
29
30        Ok(Config {
31            query,
32            file_path,
33            ignore_case,
34        })
35    }
36}
37
38pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
39    let contents = fs::read_to_string(config.file_path)?;
40
41    let results = if config.ignore_case {
42        search_case_insensitive(&config.query, &contents)
43    } else {
44        search(&config.query, &contents)
45    };
46
47    for line in search(&config.query, &contents) {
48        println!("{line}");
49    }
50
51    Ok(())
52}
53
54pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
55    contents
56        .lines()
57        .filter(|line| line.contains(query))
58        .collect()
59}
60
61pub fn search_case_insensitive<'a>(
62    query: &str,
63    contents: &'a str,
64) -> Vec<&'a str> {
65    let query = query.to_lowercase();
66    let mut results = Vec::new();
67
68    for line in contents.lines() {
69        if line.to_lowercase().contains(&query) {
70            results.push(line);
71        }
72    }
73
74    results
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn one_result() {
83        let query = "duct";
84        let contents = "\
85Rust:
86safe, fast, productive.
87Pick three.";
88
89        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
90    }
91
92    #[test]
93    fn case_sensitive() {
94        let query = "duct";
95        let contents = "\
96Rust:
97safe, fast, productive.
98Pick three.
99Duct tape.";
100
101        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
102    }
103
104    #[test]
105    fn case_insensitive() {
106        let query = "rUsT";
107        let contents = "\
108Rust:
109safe, fast, productive.
110Pick three.
111Trust me.";
112
113        assert_eq!(
114            vec!["Rust:", "Trust me."],
115            search_case_insensitive(query, contents)
116        );
117    }
118
119}