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