version_manager/
lib.rs

1pub mod cli;
2pub mod files;
3pub mod version;
4
5use clap::{
6    error::{Error, ErrorKind},
7    Command,
8};
9use core::fmt::Display;
10
11pub trait CommandRun {
12    fn run(&self, version: &mut version::VersionFile) -> VersionResult<()>;
13}
14
15#[derive(Debug)]
16pub enum VersionError {
17    IoError(std::io::Error),
18    TomlDeError(toml::de::Error),
19    TomlSerError(toml::ser::Error),
20    RegexError(regex::Error),
21    IncompleteCommand,
22    InvalidOperation,
23    NoCommand,
24    NoValue,
25    NoNegatives,
26}
27
28pub type VersionResult<T> = Result<T, VersionError>;
29
30impl Display for VersionError {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{}", self.to_string())
33    }
34}
35
36impl VersionError {
37    pub fn to_string(&self) -> String {
38        match self {
39            VersionError::IoError(e) => format!("IO Error: {}", e),
40            VersionError::TomlDeError(e) => format!("TOML Deserialize Error: {}", e),
41            VersionError::TomlSerError(e) => format!("TOML Serialize Error: {}", e),
42            VersionError::RegexError(e) => format!("Regex Error: {}", e),
43            VersionError::IncompleteCommand => "Please specify a subcommand".to_string(),
44            VersionError::InvalidOperation => "Invalid operation".to_string(),
45            VersionError::NoCommand => "Unable to parse the command".to_string(),
46            VersionError::NoValue => "No value given".to_string(),
47            VersionError::NoNegatives => "Negative values are not allowed".to_string(),
48        }
49    }
50
51    pub fn error(&self, cmd: &mut Command) -> Error {
52        cmd.error(Into::<ErrorKind>::into(self), self.to_string())
53    }
54
55    pub fn terminate(&self, cmd: &mut Command) -> ! {
56        let err = self.error(cmd);
57        err.exit()
58    }
59}
60
61impl Into<ErrorKind> for &VersionError {
62    fn into(self) -> ErrorKind {
63        match self {
64            VersionError::IoError(_) => ErrorKind::Io,
65            VersionError::TomlDeError(_) => ErrorKind::Io,
66            VersionError::TomlSerError(_) => ErrorKind::Io,
67            VersionError::RegexError(_) => ErrorKind::ValueValidation,
68            VersionError::IncompleteCommand => ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
69            VersionError::InvalidOperation => ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
70            VersionError::NoCommand => ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
71            VersionError::NoValue => ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
72            VersionError::NoNegatives => ErrorKind::InvalidValue,
73        }
74    }
75}
76
77#[cfg(test)]
78mod test {
79
80    use super::*;
81    use clap::CommandFactory;
82    #[test]
83    fn no_cmd() {
84        let error = VersionError::NoCommand;
85        let displ = error.to_string();
86        assert!(displ.len() > 0);
87        let cmd = cli::Cli::command();
88        let err = error.error(&mut cmd.clone());
89        let render = format!("{}", err.render());
90        assert!(render.len() > 0);
91        assert_eq!(
92            Into::<ErrorKind>::into(&error),
93            ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
94        );
95    }
96    #[test]
97    fn io_error() {
98        let error =
99            VersionError::IoError(std::io::Error::new(std::io::ErrorKind::NotFound, "test"));
100        let displ = error.to_string();
101        assert!(displ.len() > 0);
102        let cmd = cli::Cli::command();
103        let err = error.error(&mut cmd.clone());
104        let render = format!("{}", err.render());
105        assert!(render.len() > 0);
106        assert_eq!(Into::<ErrorKind>::into(&error), ErrorKind::Io);
107    }
108    #[test]
109    fn regex_error() {
110        let error = VersionError::RegexError(regex::Error::Syntax("test".to_string()));
111        let displ = error.to_string();
112        assert!(displ.len() > 0);
113        let cmd = cli::Cli::command();
114        let err = error.error(&mut cmd.clone());
115        let render = format!("{}", err.render());
116        assert!(render.len() > 0);
117        assert_eq!(Into::<ErrorKind>::into(&error), ErrorKind::ValueValidation);
118    }
119    #[test]
120    fn toml_de_error() {
121        use serde::de::Error;
122        let error = VersionError::TomlDeError(toml::de::Error::missing_field("test"));
123        let displ = error.to_string();
124        assert!(displ.len() > 0);
125        let cmd = cli::Cli::command();
126        let err = error.error(&mut cmd.clone());
127        let render = format!("{}", err.render());
128        assert!(render.len() > 0);
129        assert_eq!(Into::<ErrorKind>::into(&error), ErrorKind::Io);
130    }
131    #[test]
132    fn toml_ser_error() {
133        use serde::ser::Error;
134        let error = VersionError::TomlSerError(toml::ser::Error::custom("test"));
135        let displ = error.to_string();
136        assert!(displ.len() > 0);
137        let cmd = cli::Cli::command();
138        let err = error.error(&mut cmd.clone());
139        let render = format!("{}", err.render());
140        assert!(render.len() > 0);
141        assert_eq!(Into::<ErrorKind>::into(&error), ErrorKind::Io);
142    }
143    #[test]
144    fn incomplete_command_error() {
145        let error = VersionError::IncompleteCommand;
146        let displ = error.to_string();
147        assert!(displ.len() > 0);
148        let cmd = cli::Cli::command();
149        let err = error.error(&mut cmd.clone());
150        let render = format!("{}", err.render());
151        assert!(render.len() > 0);
152        assert_eq!(
153            Into::<ErrorKind>::into(&error),
154            ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
155        );
156    }
157    #[test]
158    fn invalid_operation_error() {
159        let error = VersionError::InvalidOperation;
160        let displ = error.to_string();
161        assert!(displ.len() > 0);
162        let cmd = cli::Cli::command();
163        let err = error.error(&mut cmd.clone());
164        let render = format!("{}", err.render());
165        assert!(render.len() > 0);
166        assert_eq!(
167            Into::<ErrorKind>::into(&error),
168            ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
169        );
170    }
171    #[test]
172    fn no_value_error() {
173        let error = VersionError::NoValue;
174        let displ = error.to_string();
175        assert!(displ.len() > 0);
176        let cmd = cli::Cli::command();
177        let err = error.error(&mut cmd.clone());
178        let render = format!("{}", err.render());
179        assert!(render.len() > 0);
180        assert_eq!(
181            Into::<ErrorKind>::into(&error),
182            ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
183        );
184    }
185    #[test]
186    fn no_negatives_error() {
187        let error = VersionError::NoNegatives;
188        let displ = error.to_string();
189        assert!(displ.len() > 0);
190        let cmd = cli::Cli::command();
191        let err = error.error(&mut cmd.clone());
192        let render = format!("{}", err.render());
193        assert!(render.len() > 0);
194        assert_eq!(Into::<ErrorKind>::into(&error), ErrorKind::InvalidValue);
195    }
196}