automapper_validation/validator/
kind.rs1use mig_assembly::StructureDiagnosticKind;
7use serde::{Deserialize, Serialize};
8
9use super::issue::ValidationCategory;
10
11#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
15pub struct UnresolvedConditions {
16 pub external: Vec<u32>,
18 pub undetermined: Vec<u32>,
20 pub missing: Vec<u32>,
22}
23
24impl UnresolvedConditions {
25 pub fn is_empty(&self) -> bool {
27 self.external.is_empty() && self.undetermined.is_empty() && self.missing.is_empty()
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(tag = "type", rename_all = "camelCase")]
38pub enum IssueKind {
39 MissingRequiredField { field_name: String },
41 FieldConditionNotSatisfied { field_name: String },
43 ConditionUnknown {
45 field_name: String,
46 unresolved: UnresolvedConditions,
47 },
48 PackageCardinality {
50 package_id: String,
51 present: usize,
52 min: usize,
53 max: usize,
54 codes: Vec<String>,
55 },
56 CodeNotAllowedForPid { value: String, allowed: Vec<String> },
58 UntSegmentCountMismatch { declared: usize, actual: usize },
60 UntCountNotVerifiable { unh_count: usize },
62 StructureDiagnostic {
69 kind: StructureDiagnosticKind,
70 segment_id: String,
71 position: usize,
72 detail: String,
73 },
74}
75
76impl IssueKind {
77 pub fn code(&self) -> &'static str {
79 match self {
80 Self::MissingRequiredField { .. } => "AHB001",
81 Self::FieldConditionNotSatisfied { .. } => "AHB003",
82 Self::ConditionUnknown { .. } => "AHB005",
83 Self::PackageCardinality { .. } => "AHB006",
84 Self::CodeNotAllowedForPid { .. } => "COD002",
85 Self::UntSegmentCountMismatch { .. } | Self::UntCountNotVerifiable { .. } => "STR007",
86 Self::StructureDiagnostic { kind, .. } => match kind {
90 StructureDiagnosticKind::SkippedUnknownSegment => "STR008",
91 _ => "STR003",
92 },
93 }
94 }
95
96 pub fn category(&self) -> ValidationCategory {
98 match self {
99 Self::MissingRequiredField { .. }
100 | Self::FieldConditionNotSatisfied { .. }
101 | Self::ConditionUnknown { .. }
102 | Self::PackageCardinality { .. } => ValidationCategory::Ahb,
103 Self::CodeNotAllowedForPid { .. } => ValidationCategory::Code,
104 Self::UntSegmentCountMismatch { .. }
105 | Self::UntCountNotVerifiable { .. }
106 | Self::StructureDiagnostic { .. } => ValidationCategory::Structure,
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use mig_assembly::StructureDiagnosticKind;
115
116 #[test]
117 fn code_matches_the_legacy_error_code_for_every_kind() {
118 let cases: Vec<(IssueKind, &str)> = vec![
119 (
120 IssueKind::MissingRequiredField {
121 field_name: "f".into(),
122 },
123 "AHB001",
124 ),
125 (
126 IssueKind::FieldConditionNotSatisfied {
127 field_name: "f".into(),
128 },
129 "AHB003",
130 ),
131 (
132 IssueKind::ConditionUnknown {
133 field_name: "f".into(),
134 unresolved: UnresolvedConditions::default(),
135 },
136 "AHB005",
137 ),
138 (
139 IssueKind::PackageCardinality {
140 package_id: "1P0..1".into(),
141 present: 2,
142 min: 0,
143 max: 1,
144 codes: vec![],
145 },
146 "AHB006",
147 ),
148 (
149 IssueKind::CodeNotAllowedForPid {
150 value: "X".into(),
151 allowed: vec![],
152 },
153 "COD002",
154 ),
155 (
156 IssueKind::UntSegmentCountMismatch {
157 declared: 30,
158 actual: 31,
159 },
160 "STR007",
161 ),
162 (IssueKind::UntCountNotVerifiable { unh_count: 2 }, "STR007"),
163 (
164 IssueKind::StructureDiagnostic {
165 kind: StructureDiagnosticKind::SkippedUnknownSegment,
166 segment_id: "CCI".into(),
167 position: 15,
168 detail: "irrelevant to the code".into(),
169 },
170 "STR008",
171 ),
172 (
173 IssueKind::StructureDiagnostic {
174 kind: StructureDiagnosticKind::UnexpectedSegment,
175 segment_id: "CCI".into(),
176 position: 15,
177 detail: "irrelevant to the code".into(),
178 },
179 "STR003",
180 ),
181 ];
182 for (kind, expected) in cases {
183 assert_eq!(kind.code(), expected, "wrong code for {kind:?}");
184 }
185 }
186
187 #[test]
188 fn category_is_derived_from_the_kind() {
189 assert_eq!(
190 IssueKind::MissingRequiredField {
191 field_name: "f".into()
192 }
193 .category(),
194 ValidationCategory::Ahb
195 );
196 assert_eq!(
197 IssueKind::CodeNotAllowedForPid {
198 value: "X".into(),
199 allowed: vec![]
200 }
201 .category(),
202 ValidationCategory::Code
203 );
204 assert_eq!(
205 IssueKind::UntSegmentCountMismatch {
206 declared: 1,
207 actual: 2
208 }
209 .category(),
210 ValidationCategory::Structure
211 );
212 }
213}