expect_json/expect/ops/
expect_uuid.rs

1use crate::expect_op;
2use crate::expect_op::Context;
3use crate::expect_op::ExpectOp;
4use crate::expect_op::ExpectOpError;
5use crate::expect_op::ExpectOpResult;
6use crate::JsonType;
7use uuid::Uuid;
8
9///
10/// Expects a UUID string.
11///
12/// ```rust
13/// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
14/// #
15/// # use axum::Router;
16/// # use axum::extract::Json;
17/// # use axum::routing::get;
18/// # use axum_test::TestServer;
19/// # use serde_json::json;
20/// #
21/// # let server = TestServer::new(Router::new())?;
22/// #
23/// use axum_test::expect_json;
24///
25/// let server = TestServer::new(Router::new())?;
26///
27/// server.get(&"/user")
28///     .await
29///     .assert_json(&json!({
30///         "name": "Alice",
31///         "id": expect_json::uuid(),
32///     }));
33/// #
34/// # Ok(()) }
35/// ```
36///
37#[expect_op(internal, name = "uuid")]
38#[derive(Debug, Clone, Default, PartialEq)]
39pub struct ExpectUuid {
40    expected_version: Option<u8>,
41    is_not_nil_flag: bool,
42}
43
44impl ExpectUuid {
45    pub(crate) fn new() -> Self {
46        Self {
47            expected_version: None,
48            is_not_nil_flag: false,
49        }
50    }
51
52    pub fn is_not_nil(mut self) -> Self {
53        self.is_not_nil_flag = true;
54        self
55    }
56
57    pub fn version(mut self, version: u8) -> Self {
58        self.expected_version = Some(version);
59        self
60    }
61}
62
63impl ExpectOp for ExpectUuid {
64    fn on_string(&self, context: &mut Context, received: &str) -> ExpectOpResult<()> {
65        let uuid = Uuid::parse_str(received).map_err(|error| {
66            let error_message = format!("failed to parse string '{received}' as uuid");
67            ExpectOpError::custom_error(context, self, error_message, error)
68        })?;
69
70        if let Some(expected_version) = self.expected_version {
71            let received_version = uuid.get_version_num();
72            if received_version != (expected_version as usize) {
73                let error_message = format!("expected uuid version '{expected_version}', received version '{received_version}', for uuid '{received}'");
74                return Err(ExpectOpError::custom(context, self, error_message));
75            }
76        }
77
78        if self.is_not_nil_flag && uuid.is_nil() {
79            let error_message =
80                format!("expected uuid to be not nil, but it is, received '{received}'");
81            return Err(ExpectOpError::custom(context, self, error_message));
82        }
83
84        Ok(())
85    }
86
87    fn supported_types(&self) -> &'static [JsonType] {
88        &[JsonType::String]
89    }
90}
91
92#[cfg(test)]
93mod test_uuid {
94    use crate::expect;
95    use crate::expect_json_eq;
96    use pretty_assertions::assert_eq;
97    use serde_json::json;
98
99    #[test]
100    fn it_should_parse_a_simple_uuid() {
101        let left = json!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8");
102        let right = json!(expect::uuid());
103
104        let output = expect_json_eq(&left, &right);
105        assert!(output.is_ok(), "assertion error: {output:#?}");
106    }
107
108    #[test]
109    fn it_should_parse_a_hyphenated_uuid() {
110        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
111        let right = json!(expect::uuid());
112
113        let output = expect_json_eq(&left, &right);
114        assert!(output.is_ok(), "assertion error: {output:#?}");
115    }
116
117    #[test]
118    fn it_should_fail_to_parse_an_invalid_uuid() {
119        let left = json!("🦊");
120        let right = json!(expect::uuid());
121
122        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
123        assert_eq!(
124            output,
125            r#"Json expect::uuid() error at root:
126    failed to parse string '🦊' as uuid,
127    invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `🦊` at 1"#
128        );
129    }
130}
131
132#[cfg(test)]
133mod test_is_not_nil {
134    use crate::expect;
135    use crate::expect_json_eq;
136    use serde_json::json;
137
138    #[test]
139    fn it_should_return_true_for_a_non_nil_uuid() {
140        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
141        let right = json!(expect::uuid().is_not_nil());
142
143        let output = expect_json_eq(&left, &right);
144        assert!(output.is_ok(), "assertion error: {output:#?}");
145    }
146
147    #[test]
148    fn it_should_return_false_for_a_nil_uuid() {
149        let left = json!("00000000-0000-0000-0000-000000000000");
150        let right = json!(expect::uuid().is_not_nil());
151
152        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
153        assert_eq!(
154            output,
155            r#"Json expect::uuid() error at root:
156    expected uuid to be not nil, but it is, received '00000000-0000-0000-0000-000000000000'"#
157        );
158    }
159}
160
161#[cfg(test)]
162mod test_version {
163    use crate::expect;
164    use crate::expect_json_eq;
165    use pretty_assertions::assert_eq;
166    use serde_json::json;
167
168    #[test]
169    fn it_should_return_true_for_matching_version_1_uuid() {
170        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
171        let right = json!(expect::uuid().version(1));
172
173        let output = expect_json_eq(&left, &right);
174        assert!(output.is_ok(), "assertion error: {output:#?}");
175    }
176
177    #[test]
178    fn it_should_return_false_for_uuid_with_different_version() {
179        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
180        let right = json!(expect::uuid().version(2));
181
182        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
183        assert_eq!(
184            output,
185            r#"Json expect::uuid() error at root:
186    expected uuid version '2', received version '1', for uuid 'f3b4958c-52a1-11e7-802a-010203040506'"#
187        );
188    }
189}