Skip to content

Commit

Permalink
Separate functions and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dani-garcia committed Oct 9, 2023
1 parent df09326 commit e4729ac
Showing 1 changed file with 46 additions and 16 deletions.
62 changes: 46 additions & 16 deletions crates/bitwarden/src/tool/generators/passphrase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const DEFAULT_PASSPHRASE_NUM_WORDS: u8 = 3;
const DEFAULT_PASSPHRASE_SEPARATOR: char = ' ';

pub(super) fn passphrase(input: PassphraseGeneratorRequest) -> Result<String> {
let words = input.num_words.unwrap_or(DEFAULT_PASSPHRASE_NUM_WORDS);
let num_words = input.num_words.unwrap_or(DEFAULT_PASSPHRASE_NUM_WORDS);
let separator = input
.word_separator
.and_then(|s| s.chars().next())
Expand All @@ -30,19 +30,13 @@ pub(super) fn passphrase(input: PassphraseGeneratorRequest) -> Result<String> {

let mut rand = rand::thread_rng();

let mut passphrase_words = gen_words(&mut rand, words);
let mut passphrase_words = gen_words(&mut rand, num_words);
if include_number {
let number_idx = rand.gen_range(0..words as usize);
passphrase_words[number_idx].push_str(&rand.gen_range(0..=9).to_string());
include_number_in_words(&mut rand, &mut passphrase_words);
}

if capitalize {
passphrase_words = passphrase_words
.iter()
.map(|w| capitalize_first_letter(w))
.collect();
capitalize_words(&mut passphrase_words);
}

Ok(passphrase_words.join(&separator.to_string()))
}

Expand All @@ -57,6 +51,17 @@ fn gen_words(mut rng: impl RngCore, num_words: u8) -> Vec<String> {
.collect()
}

fn include_number_in_words(mut rng: impl RngCore, words: &mut [String]) {
let number_idx = rng.gen_range(0..words.len());
words[number_idx].push_str(&rng.gen_range(0..=9).to_string());
}

fn capitalize_words(words: &mut [String]) {
words
.iter_mut()
.for_each(|w| *w = capitalize_first_letter(w));
}

fn capitalize_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
Expand All @@ -67,16 +72,41 @@ fn capitalize_first_letter(s: &str) -> String {

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_capitalize() {
assert_eq!(super::capitalize_first_letter("hello"), "Hello");
assert_eq!(super::capitalize_first_letter("1ello"), "1ello");
assert_eq!(super::capitalize_first_letter("Hello"), "Hello");
assert_eq!(super::capitalize_first_letter("h"), "H");
assert_eq!(super::capitalize_first_letter(""), "");
assert_eq!(capitalize_first_letter("hello"), "Hello");
assert_eq!(capitalize_first_letter("1ello"), "1ello");
assert_eq!(capitalize_first_letter("Hello"), "Hello");
assert_eq!(capitalize_first_letter("h"), "H");
assert_eq!(capitalize_first_letter(""), "");

// Also supports non-ascii, though the EFF list doesn't have any
assert_eq!(super::capitalize_first_letter("áéíóú"), "Áéíóú");
assert_eq!(capitalize_first_letter("áéíóú"), "Áéíóú");
}

#[test]
fn test_capitalize_words() {
let mut words = vec!["hello".to_string(), "world".to_string()];
capitalize_words(&mut words);
assert_eq!(words, &["Hello", "World"]);
}

#[test]
fn test_include_number() {
let mut rng = rand::thread_rng();

fn count_numbers(words: &[String]) -> usize {
words
.iter()
.map(|w| w.chars().filter(|c| c.is_numeric()).count())
.sum()
}

let mut words = vec!["hello".to_string(), "world".to_string()];
assert_eq!(count_numbers(&words), 0);
include_number_in_words(&mut rng, &mut words);
assert_eq!(count_numbers(&words), 1);
}
}

0 comments on commit e4729ac

Please sign in to comment.