use mig_assembly::StructureDiagnosticKind;
use serde::{Deserialize, Serialize};
use super::issue::ValidationCategory;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnresolvedConditions {
pub external: Vec<u32>,
pub undetermined: Vec<u32>,
pub missing: Vec<u32>,
}
impl UnresolvedConditions {
pub fn is_empty(&self) -> bool {
self.external.is_empty() && self.undetermined.is_empty() && self.missing.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum IssueKind {
MissingRequiredField { field_name: String },
FieldConditionNotSatisfied { field_name: String },
ConditionUnknown {
field_name: String,
unresolved: UnresolvedConditions,
},
PackageCardinality {
package_id: String,
present: usize,
min: usize,
max: usize,
codes: Vec<String>,
},
CodeNotAllowedForPid { value: String, allowed: Vec<String> },
UntSegmentCountMismatch { declared: usize, actual: usize },
UntCountNotVerifiable { unh_count: usize },
StructureDiagnostic {
kind: StructureDiagnosticKind,
segment_id: String,
position: usize,
detail: String,
},
}
impl IssueKind {
pub fn code(&self) -> &'static str {
match self {
Self::MissingRequiredField { .. } => "AHB001",
Self::FieldConditionNotSatisfied { .. } => "AHB003",
Self::ConditionUnknown { .. } => "AHB005",
Self::PackageCardinality { .. } => "AHB006",
Self::CodeNotAllowedForPid { .. } => "COD002",
Self::UntSegmentCountMismatch { .. } | Self::UntCountNotVerifiable { .. } => "STR007",
Self::StructureDiagnostic { kind, .. } => match kind {
StructureDiagnosticKind::SkippedUnknownSegment
| StructureDiagnosticKind::OrphanedGroupSegment => "STR008",
_ => "STR003",
},
}
}
pub fn category(&self) -> ValidationCategory {
match self {
Self::MissingRequiredField { .. }
| Self::FieldConditionNotSatisfied { .. }
| Self::ConditionUnknown { .. }
| Self::PackageCardinality { .. } => ValidationCategory::Ahb,
Self::CodeNotAllowedForPid { .. } => ValidationCategory::Code,
Self::UntSegmentCountMismatch { .. }
| Self::UntCountNotVerifiable { .. }
| Self::StructureDiagnostic { .. } => ValidationCategory::Structure,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use mig_assembly::StructureDiagnosticKind;
#[test]
fn code_matches_the_legacy_error_code_for_every_kind() {
let cases: Vec<(IssueKind, &str)> = vec![
(
IssueKind::MissingRequiredField {
field_name: "f".into(),
},
"AHB001",
),
(
IssueKind::FieldConditionNotSatisfied {
field_name: "f".into(),
},
"AHB003",
),
(
IssueKind::ConditionUnknown {
field_name: "f".into(),
unresolved: UnresolvedConditions::default(),
},
"AHB005",
),
(
IssueKind::PackageCardinality {
package_id: "1P0..1".into(),
present: 2,
min: 0,
max: 1,
codes: vec![],
},
"AHB006",
),
(
IssueKind::CodeNotAllowedForPid {
value: "X".into(),
allowed: vec![],
},
"COD002",
),
(
IssueKind::UntSegmentCountMismatch {
declared: 30,
actual: 31,
},
"STR007",
),
(IssueKind::UntCountNotVerifiable { unh_count: 2 }, "STR007"),
(
IssueKind::StructureDiagnostic {
kind: StructureDiagnosticKind::SkippedUnknownSegment,
segment_id: "CCI".into(),
position: 15,
detail: "irrelevant to the code".into(),
},
"STR008",
),
(
IssueKind::StructureDiagnostic {
kind: StructureDiagnosticKind::UnexpectedSegment,
segment_id: "CCI".into(),
position: 15,
detail: "irrelevant to the code".into(),
},
"STR003",
),
];
for (kind, expected) in cases {
assert_eq!(kind.code(), expected, "wrong code for {kind:?}");
}
}
#[test]
fn category_is_derived_from_the_kind() {
assert_eq!(
IssueKind::MissingRequiredField {
field_name: "f".into()
}
.category(),
ValidationCategory::Ahb
);
assert_eq!(
IssueKind::CodeNotAllowedForPid {
value: "X".into(),
allowed: vec![]
}
.category(),
ValidationCategory::Code
);
assert_eq!(
IssueKind::UntSegmentCountMismatch {
declared: 1,
actual: 2
}
.category(),
ValidationCategory::Structure
);
}
}