From 63e9405afe56c9ddcab92667aa6ff59bcce7d4b1 Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 17:32:55 +0530 Subject: [PATCH 1/7] added uppercase arg in clap --- src/args.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/args.rs b/src/args.rs index 92d8365..e0af22c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -22,4 +22,8 @@ pub struct Args { /// path to dictionary file #[arg(long)] pub dictionary_path: Option, + + /// indicates if test should include words beginning with uppercase letters + #[arg(short, long)] + pub uppercase: Option } From c25363bafcd53ca02273a274f78ddcd484ef7fb7 Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 17:36:03 +0530 Subject: [PATCH 2/7] added uppercase to Config and ConfigFile structs. --- src/config.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/config.rs b/src/config.rs index fca77e7..7d4f0d5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,6 +45,7 @@ pub struct Config { pub numbers: bool, pub numbers_ratio: f64, pub dictionary_path: PathBuf, + pub uppercase: bool } /// Used by `serde` crate to parse config file into a rust struct @@ -54,6 +55,7 @@ struct ConfigFile { pub numbers: Option, pub numbers_ratio: Option, pub dictionary_path: Option, + pub uppercase: Option } #[automock] @@ -65,6 +67,7 @@ impl Config { numbers: false, numbers_ratio: 0.05, dictionary_path: PathBuf::from("src/dict/words.txt"), + uppercase: false } } @@ -120,6 +123,10 @@ fn augment_config_with_config_file(config: &mut Config, mut config_file: fs::Fil if let Some(dictionary_path) = config_from_file.dictionary_path { config.dictionary_path = PathBuf::from(dictionary_path); } + + if let Some(uppercase) = config_from_file.uppercase { + config.uppercase = uppercase; + } } Ok(()) @@ -150,6 +157,10 @@ fn augment_config_with_args(config: &mut Config, args: Args) { if let Some(dictionary_path) = args.dictionary_path { config.dictionary_path = PathBuf::from(dictionary_path); } + + if let Some(uppercase_flag) = args.uppercase { + config.uppercase = uppercase_flag + } } #[cfg(test)] @@ -174,6 +185,7 @@ mod tests { numbers: None, numbers_ratio: None, dictionary_path: None, + uppercase: None }; let config = Config::new(args, PathBuf::new()).expect("Unable to create config"); @@ -194,6 +206,7 @@ mod tests { numbers: None, numbers_ratio: None, dictionary_path: None, + uppercase: None }; let config = Config::new(args, config_file.path().to_path_buf()).expect("Unable to create config"); @@ -210,6 +223,7 @@ mod tests { numbers: Some(true), numbers_ratio: None, dictionary_path: None, + uppercase: None }; let config = Config::new(args, PathBuf::new()).expect("Unable to create config"); @@ -230,6 +244,7 @@ mod tests { numbers: Some(false), numbers_ratio: None, dictionary_path: Some(String::from("/etc/dict/words")), + uppercase: None }; let config = Config::new(args, config_file.path().to_path_buf()).expect("Unable to create config"); From 04305e90fcc87f2aacf5e9b6d8905da73be54aa6 Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 23:08:13 +0530 Subject: [PATCH 3/7] implemented uppercase functionality --- src/expected_input.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/expected_input.rs b/src/expected_input.rs index be8a528..3c6f588 100644 --- a/src/expected_input.rs +++ b/src/expected_input.rs @@ -38,13 +38,23 @@ impl ExpectedInput { let mut string_vec: Vec = str_vec.iter().map(|s| s.to_string()).collect(); str_vec.shuffle(&mut rng); + // creating a pointer which points to where the words starts in the vector to help with uppercase words since we replace + // words in the beginning with numbers when numbers are enabled. + let mut words_start_pos:usize = 0; + if config.numbers == true { - replace_words_with_numbers(&mut string_vec, &mut rng, config.numbers_ratio); + words_start_pos = replace_words_with_numbers(&mut string_vec, &mut rng, config.numbers_ratio); + str_vec = string_vec.iter().map(|s| s.as_str()).collect(); + } + if config.uppercase == true { + let uppercase_string_vec = create_uppercase_words(&string_vec, words_start_pos); + string_vec = uppercase_string_vec; str_vec = string_vec.iter().map(|s| s.as_str()).collect(); - str_vec.shuffle(&mut rng); } + str_vec.shuffle(&mut rng); + let str = str_vec.join(" ").trim().to_string(); Ok(Self { str }) @@ -60,7 +70,7 @@ fn replace_words_with_numbers( string_vec: &mut Vec, rng: &mut rand::rngs::ThreadRng, numbers_ratio: f64, -) { +) -> usize { let change_to_num_treshold = (numbers_ratio * string_vec.len() as f64).round() as usize; *string_vec = string_vec @@ -76,6 +86,23 @@ fn replace_words_with_numbers( return word.to_string(); }) .collect(); + + return change_to_num_treshold - 1 +} + +fn create_uppercase_words (string_vec: &Vec, pos: usize) -> Vec { + let mut string_vec2 = string_vec.clone(); + let num_uppercase_words = string_vec2[pos..].len() as usize; + + for i in pos..pos+num_uppercase_words{ + if string_vec2[i] != ""{ + let mut v: Vec = string_vec2[i].chars().collect(); + v[0] = v[0].to_uppercase().nth(0).unwrap(); + let s: String = v.into_iter().collect(); + string_vec2[i] = s; + } + } + return string_vec2; } /// extracted to trait to create mock with `mockall` crate @@ -123,6 +150,7 @@ mod tests { numbers: false, numbers_ratio: 0.05, dictionary_path: config_file.path().to_path_buf(), + uppercase: false }; let expected_input = ExpectedInput::new(&config).expect("unable to create expected input"); From ffc098609bcf9e7e20171e84cf380e42bdb34cca Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 23:41:10 +0530 Subject: [PATCH 4/7] added uppercase ratio to CLAP args --- src/args.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/args.rs b/src/args.rs index e0af22c..2f13bc5 100644 --- a/src/args.rs +++ b/src/args.rs @@ -25,5 +25,10 @@ pub struct Args { /// indicates if test should include words beginning with uppercase letters #[arg(short, long)] - pub uppercase: Option + pub uppercase: Option, + + /// uppercase-ratio argument + #[arg(long)] + pub uppercase_ratio: Option, + } From f082c51d3bb0b7c533e4f2aa0552df86cc1ca463 Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 23:41:56 +0530 Subject: [PATCH 5/7] added uppercase ratio to Config, ConfigFile and related functions --- src/config.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7d4f0d5..96b36a6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,7 +45,8 @@ pub struct Config { pub numbers: bool, pub numbers_ratio: f64, pub dictionary_path: PathBuf, - pub uppercase: bool + pub uppercase: bool, + pub uppercase_ratio: f64, } /// Used by `serde` crate to parse config file into a rust struct @@ -55,7 +56,8 @@ struct ConfigFile { pub numbers: Option, pub numbers_ratio: Option, pub dictionary_path: Option, - pub uppercase: Option + pub uppercase: Option, + pub uppercase_ratio: Option } #[automock] @@ -67,7 +69,8 @@ impl Config { numbers: false, numbers_ratio: 0.05, dictionary_path: PathBuf::from("src/dict/words.txt"), - uppercase: false + uppercase: false, + uppercase_ratio: 0.45 } } @@ -127,6 +130,12 @@ fn augment_config_with_config_file(config: &mut Config, mut config_file: fs::Fil if let Some(uppercase) = config_from_file.uppercase { config.uppercase = uppercase; } + + if let Some(uppercase_ratio) = config_from_file.uppercase_ratio { + if uppercase_ratio >= 0.0 && uppercase_ratio <= 1.0 { + config.uppercase_ratio = uppercase_ratio + } + } } Ok(()) @@ -161,6 +170,12 @@ fn augment_config_with_args(config: &mut Config, args: Args) { if let Some(uppercase_flag) = args.uppercase { config.uppercase = uppercase_flag } + + if let Some(uppercase_ratio) = args.uppercase_ratio { + if uppercase_ratio >= 0.0 && uppercase_ratio <= 1.0 { + config.uppercase_ratio = uppercase_ratio + } + } } #[cfg(test)] @@ -185,7 +200,8 @@ mod tests { numbers: None, numbers_ratio: None, dictionary_path: None, - uppercase: None + uppercase: None, + uppercase_ratio: None }; let config = Config::new(args, PathBuf::new()).expect("Unable to create config"); @@ -206,7 +222,8 @@ mod tests { numbers: None, numbers_ratio: None, dictionary_path: None, - uppercase: None + uppercase: None, + uppercase_ratio: None }; let config = Config::new(args, config_file.path().to_path_buf()).expect("Unable to create config"); @@ -223,7 +240,8 @@ mod tests { numbers: Some(true), numbers_ratio: None, dictionary_path: None, - uppercase: None + uppercase: None, + uppercase_ratio: None }; let config = Config::new(args, PathBuf::new()).expect("Unable to create config"); @@ -244,7 +262,8 @@ mod tests { numbers: Some(false), numbers_ratio: None, dictionary_path: Some(String::from("/etc/dict/words")), - uppercase: None + uppercase: None, + uppercase_ratio: None }; let config = Config::new(args, config_file.path().to_path_buf()).expect("Unable to create config"); From 93f83ce85e3190f4ea5bacf3231fac7d0492990a Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Wed, 4 Oct 2023 23:42:29 +0530 Subject: [PATCH 6/7] implemented uppercase ratio logic --- src/expected_input.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/expected_input.rs b/src/expected_input.rs index 3c6f588..c7d58ba 100644 --- a/src/expected_input.rs +++ b/src/expected_input.rs @@ -48,7 +48,7 @@ impl ExpectedInput { } if config.uppercase == true { - let uppercase_string_vec = create_uppercase_words(&string_vec, words_start_pos); + let uppercase_string_vec = create_uppercase_words(&string_vec, words_start_pos, config.uppercase_ratio); string_vec = uppercase_string_vec; str_vec = string_vec.iter().map(|s| s.as_str()).collect(); } @@ -90,10 +90,9 @@ fn replace_words_with_numbers( return change_to_num_treshold - 1 } -fn create_uppercase_words (string_vec: &Vec, pos: usize) -> Vec { +fn create_uppercase_words (string_vec: &Vec, pos: usize, uppercase_ratio: f64) -> Vec { let mut string_vec2 = string_vec.clone(); - let num_uppercase_words = string_vec2[pos..].len() as usize; - + let num_uppercase_words = (uppercase_ratio * string_vec2[pos..].len() as f64).round() as usize; for i in pos..pos+num_uppercase_words{ if string_vec2[i] != ""{ let mut v: Vec = string_vec2[i].chars().collect(); @@ -150,7 +149,8 @@ mod tests { numbers: false, numbers_ratio: 0.05, dictionary_path: config_file.path().to_path_buf(), - uppercase: false + uppercase: false, + uppercase_ratio: 0.45 }; let expected_input = ExpectedInput::new(&config).expect("unable to create expected input"); From f2a279546d9514e95316dc3ed3211e69181cb7e9 Mon Sep 17 00:00:00 2001 From: MercMayhem Date: Thu, 5 Oct 2023 06:47:50 +0530 Subject: [PATCH 7/7] modified string vector in memory instead of cloning in function --- src/expected_input.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/expected_input.rs b/src/expected_input.rs index c7d58ba..4fa3140 100644 --- a/src/expected_input.rs +++ b/src/expected_input.rs @@ -48,8 +48,7 @@ impl ExpectedInput { } if config.uppercase == true { - let uppercase_string_vec = create_uppercase_words(&string_vec, words_start_pos, config.uppercase_ratio); - string_vec = uppercase_string_vec; + create_uppercase_words(&mut string_vec, words_start_pos, config.uppercase_ratio); str_vec = string_vec.iter().map(|s| s.as_str()).collect(); } @@ -90,18 +89,17 @@ fn replace_words_with_numbers( return change_to_num_treshold - 1 } -fn create_uppercase_words (string_vec: &Vec, pos: usize, uppercase_ratio: f64) -> Vec { - let mut string_vec2 = string_vec.clone(); - let num_uppercase_words = (uppercase_ratio * string_vec2[pos..].len() as f64).round() as usize; +fn create_uppercase_words (string_vec: &mut Vec, pos: usize, uppercase_ratio: f64) { + // let mut string_vec2 = string_vec.clone(); + let num_uppercase_words = (uppercase_ratio * string_vec[pos..].len() as f64).round() as usize; for i in pos..pos+num_uppercase_words{ - if string_vec2[i] != ""{ - let mut v: Vec = string_vec2[i].chars().collect(); + if string_vec[i] != ""{ + let mut v: Vec = string_vec[i].chars().collect(); v[0] = v[0].to_uppercase().nth(0).unwrap(); let s: String = v.into_iter().collect(); - string_vec2[i] = s; + string_vec[i] = s; } } - return string_vec2; } /// extracted to trait to create mock with `mockall` crate