use regex::Regex;
use std::collections::HashMap;
pub fn params_match(expected: &HashMap<String, String>, actual: &serde_json::Value) -> bool {
for (key, pattern) in expected {
let actual_value = actual.get(key);
let actual_str = match actual_value {
Some(serde_json::Value::String(s)) => s.clone(),
Some(v) => v.to_string(),
None => return false,
};
match Regex::new(pattern) {
Ok(re) => {
if !re.is_match(&actual_str) {
return false;
}
}
Err(_) => {
if &actual_str != pattern {
return false;
}
}
}
}
true
}
#[macro_export]
macro_rules! params {
($($key:expr => $value:expr),* $(,)?) => {{
let mut map = std::collections::HashMap::new();
$(
map.insert($key.to_string(), $value.to_string());
)*
map
}};
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_regex_file_extension() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), r".*\.env$".to_string());
assert!(params_match(¶ms, &json!({"file_path": ".env"})));
assert!(params_match(¶ms, &json!({"file_path": "test.env"})));
assert!(!params_match(¶ms, &json!({"file_path": "test.txt"})));
}
#[test]
fn test_regex_path_matching() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), r"(.*/)config\.json$".to_string());
assert!(params_match(
¶ms,
&json!({"file_path": "src/config.json"})
));
assert!(params_match(¶ms, &json!({"file_path": "/config.json"})));
assert!(params_match(
¶ms,
&json!({"file_path": "/a/b/c/config.json"})
));
}
#[test]
fn test_regex_alternation() {
let mut params = HashMap::new();
params.insert("command".to_string(), r"^npm (install|i)$".to_string());
assert!(params_match(¶ms, &json!({"command": "npm install"})));
assert!(params_match(¶ms, &json!({"command": "npm i"})));
assert!(!params_match(¶ms, &json!({"command": "npm run"})));
}
#[test]
fn test_regex_partial_match() {
let mut params = HashMap::new();
params.insert("command".to_string(), r"node run\.js".to_string());
assert!(params_match(¶ms, &json!({"command": "node run.js"})));
assert!(params_match(
¶ms,
&json!({"command": "cd /some/path && node run.js --flag"})
));
assert!(!params_match(¶ms, &json!({"command": "node other.js"})));
}
#[test]
fn test_exact_matching() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), "/tmp/test.txt".to_string());
assert!(params_match(
¶ms,
&json!({"file_path": "/tmp/test.txt"})
));
assert!(params_match(
¶ms,
&json!({"file_path": "/tmp/test.txt.bak"})
));
}
#[test]
fn test_exact_matching_with_anchors() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), r"^/tmp/test\.txt$".to_string());
assert!(params_match(
¶ms,
&json!({"file_path": "/tmp/test.txt"})
));
assert!(!params_match(
¶ms,
&json!({"file_path": "/tmp/test.txt.bak"})
));
}
#[test]
fn test_missing_key() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), "test.txt".to_string());
assert!(!params_match(¶ms, &json!({"other_key": "test.txt"})));
}
#[test]
fn test_multiple_params() {
let mut params = HashMap::new();
params.insert("file_path".to_string(), r".*\.txt".to_string());
params.insert("content".to_string(), "hello.*".to_string());
assert!(params_match(
¶ms,
&json!({"file_path": "test.txt", "content": "hello world"})
));
assert!(!params_match(
¶ms,
&json!({"file_path": "test.txt", "content": "goodbye"})
));
}
#[test]
fn test_non_string_values() {
let mut params = HashMap::new();
params.insert("count".to_string(), "42".to_string());
assert!(params_match(¶ms, &json!({"count": 42})));
}
#[test]
fn test_params_macro() {
let params = params! {
"file_path" => "test.txt",
"content" => "hello"
};
assert_eq!(params.get("file_path"), Some(&"test.txt".to_string()));
assert_eq!(params.get("content"), Some(&"hello".to_string()));
}
}