json_matcher/matchers/
string.rs

1use serde_json::Value;
2
3use crate::{JsonMatcher, JsonMatcherError};
4
5pub struct StrMatcher<'a> {
6    value: &'a str,
7}
8
9impl<'a> StrMatcher<'a> {
10    pub fn new(value: &'a str) -> Self {
11        Self { value }
12    }
13}
14
15impl JsonMatcher for StrMatcher<'_> {
16    fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
17        match value {
18            Value::String(actual) => {
19                if actual == self.value {
20                    vec![]
21                } else {
22                    vec![JsonMatcherError::at_root(format!(
23                        "Expected string \"{}\" but got \"{}\"",
24                        self.value, actual
25                    ))]
26                }
27            }
28            _ => vec![JsonMatcherError::at_root("Value is not a string")],
29        }
30    }
31}
32
33impl JsonMatcher for &str {
34    fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
35        StringMatcher::new(*self).json_matches(value)
36    }
37}
38
39impl JsonMatcher for &String {
40    fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
41        StrMatcher::new(self.as_str()).json_matches(value)
42    }
43}
44
45pub struct StringMatcher {
46    value: String,
47}
48
49impl StringMatcher {
50    pub fn new<T: Into<String>>(value: T) -> Self {
51        Self {
52            value: value.into(),
53        }
54    }
55}
56
57impl JsonMatcher for StringMatcher {
58    fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
59        StrMatcher::new(&self.value).json_matches(value)
60    }
61}
62
63impl JsonMatcher for String {
64    fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
65        StrMatcher::new(self.as_str()).json_matches(value)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::assert_jm;
72
73    use super::*;
74
75    #[test]
76    fn test_string_matcher() {
77        let get_matcher = || StringMatcher::new("hello");
78        assert_jm!(Value::String("hello".to_string()), get_matcher());
79        // not a string
80        assert_eq!(
81            *std::panic::catch_unwind(|| { assert_jm!(Value::Number(2.into()), get_matcher()) })
82                .err()
83                .unwrap()
84                .downcast::<String>()
85                .unwrap(),
86            r#"
87Json matcher failed:
88  - $: Value is not a string
89
90Actual:
912"#
92        );
93        // is string, but not expected value
94        assert_eq!(
95            *std::panic::catch_unwind(|| {
96                assert_jm!(Value::String("world".to_string()), get_matcher())
97            })
98            .err()
99            .unwrap()
100            .downcast::<String>()
101            .unwrap(),
102            r#"
103Json matcher failed:
104  - $: Expected string "hello" but got "world"
105
106Actual:
107"world""#
108        );
109    }
110
111    #[test]
112    fn test_raw_implementations() {
113        assert_eq!(
114            "hello".json_matches(&Value::String("hello".to_string())),
115            vec![]
116        );
117        assert_eq!(
118            "hello"
119                .json_matches(&Value::String("world".to_string()))
120                .into_iter()
121                .map(|x| x.to_string())
122                .collect::<String>(),
123            "$: Expected string \"hello\" but got \"world\""
124        );
125    }
126}