1use crate::content::types::MatchMode;
2
3pub struct Matcher;
4
5impl Matcher {
6 pub fn check(actual: &str, expected: &str, mode: &MatchMode) -> bool {
8 match mode {
9 MatchMode::Exact => actual == expected,
11
12 MatchMode::Normalized => normalize(actual) == normalize(expected),
14
15 MatchMode::Sorted => {
17 let mut a = sorted_lines(actual);
18 let mut e = sorted_lines(expected);
19 a.sort_unstable();
20 e.sort_unstable();
21 a == e
22 }
23
24 MatchMode::Regex => regex_match(actual, expected),
26 }
27 }
28}
29
30fn normalize(s: &str) -> String {
31 let mut lines: Vec<&str> = s.lines().map(|l| l.trim_end()).collect();
32 while lines.last().map(|l| l.is_empty()).unwrap_or(false) {
33 lines.pop();
34 }
35 lines.join("\n")
36}
37
38fn sorted_lines(s: &str) -> Vec<String> {
39 s.lines()
40 .map(|l| l.trim_end().to_string())
41 .filter(|l| !l.is_empty())
42 .collect()
43}
44
45fn regex_match(actual: &str, pattern: &str) -> bool {
46 actual.contains(pattern.trim())
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn exact_match_passes() {
59 assert!(Matcher::check("hello\n", "hello\n", &MatchMode::Exact));
60 }
61
62 #[test]
63 fn exact_match_fails_on_diff() {
64 assert!(!Matcher::check("hello\n", "world\n", &MatchMode::Exact));
65 }
66
67 #[test]
68 fn normalized_strips_trailing_space() {
69 assert!(Matcher::check(
70 "hello \n",
71 "hello\n",
72 &MatchMode::Normalized
73 ));
74 }
75
76 #[test]
77 fn normalized_strips_trailing_blank_lines() {
78 assert!(Matcher::check(
79 "hello\n\n\n",
80 "hello\n",
81 &MatchMode::Normalized
82 ));
83 }
84
85 #[test]
86 fn sorted_order_independent() {
87 assert!(Matcher::check("b\na\nc\n", "a\nb\nc\n", &MatchMode::Sorted));
88 }
89
90 #[test]
91 fn sorted_fails_on_missing_line() {
92 assert!(!Matcher::check("a\nb\n", "a\nb\nc\n", &MatchMode::Sorted));
93 }
94
95 #[test]
96 fn regex_simple_match() {
97 assert!(Matcher::check("hello world", "hello", &MatchMode::Regex));
98 }
99
100 #[test]
101 fn regex_no_match() {
102 assert!(!Matcher::check("hello world", "goodbye", &MatchMode::Regex));
103 }
104}