1use std::fmt;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum TuiError {
12 EmptyDataset,
14 RowOutOfBounds {
16 requested: usize,
18 total: usize,
20 },
21 ColumnOutOfBounds {
23 requested: usize,
25 total: usize,
27 },
28 FormatError {
30 row: usize,
32 col: usize,
34 reason: String,
36 },
37 SchemaMismatch {
39 description: String,
41 },
42 UnsupportedType {
44 type_name: String,
46 },
47 RenderConstraint {
49 description: String,
51 },
52 InvalidScroll {
54 requested: usize,
56 max_valid: usize,
58 },
59}
60
61impl fmt::Display for TuiError {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 match self {
64 Self::EmptyDataset => write!(f, "Dataset is empty"),
65 Self::RowOutOfBounds { requested, total } => {
66 write!(f, "Row index {requested} out of bounds (total: {total})")
67 }
68 Self::ColumnOutOfBounds { requested, total } => {
69 write!(f, "Column index {requested} out of bounds (total: {total})")
70 }
71 Self::FormatError { row, col, reason } => {
72 write!(f, "Failed to format cell ({row}, {col}): {reason}")
73 }
74 Self::SchemaMismatch { description } => {
75 write!(f, "Schema mismatch: {description}")
76 }
77 Self::UnsupportedType { type_name } => {
78 write!(f, "Unsupported Arrow type: {type_name}")
79 }
80 Self::RenderConstraint { description } => {
81 write!(f, "Render constraint violation: {description}")
82 }
83 Self::InvalidScroll {
84 requested,
85 max_valid,
86 } => {
87 write!(f, "Invalid scroll position {requested} (max: {max_valid})")
88 }
89 }
90 }
91}
92
93impl std::error::Error for TuiError {}
94
95pub type TuiResult<T> = Result<T, TuiError>;
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn f_error_display_empty_dataset() {
104 let err = TuiError::EmptyDataset;
105 assert_eq!(err.to_string(), "Dataset is empty");
106 }
107
108 #[test]
109 fn f_error_display_row_out_of_bounds() {
110 let err = TuiError::RowOutOfBounds {
111 requested: 100,
112 total: 80,
113 };
114 assert!(err.to_string().contains("100"));
115 assert!(err.to_string().contains("80"));
116 }
117
118 #[test]
119 fn f_error_display_column_out_of_bounds() {
120 let err = TuiError::ColumnOutOfBounds {
121 requested: 15,
122 total: 11,
123 };
124 assert!(err.to_string().contains("15"));
125 assert!(err.to_string().contains("11"));
126 }
127
128 #[test]
129 fn f_error_display_format_error() {
130 let err = TuiError::FormatError {
131 row: 5,
132 col: 3,
133 reason: "null value".to_string(),
134 };
135 assert!(err.to_string().contains('5'));
136 assert!(err.to_string().contains('3'));
137 assert!(err.to_string().contains("null value"));
138 }
139
140 #[test]
141 fn f_error_is_clone() {
142 let err = TuiError::EmptyDataset;
143 let cloned = err.clone();
144 assert_eq!(err, cloned);
145 }
146
147 #[test]
148 fn f_error_is_debug() {
149 let err = TuiError::EmptyDataset;
150 let debug_str = format!("{:?}", err);
151 assert!(debug_str.contains("EmptyDataset"));
152 }
153
154 #[test]
155 fn f_error_implements_error_trait() {
156 let err: Box<dyn std::error::Error> = Box::new(TuiError::EmptyDataset);
157 assert!(err.to_string().contains("empty"));
158 }
159
160 #[test]
161 fn f_error_display_schema_mismatch() {
162 let err = TuiError::SchemaMismatch {
163 description: "column count differs".to_string(),
164 };
165 let s = err.to_string();
166 assert!(s.contains("Schema mismatch"));
167 assert!(s.contains("column count differs"));
168 }
169
170 #[test]
171 fn f_error_display_unsupported_type() {
172 let err = TuiError::UnsupportedType {
173 type_name: "FixedSizeBinary".to_string(),
174 };
175 let s = err.to_string();
176 assert!(s.contains("Unsupported Arrow type"));
177 assert!(s.contains("FixedSizeBinary"));
178 }
179
180 #[test]
181 fn f_error_display_render_constraint() {
182 let err = TuiError::RenderConstraint {
183 description: "width exceeds terminal".to_string(),
184 };
185 let s = err.to_string();
186 assert!(s.contains("Render constraint"));
187 assert!(s.contains("width exceeds terminal"));
188 }
189
190 #[test]
191 fn f_error_display_invalid_scroll() {
192 let err = TuiError::InvalidScroll {
193 requested: 100,
194 max_valid: 80,
195 };
196 let s = err.to_string();
197 assert!(s.contains("Invalid scroll position"));
198 assert!(s.contains("100"));
199 assert!(s.contains("80"));
200 }
201}