diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/command.rs | 500 |
1 files changed, 378 insertions, 122 deletions
diff --git a/src/command.rs b/src/command.rs index d474e35..9809718 100644 --- a/src/command.rs +++ b/src/command.rs | |||
@@ -118,9 +118,25 @@ pub enum Command { | |||
118 | Blank, | 118 | Blank, |
119 | } | 119 | } |
120 | 120 | ||
121 | #[derive(Debug)] | 121 | #[derive(PartialEq, Debug)] |
122 | enum CommandName { | ||
123 | Add, | ||
124 | AddAuto, | ||
125 | MonthPrev, | ||
126 | MonthNext, | ||
127 | Delete, | ||
128 | TrackUp, | ||
129 | TrackDown, | ||
130 | Help, | ||
131 | Write, | ||
132 | Quit, | ||
133 | Blank, | ||
134 | } | ||
135 | |||
136 | #[derive(PartialEq, Debug)] | ||
122 | pub enum CommandLineError { | 137 | pub enum CommandLineError { |
123 | InvalidCommand(String), // command name | 138 | InvalidCommand(String), // command name |
139 | InvalidArg(u32), // position | ||
124 | NotEnoughArgs(String, u32), // command name, required no. of args | 140 | NotEnoughArgs(String, u32), // command name, required no. of args |
125 | } | 141 | } |
126 | 142 | ||
@@ -130,6 +146,7 @@ impl fmt::Display for CommandLineError { | |||
130 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 146 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
131 | match self { | 147 | match self { |
132 | CommandLineError::InvalidCommand(s) => write!(f, "Invalid command: `{}`", s), | 148 | CommandLineError::InvalidCommand(s) => write!(f, "Invalid command: `{}`", s), |
149 | CommandLineError::InvalidArg(p) => write!(f, "Invalid argument at position {}", p), | ||
133 | CommandLineError::NotEnoughArgs(s, n) => { | 150 | CommandLineError::NotEnoughArgs(s, n) => { |
134 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) | 151 | write!(f, "Command `{}` requires atleast {} argument(s)!", s, n) |
135 | } | 152 | } |
@@ -141,77 +158,191 @@ type Result<T> = std::result::Result<T, CommandLineError>; | |||
141 | 158 | ||
142 | impl Command { | 159 | impl Command { |
143 | pub fn from_string<P: AsRef<str>>(input: P) -> Result<Command> { | 160 | pub fn from_string<P: AsRef<str>>(input: P) -> Result<Command> { |
144 | let mut strings: Vec<&str> = input.as_ref().trim().split(' ').collect(); | 161 | let input_str = input.as_ref().trim(); |
145 | if strings.is_empty() { | 162 | let parsed = parse_command_name(input_str); |
146 | return Ok(Command::Blank); | 163 | if let Ok((command_name, rest)) = parsed { |
147 | } | 164 | match command_name { |
148 | 165 | CommandName::Add => return parse_add(rest), | |
149 | let first = strings.first().unwrap().to_string(); | 166 | CommandName::AddAuto => return parse_add_auto(rest), |
150 | let args: Vec<String> = strings.iter_mut().skip(1).map(|s| s.to_string()).collect(); | 167 | CommandName::Delete => return parse_delete(rest), |
151 | let mut _add = |auto: bool, first: String| { | 168 | CommandName::TrackUp => return parse_track_up(rest), |
152 | return parse_add(first, args.clone(), auto); | 169 | CommandName::TrackDown => return parse_track_down(rest), |
153 | }; | 170 | CommandName::Help => return parse_help(rest), |
154 | 171 | CommandName::MonthPrev => return Ok(Command::MonthPrev), | |
155 | match first.as_ref() { | 172 | CommandName::MonthNext => return Ok(Command::MonthNext), |
156 | "add" | "a" => _add(false, first), | 173 | CommandName::Quit => return Ok(Command::Quit), |
157 | "add-auto" | "aa" => _add(true, first), | 174 | CommandName::Write => return Ok(Command::Write), |
158 | "delete" | "d" => { | 175 | CommandName::Blank => return Ok(Command::Blank), |
159 | if args.is_empty() { | ||
160 | return Err(CommandLineError::NotEnoughArgs(first, 1)); | ||
161 | } | ||
162 | return Ok(Command::Delete(args[0].to_string())); | ||
163 | } | ||
164 | "track-up" | "tup" => { | ||
165 | if args.is_empty() { | ||
166 | return Err(CommandLineError::NotEnoughArgs(first, 1)); | ||
167 | } | ||
168 | return Ok(Command::TrackUp(args[0].to_string())); | ||
169 | } | ||
170 | "track-down" | "tdown" => { | ||
171 | if args.is_empty() { | ||
172 | return Err(CommandLineError::NotEnoughArgs(first, 1)); | ||
173 | } | ||
174 | return Ok(Command::TrackDown(args[0].to_string())); | ||
175 | } | ||
176 | "h" | "?" | "help" => { | ||
177 | if args.is_empty() { | ||
178 | return Ok(Command::Help(None)); | ||
179 | } | ||
180 | return Ok(Command::Help(Some(args[0].to_string()))); | ||
181 | } | 176 | } |
182 | "mprev" | "month-prev" => return Ok(Command::MonthPrev), | 177 | } else { |
183 | "mnext" | "month-next" => return Ok(Command::MonthNext), | 178 | return Err(parsed.err().unwrap()); |
184 | "q" | "quit" => return Ok(Command::Quit), | ||
185 | "w" | "write" => return Ok(Command::Write), | ||
186 | "" => return Ok(Command::Blank), | ||
187 | s => return Err(CommandLineError::InvalidCommand(s.into())), | ||
188 | } | 179 | } |
189 | } | 180 | } |
190 | } | 181 | } |
191 | 182 | ||
192 | fn parse_add(verb: String, args: Vec<String>, auto: bool) -> Result<Command> { | 183 | fn parse_command_name(input: &str) -> Result<(CommandName, &str)> { |
193 | if args.is_empty() { | 184 | let chars = input.trim().chars(); |
194 | return Err(CommandLineError::NotEnoughArgs(verb, 1)); | 185 | let mut parsed_name = "".to_owned(); |
186 | let mut pos = 0; | ||
187 | |||
188 | for c in chars { | ||
189 | pos = pos + 1; | ||
190 | if c == ' ' { | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | parsed_name.push(c); | ||
195 | } | 195 | } |
196 | 196 | ||
197 | let mut pos = 1; | 197 | match parsed_name.as_ref() { |
198 | let mut acc = "".to_owned(); | 198 | "add" | "a" => Ok((CommandName::Add, &input[pos..])), |
199 | let mut new_goal: Option<u32> = None; | 199 | "add-auto" | "aa" => Ok((CommandName::AddAuto, &input[pos..])), |
200 | for s1 in args { | 200 | "delete" | "d" => Ok((CommandName::Delete, &input[pos..])), |
201 | if pos == 1 { | 201 | "track-up" | "tup" => Ok((CommandName::TrackUp, &input[pos..])), |
202 | acc.push_str(&s1); | 202 | "track-down" | "tdown" => Ok((CommandName::TrackDown, &input[pos..])), |
203 | } else { | 203 | "h" | "?" | "help" => Ok((CommandName::Help, &input[pos..])), |
204 | if let Ok(n) = s1.parse::<u32>() { | 204 | "mprev" => Ok((CommandName::MonthPrev, &input[pos..])), |
205 | new_goal = Some(n); | 205 | "mnext" => Ok((CommandName::MonthNext, &input[pos..])), |
206 | "quit" | "q" => Ok((CommandName::Quit, &input[pos..])), | ||
207 | "write" | "w" => Ok((CommandName::Write, &input[pos..])), | ||
208 | "" => Ok((CommandName::Blank, &input[pos..])), | ||
209 | _ => Err(CommandLineError::InvalidCommand(parsed_name)), | ||
210 | } | ||
211 | } | ||
212 | |||
213 | fn parse_name(input: &str) -> (String, &str) { | ||
214 | let chars = input.trim().chars(); | ||
215 | let mut name = "".to_owned(); | ||
216 | let mut pos = 0; | ||
217 | let mut parenthesis = false; | ||
218 | |||
219 | for c in chars { | ||
220 | pos = pos + 1; | ||
221 | if c == '"' || c == '\"' { | ||
222 | if parenthesis { | ||
223 | return (name, &input[pos..]); | ||
206 | } else { | 224 | } else { |
207 | acc.push(' '); | 225 | parenthesis = true; |
208 | acc.push_str(&s1); | 226 | continue; |
209 | } | 227 | } |
210 | } | 228 | } |
229 | |||
230 | if parenthesis { | ||
231 | name.push(c); | ||
232 | continue; | ||
233 | } | ||
234 | |||
235 | if c == ' ' { | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | name.push(c); | ||
240 | } | ||
241 | |||
242 | (name, &input[pos..]) | ||
243 | } | ||
244 | |||
245 | fn parse_goal(input: &str) -> Option<(Option<u32>, &str)> { | ||
246 | let chars = input.trim().chars(); | ||
247 | let mut goal_string = "".to_owned(); | ||
248 | let mut pos = 0; | ||
249 | |||
250 | if input.is_empty() { | ||
251 | return Some((None, input)); | ||
252 | } | ||
253 | |||
254 | for c in chars { | ||
211 | pos = pos + 1; | 255 | pos = pos + 1; |
256 | if c == ' ' { | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | goal_string.push(c); | ||
261 | } | ||
262 | |||
263 | let parsed = goal_string.parse::<u32>(); | ||
264 | |||
265 | if parsed.is_err() { | ||
266 | return None; | ||
267 | } | ||
268 | |||
269 | if pos + 1 > input.len() { | ||
270 | return Some((parsed.ok(), "")); | ||
271 | } | ||
272 | |||
273 | Some((parsed.ok(), &input[pos..])) | ||
274 | } | ||
275 | |||
276 | fn parse_add(input: &str) -> Result<Command> { | ||
277 | let (name, rest) = parse_name(input); | ||
278 | |||
279 | if name.is_empty() { | ||
280 | return Err(CommandLineError::NotEnoughArgs("add".to_owned(), 2)); | ||
281 | } | ||
282 | |||
283 | let parsed_goal = parse_goal(rest); | ||
284 | |||
285 | if parsed_goal.is_none() { | ||
286 | return Err(CommandLineError::InvalidArg(2)); | ||
287 | } | ||
288 | |||
289 | Ok(Command::Add(name, parsed_goal.unwrap().0, false)) | ||
290 | } | ||
291 | |||
292 | fn parse_add_auto(input: &str) -> Result<Command> { | ||
293 | let (name, rest) = parse_name(input); | ||
294 | |||
295 | if name.is_empty() { | ||
296 | return Err(CommandLineError::NotEnoughArgs("add-auto".to_owned(), 2)); | ||
297 | } | ||
298 | |||
299 | let parsed_goal = parse_goal(rest); | ||
300 | |||
301 | if parsed_goal.is_none() { | ||
302 | return Err(CommandLineError::InvalidArg(2)); | ||
303 | } | ||
304 | |||
305 | Ok(Command::Add(name, parsed_goal.unwrap().0, true)) | ||
306 | } | ||
307 | |||
308 | fn parse_delete(input: &str) -> Result<Command> { | ||
309 | let (name, _) = parse_name(input); | ||
310 | |||
311 | if name.is_empty() { | ||
312 | return Err(CommandLineError::NotEnoughArgs("delete".to_owned(), 1)); | ||
313 | } | ||
314 | |||
315 | Ok(Command::Delete(name)) | ||
316 | } | ||
317 | |||
318 | fn parse_track_up(input: &str) -> Result<Command> { | ||
319 | let (name, _) = parse_name(input); | ||
320 | |||
321 | if name.is_empty() { | ||
322 | return Err(CommandLineError::NotEnoughArgs("track-up".to_owned(), 1)); | ||
323 | } | ||
324 | |||
325 | Ok(Command::TrackUp(name)) | ||
326 | } | ||
327 | |||
328 | fn parse_track_down(input: &str) -> Result<Command> { | ||
329 | let (name, _) = parse_name(input); | ||
330 | |||
331 | if name.is_empty() { | ||
332 | return Err(CommandLineError::NotEnoughArgs("track-down".to_owned(), 1)); | ||
333 | } | ||
334 | |||
335 | Ok(Command::TrackDown(name)) | ||
336 | } | ||
337 | |||
338 | fn parse_help(input: &str) -> Result<Command> { | ||
339 | let (name, _) = parse_name(input); | ||
340 | |||
341 | if name.is_empty() { | ||
342 | return Ok(Command::Help(None)); | ||
212 | } | 343 | } |
213 | 344 | ||
214 | return Ok(Command::Add(acc, new_goal, auto)); | 345 | Ok(Command::Help(Some(name))) |
215 | } | 346 | } |
216 | 347 | ||
217 | #[cfg(test)] | 348 | #[cfg(test)] |
@@ -220,113 +351,179 @@ mod tests { | |||
220 | 351 | ||
221 | #[test] | 352 | #[test] |
222 | fn parse_add_command() { | 353 | fn parse_add_command() { |
223 | let result = Command::from_string("add eat 2"); | 354 | let inputs = ["add eat 2", "a eat 2"]; |
224 | 355 | ||
225 | assert!(result.is_ok()); | 356 | for input in inputs.iter() { |
226 | match result.unwrap() { | 357 | let result = Command::from_string(input); |
227 | Command::Add(name, goal, auto) => { | 358 | |
228 | assert_eq!(name, "eat"); | 359 | assert!(result.is_ok()); |
229 | assert_eq!(goal.unwrap(), 2); | 360 | match result.unwrap() { |
230 | assert_eq!(auto, false); | 361 | Command::Add(name, goal, auto) => { |
362 | assert_eq!(name, "eat"); | ||
363 | assert_eq!(goal.unwrap(), 2); | ||
364 | assert_eq!(auto, false); | ||
365 | } | ||
366 | _ => panic!(), | ||
231 | } | 367 | } |
232 | _ => panic!(), | ||
233 | } | 368 | } |
234 | } | 369 | } |
235 | 370 | ||
236 | #[test] | 371 | #[test] |
237 | fn parse_add_command_without_goal() { | 372 | fn parse_add_command_without_goal() { |
238 | let result = Command::from_string("add eat"); | 373 | let inputs = ["add eat", "a eat"]; |
239 | 374 | ||
240 | assert!(result.is_ok()); | 375 | for input in inputs.iter() { |
241 | match result.unwrap() { | 376 | let result = Command::from_string(input); |
242 | Command::Add(name, goal, auto) => { | 377 | |
243 | assert_eq!(name, "eat"); | 378 | assert!(result.is_ok()); |
244 | assert!(goal.is_none()); | 379 | match result.unwrap() { |
245 | assert_eq!(auto, false); | 380 | Command::Add(name, goal, auto) => { |
381 | assert_eq!(name, "eat"); | ||
382 | assert!(goal.is_none()); | ||
383 | assert_eq!(auto, false); | ||
384 | } | ||
385 | _ => panic!(), | ||
246 | } | 386 | } |
247 | _ => panic!(), | ||
248 | } | 387 | } |
249 | } | 388 | } |
250 | 389 | ||
251 | // #[test] | 390 | #[test] |
252 | fn parse_add_command_with_long_name() { | 391 | fn parse_add_command_with_long_name() { |
253 | let result = Command::from_string("add \"eat healthy\" 5"); | 392 | let inputs = ["add \"eat healthy\" 5", "a \"eat healthy\" 5"]; |
254 | 393 | ||
255 | assert!(result.is_ok()); | 394 | for input in inputs.iter() { |
256 | match result.unwrap() { | 395 | let result = Command::from_string(input); |
257 | Command::Add(name, goal, auto) => { | 396 | |
258 | assert_eq!(name, "eat healthy"); | 397 | assert!(result.is_ok()); |
259 | assert_eq!(goal.unwrap(), 5); | 398 | match result.unwrap() { |
260 | assert_eq!(auto, false); | 399 | Command::Add(name, goal, auto) => { |
400 | assert_eq!(name, "eat healthy"); | ||
401 | assert_eq!(goal.unwrap(), 5); | ||
402 | assert_eq!(auto, false); | ||
403 | } | ||
404 | _ => panic!(), | ||
261 | } | 405 | } |
262 | _ => panic!(), | ||
263 | } | 406 | } |
264 | } | 407 | } |
265 | 408 | ||
266 | #[test] | 409 | #[test] |
267 | fn parse_add_auto_command() { | 410 | fn parse_add_auto_command() { |
268 | let result = Command::from_string("add-auto eat 2"); | 411 | let inputs = ["add-auto eat 2", "aa eat 2"]; |
269 | 412 | ||
270 | assert!(result.is_ok()); | 413 | for input in inputs.iter() { |
271 | match result.unwrap() { | 414 | let result = Command::from_string(input); |
272 | Command::Add(name, goal, auto) => { | 415 | |
273 | assert_eq!(name, "eat"); | 416 | assert!(result.is_ok()); |
274 | assert_eq!(goal.unwrap(), 2); | 417 | match result.unwrap() { |
275 | assert_eq!(auto, true); | 418 | Command::Add(name, goal, auto) => { |
419 | assert_eq!(name, "eat"); | ||
420 | assert_eq!(goal.unwrap(), 2); | ||
421 | assert_eq!(auto, true); | ||
422 | } | ||
423 | _ => panic!(), | ||
276 | } | 424 | } |
277 | _ => panic!(), | ||
278 | } | 425 | } |
279 | } | 426 | } |
280 | 427 | ||
281 | #[test] | 428 | #[test] |
282 | fn parse_delete_command() { | 429 | fn parse_delete_command() { |
283 | let result = Command::from_string("delete eat"); | 430 | let inputs = ["delete eat", "d eat"]; |
284 | 431 | ||
285 | assert!(result.is_ok()); | 432 | for input in inputs.iter() { |
286 | match result.unwrap() { | 433 | let result = Command::from_string(input); |
287 | Command::Delete(name) => { | 434 | |
288 | assert_eq!(name, "eat"); | 435 | assert!(result.is_ok()); |
436 | match result.unwrap() { | ||
437 | Command::Delete(name) => { | ||
438 | assert_eq!(name, "eat"); | ||
439 | } | ||
440 | _ => panic!(), | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn parse_delete_long_name_command() { | ||
447 | let inputs = ["delete \"eat healthy\"", "d \"eat healthy\""]; | ||
448 | |||
449 | for input in inputs.iter() { | ||
450 | let result = Command::from_string(input); | ||
451 | |||
452 | assert!(result.is_ok()); | ||
453 | match result.unwrap() { | ||
454 | Command::Delete(name) => { | ||
455 | assert_eq!(name, "eat healthy"); | ||
456 | } | ||
457 | _ => panic!(), | ||
289 | } | 458 | } |
290 | _ => panic!(), | ||
291 | } | 459 | } |
292 | } | 460 | } |
293 | 461 | ||
294 | #[test] | 462 | #[test] |
295 | fn parse_track_up_command() { | 463 | fn parse_track_up_command() { |
296 | let result = Command::from_string("track-up eat"); | 464 | let inputs = ["track-up eat", "tup eat"]; |
297 | 465 | ||
298 | assert!(result.is_ok()); | 466 | for input in inputs.iter() { |
299 | match result.unwrap() { | 467 | let result = Command::from_string(input); |
300 | Command::TrackUp(name) => { | 468 | |
301 | assert_eq!(name, "eat"); | 469 | assert!(result.is_ok()); |
470 | match result.unwrap() { | ||
471 | Command::TrackUp(name) => { | ||
472 | assert_eq!(name, "eat"); | ||
473 | } | ||
474 | _ => panic!(), | ||
302 | } | 475 | } |
303 | _ => panic!(), | ||
304 | } | 476 | } |
305 | } | 477 | } |
306 | 478 | ||
307 | #[test] | 479 | #[test] |
308 | fn parse_track_down_command() { | 480 | fn parse_track_down_command() { |
309 | let result = Command::from_string("track-down eat"); | 481 | let inputs = ["track-down eat", "tdown eat"]; |
310 | 482 | ||
311 | assert!(result.is_ok()); | 483 | for input in inputs.iter() { |
312 | match result.unwrap() { | 484 | let result = Command::from_string(input); |
313 | Command::TrackDown(name) => { | 485 | |
314 | assert_eq!(name, "eat"); | 486 | assert!(result.is_ok()); |
487 | match result.unwrap() { | ||
488 | Command::TrackDown(name) => { | ||
489 | assert_eq!(name, "eat"); | ||
490 | } | ||
491 | _ => panic!(), | ||
315 | } | 492 | } |
316 | _ => panic!(), | ||
317 | } | 493 | } |
318 | } | 494 | } |
319 | 495 | ||
320 | #[test] | 496 | #[test] |
321 | fn parse_help_command() { | 497 | fn parse_help_command() { |
322 | let result = Command::from_string("help add"); | 498 | let inputs = ["help add", "? add", "h add"]; |
323 | 499 | ||
324 | assert!(result.is_ok()); | 500 | for input in inputs.iter() { |
325 | match result.unwrap() { | 501 | let result = Command::from_string(input); |
326 | Command::Help(name) => { | 502 | |
327 | assert_eq!(name.unwrap(), "add"); | 503 | assert!(result.is_ok()); |
504 | match result.unwrap() { | ||
505 | Command::Help(name) => { | ||
506 | assert_eq!(name.unwrap(), "add"); | ||
507 | } | ||
508 | _ => panic!(), | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | #[test] | ||
514 | fn parse_help_global_command() { | ||
515 | let inputs = ["help", "?", "h"]; | ||
516 | |||
517 | for input in inputs.iter() { | ||
518 | let result = Command::from_string(input); | ||
519 | |||
520 | assert!(result.is_ok()); | ||
521 | match result.unwrap() { | ||
522 | Command::Help(name) => { | ||
523 | assert!(name.is_none()); | ||
524 | } | ||
525 | _ => panic!(), | ||
328 | } | 526 | } |
329 | _ => panic!(), | ||
330 | } | 527 | } |
331 | } | 528 | } |
332 | 529 | ||
@@ -348,18 +545,26 @@ mod tests { | |||
348 | 545 | ||
349 | #[test] | 546 | #[test] |
350 | fn parse_quit_command() { | 547 | fn parse_quit_command() { |
351 | let result = Command::from_string("q"); | 548 | let inputs = ["q", "quit"]; |
352 | 549 | ||
353 | assert!(result.is_ok()); | 550 | for input in inputs.iter() { |
354 | assert_eq!(result.unwrap(), Command::Quit); | 551 | let result = Command::from_string(input); |
552 | |||
553 | assert!(result.is_ok()); | ||
554 | assert_eq!(result.unwrap(), Command::Quit); | ||
555 | } | ||
355 | } | 556 | } |
356 | 557 | ||
357 | #[test] | 558 | #[test] |
358 | fn parse_write_command() { | 559 | fn parse_write_command() { |
359 | let result = Command::from_string("w"); | 560 | let inputs = ["w", "write"]; |
360 | 561 | ||
361 | assert!(result.is_ok()); | 562 | for input in inputs.iter() { |
362 | assert_eq!(result.unwrap(), Command::Write); | 563 | let result = Command::from_string(input); |
564 | |||
565 | assert!(result.is_ok()); | ||
566 | assert_eq!(result.unwrap(), Command::Write); | ||
567 | } | ||
363 | } | 568 | } |
364 | 569 | ||
365 | #[test] | 570 | #[test] |
@@ -369,4 +574,55 @@ mod tests { | |||
369 | assert!(result.is_ok()); | 574 | assert!(result.is_ok()); |
370 | assert_eq!(result.unwrap(), Command::Blank); | 575 | assert_eq!(result.unwrap(), Command::Blank); |
371 | } | 576 | } |
577 | |||
578 | #[test] | ||
579 | fn parse_error_invalid_command() { | ||
580 | let input = "non-existing-command".to_owned(); | ||
581 | let result = Command::from_string(&input); | ||
582 | |||
583 | assert!(result.is_err()); | ||
584 | assert_eq!( | ||
585 | result.err().unwrap(), | ||
586 | CommandLineError::InvalidCommand(input) | ||
587 | ); | ||
588 | } | ||
589 | |||
590 | #[test] | ||
591 | fn parse_error_not_enough_args() { | ||
592 | let test_cases = [ | ||
593 | ("add".to_owned(), "add".to_owned(), 2), | ||
594 | ("add-auto".to_owned(), "add-auto".to_owned(), 2), | ||
595 | ("delete".to_owned(), "delete".to_owned(), 1), | ||
596 | ("track-up".to_owned(), "track-up".to_owned(), 1), | ||
597 | ("track-down".to_owned(), "track-down".to_owned(), 1), | ||
598 | ]; | ||
599 | |||
600 | for test_case in test_cases.iter() { | ||
601 | let result = Command::from_string(&test_case.0); | ||
602 | |||
603 | assert!(result.is_err()); | ||
604 | assert_eq!( | ||
605 | result.err().unwrap(), | ||
606 | CommandLineError::NotEnoughArgs(test_case.1.clone(), test_case.2) | ||
607 | ); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | #[test] | ||
612 | fn parse_error_invalid_arg() { | ||
613 | let test_cases = [ | ||
614 | ("add habit n".to_owned(), 2), | ||
615 | ("add-auto habit n".to_owned(), 2), | ||
616 | ]; | ||
617 | |||
618 | for test_case in test_cases.iter() { | ||
619 | let result = Command::from_string(&test_case.0); | ||
620 | |||
621 | assert!(result.is_err()); | ||
622 | assert_eq!( | ||
623 | result.err().unwrap(), | ||
624 | CommandLineError::InvalidArg(test_case.1) | ||
625 | ); | ||
626 | } | ||
627 | } | ||
372 | } | 628 | } |