use super::*;
use crate::model::{Briefing, Product, ProductKind};
fn briefing(source: &str, products: Vec<Product>) -> Briefing {
Briefing::new(source).with_products(products)
}
fn product(kind: ProductKind, location: &str, raw_text: &str) -> Product {
Product::new(kind, raw_text).with_location(Some(location.to_owned()))
}
fn find<'a>(
report: &'a ComparisonReport,
location: &str,
kind: &ProductKind,
) -> &'a ProductComparison {
report
.comparisons
.iter()
.find(|c| c.key.location.as_deref() == Some(location) && &c.key.kind == kind)
.unwrap_or_else(|| panic!("no comparison for {location} {kind:?}"))
}
#[test]
fn matching_text_across_sources_is_agreement_even_with_keyword_and_equals() {
let awc = briefing(
"awc",
vec![product(
ProductKind::Metar,
"KIAD",
"KIAD 041952Z 28008KT 10SM FEW250 29/13 A3003",
)],
);
let leidos = briefing(
"leidos",
vec![product(
ProductKind::Metar,
"KIAD",
"METAR KIAD 041952Z 28008KT 10SM FEW250 29/13 A3003=",
)],
);
let report = compare(&[awc, leidos]);
let kiad = find(&report, "KIAD", &ProductKind::Metar);
assert_eq!(kiad.agreement, Agreement::Agree);
assert_eq!(kiad.values.len(), 2);
assert!(
kiad.values
.iter()
.any(|v| v.source == "awc" && !v.raw_text.starts_with("METAR"))
);
assert!(
kiad.values
.iter()
.any(|v| v.source == "leidos" && v.raw_text.ends_with('='))
);
}
#[test]
fn differing_text_is_a_disagreement_attributed_to_each_source() {
let awc = briefing(
"awc",
vec![product(
ProductKind::Taf,
"KIAD",
"KIAD 041730Z 0418/0524 27010KT P6SM SCT250",
)],
);
let leidos = briefing(
"leidos",
vec![product(
ProductKind::Taf,
"KIAD",
"TAF KIAD 041730Z 0418/0524 30015KT P6SM BKN040=",
)],
);
let report = compare(&[awc, leidos]);
let taf = find(&report, "KIAD", &ProductKind::Taf);
assert_eq!(taf.agreement, Agreement::Disagree);
let awc_value = taf
.values
.iter()
.find(|v| v.source == "awc")
.expect("awc value");
let leidos_value = taf
.values
.iter()
.find(|v| v.source == "leidos")
.expect("leidos value");
assert!(
awc_value.raw_text.contains("SCT250"),
"awc text is preserved"
);
assert!(
leidos_value.raw_text.contains("BKN040"),
"leidos text is preserved"
);
let rendered = report.to_string();
assert!(rendered.contains("DISAGREE"));
assert!(rendered.contains("awc: KIAD 041730Z"));
assert!(rendered.contains("leidos: TAF KIAD 041730Z"));
}
#[test]
fn product_in_only_one_source_is_attributed_to_it() {
let awc = briefing(
"awc",
vec![product(
ProductKind::Metar,
"KDCA",
"KDCA 041952Z 30010KT 10SM CLR 30/12 A3001",
)],
);
let leidos = briefing(
"leidos",
vec![product(
ProductKind::Metar,
"KJYO",
"METAR KJYO 041952Z 27005KT 10SM CLR 28/14 A3003=",
)],
);
let report = compare(&[awc, leidos]);
let kdca = find(&report, "KDCA", &ProductKind::Metar);
assert_eq!(kdca.agreement, Agreement::Single);
assert_eq!(kdca.values.len(), 1);
assert_eq!(kdca.values[0].source, "awc");
let kjyo = find(&report, "KJYO", &ProductKind::Metar);
assert_eq!(kjyo.agreement, Agreement::Single);
assert_eq!(kjyo.values[0].source, "leidos");
let rendered = report.to_string();
assert!(rendered.contains("KDCA Metar [only awc]"));
assert!(rendered.contains("KJYO Metar [only leidos]"));
}
#[test]
fn disagreements_helper_filters_to_conflicts_only() {
let awc = briefing(
"awc",
vec![
product(ProductKind::Metar, "KIAD", "KIAD 041952Z 28008KT A3003"),
product(ProductKind::Taf, "KIAD", "KIAD 041730Z 27010KT SCT250"),
],
);
let leidos = briefing(
"leidos",
vec![
product(
ProductKind::Metar,
"KIAD",
"METAR KIAD 041952Z 28008KT A3003=",
),
product(ProductKind::Taf, "KIAD", "TAF KIAD 041730Z 30015KT BKN040="),
],
);
let report = compare(&[awc, leidos]);
let conflicts: Vec<&ProductComparison> = report.disagreements().collect();
assert_eq!(conflicts.len(), 1);
assert_eq!(conflicts[0].key.kind, ProductKind::Taf);
}
#[test]
fn output_order_is_deterministic_by_location_then_kind() {
let a = briefing(
"awc",
vec![
product(ProductKind::Taf, "KSEA", "..."),
product(ProductKind::Metar, "KSEA", "..."),
product(ProductKind::Metar, "KBOS", "..."),
],
);
let report = compare(&[a]);
let order: Vec<(&str, &ProductKind)> = report
.comparisons
.iter()
.map(|c| (c.key.location.as_deref().unwrap_or(""), &c.key.kind))
.collect();
assert_eq!(
order,
vec![
("KBOS", &ProductKind::Metar),
("KSEA", &ProductKind::Metar),
("KSEA", &ProductKind::Taf),
]
);
}