Skip to main content

apif_source_error/
lib.rs

1use std::fmt;
2
3#[derive(Debug)]
4pub enum SourceError {
5    FileOpenFailed(String, std::io::Error),
6    EmptyFile(String),
7    DuplicateColumn(String),
8    FieldCountMismatch {
9        row: usize,
10        fields: usize,
11        expected: usize,
12    },
13    InvalidJson(usize, String),
14    UnknownFormat(String),
15    SourceNotFound(String),
16    ColumnNotFound(String, String),
17}
18
19impl fmt::Display for SourceError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            SourceError::FileOpenFailed(path, err) => {
23                write!(f, "failed to open source file '{path}': {err}")
24            }
25            SourceError::EmptyFile(fmt) => {
26                write!(f, "header required but file is empty: {fmt}")
27            }
28            SourceError::DuplicateColumn(col) => {
29                write!(f, "duplicate column name '{col}' in header")
30            }
31            SourceError::FieldCountMismatch {
32                row,
33                fields,
34                expected,
35            } => {
36                write!(f, "row {row} has {fields} fields, expected {expected}")
37            }
38            SourceError::InvalidJson(line, msg) => {
39                write!(f, "invalid JSON on line {line}: {msg}")
40            }
41            SourceError::UnknownFormat(file) => {
42                write!(f, "unknown format for file: {file}")
43            }
44            SourceError::SourceNotFound(name) => {
45                write!(f, "source '{name}' not found")
46            }
47            SourceError::ColumnNotFound(col, source) => {
48                write!(f, "column '{col}' not found in source '{source}'")
49            }
50        }
51    }
52}
53
54impl std::error::Error for SourceError {}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_source_error_display() {
62        let err = SourceError::FileOpenFailed(
63            "test.csv".into(),
64            std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"),
65        );
66        assert!(err.to_string().contains("test.csv"));
67
68        let err = SourceError::EmptyFile("empty.csv".into());
69        assert!(err.to_string().contains("empty.csv"));
70
71        let err = SourceError::DuplicateColumn("id".into());
72        assert!(err.to_string().contains("id"));
73
74        let err = SourceError::FieldCountMismatch {
75            row: 5,
76            fields: 2,
77            expected: 3,
78        };
79        assert!(err.to_string().contains("5"));
80
81        let err = SourceError::InvalidJson(10, "bad json".into());
82        assert!(err.to_string().contains("bad json"));
83
84        let err = SourceError::UnknownFormat("file.bin".into());
85        assert!(err.to_string().contains("file.bin"));
86
87        let err = SourceError::SourceNotFound("users".into());
88        assert!(err.to_string().contains("users"));
89
90        let err = SourceError::ColumnNotFound("name".into(), "users".into());
91        assert!(err.to_string().contains("name"));
92    }
93
94    #[test]
95    fn test_source_error_debug() {
96        let err = SourceError::EmptyFile("test.csv".into());
97        let s = format!("{:?}", err);
98        assert!(!s.is_empty());
99    }
100}