Skip to main content

bo4e_core/com/
validation_result.rs

1//! Validation result (Validierungsergebnis) component.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// Result of a validation check on measured data.
9///
10/// German: Validierungsergebnis
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::ValidationResult;
16/// use chrono::Utc;
17///
18/// let result = ValidationResult {
19///     validation_timestamp: Some(Utc::now()),
20///     is_valid: Some(true),
21///     ..Default::default()
22/// };
23/// ```
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
26#[cfg_attr(feature = "json-schema", schemars(rename = "Validierungsergebnis"))]
27#[serde(rename_all = "camelCase")]
28pub struct ValidationResult {
29    /// BO4E metadata
30    #[serde(flatten)]
31    pub meta: Bo4eMeta,
32
33    /// Timestamp of validation (Validierungszeitpunkt)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    #[cfg_attr(feature = "json-schema", schemars(rename = "validierungszeitpunkt"))]
36    pub validation_timestamp: Option<DateTime<Utc>>,
37
38    /// Whether validation passed (Gültig)
39    #[serde(skip_serializing_if = "Option::is_none")]
40    #[cfg_attr(feature = "json-schema", schemars(rename = "gueltig"))]
41    pub is_valid: Option<bool>,
42
43    /// Validation rule ID (Validierungsregel)
44    #[serde(skip_serializing_if = "Option::is_none")]
45    #[cfg_attr(feature = "json-schema", schemars(rename = "validierungsregel"))]
46    pub validation_rule_id: Option<String>,
47
48    /// Validation rule name (Regelbezeichnung)
49    #[serde(skip_serializing_if = "Option::is_none")]
50    #[cfg_attr(feature = "json-schema", schemars(rename = "regelbezeichnung"))]
51    pub validation_rule_name: Option<String>,
52
53    /// Error code if validation failed (Fehlercode)
54    #[serde(skip_serializing_if = "Option::is_none")]
55    #[cfg_attr(feature = "json-schema", schemars(rename = "fehlercode"))]
56    pub error_code: Option<String>,
57
58    /// Error message (Fehlermeldung)
59    #[serde(skip_serializing_if = "Option::is_none")]
60    #[cfg_attr(feature = "json-schema", schemars(rename = "fehlermeldung"))]
61    pub error_message: Option<String>,
62
63    /// Severity level (Schweregrad)
64    #[serde(skip_serializing_if = "Option::is_none")]
65    #[cfg_attr(feature = "json-schema", schemars(rename = "schweregrad"))]
66    pub severity: Option<String>,
67}
68
69impl Bo4eObject for ValidationResult {
70    fn type_name_german() -> &'static str {
71        "Validierungsergebnis"
72    }
73
74    fn type_name_english() -> &'static str {
75        "ValidationResult"
76    }
77
78    fn meta(&self) -> &Bo4eMeta {
79        &self.meta
80    }
81
82    fn meta_mut(&mut self) -> &mut Bo4eMeta {
83        &mut self.meta
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use chrono::TimeZone;
91
92    #[test]
93    fn test_validation_passed() {
94        let result = ValidationResult {
95            validation_timestamp: Some(Utc.with_ymd_and_hms(2024, 1, 15, 12, 0, 0).unwrap()),
96            is_valid: Some(true),
97            validation_rule_id: Some("RULE_001".to_string()),
98            ..Default::default()
99        };
100
101        let json = serde_json::to_string(&result).unwrap();
102        assert!(json.contains("true"));
103        assert!(json.contains("RULE_001"));
104    }
105
106    #[test]
107    fn test_validation_failed() {
108        let result = ValidationResult {
109            validation_timestamp: Some(Utc::now()),
110            is_valid: Some(false),
111            error_code: Some("E001".to_string()),
112            error_message: Some("Value out of range".to_string()),
113            severity: Some("ERROR".to_string()),
114            ..Default::default()
115        };
116
117        let json = serde_json::to_string(&result).unwrap();
118        assert!(json.contains("false"));
119        assert!(json.contains("E001"));
120    }
121
122    #[test]
123    fn test_roundtrip() {
124        let result = ValidationResult {
125            is_valid: Some(true),
126            validation_rule_name: Some("Range check".to_string()),
127            ..Default::default()
128        };
129
130        let json = serde_json::to_string(&result).unwrap();
131        let parsed: ValidationResult = serde_json::from_str(&json).unwrap();
132        assert_eq!(result, parsed);
133    }
134
135    #[test]
136    fn test_bo4e_object_impl() {
137        assert_eq!(ValidationResult::type_name_german(), "Validierungsergebnis");
138        assert_eq!(ValidationResult::type_name_english(), "ValidationResult");
139    }
140}