Skip to main content

tess/
error.rs

1use std::fmt;
2use std::path::PathBuf;
3
4#[derive(Debug)]
5pub enum Error {
6    OpenFile { path: PathBuf, source: std::io::Error },
7    NotAFile { path: PathBuf },
8    NoInput,
9    Runtime(String),
10}
11
12impl Error {
13    pub fn exit_code(&self) -> i32 {
14        match self {
15            Error::OpenFile { .. } | Error::NotAFile { .. } | Error::NoInput => 1,
16            Error::Runtime(_) => 2,
17        }
18    }
19}
20
21impl fmt::Display for Error {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Error::OpenFile { path, source } => {
25                write!(f, "tess: {}: {}", path.display(), source)
26            }
27            Error::NotAFile { path } => {
28                write!(f, "tess: {}: not a regular file", path.display())
29            }
30            Error::NoInput => write!(f, "tess: no input (specify a file or pipe stdin)"),
31            Error::Runtime(msg) => write!(f, "tess: {}", msg),
32        }
33    }
34}
35
36impl std::error::Error for Error {}
37
38pub type Result<T> = std::result::Result<T, Error>;
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn display_wraps_io_error_with_context() {
46        let io = std::io::Error::new(std::io::ErrorKind::NotFound, "no such file");
47        let e = Error::OpenFile { path: "/nope".into(), source: io };
48        assert_eq!(format!("{}", e), "tess: /nope: no such file");
49    }
50
51    #[test]
52    fn exit_code_for_startup_is_one() {
53        let io = std::io::Error::new(std::io::ErrorKind::NotFound, "x");
54        let e = Error::OpenFile { path: "/nope".into(), source: io };
55        assert_eq!(e.exit_code(), 1);
56    }
57
58    #[test]
59    fn exit_code_for_runtime_is_two() {
60        let e = Error::Runtime("stdout closed".into());
61        assert_eq!(e.exit_code(), 2);
62    }
63}