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