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/ukrainian/base.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded ukrainian/base.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Ukrainian 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(),
"Ukrainian base rules should not be empty"
);
assert!(
rules.len() >= 40,
"expected >=40 base rules, got {}",
rules.len()
);
}
#[test]
fn test_unique_yi() {
let rules = base();
let result = rules.apply("ї");
assert!(result.contains("yi"), "ї should become yi, got: {}", result);
}
#[test]
fn test_unique_ye() {
let rules = base();
let result = rules.apply("є");
assert!(
result.contains("ye") || result.contains("je"),
"є should become ye or je, got: {}",
result
);
}
#[test]
fn test_unique_i() {
let rules = base();
let result = rules.apply("і");
assert!(result.contains('i'), "і should become i, got: {}", result);
}
#[test]
fn test_unique_plosive_g() {
let rules = base();
let result = rules.apply("ґ");
assert!(result.contains('ɡ'), "ґ should become g, got: {}", result);
}
#[test]
fn test_ukrainian_h() {
let rules = base();
let result = rules.apply("г");
assert!(
result.contains('h') || result.contains('ɦ'),
"г should become h or ɦ (not g!), got: {}",
result
);
}
#[test]
fn test_ukrainian_y_vowel() {
let rules = base();
let result = rules.apply("и");
assert!(
result.contains('y') || result.contains('ɪ'),
"и should become y or ɪ (like Russian ы), got: {}",
result
);
}
#[test]
fn test_complex_consonants() {
let rules = base();
let result = rules.apply("щ");
assert!(
result.contains("ʃt͡ʃ"),
"щ should become shch, got: {}",
result
);
let result = rules.apply("жа");
assert!(result.contains("ʒ"), "ж should become zh, got: {}", result);
let result = rules.apply("ш");
assert!(result.contains("ʃ"), "ш should become sh, got: {}", result);
}
#[test]
fn test_iotated_vowels() {
let rules = base();
let result = rules.apply("ю");
assert!(result.contains("ju"), "ю should become yu, got: {}", result);
let result = rules.apply("я");
assert!(result.contains("ja"), "я should become ya, got: {}", result);
}
#[test]
fn test_simple_vowels() {
let rules = base();
let result = rules.apply("а");
assert!(result.contains('a'), "а should become a, got: {}", result);
let result = rules.apply("о");
assert!(
result.contains('o') || result.contains('ɔ'),
"о should become o or ɔ, got: {}",
result
);
let result = rules.apply("у");
assert!(result.contains('u'), "у should become u, got: {}", result);
}
#[test]
fn test_word_kyiv() {
let rules = base();
let result = rules.apply("Київ");
assert!(
result.contains('k') && result.contains('y'),
"Київ should contain k and y, got: {}",
result
);
}
#[test]
fn test_word_ukraina() {
let rules = base();
let result = rules.apply("Україна");
assert!(
result.contains('u') && result.contains('k') && result.contains('n'),
"Україна should contain u, k, n, got: {}",
result
);
}
}