charted_testkit/macros.rs
1// 📦🦋 charted TestKit: testing library for Axum services with testcontainers support
2// Copyright (c) 2024 Noelware, LLC. <team@noelware.org>
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in all
12// copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20// SOFTWARE.
21
22/// Checks whenever if a [`Response`][axum::http::response::Response] is successful
23/// or not.
24///
25/// ## Example
26/// ```rust
27/// # use axum::http::{response::Response, StatusCode};
28/// #
29/// let res = Response::builder().status(StatusCode::OK).body(()).expect("response to be avaliable");
30/// charted_testkit::assert_successful!(res);
31/// ```
32#[macro_export]
33macro_rules! assert_successful {
34 ($res:expr) => {
35 assert!(($res).status().is_success());
36 };
37}
38
39/// Checks whenever if a [`Response`][axum::http::response::Response] failed.
40///
41/// ## Example
42/// ```rust
43/// # use axum::http::{response::Response, StatusCode};
44/// #
45/// let res = Response::builder().status(StatusCode::NOT_FOUND).body(()).expect("response to be avaliable");
46/// charted_testkit::assert_failure!(res);
47/// ```
48#[macro_export]
49macro_rules! assert_failure {
50 ($res:expr) => {
51 assert!(!($res).status().is_success());
52 };
53}
54
55/// Macro to easily assert if a given [response][axum::http::response::Response]'s status code
56/// is the same as one you provide.
57///
58/// ## Example
59/// ```rust
60/// # use axum::http::{response::Response, StatusCode};
61/// #
62/// let res = Response::builder().status(StatusCode::OK).body(()).expect("response to be avaliable");
63/// charted_testkit::assert_status_code!(res, StatusCode::OK);
64/// ```
65#[macro_export]
66macro_rules! assert_status_code {
67 ($res:expr, $status:expr) => {
68 assert_eq!($status, ($res).status());
69 };
70}
71
72/// Macro to consume the full body of a [response][axum::http::response::Response] and returns
73/// a [`Bytes`][axum::body::Bytes] container.
74///
75/// ```rust
76/// # use axum::{http::response::Response, http::StatusCode, body::Bytes};
77/// #
78/// # #[tokio::main]
79/// # async fn main() {
80/// let res = Response::builder()
81/// .status(StatusCode::OK)
82/// .body(String::from("Hello, world!"))
83/// .expect("response to be constructed");
84///
85/// assert_eq!(charted_testkit::consume_body!(res), Bytes::from_static(b"Hello, world!"));
86/// # }
87/// ```
88#[macro_export]
89macro_rules! consume_body {
90 ($res:expr) => {{
91 use $crate::__private::BodyExt;
92
93 let collected = ($res).collect().await.expect("failed to consume full body");
94 collected.to_bytes()
95 }};
96}
97
98/// Assertion macro to indicate that a [`Response`][axum::http::response::Response] has the header it needs.
99///
100/// ## Example
101/// ```
102/// # use axum::http::{response::Response, StatusCode, header};
103/// #
104/// let res = Response::builder()
105/// .status(StatusCode::OK)
106/// .header("Accept", "application/json")
107/// .body(())
108/// .expect("response to be avaliable");
109///
110/// charted_testkit::assert_has_header!(res, header::ACCEPT);
111/// ```
112#[macro_export]
113macro_rules! assert_has_header {
114 ($res:expr, $header:ident) => {
115 $crate::assert_has_header!($res, $crate::__private::header::$header);
116 };
117
118 ($res:expr, $header:expr) => {
119 assert!($res.headers().get($header).is_some());
120 };
121}
122
123/// Assertion macro to indicate that a [`Response`][axum::http::response::Response] doesn't have the header it needs.
124///
125/// ## Example
126/// ```
127/// # use axum::http::{response::Response, StatusCode, header};
128/// #
129/// let res = Response::builder().status(StatusCode::OK).body(()).expect("response to be avaliable");
130/// charted_testkit::assert_doesnt_have_header!(res, header::ACCEPT);
131/// ```
132#[macro_export]
133macro_rules! assert_doesnt_have_header {
134 ($res:expr, $header:ident) => {
135 $crate::assert_has_header!($res, $crate::__private::header::$header);
136 };
137
138 ($res:expr, $header:expr) => {
139 assert!($res.headers().get($header).is_none());
140 };
141}