pub fn alternating_case(payload: &str, start_upper: bool) -> String {
let mut upper = start_upper;
payload
.chars()
.map(|ch| {
if ch.is_ascii_alphabetic() {
let result = if upper {
ch.to_ascii_uppercase()
} else {
ch.to_ascii_lowercase()
};
upper = !upper;
result
} else {
ch
}
})
.collect()
}
pub fn case_alternate(payload: &str) -> String {
alternating_case(payload, true)
}
pub fn random_case_alternate(payload: &str) -> String {
payload
.chars()
.map(|ch| {
if ch.is_ascii_alphabetic() {
if rand::random::<bool>() {
ch.to_ascii_uppercase()
} else {
ch.to_ascii_lowercase()
}
} else {
ch
}
})
.collect()
}
pub fn lowercase(payload: &str) -> String {
payload.to_ascii_lowercase()
}
pub fn uppercase(payload: &str) -> String {
payload.to_ascii_uppercase()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn case_alternate_basic() {
assert_eq!(case_alternate("select"), "SeLeCt");
}
#[test]
fn random_case_non_deterministic() {
let a = random_case_alternate("SELECT");
let b = random_case_alternate("SELECT");
assert_eq!(a.to_ascii_lowercase(), "select");
assert_eq!(b.to_ascii_lowercase(), "select");
}
#[test]
fn lowercase_basic() {
assert_eq!(lowercase("SeLeCt"), "select");
}
#[test]
fn uppercase_basic() {
assert_eq!(uppercase("SeLeCt"), "SELECT");
}
#[test]
fn case_alternate_idempotent_after_first() {
let once = case_alternate("select");
let twice = case_alternate(&once);
assert_eq!(
once, twice,
"case_alternate must be idempotent after first application"
);
assert_eq!(once, "SeLeCt");
}
#[test]
fn random_case_not_idempotent() {
let a = random_case_alternate("SELECT");
let b = random_case_alternate(&a);
assert_ne!(
a, b,
"random_case should re-randomise on second application"
);
}
}