expect_json/expects/
expect_op.rs

1use crate::internals::objects::IntegerObject;
2use crate::internals::objects::NullObject;
3use crate::internals::objects::ValueObject;
4use crate::Context;
5use crate::ExpectOpError;
6use crate::ExpectOpExt;
7use crate::ExpectOpResult;
8use crate::JsonType;
9use serde_json::Map;
10use serde_json::Value;
11use std::fmt::Debug;
12
13pub trait ExpectOp: ExpectOpExt + Debug + Send + 'static {
14    fn on_any(&self, context: &mut Context<'_>, received: &Value) -> ExpectOpResult<()> {
15        match received {
16            Value::Null => self.on_null(context),
17            Value::Number(received_number) => {
18                let value_num = ValueObject::from(received_number.clone());
19                match value_num {
20                    ValueObject::Float(received_float) => self.on_f64(context, received_float.into()),
21                    ValueObject::Integer(IntegerObject::Positive(received_integer)) => self.on_u64(context, received_integer),
22                    ValueObject::Integer(IntegerObject::Negative(received_integer)) => self.on_i64(context, received_integer),
23                    _ => panic!("Unexpected non-number value, expected a float or an integer, found {value_num:?}. (This is a bug, please report at: https://github.com/JosephLenton/expect-json/issues)"),
24                }
25            }
26            Value::String(received_string) => self.on_string(context, received_string),
27            Value::Bool(received_boolean) => self.on_boolean(context, *received_boolean),
28            Value::Array(received_array) => self.on_array(context, received_array),
29            Value::Object(received_object) => self.on_object(context, received_object),
30        }
31    }
32
33    #[allow(unused_variables)]
34    fn on_null(&self, context: &mut Context<'_>) -> ExpectOpResult<()> {
35        Err(ExpectOpError::unsupported_operation_type(
36            context, self, NullObject,
37        ))
38    }
39
40    #[allow(unused_variables)]
41    fn on_f64(&self, context: &mut Context<'_>, received: f64) -> ExpectOpResult<()> {
42        Err(ExpectOpError::unsupported_operation_type(
43            context, self, received,
44        ))
45    }
46
47    #[allow(unused_variables)]
48    fn on_u64(&self, context: &mut Context<'_>, received: u64) -> ExpectOpResult<()> {
49        Err(ExpectOpError::unsupported_operation_type(
50            context, self, received,
51        ))
52    }
53
54    #[allow(unused_variables)]
55    fn on_i64(&self, context: &mut Context<'_>, received: i64) -> ExpectOpResult<()> {
56        Err(ExpectOpError::unsupported_operation_type(
57            context, self, received,
58        ))
59    }
60
61    #[allow(unused_variables)]
62    fn on_boolean(&self, context: &mut Context<'_>, received: bool) -> ExpectOpResult<()> {
63        Err(ExpectOpError::unsupported_operation_type(
64            context, self, received,
65        ))
66    }
67
68    #[allow(unused_variables)]
69    fn on_string(&self, context: &mut Context<'_>, received: &str) -> ExpectOpResult<()> {
70        Err(ExpectOpError::unsupported_operation_type(
71            context,
72            self,
73            received.to_owned(),
74        ))
75    }
76
77    #[allow(unused_variables)]
78    fn on_array(&self, context: &mut Context<'_>, received: &[Value]) -> ExpectOpResult<()> {
79        Err(ExpectOpError::unsupported_operation_type(
80            context,
81            self,
82            received.to_owned(),
83        ))
84    }
85
86    #[allow(unused_variables)]
87    fn on_object(
88        &self,
89        context: &mut Context<'_>,
90        received: &Map<String, Value>,
91    ) -> ExpectOpResult<()> {
92        Err(ExpectOpError::unsupported_operation_type(
93            context,
94            self,
95            received.to_owned(),
96        ))
97    }
98
99    fn supported_types(&self) -> &'static [JsonType] {
100        &[]
101    }
102}
103
104#[cfg(test)]
105mod test_on_any {
106    use super::*;
107    use crate::internals::objects::ArrayObject;
108    use crate::internals::objects::BooleanObject;
109    use crate::internals::objects::FloatObject;
110    use crate::internals::objects::ObjectObject;
111    use crate::internals::objects::StringObject;
112    use crate::internals::objects::ValueTypeObject;
113    use crate::internals::ExpectOpMeta;
114    use serde_json::json;
115
116    // An empty implementation which will hit the errors by default.
117    #[crate::expect_op(internal)]
118    #[derive(Debug, Clone)]
119    struct TestJsonExpectOp;
120
121    impl ExpectOp for TestJsonExpectOp {}
122
123    #[test]
124    fn it_should_error_by_default_against_json_null() {
125        let mut outer_context = Context::new();
126        let received = json!(null);
127        let output = TestJsonExpectOp
128            .on_any(&mut outer_context, &received)
129            .unwrap_err();
130        assert!(matches!(
131            output,
132            ExpectOpError::UnsupportedOperation {
133                context,
134                received: ValueTypeObject(ValueObject::Null(NullObject)),
135                expected_operation: ExpectOpMeta {
136                    name: "TestJsonExpectOp",
137                    types: &[],
138                },
139            } if context == outer_context.to_static()
140        ));
141    }
142
143    #[test]
144    fn it_should_error_by_default_against_json_boolean() {
145        let mut outer_context = Context::new();
146        let received = json!(true);
147        let output = TestJsonExpectOp
148            .on_any(&mut outer_context, &received)
149            .unwrap_err();
150        assert!(matches!(
151            output,
152            ExpectOpError::UnsupportedOperation {
153                context,
154                received: ValueTypeObject(ValueObject::Boolean(BooleanObject(true))),
155                expected_operation: ExpectOpMeta {
156                    name: "TestJsonExpectOp",
157                    types: &[],
158                },
159            } if context == outer_context.to_static()
160        ));
161    }
162
163    #[test]
164    fn it_should_error_by_default_against_json_positive_integer() {
165        let mut outer_context = Context::new();
166        let received = json!(123);
167        let output = TestJsonExpectOp
168            .on_any(&mut outer_context, &received)
169            .unwrap_err();
170        assert!(matches!(
171            output,
172            ExpectOpError::UnsupportedOperation {
173                context,
174                received: ValueTypeObject(ValueObject::Integer(IntegerObject::Positive(123))),
175                expected_operation: ExpectOpMeta {
176                    name: "TestJsonExpectOp",
177                    types: &[],
178                },
179            } if context == outer_context.to_static()
180        ));
181    }
182
183    #[test]
184    fn it_should_error_by_default_against_json_negative_integer() {
185        let mut outer_context = Context::new();
186        let received = json!(-123);
187        let output = TestJsonExpectOp
188            .on_any(&mut outer_context, &received)
189            .unwrap_err();
190        assert!(matches!(
191            output,
192            ExpectOpError::UnsupportedOperation {
193                context,
194                received: ValueTypeObject(ValueObject::Integer(IntegerObject::Negative(-123))),
195                expected_operation: ExpectOpMeta {
196                    name: "TestJsonExpectOp",
197                    types: &[],
198                },
199            } if context == outer_context.to_static()
200        ));
201    }
202
203    #[test]
204    fn it_should_error_by_default_against_json_float() {
205        let mut outer_context = Context::new();
206        let received = json!(123.456);
207        let output = TestJsonExpectOp
208            .on_any(&mut outer_context, &received)
209            .unwrap_err();
210        assert!(matches!(
211            output,
212            ExpectOpError::UnsupportedOperation {
213                context,
214                received: ValueTypeObject(ValueObject::Float(FloatObject(123.456))),
215                expected_operation: ExpectOpMeta {
216                    name: "TestJsonExpectOp",
217                    types: &[],
218                },
219            } if context == outer_context.to_static()
220        ));
221    }
222
223    #[test]
224    fn it_should_error_by_default_against_json_string() {
225        let mut outer_context = Context::new();
226        let received = json!("🦊");
227        let output = TestJsonExpectOp
228            .on_any(&mut outer_context, &received)
229            .unwrap_err();
230        assert!(matches!(
231            output,
232            ExpectOpError::UnsupportedOperation {
233                context,
234                received,
235                expected_operation: ExpectOpMeta {
236                    name: "TestJsonExpectOp",
237                    types: &[],
238                },
239            } if context == outer_context.to_static()
240                && received == ValueTypeObject(ValueObject::String(StringObject("🦊".to_string())))
241        ));
242    }
243
244    #[test]
245    fn it_should_error_by_default_against_json_array() {
246        let mut outer_context = Context::new();
247        let received = json!([]);
248        let output = TestJsonExpectOp
249            .on_any(&mut outer_context, &received)
250            .unwrap_err();
251        assert!(matches!(
252            output,
253            ExpectOpError::UnsupportedOperation {
254                context,
255                received,
256                expected_operation: ExpectOpMeta {
257                    name: "TestJsonExpectOp",
258                    types: &[],
259                },
260            } if context == outer_context.to_static()
261                && received == ValueTypeObject(ValueObject::Array(ArrayObject(vec![])))
262        ));
263    }
264
265    #[test]
266    fn it_should_error_by_default_against_json_object() {
267        let mut outer_context = Context::new();
268        let received = json!({});
269        let output = TestJsonExpectOp
270            .on_any(&mut outer_context, &received)
271            .unwrap_err();
272        assert!(matches!(
273            output,
274            ExpectOpError::UnsupportedOperation {
275                context,
276                received,
277                expected_operation: ExpectOpMeta {
278                    name: "TestJsonExpectOp",
279                    types: &[],
280                },
281            } if context == outer_context.to_static()
282                && received == ValueTypeObject(ValueObject::Object(ObjectObject(Map::new())))
283        ));
284    }
285}