Skip to main content

sel/
error.rs

1//! Error types for `sel`.
2
3use std::io;
4use std::path::PathBuf;
5use thiserror::Error;
6
7/// Main error type for the `sel` utility.
8#[derive(Error, Debug)]
9pub enum SelError {
10    /// Invalid selector syntax.
11    #[error("invalid selector: {0}")]
12    InvalidSelector(String),
13
14    /// Invalid regular expression.
15    #[error("invalid regex: {0}")]
16    InvalidRegex(String),
17
18    /// Positional selectors used with stdin (unseekable).
19    #[error("positional selectors require a seekable file; stdin is line-only")]
20    PositionalWithStdin,
21
22    /// `--invert-match` used without `--regex`.
23    #[error("--invert-match requires --regex")]
24    InvertWithoutRegex,
25
26    /// `--char-context` used without a target.
27    #[error("--char-context requires --regex or a positional selector")]
28    CharContextWithoutTarget,
29
30    /// I/O error with the offending path.
31    #[error("{path}: {source}")]
32    Io {
33        path: String,
34        #[source]
35        source: io::Error,
36    },
37
38    /// Output file already exists and `--force` was not given.
39    #[error("output file already exists: {} (use --force to overwrite)", .0.display())]
40    OutputExists(PathBuf),
41}
42
43/// Result type alias for `sel`.
44pub type Result<T> = std::result::Result<T, SelError>;
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use std::io;
50    use std::path::PathBuf;
51
52    #[test]
53    fn io_error_includes_path() {
54        let err = SelError::Io {
55            path: "nope.txt".into(),
56            source: io::Error::new(io::ErrorKind::NotFound, "no such"),
57        };
58        let msg = format!("{err}");
59        assert!(msg.contains("nope.txt"), "got: {msg}");
60    }
61
62    #[test]
63    fn positional_with_stdin_has_clear_message() {
64        let err = SelError::PositionalWithStdin;
65        let msg = format!("{err}");
66        assert!(msg.contains("stdin"));
67    }
68
69    #[test]
70    fn output_exists_names_path() {
71        let err = SelError::OutputExists(PathBuf::from("out.txt"));
72        let msg = format!("{err}");
73        assert!(msg.contains("out.txt"));
74        assert!(msg.contains("--force"));
75    }
76}