use typoglycemia::{typoglycemia, typoglycemia_leet};
use unicode_segmentation::UnicodeSegmentation;
#[cfg(test)]
#[test]
fn it_handles_a_string_slice() {
let s: &str = "slice";
let result = typoglycemia(s);
assert_eq!(result.chars().nth(0), Some('s'));
assert_eq!(result.chars().nth(4), Some('e'));
}
#[test]
fn it_does_not_typoglycemify_short_words() {
let lst = [String::from("a"), String::from("an"), String::from("foo")];
for word in lst.iter() {
let result = typoglycemia(word);
assert_eq!(result, *word);
}
}
#[test]
fn it_does_not_typoglycemify_long_words() {
let lst = [
String::from("glossolabiopharyngeal"),
String::from("constitutionalization"),
String::from("paleoceanographically"),
String::from("electrochromatography"),
String::from("sesquipedalianistically"),
];
for word in lst.iter() {
let result = typoglycemia(word);
assert_eq!(result, *word);
}
}
#[test]
fn it_ignores_beginning_non_ascii() {
let input = "❤️Hi";
let result: String = typoglycemia(input);
let g = result.graphemes(true).collect::<Vec<&str>>();
assert_eq!(result, input.to_string());
assert_eq!(g.get(0), Some(&"❤️"));
}
#[test]
fn it_ignores_ending_non_ascii() {
let input = "Hi❤️";
let result: String = typoglycemia(input);
let g = result.graphemes(true).collect::<Vec<&str>>();
assert_eq!(result, input.to_string());
assert_eq!(g.get(2), Some(&"❤️"));
}
#[test]
fn it_ignores_beginning_and_ending_non_ascii() {
let input = "😈Hi❤️";
let result: String = typoglycemia(input);
let g = result.graphemes(true).collect::<Vec<&str>>();
assert_eq!(result, input.to_string());
assert_eq!(g.get(0), Some(&"😈"));
assert_eq!(g.get(3), Some(&"❤️"));
}
#[test]
fn poe_the_raven_english() {
let input: &'static str = "Once upon a midnight dreary, while I pondered, weak and weary, \
Over many a quaint and curious volume of forgotten lore, \
While I nodded, nearly napping, suddenly there came a tapping, \
As of some one gently rapping, rapping at my chamber door.";
let result: String = typoglycemia(input);
println!("");
println!("{}", "*".repeat(40));
println!("Integration test example ouput: poe_the_raven_english()");
println!("{}", "*".repeat(40));
println!("Original:\n");
println!("{}", input);
println!("\nResult:\n");
println!("{}", result);
assert_eq!(1, 1);
}
#[test]
fn poe_the_raven_french() {
let input = "Jadis, par une minuit lugubre, tandis que je pensais, faible et las, à maints \
grimoires oubliés, et que je hochais la tête, presque endormi, soudain il se fit un heurt, \
comme de quelqu'un qui frapperait doucement, frappant à la porte de ma chambre";
let result = typoglycemia(input);
println!("");
println!("{}", "*".repeat(40));
println!("Integration test example ouput: poe_the_raven_french()");
println!("{}", "*".repeat(40));
println!("Original:\n");
println!("{}", input);
println!("\nResult:\n");
println!("{}", result);
assert_eq!(1, 1);
}
#[test]
fn poe_the_raven_german() {
let input = "Einst in einer Mittnacht schaurig, als ich in entschwundner Kunde wunderlicher Bücher forschte, \
bis mein Geist die Kraft verlor, und mir's trübe ward im Kopfe, kam mir's plötzlich vor, als klopfe, \
jemand leis ans Tor, als klopfe - klopfe jemand sacht ans Tor.";
let result = typoglycemia(input);
println!("");
println!("{}", "*".repeat(40));
println!("Integration test example ouput: poe_the_raven_german()");
println!("{}", "*".repeat(40));
println!("Original:\n");
println!("{}", input);
println!("\nResult:\n");
println!("{}", result);
assert_eq!(1, 1);
}
#[test]
fn gettysburg_address_with_emojis() {
let input = "Four score and seven years ago📜, our 🧓fathers brought \
forth on this continent a new nation, conceived in Liberty, and dedicated to the \
proposition that all men are created equal. 🇺🇸";
let result = typoglycemia(input);
println!("");
println!("{}", "*".repeat(40));
println!("Integration test example ouput: gettysburg_address_with_emojis");
println!("{}", "*".repeat(40));
println!("Original:\n");
println!("{}", input);
println!("\nResult:\n");
println!("{}", result);
assert_eq!(1, 1);
}
#[test]
fn typoglycemia_leet_test() {
let input = "Leet-speak is a mixture of words (mostly computer-related \
jargon) spelled incorrectly intentionally*, usually coming from typographical errors \
(e.g. the becomes t3h). The words of Leet-speak are usually put together to create a \
dialect (small language). This dialect is used in some places for funniness. Leet-speak \
uses numbers, ASCII symbols, and diacritics together to make symbols that look like \
Latin letters.";
let result = typoglycemia_leet(input, 1);
println!("");
println!("{}", "*".repeat(40));
println!("Integration test example ouput: typoglycemia_leet_test()");
println!("{}", "*".repeat(40));
println!("Original:\n");
println!("{}", input);
println!("\nResult:\n");
println!("{}", result);
assert_eq!(1, 1);
}
#[test]
fn digit_nine_is_valid_end_boundary() {
let result = typoglycemia("testing9"); let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.first(), Some(&"t"));
assert_eq!(g.last(), Some(&"9"));
assert_eq!(g.len(), 8);
}
#[test]
fn digit_nine_triggers_starts_with_digit_guard() {
let result = typoglycemia("9eleven");
assert_eq!(result, "9eleven");
}
#[test]
fn latin1_char_is_valid_start_boundary() {
let result = typoglycemia("école"); let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.first(), Some(&"é"));
assert_eq!(g.last(), Some(&"e"));
assert_eq!(g.len(), 5);
}
#[test]
fn latin1_char_is_valid_end_boundary() {
let result = typoglycemia("café"); let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.first(), Some(&"c"));
assert_eq!(g.last(), Some(&"é"));
assert_eq!(g.len(), 4);
}
#[test]
fn latin2_char_is_valid_start_boundary() {
let result = typoglycemia("übersee"); let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.first(), Some(&"ü"));
assert_eq!(g.last(), Some(&"e"));
assert_eq!(g.len(), 7);
}
#[test]
fn misc_char_is_valid_start_boundary() {
let result = typoglycemia("Šimon"); let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.first(), Some(&"Š"));
assert_eq!(g.last(), Some(&"n"));
assert_eq!(g.len(), 5);
}
#[test]
fn non_alpha_prefix_with_latin1_chars_has_correct_boundaries() {
let input = "__àéîõ__"; let result = typoglycemia(input);
let g: Vec<&str> = result.graphemes(true).collect();
assert_eq!(g.get(0), Some(&"_"), "leading '_' at [0] must not move");
assert_eq!(g.get(1), Some(&"_"), "leading '_' at [1] must not move");
assert_eq!(g.get(2), Some(&"à"), "'à' is the protected start boundary");
assert_eq!(g.get(5), Some(&"õ"), "'õ' is the protected end boundary");
assert_eq!(g.get(6), Some(&"_"), "trailing '_' at [6] must not move");
assert_eq!(g.get(7), Some(&"_"), "trailing '_' at [7] must not move");
}
#[test]
fn all_non_ascii_token_is_returned_unchanged() {
let input = "😈❤️🔥🎉😊🌟"; let result = typoglycemia(input);
assert_eq!(result, input);
}
#[test]
fn numeric_prefix_tokens_are_returned_unchanged() {
let cases = [
("12/22/1986", "date"),
("3.1415926", "decimal"),
("9lives", "digit-prefixed word"),
];
for (input, label) in cases.iter() {
assert_eq!(
typoglycemia(input),
*input,
"{} \"{}\" should be returned unchanged",
label,
input
);
}
}
#[test]
fn smart_tick_apostrophe_is_treated_as_regular_apostrophe() {
let input = "doesn\u{2019}t";
let result = typoglycemia(input);
let parts: Vec<&str> = result.split('\'').collect();
assert_eq!(
parts.len(),
2,
"U+2019 should be normalized to ' and produce two parts"
);
assert_eq!(
parts[0].chars().next(),
Some('d'),
"first char of 'doesn' must stay 'd'"
);
assert_eq!(
parts[0].chars().last(),
Some('n'),
"last char of 'doesn' must stay 'n'"
);
assert_eq!(
parts[1], "t",
"'t' is too short to scramble and must be unchanged"
);
}
#[test]
fn smart_tick_word_length_is_preserved() {
let input = "couldn\u{2019}t";
let result = typoglycemia(input);
use unicode_segmentation::UnicodeSegmentation;
let in_len = input.graphemes(true).count();
let out_len = result.graphemes(true).count();
assert_eq!(in_len, out_len, "grapheme count must not change");
}
#[test]
fn left_smart_tick_mid_word_is_not_shuffled() {
let input = "O\u{2018}Brien"; let result = typoglycemia(input);
let parts: Vec<&str> = result.split('\'').collect();
assert_eq!(parts.len(), 2, "U+2018 should be normalized to ' and produce two parts");
assert_eq!(parts[0], "O", "'O' must not move");
assert_eq!(parts[1].chars().next(), Some('B'), "first char of 'Brien' must stay 'B'");
assert_eq!(parts[1].chars().last(), Some('n'), "last char of 'Brien' must stay 'n'");
}