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/welsh/base.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded welsh/base.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Welsh 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(), "Welsh base rules should not be empty");
assert!(
rules.len() >= 40,
"expected >=40 base rules, got {}",
rules.len()
);
}
#[test]
fn test_ll_digraph() {
let rules = base();
let result = rules.apply("ll");
assert!(
result.contains('ɬ') || result.contains('l') || result.contains("ʎ"),
"ll should become ɬ (or l via soft mutation), got: {}",
result
);
}
#[test]
fn test_dd_digraph() {
let rules = base();
let result = rules.apply("dd");
assert!(result.contains("ð"), "dd should become DH, got: {}", result);
}
#[test]
fn test_ff_digraph() {
let rules = base();
let result = rules.apply("ff");
assert!(
result.contains('v'),
"ff should become v (via F→v rule), got: {}",
result
);
}
#[test]
fn test_ch_digraph() {
let rules = base();
let result = rules.apply("ch");
assert!(
result.contains('x') || result.contains("t͡ʃ"),
"ch should become x (velar fricative), got: {}",
result
);
}
#[test]
fn test_f_to_v() {
let rules = base();
let result = rules.apply("f");
assert!(
result.contains('v'),
"f should become v in Welsh, got: {}",
result
);
}
#[test]
fn test_c_to_k() {
let rules = base();
let result = rules.apply("c");
assert!(result.contains('k'), "c should become k, got: {}", result);
}
#[test]
fn test_w_vowel() {
let rules = base();
let result = rules.apply("w");
assert!(result.contains('w'), "w should remain w, got: {}", result);
}
#[test]
fn test_y_vowel() {
let rules = base();
let result = rules.apply("y");
assert!(result.contains('y'), "y should remain y, got: {}", result);
}
#[test]
fn test_circumflex_a() {
let rules = base();
let result = rules.apply("â");
assert!(result.contains('a'), "â should become a, got: {}", result);
}
#[test]
fn test_circumflex_w() {
let rules = base();
let result = rules.apply("ŵ");
assert!(result.contains('w'), "ŵ should become w, got: {}", result);
}
#[test]
fn test_word_cymru() {
let rules = base();
let result = rules.apply("c");
assert!(result.contains('k'), "c should become k, got: {}", result);
let result_y = rules.apply("y");
assert!(
result_y.to_lowercase().contains('y'),
"y should remain y, got: {}",
result_y
);
}
#[test]
fn test_word_llanfair() {
let rules = base();
let result = rules.apply_full("llanfair");
assert!(
result.contains('ɬ') || result.contains('l') || result.contains("ʎ"),
"llanfair should contain ɬ (or l via soft mutation), got: {}",
result
);
}
}