1pub fn command_string(argv: &[String]) -> String {
2 argv.join(" ")
3}
4
5pub fn matches(pattern: &str, command: &str) -> bool {
6 if !pattern.contains('*') {
7 return pattern == command;
8 }
9
10 let starts_with_wildcard = pattern.starts_with('*');
11 let ends_with_wildcard = pattern.ends_with('*');
12 let parts: Vec<&str> = pattern.split('*').filter(|part| !part.is_empty()).collect();
13
14 if parts.is_empty() {
15 return true;
16 }
17
18 let mut cursor = 0usize;
19
20 for (index, part) in parts.iter().enumerate() {
21 if index == 0 && !starts_with_wildcard {
22 if !command[cursor..].starts_with(part) {
23 return false;
24 }
25 cursor += part.len();
26 continue;
27 }
28
29 match command[cursor..].find(part) {
30 Some(found) => cursor += found + part.len(),
31 None => return false,
32 }
33 }
34
35 if !ends_with_wildcard {
36 let last = parts.last().expect("parts is not empty");
37 return command.ends_with(last);
38 }
39
40 true
41}
42
43#[cfg(test)]
44mod tests {
45 use super::{command_string, matches};
46
47 #[test]
48 fn joins_command_tokens_with_single_spaces() {
49 let command = vec![
50 "cargo".to_string(),
51 "build".to_string(),
52 "--release".to_string(),
53 ];
54 assert_eq!(command_string(&command), "cargo build --release");
55 }
56
57 #[test]
58 fn exact_match_requires_full_string_equality() {
59 assert!(matches("npm install", "npm install"));
60 assert!(!matches("npm install", "npm install lodash"));
61 }
62
63 #[test]
64 fn wildcard_match_handles_prefix_suffix_and_infix() {
65 assert!(matches("cargo build*", "cargo build --release"));
66 assert!(matches("*pytest", "python -m pytest"));
67 assert!(matches("python * pytest", "python -m pytest"));
68 assert!(!matches("cargo build*", "cargo test"));
69 }
70}