spatialrust_platform/
conformance.rs1use crate::{PlatformError, PlatformResult};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7pub enum ConformanceStatus {
8 Pass,
10 Fail,
12 Skip,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct ConformanceCase {
19 pub id: String,
21 pub status: ConformanceStatus,
23 pub detail: Option<String>,
25}
26
27#[derive(Clone, Debug, Default, PartialEq, Eq)]
29pub struct ConformanceReport {
30 cases: Vec<ConformanceCase>,
31}
32
33impl ConformanceReport {
34 #[must_use]
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 pub fn record(
42 &mut self,
43 id: impl Into<String>,
44 status: ConformanceStatus,
45 detail: Option<String>,
46 ) {
47 self.cases.push(ConformanceCase { id: id.into(), status, detail });
48 }
49
50 #[must_use]
52 pub fn cases(&self) -> &[ConformanceCase] {
53 &self.cases
54 }
55
56 #[must_use]
58 pub fn pass_count(&self) -> usize {
59 self.count(ConformanceStatus::Pass)
60 }
61
62 #[must_use]
64 pub fn fail_count(&self) -> usize {
65 self.count(ConformanceStatus::Fail)
66 }
67
68 #[must_use]
70 pub fn skip_count(&self) -> usize {
71 self.count(ConformanceStatus::Skip)
72 }
73
74 fn count(&self, status: ConformanceStatus) -> usize {
75 self.cases.iter().filter(|case| case.status == status).count()
76 }
77
78 #[must_use]
80 pub fn summary(&self) -> String {
81 format!("pass={} fail={} skip={}", self.pass_count(), self.fail_count(), self.skip_count())
82 }
83
84 pub fn assert_no_failures(&self) -> PlatformResult<()> {
86 if self.cases.iter().any(|case| case.status == ConformanceStatus::Fail) {
87 return Err(PlatformError::InvalidConfiguration(
88 "conformance report contains failures".into(),
89 ));
90 }
91 Ok(())
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::{ConformanceReport, ConformanceStatus};
98
99 #[test]
100 fn rejects_failures_and_summarizes() {
101 let mut report = ConformanceReport::new();
102 report.record("arrow-roundtrip", ConformanceStatus::Pass, None);
103 report.record("mcap-optional", ConformanceStatus::Skip, Some("feature off".into()));
104 assert!(report.assert_no_failures().is_ok());
105 assert_eq!(report.summary(), "pass=1 fail=0 skip=1");
106 report.record("bad", ConformanceStatus::Fail, None);
107 assert!(report.assert_no_failures().is_err());
108 assert_eq!(report.fail_count(), 1);
109 }
110}