use std::collections::BTreeSet;
use http::HeaderMap;
use parlov_core::DiffedHeader;
pub(super) fn diff_headers(baseline: &HeaderMap, probe: &HeaderMap) -> Vec<DiffedHeader> {
let names: BTreeSet<&str> = baseline
.keys()
.chain(probe.keys())
.map(http::HeaderName::as_str)
.collect();
names
.into_iter()
.filter_map(|name| {
let b_val = header_str(baseline, name);
let p_val = header_str(probe, name);
if b_val == p_val {
return None;
}
Some(DiffedHeader {
name: name.to_owned(),
baseline: b_val,
probe: p_val,
})
})
.collect()
}
fn header_str(map: &HeaderMap, name: &str) -> Option<String> {
map.get(name)
.and_then(|v| v.to_str().ok())
.map(str::to_owned)
}
#[cfg(test)]
mod tests {
use super::*;
use http::{HeaderMap, HeaderName, HeaderValue};
fn map_with(name: &str, value: &str) -> HeaderMap {
let mut m = HeaderMap::new();
m.insert(
HeaderName::from_bytes(name.as_bytes()).unwrap(),
HeaderValue::from_str(value).unwrap(),
);
m
}
#[test]
fn identical_headers_produce_no_diffs() {
let a = map_with("x-foo", "bar");
let b = map_with("x-foo", "bar");
assert!(diff_headers(&a, &b).is_empty());
}
#[test]
fn differing_value_produces_one_entry() {
let a = map_with("x-foo", "one");
let b = map_with("x-foo", "two");
let diffs = diff_headers(&a, &b);
assert_eq!(diffs.len(), 1);
assert_eq!(diffs[0].name, "x-foo");
assert_eq!(diffs[0].baseline, Some("one".to_owned()));
assert_eq!(diffs[0].probe, Some("two".to_owned()));
}
#[test]
fn header_absent_on_probe_side() {
let a = map_with("x-only-baseline", "hello");
let b = HeaderMap::new();
let diffs = diff_headers(&a, &b);
assert_eq!(diffs.len(), 1);
assert_eq!(diffs[0].baseline, Some("hello".to_owned()));
assert_eq!(diffs[0].probe, None);
}
#[test]
fn header_absent_on_baseline_side() {
let a = HeaderMap::new();
let b = map_with("x-only-probe", "world");
let diffs = diff_headers(&a, &b);
assert_eq!(diffs.len(), 1);
assert_eq!(diffs[0].baseline, None);
assert_eq!(diffs[0].probe, Some("world".to_owned()));
}
#[test]
fn both_empty_maps_produce_no_diffs() {
assert!(diff_headers(&HeaderMap::new(), &HeaderMap::new()).is_empty());
}
}