1use crate::model::Claim;
11use crate::DeviceHistory;
12
13pub trait HistorySource {
15 fn claims(&self) -> Vec<Claim>;
17}
18
19#[must_use]
22pub fn correlate_sources(sources: &[&dyn HistorySource]) -> Vec<DeviceHistory> {
23 let all: Vec<Claim> = sources.iter().flat_map(|s| s.claims()).collect();
24 let reconciled = crate::reconcile_volume_serials(&all);
27 crate::correlate(&reconciled)
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use crate::model::{Attribute, DeviceKey, Provenance, SourceKind, Value};
34 use crate::Consistency;
35
36 struct Mock(Vec<Claim>);
37 impl HistorySource for Mock {
38 fn claims(&self) -> Vec<Claim> {
39 self.0.clone()
40 }
41 }
42
43 fn claim(src: SourceKind) -> Claim {
44 Claim {
45 device: DeviceKey("SN1".into()),
46 attribute: Attribute::FirstConnected,
47 value: Value::Timestamp(1_700_000_000),
48 provenance: Provenance {
49 source: src,
50 locator: "x".into(),
51 },
52 }
53 }
54
55 #[test]
56 fn correlate_sources_merges_claims_from_every_source() {
57 let a = Mock(vec![claim(SourceKind::Usbstor)]);
58 let b = Mock(vec![claim(SourceKind::SetupApi)]);
59 let sources: [&dyn HistorySource; 2] = [&a, &b];
60 let hist = correlate_sources(&sources);
61 assert_eq!(hist.len(), 1);
62 assert_eq!(hist[0].attributes[0].consistency, Consistency::Corroborated);
64 }
65}