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 {
92 StructureDiagnosticKind::SkippedUnknownSegment
93 | StructureDiagnosticKind::OrphanedGroupSegment => "STR008",
94 _ => "STR003",
95 },
96 }
97 }
98
99 pub fn category(&self) -> ValidationCategory {
101 match self {
102 Self::MissingRequiredField { .. }
103 | Self::FieldConditionNotSatisfied { .. }
104 | Self::ConditionUnknown { .. }
105 | Self::PackageCardinality { .. } => ValidationCategory::Ahb,
106 Self::CodeNotAllowedForPid { .. } => ValidationCategory::Code,
107 Self::UntSegmentCountMismatch { .. }
108 | Self::UntCountNotVerifiable { .. }
109 | Self::StructureDiagnostic { .. } => ValidationCategory::Structure,
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use mig_assembly::StructureDiagnosticKind;
118
119 #[test]
120 fn code_matches_the_legacy_error_code_for_every_kind() {
121 let cases: Vec<(IssueKind, &str)> = vec![
122 (
123 IssueKind::MissingRequiredField {
124 field_name: "f".into(),
125 },
126 "AHB001",
127 ),
128 (
129 IssueKind::FieldConditionNotSatisfied {
130 field_name: "f".into(),
131 },
132 "AHB003",
133 ),
134 (
135 IssueKind::ConditionUnknown {
136 field_name: "f".into(),
137 unresolved: UnresolvedConditions::default(),
138 },
139 "AHB005",
140 ),
141 (
142 IssueKind::PackageCardinality {
143 package_id: "1P0..1".into(),
144 present: 2,
145 min: 0,
146 max: 1,
147 codes: vec![],
148 },
149 "AHB006",
150 ),
151 (
152 IssueKind::CodeNotAllowedForPid {
153 value: "X".into(),
154 allowed: vec![],
155 },
156 "COD002",
157 ),
158 (
159 IssueKind::UntSegmentCountMismatch {
160 declared: 30,
161 actual: 31,
162 },
163 "STR007",
164 ),
165 (IssueKind::UntCountNotVerifiable { unh_count: 2 }, "STR007"),
166 (
167 IssueKind::StructureDiagnostic {
168 kind: StructureDiagnosticKind::SkippedUnknownSegment,
169 segment_id: "CCI".into(),
170 position: 15,
171 detail: "irrelevant to the code".into(),
172 },
173 "STR008",
174 ),
175 (
176 IssueKind::StructureDiagnostic {
177 kind: StructureDiagnosticKind::UnexpectedSegment,
178 segment_id: "CCI".into(),
179 position: 15,
180 detail: "irrelevant to the code".into(),
181 },
182 "STR003",
183 ),
184 ];
185 for (kind, expected) in cases {
186 assert_eq!(kind.code(), expected, "wrong code for {kind:?}");
187 }
188 }
189
190 #[test]
191 fn category_is_derived_from_the_kind() {
192 assert_eq!(
193 IssueKind::MissingRequiredField {
194 field_name: "f".into()
195 }
196 .category(),
197 ValidationCategory::Ahb
198 );
199 assert_eq!(
200 IssueKind::CodeNotAllowedForPid {
201 value: "X".into(),
202 allowed: vec![]
203 }
204 .category(),
205 ValidationCategory::Code
206 );
207 assert_eq!(
208 IssueKind::UntSegmentCountMismatch {
209 declared: 1,
210 actual: 2
211 }
212 .category(),
213 ValidationCategory::Structure
214 );
215 }
216}