use super::{Fold, TABLE, of};
use alloc::string::String;
const CASE_FOLDING: &str = include_str!("../../test-data/CaseFolding.txt");
fn folded(c: char) -> String {
match of(c) {
Fold::Mapped(mapped) => String::from(mapped),
Fold::One(one) => String::from(one),
Fold::Lowercase => c.to_lowercase().collect(),
}
}
#[test]
fn every_published_full_fold_is_the_fold_applied() {
let mut checked = 0usize;
for line in CASE_FOLDING.lines() {
let Some(body) = line.split('#').next() else {
continue;
};
let fields: [&str; 3] = {
let mut parts = body.split(';').map(str::trim);
match (parts.next(), parts.next(), parts.next()) {
(Some(a), Some(b), Some(c)) if !a.is_empty() => [a, b, c],
_ => continue,
}
};
if !matches!(fields[1], "C" | "F") {
continue;
}
let from = char::from_u32(u32::from_str_radix(fields[0], 16).unwrap()).unwrap();
let to: String = fields[2]
.split_whitespace()
.map(|point| char::from_u32(u32::from_str_radix(point, 16).unwrap()).unwrap())
.collect();
assert_eq!(folded(from), to, "{from:?} ({:04X})", u32::from(from));
checked += 1;
}
assert!(checked > 1_000, "{checked}");
}
#[test]
fn a_character_the_file_does_not_fold_folds_to_itself() {
let mut folds: alloc::collections::BTreeSet<char> = alloc::collections::BTreeSet::new();
for line in CASE_FOLDING.lines() {
let Some(body) = line.split('#').next() else {
continue;
};
let mut parts = body.split(';').map(str::trim);
let (Some(point), Some(status)) = (parts.next(), parts.next()) else {
continue;
};
if point.is_empty() || !matches!(status, "C" | "F") {
continue;
}
folds.insert(char::from_u32(u32::from_str_radix(point, 16).unwrap()).unwrap());
}
let mut checked = 0usize;
for point in 0..=0x10_FFFFu32 {
let Some(c) = char::from_u32(point) else {
continue;
};
if folds.contains(&c) {
continue;
}
assert_eq!(folded(c), String::from(c), "{c:?} ({point:04X})");
checked += 1;
}
assert!(checked > 1_000_000, "{checked}");
}
#[test]
fn the_table_is_searchable_and_earns_its_entries() {
assert!(
TABLE.windows(2).all(|pair| pair[0].0 < pair[1].0),
"the table is not sorted"
);
for &(from, to) in &TABLE {
let lowered: String = from.to_lowercase().collect();
assert_ne!(lowered, to, "{from:?}");
}
}
#[test]
fn a_letter_whose_fold_changes_its_length_folds() {
assert_eq!(folded('ß'), "ss");
assert_eq!(folded('ẞ'), "ss");
assert_eq!(folded('ς'), "σ");
assert_eq!(folded('fi'), "fi");
assert_eq!(folded('\u{13F8}'), "\u{13F0}");
assert_eq!(folded('\u{13FD}'), "\u{13F5}");
assert_eq!(folded('\u{AB70}'), "\u{13A0}");
assert_eq!(folded('\u{ABBF}'), "\u{13EF}");
assert_eq!(folded('\u{13F7}'), "\u{13F7}");
assert_eq!(folded('\u{13FE}'), "\u{13FE}");
assert_eq!(folded('и'), "и");
assert_eq!(folded('И'), "и");
}