use crate::phonetic::llev::RuleSetChar;
use std::sync::OnceLock;
pub fn base() -> &'static RuleSetChar {
static RULESET: OnceLock<RuleSetChar> = OnceLock::new();
RULESET.get_or_init(|| {
let content = include_str!("../../../data/rules/polish/base.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded polish/base.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Polish base rules - this is a bug in liblevenshtein")
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_base_loads() {
let rules = base();
assert!(!rules.is_empty(), "Polish base rules should not be empty");
assert!(
rules.len() > 25,
"expected >25 base rules, got {}",
rules.len()
);
}
#[test]
fn test_digraphs() {
let rules = base();
let result = rules.apply("sz");
assert!(
result.contains('ʃ') || result.contains('S'),
"sz should become ʃ, got: {}",
result
);
let result = rules.apply("cz");
assert!(
result.contains("t͡ʃ") || result.contains('C'),
"cz should become t͡ʃ, got: {}",
result
);
let result = rules.apply("rz");
assert!(
result.contains('ʃ') || result.contains('ʒ') || result.contains('Z'),
"rz should become ʃ/ʒ, got: {}",
result
);
let result = rules.apply("ch");
assert!(
result.contains('x') || result.contains('X'),
"ch should become x, got: {}",
result
);
}
#[test]
fn test_nasal_vowels() {
let rules = base();
let result = rules.apply("ą");
assert!(
result.contains('ɔ') || result.contains("on"),
"ą should become ɔ̃ or on, got: {}",
result
);
let result = rules.apply("ę");
assert!(
result.contains('ɛ') || result.contains("en"),
"ę should become ɛ̃ or en, got: {}",
result
);
}
#[test]
fn test_special_letters() {
let rules = base();
let result = rules.apply("ć");
assert!(
result.contains("tɕ") || result.contains('C'),
"ć should become tɕ, got: {}",
result
);
let result = rules.apply("ś");
assert!(
result.contains('ɕ') || result.contains('ʃ'),
"ś should become ɕ, got: {}",
result
);
let result = rules.apply("ź");
assert!(
result.contains('ɕ') || result.contains('ʑ') || result.contains('Z'),
"ź should become ɕ/ʑ, got: {}",
result
);
let result = rules.apply("ż");
assert!(
result.contains('ʃ') || result.contains('ʒ') || result.contains('Z'),
"ż should become ʃ/ʒ, got: {}",
result
);
let result = rules.apply("ł");
assert!(
result.contains('w') || result.contains('W') || result.contains('f'),
"ł should become w/f, got: {}",
result
);
let result = rules.apply("ó");
assert!(result.contains('u'), "ó should become u, got: {}", result);
let result = rules.apply("ń");
assert!(
result.contains('ɲ') || result.contains('ŋ') || result.contains('N'),
"ń should become ɲ, got: {}",
result
);
}
#[test]
fn test_basic_consonants() {
let rules = base();
let result = rules.apply("c");
assert!(result.contains("t͡s"), "c should become t͡s, got: {}", result);
let result = rules.apply("j");
assert!(
result.contains('j') || result.contains('y'),
"j should become j or y, got: {}",
result
);
let result = rules.apply("w");
assert!(
result.contains('v') || result.contains('f'),
"w should become v/f, got: {}",
result
);
let result = rules.apply("h");
assert!(
result.contains('x') || result.contains('X'),
"h should become x, got: {}",
result
);
}
#[test]
fn test_word_warszawa() {
let rules = base();
let result = rules.apply("Warszawa");
assert!(
result.contains('v')
&& (result.contains('ʃ') || result.contains('S'))
&& result.contains('a'),
"Warszawa should normalize properly, got: {}",
result
);
}
#[test]
fn test_word_lodz() {
let rules = base();
let result = rules.apply("Łódź");
assert!(
(result.contains('w') || result.contains('W')) && result.contains('u'),
"Łódź should have w (from Ł) and u (from ó), got: {}",
result
);
}
#[test]
fn test_word_szczecin() {
let rules = base();
let result = rules.apply("Szczecin");
assert!(
(result.contains('ʃ') || result.contains('S'))
&& (result.contains("t͡ʃ") || result.contains('C')),
"Szczecin should have ʃ and t͡ʃ markers, got: {}",
result
);
}
}