expect_json/expect_core/
expect_op_error.rs

1use crate::ExpectJsonError;
2use crate::JsonType;
3use crate::expect_core::Context;
4use crate::expect_core::ExpectOp;
5use crate::internals::ExpectOpMeta;
6use crate::internals::objects::ArrayObject;
7use crate::internals::objects::FloatObject;
8use crate::internals::objects::IntegerObject;
9use crate::internals::objects::ValueObject;
10use crate::internals::objects::ValueTypeObject;
11use std::error::Error as StdError;
12use thiserror::Error;
13
14pub type ExpectOpResult<V> = Result<V, ExpectOpError>;
15
16#[derive(Debug, Error)]
17pub enum ExpectOpError {
18    // TODO, this error message should include which operations it _can_ be performed on.
19    // The underlying problem might be the server returned different data to what we expected.
20    #[error(
21        "Json expect::{}() at {context}, received wrong type:
22    expected {}
23    received {received}",
24        expected_operation.name,
25        format_expected_operation_types(expected_operation),
26    )]
27    UnsupportedOperation {
28        context: Context<'static>,
29        received: ValueTypeObject,
30        expected_operation: ExpectOpMeta,
31    },
32
33    #[error(
34        "Json object at {context} is missing key for {}:
35    expected field '{expected_key}',
36    but it was not found",
37        expected_operation.name
38    )]
39    ObjectKeyMissingForExpectOp {
40        context: Context<'static>,
41        expected_key: String,
42        expected_operation: ExpectOpMeta,
43    },
44
45    #[error(
46        "Json at {context} has key with value, expecting either key not present or different value.
47    received {received}"
48    )]
49    ObjectKeyValueIsEqual {
50        context: Context<'static>,
51        received: ValueObject,
52        expected_operation: ExpectOpMeta,
53    },
54
55    #[error(
56        "Json {json_type} at {context} contains value was expecting to not be there:
57    expected {json_type} to not contain {expected}, but it was found.
58    received {received}"
59    )]
60    ContainsFound {
61        context: Context<'static>,
62        json_type: JsonType,
63        expected: ValueObject,
64        received: ValueObject,
65    },
66
67    #[error(
68        "Json {json_type} at {context} does not contain expected value:
69    expected {json_type} to contain {expected}, but it was not found.
70    received {received}"
71    )]
72    ContainsNotFound {
73        context: Context<'static>,
74        json_type: JsonType,
75        expected: ValueObject,
76        received: ValueObject,
77    },
78
79    #[error(
80        "Json {json_type} error at {context}, regex did not match:
81    expected {json_type} to match regex pattern '{pattern}',
82    received {received}"
83    )]
84    RegexNoMatch {
85        context: Context<'static>,
86        json_type: JsonType,
87        pattern: String,
88        received: ValueObject,
89    },
90
91    #[error(
92        "Json expect::array() error at {context},
93    expected array to contain all unique values.
94    found duplicate {duplicate}
95    received full array {received_array}"
96    )]
97    ArrayContainsDuplicate {
98        context: Context<'static>,
99        duplicate: ValueObject,
100        received_array: ArrayObject,
101    },
102
103    #[error(
104        "{error}
105    received full array {received_full_array}"
106    )]
107    ArrayAllEqual {
108        #[source]
109        error: Box<ExpectJsonError>,
110        received_full_array: ArrayObject,
111    },
112
113    #[error(
114        "Json expect::array() error at {context}, mismatch:
115    expected array (up to order): {expected_array},
116    received array: {received_array}"
117    )]
118    ArrayUnorderedMismatch {
119        context: Context<'static>,
120        expected_array: ArrayObject,
121        received_array: ArrayObject,
122    },
123
124    #[error(
125        "Json expect::integer() error at {context}, is zero:
126    expected non-zero integer
127    received {received}"
128    )]
129    IntegerIsZero {
130        context: Context<'static>,
131        received: IntegerObject,
132    },
133
134    #[error(
135        "Json expect::integer() error at {context}, is not zero:
136    expected 0
137    received {received}"
138    )]
139    IntegerIsNotZero {
140        context: Context<'static>,
141        received: IntegerObject,
142    },
143
144    #[error(
145        "Json expect::float() error at {context}, is zero:
146    expected non-zero float
147    received {received}"
148    )]
149    FloatIsZero {
150        context: Context<'static>,
151        received: FloatObject,
152    },
153
154    #[error(
155        "Json expect::float() error at {context}, is not zero:
156    expected 0.0
157    received {received}"
158    )]
159    FloatIsNotZero {
160        context: Context<'static>,
161        received: FloatObject,
162    },
163
164    #[error(
165        "Json expect::{}() error at {context}:
166    {message},
167    {error}",
168    expected_operation.name,
169    )]
170    UnknownError {
171        #[source]
172        error: Box<dyn StdError>,
173        context: Context<'static>,
174        message: String,
175        expected_operation: ExpectOpMeta,
176    },
177
178    #[error(
179        "Json expect::{}() error at {context}:
180    {message}",
181    expected_operation.name,
182    )]
183    UnknownErrorMessage {
184        context: Context<'static>,
185        message: String,
186        expected_operation: ExpectOpMeta,
187    },
188
189    #[error("{error}")]
190    ExpectJsonError {
191        #[source]
192        error: Box<ExpectJsonError>,
193    },
194}
195
196impl ExpectOpError {
197    pub fn custom<O, S>(expect_op: &O, context: &Context<'_>, message: S) -> Self
198    where
199        O: ExpectOp + ?Sized,
200        S: Into<String>,
201    {
202        Self::UnknownErrorMessage {
203            context: context.to_static(),
204            message: message.into(),
205            expected_operation: ExpectOpMeta::new(expect_op),
206        }
207    }
208
209    pub fn custom_error<O, S, E>(expect_op: &O, context: &Context<'_>, message: S, error: E) -> Self
210    where
211        O: ExpectOp + ?Sized,
212        S: Into<String>,
213        E: StdError + 'static,
214    {
215        Self::UnknownError {
216            context: context.to_static(),
217            error: Box::new(error),
218            message: message.into(),
219            expected_operation: ExpectOpMeta::new(expect_op),
220        }
221    }
222
223    pub fn unsupported_operation_type<O, V>(
224        context: &Context<'_>,
225        expect_op: &O,
226        received: V,
227    ) -> Self
228    where
229        O: ExpectOp + ?Sized,
230        V: Into<ValueTypeObject>,
231    {
232        Self::UnsupportedOperation {
233            context: context.to_static(),
234            received: received.into(),
235            expected_operation: ExpectOpMeta::new(expect_op),
236        }
237    }
238}
239
240impl From<ExpectJsonError> for ExpectOpError {
241    fn from(error: ExpectJsonError) -> Self {
242        Self::ExpectJsonError {
243            error: Box::new(error),
244        }
245    }
246}
247
248fn format_expected_operation_types(expected_operation: &ExpectOpMeta) -> String {
249    let types = expected_operation.types;
250    if types.is_empty() {
251        return "no supported types listed (need to implement ExpectOp::supported_types)"
252            .to_string();
253    }
254
255    types.join(", ")
256}