use crate::common;
pub fn random_string(size: usize, charset: &[char]) -> String {
if size == 0 {
panic!("common::random_string: Size parameter must be greater than 0");
}
if charset.is_empty() {
panic!("common::random_string: Charset parameter must not be empty");
}
let charset_len = charset.len();
let letter_id_bits = common::ceil_log2(charset_len);
let letter_id_mask = (1 << letter_id_bits) - 1;
let letter_id_max = 63 / letter_id_bits;
let mut result = String::with_capacity(size);
let mut bits_remaining = 0;
let mut cache: u64 = 0;
for _ in 0..size {
if bits_remaining == 0 {
cache = common::random_u64();
bits_remaining = letter_id_max;
}
let idx = (cache & letter_id_mask as u64) as usize;
cache >>= letter_id_bits;
bits_remaining -= 1;
if idx < charset_len {
result.push(charset[idx]);
} else {
let new_cache = common::random_u64();
let new_idx = (new_cache & letter_id_mask as u64) as usize;
if new_idx < charset_len {
result.push(charset[new_idx]);
} else {
result.push(charset[0]);
}
}
}
result
}
#[cfg(test)]
mod tests {
use crate::common;
use super::*;
#[test]
fn test_random_string_length() {
let charset = common::ALPHANUMERIC_CHARSET;
let size = 12;
let random_str = random_string(size, charset);
assert_eq!(random_str.len(), size);
}
#[test]
fn test_random_string_characters() {
let charset = common::ALPHANUMERIC_CHARSET;
let size = 20;
let random_str = random_string(size, charset);
for c in random_str.chars() {
assert!(charset.contains(&c));
}
}
#[test]
#[should_panic(expected = "common::random_string: Size parameter must be greater than 0")]
fn test_random_string_size_zero() {
let charset = common::ALPHANUMERIC_CHARSET;
let _ = random_string(0, charset);
}
#[test]
#[should_panic(expected = "common::random_string: Charset parameter must not be empty")]
fn test_random_string_empty_charset() {
let charset: &[char] = &[];
let _ = random_string(10, charset);
}
#[test]
fn test_random_string_variety() {
let charset = common::ALPHANUMERIC_CHARSET;
let size = 15;
let random_str1 = random_string(size, charset);
let random_str2 = random_string(size, charset);
assert_ne!(
random_str1, random_str2,
"Two random strings should not be identical"
);
}
#[test]
fn test_random_string_with_special_characters() {
let charset = common::SPECIAL_CHARSET;
let size = 10;
let random_str = random_string(size, charset);
for c in random_str.chars() {
assert!(charset.contains(&c));
}
}
#[test]
fn test_random_string_full_charset() {
let charset = common::ALL_CHARSET;
let size = 25;
let random_str = random_string(size, charset);
for c in random_str.chars() {
assert!(charset.contains(&c));
}
}
}