Skip to main content

oxidite_testing/
response.rs

1use serde::de::DeserializeOwned;
2use http::StatusCode;
3use http_body_util::BodyExt;
4
5/// Test response wrapper
6pub struct TestResponse {
7    status: StatusCode,
8    body: Vec<u8>,
9}
10
11impl TestResponse {
12    /// Create a new test response
13    pub fn new(status: StatusCode, body: Vec<u8>) -> Self {
14        Self { status, body }
15    }
16
17    /// Get status code
18    pub fn status(&self) -> StatusCode {
19        self.status
20    }
21
22    /// Get body as bytes
23    pub fn body(&self) -> &[u8] {
24        &self.body
25    }
26
27    /// Get body as string
28    pub fn text(&self) -> Result<String, std::string::FromUtf8Error> {
29        String::from_utf8(self.body.clone())
30    }
31
32    /// Get body as a lossy UTF-8 string.
33    pub fn text_lossy(&self) -> String {
34        String::from_utf8_lossy(&self.body).to_string()
35    }
36
37    /// Deserialize JSON body
38    pub fn json<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
39        serde_json::from_slice(&self.body)
40    }
41
42    /// Check if response is successful (2xx)
43    pub fn is_success(&self) -> bool {
44        self.status.is_success()
45    }
46
47    /// Assert response status code.
48    pub fn assert_status(&self, expected: StatusCode) {
49        assert_eq!(
50            self.status, expected,
51            "expected status {}, got {}",
52            expected, self.status
53        );
54    }
55
56    /// Assert response status is successful (2xx).
57    pub fn assert_success(&self) {
58        assert!(
59            self.is_success(),
60            "expected successful status, got {}",
61            self.status
62        );
63    }
64
65    /// Convert from an Oxidite response for test assertions.
66    pub async fn from_oxidite_response(response: oxidite_core::OxiditeResponse) -> Self {
67        let response = response.into_inner();
68        let status = response.status();
69        let body = response.into_body();
70        let bytes = body
71            .collect()
72            .await
73            .expect("failed to collect response body")
74            .to_bytes();
75        Self::new(status, bytes.to_vec())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::TestResponse;
82    use http::StatusCode;
83
84    #[test]
85    fn text_lossy_handles_binary() {
86        let response = TestResponse::new(StatusCode::OK, vec![0xff, 0xfe, b'A']);
87        let text = response.text_lossy();
88        assert!(text.contains('A'));
89    }
90
91    #[tokio::test]
92    async fn from_oxidite_response_collects_body() {
93        let response = oxidite_core::OxiditeResponse::text("hello");
94        let test_response = TestResponse::from_oxidite_response(response).await;
95        assert_eq!(test_response.status(), StatusCode::OK);
96        assert_eq!(test_response.text().expect("text"), "hello");
97    }
98}