expect_json/expect/ops/
expect_uuid.rs

1use crate::JsonType;
2use crate::expect_core::Context;
3use crate::expect_core::ExpectOp;
4use crate::expect_core::ExpectOpError;
5use crate::expect_core::ExpectOpResult;
6use crate::expect_core::expect_op;
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///         "id": expect_json::uuid(),
31///         "name": "Alice",
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    /// Expects this is not the 'nil' UUID, which is "00000000-0000-0000-0000-000000000000".
53    pub fn not_nil(mut self) -> Self {
54        self.is_not_nil_flag = true;
55        self
56    }
57
58    /// Expects this meets the given UUID version.
59    ///
60    /// Details on the different versions can be found on Wikipedia: <https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_of_the_OSF_DCE_variant>
61    pub fn version(mut self, version: u8) -> Self {
62        self.expected_version = Some(version);
63        self
64    }
65}
66
67impl ExpectOp for ExpectUuid {
68    fn on_string(&self, context: &mut Context, received: &str) -> ExpectOpResult<()> {
69        let uuid = Uuid::parse_str(received).map_err(|error| {
70            let error_message = format!("failed to parse string '{received}' as uuid");
71            ExpectOpError::custom_error(self, context, error_message, error)
72        })?;
73
74        if let Some(expected_version) = self.expected_version {
75            let received_version = uuid.get_version_num();
76            if received_version != (expected_version as usize) {
77                let error_message = format!(
78                    "expected uuid version '{expected_version}', received version '{received_version}', for uuid '{received}'"
79                );
80                return Err(ExpectOpError::custom(self, context, error_message));
81            }
82        }
83
84        if self.is_not_nil_flag && uuid.is_nil() {
85            let error_message =
86                format!("expected uuid to be not nil, but it is, received '{received}'");
87            return Err(ExpectOpError::custom(self, context, error_message));
88        }
89
90        Ok(())
91    }
92
93    fn debug_supported_types(&self) -> &'static [JsonType] {
94        &[JsonType::String]
95    }
96}
97
98#[cfg(test)]
99mod test_uuid {
100    use crate::expect;
101    use crate::expect_json_eq;
102    use pretty_assertions::assert_eq;
103    use serde_json::json;
104
105    #[test]
106    fn it_should_parse_a_simple_uuid() {
107        let left = json!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8");
108        let right = json!(expect::uuid());
109
110        let output = expect_json_eq(&left, &right);
111        assert!(output.is_ok(), "assertion error: {output:#?}");
112    }
113
114    #[test]
115    fn it_should_parse_a_hyphenated_uuid() {
116        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
117        let right = json!(expect::uuid());
118
119        let output = expect_json_eq(&left, &right);
120        assert!(output.is_ok(), "assertion error: {output:#?}");
121    }
122
123    #[test]
124    fn it_should_fail_to_parse_an_invalid_uuid() {
125        let left = json!("🦊");
126        let right = json!(expect::uuid());
127
128        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
129        assert_eq!(
130            output,
131            r#"Json expect::uuid() error at root:
132    failed to parse string '🦊' as uuid,
133    invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `🦊` at 1"#
134        );
135    }
136}
137
138#[cfg(test)]
139mod test_not_nil {
140    use crate::expect;
141    use crate::expect_json_eq;
142    use serde_json::json;
143
144    #[test]
145    fn it_should_return_true_for_a_non_nil_uuid() {
146        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
147        let right = json!(expect::uuid().not_nil());
148
149        let output = expect_json_eq(&left, &right);
150        assert!(output.is_ok(), "assertion error: {output:#?}");
151    }
152
153    #[test]
154    fn it_should_return_false_for_a_nil_uuid() {
155        let left = json!("00000000-0000-0000-0000-000000000000");
156        let right = json!(expect::uuid().not_nil());
157
158        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
159        assert_eq!(
160            output,
161            r#"Json expect::uuid() error at root:
162    expected uuid to be not nil, but it is, received '00000000-0000-0000-0000-000000000000'"#
163        );
164    }
165}
166
167#[cfg(test)]
168mod test_version {
169    use crate::expect;
170    use crate::expect_json_eq;
171    use pretty_assertions::assert_eq;
172    use serde_json::json;
173
174    #[test]
175    fn it_should_return_true_for_matching_version_1_uuid() {
176        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
177        let right = json!(expect::uuid().version(1));
178
179        let output = expect_json_eq(&left, &right);
180        assert!(output.is_ok(), "assertion error: {output:#?}");
181    }
182
183    #[test]
184    fn it_should_return_false_for_uuid_with_different_version() {
185        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
186        let right = json!(expect::uuid().version(2));
187
188        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
189        assert_eq!(
190            output,
191            r#"Json expect::uuid() error at root:
192    expected uuid version '2', received version '1', for uuid 'f3b4958c-52a1-11e7-802a-010203040506'"#
193        );
194    }
195}