diff options
| -rw-r--r-- | CLI/rust/src/game_of_life/opts.rs | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/CLI/rust/src/game_of_life/opts.rs b/CLI/rust/src/game_of_life/opts.rs index a5da4de..f32c4a8 100644 --- a/CLI/rust/src/game_of_life/opts.rs +++ b/CLI/rust/src/game_of_life/opts.rs @@ -1 +1,167 @@ +use clap::{ArgMatches, Error}; +use rand::{thread_rng, Rng}; +use terminal_size::{terminal_size, Height, Width}; + +#[cfg(test)] +use mocktopus::macros::mockable; + pub(crate) mod validators; + +#[derive(Debug, Clone)] +pub(crate) struct Opts { + pub seed: usize, + pub input: Option<String>, + pub width: isize, + pub height: isize, + pub live_cell: char, + pub dead_cell: char, + pub delay: usize, +} + +#[cfg_attr(test, mockable)] +impl Opts { + pub fn from(args: ArgMatches) -> Result<Opts, Error> { + // Set the seed to a random generated number as default if not provided + let rnd = thread_rng().gen_range(0..1_000_000); + let seed = args.value_of_t::<usize>("seed").unwrap_or(rnd); + + // Coerce the input to Options<String> from args + let input = match args.value_of("input") { + Some(val) => Some(String::from(val)), + None => None, + }; + + // Set the width and height to the maximum terminal size possible when not provided + let (Width(term_width), Height(term_height)) = terminal_size().unwrap(); + let max_width: isize = term_width as isize; + let max_height: isize = term_height as isize - 2; + let width = args.value_of_t::<isize>("width").unwrap_or(max_width); + let height = args.value_of_t::<isize>("height").unwrap_or(max_height); + + // Unwrap the defaults of the other arguments and set them + let live_cell = args.value_of_t::<char>("live-cell")?; + let dead_cell = args.value_of_t::<char>("dead-cell")?; + if live_cell == dead_cell { + return Err(Error::with_description( + String::from( + "The arguments '--live-cell', '--dead-cell' must have different values\n", + ), + clap::ErrorKind::InvalidValue, + )); + } + + // unwrap the delay + let delay = args.value_of_t::<usize>("delay")?; + + Ok(Opts { + seed, + input, + width, + height, + live_cell, + dead_cell, + delay, + }) + } +} + +#[cfg(test)] +mod from { + use super::*; + use crate::game_of_life; + + #[test] + fn no_options() { + let (Width(term_width), Height(term_height)) = terminal_size().unwrap(); + let matches = game_of_life::app().try_get_matches_from(vec![""]).unwrap(); + let opts = Opts::from(matches).unwrap(); + assert!(matches!(opts.seed, 0..=1_000_000)); + assert_eq!(opts.input, None); + assert_eq!(opts.width, term_width as isize); + assert_eq!(opts.height, term_height as isize - 2); + assert_eq!(opts.live_cell, '█'); + assert_eq!(opts.dead_cell, ' '); + assert_eq!(opts.delay, 50); + } + + #[test] + fn invalid_seed() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--seed=leet"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert!(matches!(opts.seed, 0..=1_000_000)); + } + + #[test] + fn seed() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--seed=1337"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.seed, 1337); + } + + #[test] + fn input() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--input=file"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.input, Some(String::from("file"))); + } + + #[test] + fn width() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--width=13"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.width, 13); + } + + #[test] + fn height() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--height=13"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.height, 13); + } + + #[test] + fn live_cell() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--live-cell=l"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.live_cell, 'l'); + } + + #[test] + fn dead_cell() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--dead-cell=d"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.dead_cell, 'd'); + } + + #[test] + fn same_live_and_dead_cells() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--live-cell=x", "--dead-cell=x"]) + .unwrap(); + let opts = Opts::from(matches); + assert!(opts.is_err()); + } + + #[test] + fn delay() { + let matches = game_of_life::app() + .try_get_matches_from(vec!["", "--delay=13"]) + .unwrap(); + let opts = Opts::from(matches).unwrap(); + assert_eq!(opts.delay, 13); + } +} |
