1use serde_json::Value;
2
3pub fn json_values_match(actual: &Value, expected: &Value) -> bool {
4 match (actual, expected) {
5 (Value::String(a), Value::String(e)) => a == e,
6 (Value::Number(a), Value::Number(e)) => a == e,
7 (Value::Bool(a), Value::Bool(e)) => a == e,
8 (Value::Null, Value::Null) => true,
9 (Value::Array(a), Value::Array(e)) => {
10 a.len() == e.len() && a.iter().zip(e.iter()).all(|(a, e)| json_values_match(a, e))
11 }
12 (Value::Object(a), Value::Object(e)) => {
13 a.len() == e.len()
14 && a.iter()
15 .all(|(k, v)| e.get(k).is_some_and(|ev| json_values_match(v, ev)))
16 }
17 _ => false,
18 }
19}
20
21pub fn matches_pattern(value: &str, pattern: &str) -> bool {
22 if pattern.contains('*') {
23 let parts: Vec<&str> = pattern.split('*').collect();
24 if parts.is_empty() {
25 return true;
26 }
27
28 let mut pos = 0;
29 for (i, part) in parts.iter().enumerate() {
30 if i == 0 && !part.is_empty() {
31 if !value.starts_with(part) {
32 return false;
33 }
34 pos += part.len();
35 } else if i == parts.len() - 1 && !part.is_empty() {
36 if !value.ends_with(part) {
37 return false;
38 }
39 } else if !part.is_empty() {
40 if let Some(found_pos) = value[pos..].find(part) {
41 pos += found_pos + part.len();
42 } else {
43 return false;
44 }
45 }
46 }
47 true
48 } else {
49 value == pattern
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use serde_json::json;
57
58 #[test]
59 fn test_json_values_match() {
60 assert!(json_values_match(&json!("test"), &json!("test")));
61 assert!(json_values_match(&json!(42), &json!(42)));
62 assert!(json_values_match(&json!(true), &json!(true)));
63 assert!(json_values_match(&json!(null), &json!(null)));
64 assert!(json_values_match(
65 &json!({"a": 1, "b": 2}),
66 &json!({"a": 1, "b": 2})
67 ));
68 assert!(json_values_match(&json!([1, 2, 3]), &json!([1, 2, 3])));
69
70 assert!(!json_values_match(&json!("test"), &json!("other")));
71 assert!(!json_values_match(&json!(42), &json!(43)));
72 assert!(!json_values_match(&json!(true), &json!(false)));
73 }
74
75 #[test]
76 fn test_matches_pattern() {
77 assert!(matches_pattern("hello world", "hello world"));
78 assert!(matches_pattern("hello world", "hello*"));
79 assert!(matches_pattern("hello world", "*world"));
80 assert!(matches_pattern("hello world", "*lo wo*"));
81 assert!(matches_pattern("hello world", "hello*world"));
82
83 assert!(!matches_pattern("hello world", "goodbye*"));
84 assert!(!matches_pattern("hello world", "*universe"));
85 }
86}