diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/command.rs | 98 |
1 files changed, 18 insertions, 80 deletions
diff --git a/src/command.rs b/src/command.rs index 40801e7..e4c099e 100644 --- a/src/command.rs +++ b/src/command.rs | |||
@@ -122,6 +122,7 @@ pub enum Command { | |||
122 | #[derive(Debug)] | 122 | #[derive(Debug)] |
123 | pub enum CommandLineError { | 123 | pub enum CommandLineError { |
124 | InvalidCommand(String), // command name | 124 | InvalidCommand(String), // command name |
125 | InvalidArg(u32), // position | ||
125 | NotEnoughArgs(String, u32), // command name, required no. of args | 126 | NotEnoughArgs(String, u32), // command name, required no. of args |
126 | } | 127 | } |
127 | 128 | ||
@@ -131,6 +132,7 @@ impl fmt::Display for CommandLineError { | |||
131 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 132 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
132 | match self { | 133 | match self { |
133 | CommandLineError::InvalidCommand(s) => write!(f, "Invalid command: `{}`", s), | 134 | CommandLineError::InvalidCommand(s) => write!(f, "Invalid command: `{}`", s), |
135 | CommandLineError::InvalidArg(p) => write!(f, "Invalid argument at position {}", p), | ||
134 | CommandLineError::NotEnoughArgs(s, n) => { | 136 | CommandLineError::NotEnoughArgs(s, n) => { |
135 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) | 137 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) |
136 | } | 138 | } |
@@ -148,9 +150,23 @@ impl Command { | |||
148 | } | 150 | } |
149 | 151 | ||
150 | let first = strings.first().unwrap().to_string(); | 152 | let first = strings.first().unwrap().to_string(); |
151 | let args: Vec<String> = strings.iter_mut().skip(1).map(|s| s.to_string()).collect(); | 153 | let mut args: Vec<String> = strings.iter_mut().skip(1).map(|s| s.to_string()).collect(); |
152 | let mut _add = |auto: bool, first: String| { | 154 | let mut _add = |auto: bool, first: String| { |
153 | return parse_add(first, args.clone(), auto); | 155 | if args.is_empty() { |
156 | return Err(CommandLineError::NotEnoughArgs(first, 1)); | ||
157 | } | ||
158 | let goal = args | ||
159 | .get(1) | ||
160 | .map(|x| { | ||
161 | x.parse::<u32>() | ||
162 | .map_err(|_| CommandLineError::InvalidArg(2)) | ||
163 | }) | ||
164 | .transpose()?; | ||
165 | return Ok(Command::Add( | ||
166 | args.get_mut(0).unwrap().to_string(), | ||
167 | goal, | ||
168 | auto, | ||
169 | )); | ||
154 | }; | 170 | }; |
155 | 171 | ||
156 | match first.as_ref() { | 172 | match first.as_ref() { |
@@ -189,81 +205,3 @@ impl Command { | |||
189 | } | 205 | } |
190 | } | 206 | } |
191 | } | 207 | } |
192 | |||
193 | fn parse_add(verb: String, args: Vec<String>, auto: bool) -> Result<Command> { | ||
194 | if args.is_empty() { | ||
195 | return Err(CommandLineError::NotEnoughArgs(verb, 1)); | ||
196 | } | ||
197 | |||
198 | let mut pos = 1; | ||
199 | let mut acc = "".to_owned(); | ||
200 | let mut new_goal: Option<u32> = None; | ||
201 | for s1 in args { | ||
202 | if pos == 1 { | ||
203 | acc.push_str(&s1); | ||
204 | } else { | ||
205 | if let Ok(n) = s1.parse::<u32>() { | ||
206 | new_goal = Some(n); | ||
207 | } else { | ||
208 | acc.push(' '); | ||
209 | acc.push_str(&s1); | ||
210 | } | ||
211 | } | ||
212 | pos = pos + 1; | ||
213 | } | ||
214 | |||
215 | return Ok(Command::Add(acc, new_goal, auto)); | ||
216 | } | ||
217 | |||
218 | #[cfg(test)] | ||
219 | mod tests { | ||
220 | use super::*; | ||
221 | |||
222 | #[test] | ||
223 | fn parse_add_command_with_goal() { | ||
224 | let command: Vec<String> = "eat healthy 3" | ||
225 | .trim() | ||
226 | .split(' ') | ||
227 | .into_iter() | ||
228 | .map(|s| s.to_string()) | ||
229 | .collect(); | ||
230 | |||
231 | let verb = "add".to_owned(); | ||
232 | let auto = false; | ||
233 | |||
234 | let result = parse_add(verb, command, auto); | ||
235 | |||
236 | match result.unwrap() { | ||
237 | Command::Add(name, goal, a) => { | ||
238 | assert_eq!(name, "eat healthy".to_owned()); | ||
239 | assert_eq!(goal.unwrap(), 3); | ||
240 | assert_eq!(a, auto); | ||
241 | } | ||
242 | _ => panic!(), | ||
243 | } | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn parse_add_command_without_goal() { | ||
248 | let command: Vec<String> = "eat healthy" | ||
249 | .trim() | ||
250 | .split(' ') | ||
251 | .into_iter() | ||
252 | .map(|s| s.to_string()) | ||
253 | .collect(); | ||
254 | |||
255 | let verb = "add".to_owned(); | ||
256 | let auto = false; | ||
257 | |||
258 | let result = parse_add(verb, command, auto); | ||
259 | |||
260 | match result.unwrap() { | ||
261 | Command::Add(name, goal, a) => { | ||
262 | assert_eq!(name, "eat healthy".to_owned()); | ||
263 | assert!(goal.is_none()); | ||
264 | assert_eq!(a, auto); | ||
265 | } | ||
266 | _ => panic!(), | ||
267 | } | ||
268 | } | ||
269 | } | ||