stubr 0.6.2

Wiremock implemented in Rust
Documentation
use std::str::FromStr;

use actix_http::body::MessageBody;
use actix_web::dev::ServiceResponse as ActixServiceResponse;
use http_types::{
    headers::HeaderName as HttpHeaderName, headers::HeaderValue as HttpHeaderValue, headers::HeaderValues as HttpHeaderValues, Response,
};

use super::super::mapping::resp::StdResponse;

impl From<ActixServiceResponse> for StdResponse {
    fn from(resp: ActixServiceResponse) -> Self {
        let status = resp.status();
        let mut std_resp = Response::new(status.as_u16());
        resp.headers()
            .into_iter()
            .filter_map(|(k, v)| {
                let k = HttpHeaderName::from_str(k.as_str()).ok();
                let v = v
                    .to_str()
                    .ok()
                    .map(|it| {
                        it.split(',')
                            .map(|s| s.trim())
                            .filter_map(|i| HttpHeaderValue::from_str(i).ok())
                    })
                    .map(HttpHeaderValues::from_iter);
                k.zip(v)
            })
            .for_each(|(k, v)| std_resp.append_header(k, &v));
        if let Ok(b) = resp.into_body().try_into_bytes() {
            std_resp.set_body(b.as_ref())
        }
        Self(std_resp)
    }
}

#[cfg(test)]
mod actix_resp_mapping_tests {
    use std::str::FromStr;

    use actix_web::HttpResponse as ActixResponse;
    use actix_web::{test::TestRequest, HttpRequest};

    use super::*;

    fn req() -> HttpRequest {
        TestRequest::get().to_http_request()
    }

    mod status {
        use super::*;

        #[test]
        fn should_map_status_success() {
            let resp = ActixResponse::Ok().finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.status(), 200);
        }

        #[test]
        fn should_map_status_error() {
            let resp = ActixResponse::BadRequest().finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.status(), 400);
        }
    }

    mod headers {
        use http_types::headers::{HeaderValue, HeaderValues};

        use super::*;

        #[test]
        fn should_map_single_header() {
            let resp = ActixResponse::Ok().insert_header(("a", "b")).finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.header("a").unwrap().get(0), HeaderValue::from_str("b").ok().as_ref());
        }

        #[test]
        fn should_map_many_header() {
            let resp = ActixResponse::Ok().insert_header(("a", "b")).insert_header(("c", "d")).finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.header("a").unwrap().get(0), HeaderValue::from_str("b").ok().as_ref());
            assert_eq!(std_resp.header("c").unwrap().get(0), HeaderValue::from_str("d").ok().as_ref());
        }

        #[test]
        fn should_not_fail_when_no_headers() {
            let resp = ActixResponse::Ok().finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.header_names().count(), 1);
        }

        #[test]
        fn should_map_multi_header() {
            let resp = ActixResponse::Ok().insert_header(("a", "b, c")).finish();
            let std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            let expected = HeaderValues::from_iter(vec!["b".try_into().unwrap(), "c".try_into().unwrap()]);
            assert!(std_resp.header("a").unwrap().iter().eq(expected.iter()));
        }
    }

    mod body {
        use serde_json::{json, Value};

        use super::*;

        #[async_std::test]
        async fn should_map_json_body() {
            let resp = ActixResponse::Ok().body(json!({"a": "b"}).to_string());
            let mut std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.body_json::<Value>().await.unwrap(), json!({"a": "b"}));
        }

        #[async_std::test]
        async fn should_map_text_body() {
            let resp = ActixResponse::Ok().body("hello");
            let mut std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert_eq!(std_resp.body_string().await.unwrap(), String::from("hello"));
        }

        #[async_std::test]
        async fn should_map_missing_body() {
            let resp = ActixResponse::Ok().finish();
            let mut std_resp = StdResponse::from(ActixServiceResponse::new(req(), resp)).0;
            assert!(std_resp.body_json::<Value>().await.ok().is_none());
        }
    }
}