stubr 0.6.2

Wiremock implemented in Rust
Documentation
use itertools::Itertools;
use serde_json::{Map, Value};

use crate::{model::response::headers::HttpRespHeadersStub, record::RecordInput};

impl From<RecordInput<'_>> for HttpRespHeadersStub {
    fn from((ex, cfg): RecordInput) -> Self {
        let resp = ex.resp();
        let headers = resp
            .header_names()
            .sorted_by(|a, b| Ord::cmp(a.as_str(), b.as_str()))
            .filter(|k| {
                !cfg.except_response_headers
                    .as_ref()
                    .map(|it| it.contains(&k.as_str()))
                    .unwrap_or_default()
            })
            .filter_map(|k| resp.header(k).map(|v| (k, v)))
            .map(|(k, v)| {
                let k = k.to_string();
                let v: Value = v.iter().map(|it| it.as_str()).join(", ").into();
                (k, v)
            })
            .collect::<Map<String, Value>>();
        if headers.is_empty() {
            Self { headers: None }
        } else {
            Self { headers: Some(headers) }
        }
    }
}

#[cfg(test)]
mod resp_header_mapping_tests {
    use http_types::Response;
    use serde_json::{json, Map};

    use crate::{
        record::{RecordedExchange, RecordedResponse},
        RecordConfig,
    };

    use super::*;

    #[test]
    fn should_map_single_header() {
        let mut resp = Response::new(200);
        resp.append_header("x-key", "value");
        let mut exchange = RecordedExchange {
            1: RecordedResponse(resp),
            ..Default::default()
        };
        let expected = Map::from_iter(vec![("x-key".to_string(), json!("value"))]);
        assert_eq!(
            HttpRespHeadersStub::from((&mut exchange, &RecordConfig::default())),
            HttpRespHeadersStub { headers: Some(expected) }
        )
    }

    #[test]
    fn should_map_many_headers() {
        let mut resp = Response::new(200);
        resp.append_header("x-a", "value-a");
        resp.append_header("x-b", "value-b");
        let mut exchange = RecordedExchange {
            1: RecordedResponse(resp),
            ..Default::default()
        };
        let expected = Map::from_iter(vec![
            ("x-a".to_string(), json!("value-a")),
            ("x-b".to_string(), json!("value-b")),
        ]);
        assert_eq!(
            HttpRespHeadersStub::from((&mut exchange, &RecordConfig::default())),
            HttpRespHeadersStub { headers: Some(expected) }
        )
    }

    #[test]
    fn should_not_fail_when_no_header() {
        let resp = Response::new(200);
        let mut exchange = RecordedExchange {
            1: RecordedResponse(resp),
            ..Default::default()
        };
        assert_eq!(
            HttpRespHeadersStub::from((&mut exchange, &RecordConfig::default())),
            HttpRespHeadersStub { headers: None }
        )
    }

    #[test]
    fn should_map_multi_header() {
        let mut resp = Response::new(200);
        resp.append_header("cache-control", "no-cache, no-transform");
        let mut exchange = RecordedExchange {
            1: RecordedResponse(resp),
            ..Default::default()
        };
        let expected = Map::from_iter(vec![("cache-control".to_string(), json!("no-cache, no-transform"))]);
        assert_eq!(
            HttpRespHeadersStub::from((&mut exchange, &RecordConfig::default())),
            HttpRespHeadersStub { headers: Some(expected) }
        )
    }

    #[test]
    fn should_ignore_excluded_headers() {
        let mut resp = Response::new(200);
        resp.append_header("x-a", "a");
        resp.append_header("x-b", "b");
        let mut exchange = RecordedExchange {
            1: RecordedResponse(resp),
            ..Default::default()
        };
        let expected = Map::from_iter(vec![("x-b".to_string(), json!("b"))]);
        let cfg = RecordConfig {
            except_response_headers: Some(vec!["x-a"]),
            ..Default::default()
        };
        assert_eq!(
            HttpRespHeadersStub::from((&mut exchange, &cfg)),
            HttpRespHeadersStub { headers: Some(expected) }
        )
    }
}