toon_format/decode/
validation.rs1use crate::types::{
2 ToonError,
3 ToonResult,
4};
5
6pub fn validate_array_length(expected: usize, actual: usize, strict: bool) -> ToonResult<()> {
8 if strict && expected != actual {
9 return Err(ToonError::length_mismatch(expected, actual));
10 }
11 Ok(())
12}
13
14pub fn validate_field_list(fields: &[String]) -> ToonResult<()> {
16 if fields.is_empty() {
17 return Err(ToonError::InvalidInput(
18 "Field list cannot be empty for tabular arrays".to_string(),
19 ));
20 }
21
22 for i in 0..fields.len() {
23 for j in (i + 1)..fields.len() {
24 if fields[i] == fields[j] {
25 return Err(ToonError::InvalidInput(format!(
26 "Duplicate field name: '{}'",
27 fields[i]
28 )));
29 }
30 }
31 }
32
33 for field in fields {
34 if field.is_empty() {
35 return Err(ToonError::InvalidInput(
36 "Field name cannot be empty".to_string(),
37 ));
38 }
39 }
40
41 Ok(())
42}
43
44pub fn validate_row_length(
46 row_index: usize,
47 expected_fields: usize,
48 actual_values: usize,
49) -> ToonResult<()> {
50 if expected_fields != actual_values {
51 return Err(ToonError::InvalidStructure(format!(
52 "Row {row_index} has {actual_values} values but expected {expected_fields} fields"
53 )));
54 }
55 Ok(())
56}
57
58pub fn validate_delimiter_consistency(
60 detected: Option<crate::types::Delimiter>,
61 expected: Option<crate::types::Delimiter>,
62) -> ToonResult<()> {
63 if let (Some(detected), Some(expected)) = (detected, expected) {
64 if detected != expected {
65 return Err(ToonError::InvalidDelimiter(format!(
66 "Detected delimiter {detected} but expected {expected}"
67 )));
68 }
69 }
70 Ok(())
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_validate_array_length() {
79 assert!(validate_array_length(5, 3, false).is_ok());
80 assert!(validate_array_length(3, 5, false).is_ok());
81
82 assert!(validate_array_length(5, 5, true).is_ok());
83 assert!(validate_array_length(5, 3, true).is_err());
84 assert!(validate_array_length(3, 5, true).is_err());
85 }
86
87 #[test]
88 fn test_validate_field_list() {
89 assert!(validate_field_list(&["id".to_string(), "name".to_string()]).is_ok());
90 assert!(validate_field_list(&["field1".to_string()]).is_ok());
91
92 assert!(validate_field_list(&[]).is_err());
93
94 assert!(
95 validate_field_list(&["id".to_string(), "name".to_string(), "id".to_string()]).is_err()
96 );
97
98 assert!(
99 validate_field_list(&["id".to_string(), "".to_string(), "name".to_string()]).is_err()
100 );
101 }
102
103 #[test]
104 fn test_validate_row_length() {
105 assert!(validate_row_length(0, 3, 3).is_ok());
106 assert!(validate_row_length(1, 5, 5).is_ok());
107
108 assert!(validate_row_length(0, 3, 2).is_err());
109 assert!(validate_row_length(1, 3, 4).is_err());
110 }
111
112 #[test]
113 fn test_validate_delimiter_consistency() {
114 use crate::types::Delimiter;
115
116 assert!(
117 validate_delimiter_consistency(Some(Delimiter::Comma), Some(Delimiter::Comma)).is_ok()
118 );
119
120 assert!(
121 validate_delimiter_consistency(Some(Delimiter::Comma), Some(Delimiter::Pipe)).is_err()
122 );
123
124 assert!(validate_delimiter_consistency(None, Some(Delimiter::Comma)).is_ok());
125 assert!(validate_delimiter_consistency(Some(Delimiter::Comma), None).is_ok());
126 assert!(validate_delimiter_consistency(None, None).is_ok());
127 }
128}