expect_json/expect/ops/
expect_uuid.rs

1use crate::expect_core::expect_op;
2use crate::expect_core::Context;
3use crate::expect_core::ExpectOp;
4use crate::expect_core::ExpectOpError;
5use crate::expect_core::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///         "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!("expected uuid version '{expected_version}', received version '{received_version}', for uuid '{received}'");
78                return Err(ExpectOpError::custom(self, context, error_message));
79            }
80        }
81
82        if self.is_not_nil_flag && uuid.is_nil() {
83            let error_message =
84                format!("expected uuid to be not nil, but it is, received '{received}'");
85            return Err(ExpectOpError::custom(self, context, error_message));
86        }
87
88        Ok(())
89    }
90
91    fn debug_supported_types(&self) -> &'static [JsonType] {
92        &[JsonType::String]
93    }
94}
95
96#[cfg(test)]
97mod test_uuid {
98    use crate::expect;
99    use crate::expect_json_eq;
100    use pretty_assertions::assert_eq;
101    use serde_json::json;
102
103    #[test]
104    fn it_should_parse_a_simple_uuid() {
105        let left = json!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8");
106        let right = json!(expect::uuid());
107
108        let output = expect_json_eq(&left, &right);
109        assert!(output.is_ok(), "assertion error: {output:#?}");
110    }
111
112    #[test]
113    fn it_should_parse_a_hyphenated_uuid() {
114        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
115        let right = json!(expect::uuid());
116
117        let output = expect_json_eq(&left, &right);
118        assert!(output.is_ok(), "assertion error: {output:#?}");
119    }
120
121    #[test]
122    fn it_should_fail_to_parse_an_invalid_uuid() {
123        let left = json!("🦊");
124        let right = json!(expect::uuid());
125
126        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
127        assert_eq!(
128            output,
129            r#"Json expect::uuid() error at root:
130    failed to parse string '🦊' as uuid,
131    invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `🦊` at 1"#
132        );
133    }
134}
135
136#[cfg(test)]
137mod test_not_nil {
138    use crate::expect;
139    use crate::expect_json_eq;
140    use serde_json::json;
141
142    #[test]
143    fn it_should_return_true_for_a_non_nil_uuid() {
144        let left = json!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
145        let right = json!(expect::uuid().not_nil());
146
147        let output = expect_json_eq(&left, &right);
148        assert!(output.is_ok(), "assertion error: {output:#?}");
149    }
150
151    #[test]
152    fn it_should_return_false_for_a_nil_uuid() {
153        let left = json!("00000000-0000-0000-0000-000000000000");
154        let right = json!(expect::uuid().not_nil());
155
156        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
157        assert_eq!(
158            output,
159            r#"Json expect::uuid() error at root:
160    expected uuid to be not nil, but it is, received '00000000-0000-0000-0000-000000000000'"#
161        );
162    }
163}
164
165#[cfg(test)]
166mod test_version {
167    use crate::expect;
168    use crate::expect_json_eq;
169    use pretty_assertions::assert_eq;
170    use serde_json::json;
171
172    #[test]
173    fn it_should_return_true_for_matching_version_1_uuid() {
174        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
175        let right = json!(expect::uuid().version(1));
176
177        let output = expect_json_eq(&left, &right);
178        assert!(output.is_ok(), "assertion error: {output:#?}");
179    }
180
181    #[test]
182    fn it_should_return_false_for_uuid_with_different_version() {
183        let left = json!("f3b4958c-52a1-11e7-802a-010203040506");
184        let right = json!(expect::uuid().version(2));
185
186        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
187        assert_eq!(
188            output,
189            r#"Json expect::uuid() error at root:
190    expected uuid version '2', received version '1', for uuid 'f3b4958c-52a1-11e7-802a-010203040506'"#
191        );
192    }
193}