Skip to main content

trillium_testing/
assertions.rs

1/// assert that the status code of a conn is as specified.
2///
3/// ```
4/// use trillium_testing::prelude::*;
5/// async fn handler(conn: trillium::Conn) -> trillium::Conn {
6///     conn.with_status(418)
7/// }
8///
9/// assert_status!(get("/").on(&handler), 418);
10/// assert_status!(get("/").on(&handler), Status::ImATeapot);
11///
12/// let conn = get("/").on(&handler);
13/// assert_status!(&conn, 418);
14/// assert_status!(conn, 418);
15/// ```
16///
17///
18/// ```rust,should_panic
19/// use trillium_testing::prelude::*;
20/// async fn handler(conn: trillium::Conn) -> trillium::Conn {
21///     conn.ok("handled")
22/// }
23///
24/// assert_status!(get("/").on(&handler), 418);
25/// ```
26#[macro_export]
27macro_rules! assert_status {
28    ($conn:expr_2021, $status:expr_2021) => {{
29        use std::convert::TryInto;
30        let expected_status: $crate::prelude::Status =
31            $status.try_into().expect("expected a status code");
32
33        match $conn.status() {
34            Some(status) => assert_eq!(status, expected_status),
35            None => panic!("expected status code, but none was set"),
36        }
37    }};
38}
39
40/// assert that all of the following are true:
41/// the status was not set
42/// the body was not set
43/// the conn was not halted
44///
45/// ```
46/// use trillium_testing::prelude::*;
47/// async fn handler(conn: trillium::Conn) -> trillium::Conn {
48///     conn
49/// }
50///
51/// assert_not_handled!(get("/").on(&handler));
52///
53/// let conn = get("/").on(&handler);
54/// assert_not_handled!(&conn);
55/// assert_not_handled!(conn);
56/// ```
57///
58///
59/// ```rust,should_panic
60/// use trillium_testing::prelude::*;
61/// async fn handler(conn: trillium::Conn) -> trillium::Conn {
62///     conn.ok("handled")
63/// }
64///
65/// assert_not_handled!(get("/").on(&handler));
66/// ```
67#[macro_export]
68macro_rules! assert_not_handled {
69    ($conn:expr_2021) => {{
70        let conn = $conn;
71        assert_eq!(conn.status(), None);
72        assert!(conn.response_body().is_none());
73        assert!(!conn.is_halted());
74    }};
75}
76
77/// assert that the response body is as specified. this assertion requires mutation of the conn.
78///
79/// ```
80/// use trillium_testing::prelude::*;
81/// async fn handler(conn: trillium::Conn) -> trillium::Conn {
82///     conn.ok("it's-a-me, trillium")
83/// }
84///
85/// assert_body!(get("/").on(&handler), "it's-a-me, trillium");
86///
87/// let mut conn = get("/").on(&handler);
88/// assert_body!(&mut conn, "it's-a-me, trillium");
89///
90/// let mut conn = get("/").on(&handler);
91/// assert_body!(conn, "it's-a-me, trillium");
92/// ```
93///
94///
95/// ```rust,should_panic
96/// use trillium_testing::prelude::*;
97/// assert_body!(get("/").on(&()), "what body?");
98/// ```
99///
100/// ```rust,should_panic
101/// use trillium_testing::prelude::*;
102/// assert_body!(get("/").on(&"beach body"), "winter body");
103/// ```
104#[macro_export]
105macro_rules! assert_body {
106    ($conn:expr_2021, $body:expr_2021) => {
107        match $conn.take_response_body_string().unwrap_or_default() {
108            body => {
109                assert_eq!(body.trim_end(), $body.trim_end());
110            }
111        }
112    };
113}
114
115/// asserts that the response body matches the specified pattern, using [`str::contains`]
116/// ```
117/// use trillium_testing::prelude::*;
118/// let handler = "there's a needle in this haystack";
119/// assert_body_contains!(get("/").on(&handler), "needle");
120///
121/// let mut conn = get("/").on(&handler);
122/// let body = assert_body_contains!(&mut conn, "needle");
123/// assert!(body.contains("haystack"));
124/// ```
125///
126///
127/// ```rust,should_panic
128/// use trillium_testing::prelude::*;
129/// assert_body_contains!(get("/").on(&()), "what body?");
130/// ```
131///
132/// ```rust,should_panic
133/// use trillium_testing::prelude::*;
134/// assert_body_contains!(get("/").on(&"just a haystack"), "needle");
135/// ```
136#[macro_export]
137macro_rules! assert_body_contains {
138    ($conn:expr_2021, $pattern:expr_2021) => {
139        match $conn.take_response_body_string().unwrap_or_default() {
140            body => {
141                assert!(
142                    body.contains($pattern),
143                    "\nexpected \n`{}`\n to contain `{}`\n but it did not",
144                    &body,
145                    $pattern
146                );
147
148                body
149            }
150        }
151    };
152}
153
154/// combines several other assertions. this assertion can be used to assert:
155/// just a status code,
156/// a status code and a response body, or
157/// a status code, a response body, and any number of headers
158///
159/// ```
160/// use trillium_testing::prelude::*;
161/// async fn handler(conn: Conn) -> Conn {
162/// conn.with_body("just tea stuff here")
163/// .with_status(418)
164/// .with_response_header("server", "zojirushi")
165/// }
166///
167/// assert_response!(get("/").on(&handler), 418);
168/// assert_response!(get("/").on(&handler), Status::ImATeapot);
169/// assert_response!(get("/").on(&handler), 418, "just tea stuff here");
170/// assert_response!(get("/").on(&handler), Status::ImATeapot, "just tea stuff here");
171///
172/// assert_response!(
173/// get("/").on(&handler),
174/// Status::ImATeapot,
175/// "just tea stuff here",
176/// "server" => "zojirushi",
177/// "content-length" => "19"
178/// );
179/// ```
180#[macro_export]
181macro_rules! assert_response {
182    ($conn:expr_2021, $status:expr_2021, $body:expr_2021) => {{
183        let mut conn = $conn;
184        $crate::assert_status!(conn, $status);
185        $crate::assert_body!(conn, $body);
186    }};
187
188    ($conn:expr_2021, $status:expr_2021) => {
189        $crate::assert_status!($conn, $status);
190    };
191
192    ($conn:expr_2021, $status:expr_2021, $body:expr_2021, $($header_name:literal => $header_value:expr_2021,)+) => {
193        assert_response!($conn, $status, $body, $($header_name => $header_value),+);
194    };
195
196    ($conn:expr_2021, $status:expr_2021, $body:expr_2021, $($header_name:literal => $header_value:expr_2021),*) => {
197        let mut conn = $conn;
198        $crate::assert_response!(&mut conn, $status, $body);
199        $crate::assert_headers!(&conn, $($header_name => $header_value),*);
200    };
201
202}
203
204/// asserts any number of response headers
205///
206/// ```
207/// use trillium_testing::prelude::*;
208/// async fn handler(conn: Conn) -> Conn {
209/// conn.ok("headers")
210/// .with_response_header("server", "special-custom-server")
211/// .with_response_header("request-id", "10")
212/// }
213///
214/// assert_headers!(get("/").on(&handler), "server" => "special-custom-server");
215/// assert_headers!(
216/// get("/").on(&handler),
217/// "server" => "special-custom-server",
218/// "request-id" => "10",
219/// "content-length" => "7"
220/// );
221/// ```
222#[macro_export]
223macro_rules! assert_headers {
224    (@pair, $conn:expr_2021, $header_name:tt, None) => {
225        match $conn.response_headers().get_str($header_name) {
226            actual => {
227                assert_eq!(actual, None, concat!("for header ", stringify!($header_name)));
228            }
229        };
230    };
231
232    (@pair, $conn:expr_2021, $header_name:tt, $header_value:expr_2021) => {
233        match ($conn.response_headers().get_str($header_name), $header_value) {
234            (actual, expected) => {
235                assert_eq!(actual, Some(expected), concat!("for header ", stringify!($header_name)));
236            }
237        };
238    };
239
240    ($conn:expr_2021, $($header_name:tt => $header_value:tt,)+) => {
241        assert_headers!($conn, $($header_name => $header_value),+);
242    };
243
244    ($conn:expr_2021, $($header_name:tt => $header_value:tt),*) => {
245        match $conn {
246            conn => {
247                $(assert_headers!(@pair, conn, $header_name, $header_value);)*
248            }
249        };
250    }
251}
252
253/// assert_ok is like [`assert_response!`] except it always asserts a status of 200 Ok.
254///
255/// it can be used to assert:
256/// just that the response was successful,
257/// that the response was successful and a response body, or
258/// that the response was successful, a response body, and any number of headers
259///
260/// ```
261/// use trillium_testing::prelude::*;
262/// async fn handler(conn: Conn) -> Conn {
263/// conn.ok("body")
264/// .with_response_header("server", "special-custom-server")
265/// .with_response_header("request-id", "10")
266/// }
267///
268/// assert_ok!(get("/").on(&handler));
269/// assert_ok!(get("/").on(&handler), "body");
270/// assert_ok!(get("/").on(&handler), "body");
271/// assert_ok!(get("/").on(&handler), "body", "server" => "special-custom-server");
272///
273/// assert_ok!(
274/// get("/").on(&handler),
275/// "body",
276/// "server" => "special-custom-server",
277/// "request-id" => "10",
278/// "content-length" => "4"
279/// );
280/// ```
281#[macro_export]
282macro_rules! assert_ok {
283    ($conn:expr_2021) => {
284        $crate::assert_response!($conn, 200);
285    };
286
287    ($conn:expr_2021, $body:expr_2021) => {
288        $crate::assert_response!($conn, 200, $body);
289    };
290
291
292    ($conn:expr_2021, $body:expr_2021, $($header_name:literal => $header_value:expr_2021,)+) => {
293        assert_ok!($conn, $body, $($header_name => $header_value),+);
294    };
295
296    ($conn:expr_2021, $body:expr_2021, $($header_name:literal => $header_value:expr_2021),*) => {
297        $crate::assert_response!($conn, 200, $body, $($header_name => $header_value),*);
298    };
299}