use alloc::string::String;
#[must_use]
pub fn rot13(s: &str) -> String {
s.chars()
.map(|c| match c {
'A'..='Z' => rotate(c, b'A'),
'a'..='z' => rotate(c, b'a'),
other => other,
})
.collect()
}
fn rotate(c: char, base: u8) -> char {
let offset = (c as u8).wrapping_sub(base);
char::from(base + (offset + 13) % 26)
}
#[cfg(test)]
mod tests {
use super::rot13;
#[test]
fn rotates_both_cases() {
assert_eq!(rot13("Hello, World!"), "Uryyb, Jbeyq!");
}
#[test]
fn is_its_own_inverse() {
let plain = "The quick brown fox jumps over the lazy dog.";
assert_eq!(rot13(&rot13(plain)), plain);
}
#[test]
fn wraps_at_the_alphabet_boundary() {
assert_eq!(rot13("ABMNYZ"), "NOZALM");
assert_eq!(rot13("abmnyz"), "nozalm");
}
#[test]
fn leaves_non_letters_alone() {
assert_eq!(rot13("0123456789"), "0123456789");
assert_eq!(rot13(" \t\n{}[]|\\/@#"), " \t\n{}[]|\\/@#");
}
#[test]
fn leaves_non_ascii_alone() {
assert_eq!(rot13("café 日本語 🦀"), "pnsé 日本語 🦀");
}
#[test]
fn empty_input_yields_empty_output() {
assert_eq!(rot13(""), "");
}
#[test]
fn decodes_a_real_userassist_value_name() {
assert_eq!(
rot13(r"{P:\Jvaqbjf\flfgrz32\pzq.rkr"),
r"{C:\Windows\system32\cmd.exe"
);
}
}