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/arabic/base.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded arabic/base.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Arabic 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(), "Arabic base rules should not be empty");
assert!(
rules.len() > 50,
"expected >50 base rules, got {}",
rules.len()
);
}
#[test]
fn test_basic_consonants() {
let rules = base();
let result = rules.apply("ب");
assert!(result.contains('b'), "ب should become b, got: {}", result);
let result = rules.apply("ت");
assert!(result.contains('t'), "ت should become t, got: {}", result);
let result = rules.apply("س");
assert!(result.contains('s'), "س should become s, got: {}", result);
let result = rules.apply("ك");
assert!(result.contains('k'), "ك should become k, got: {}", result);
}
#[test]
fn test_special_consonants() {
let rules = base();
let result = rules.apply("ش");
assert!(result.contains("ʃ"), "ش should become SH, got: {}", result);
let result = rules.apply("خ");
assert!(result.contains("x"), "خ should become KH, got: {}", result);
let result = rules.apply("ث");
assert!(result.contains("θ"), "ث should become TH, got: {}", result);
let result = rules.apply("غ");
assert!(result.contains("ɣ"), "غ should become GH, got: {}", result);
}
#[test]
fn test_emphatic_consonants() {
let rules = base();
let result = rules.apply("ص");
assert!(
result.contains("sˤ"),
"ص should become sˤ (emphatic s), got: {}",
result
);
let result = rules.apply("ض");
assert!(
result.contains("dˤ"),
"ض should become dˤ (emphatic d), got: {}",
result
);
let result = rules.apply("ط");
assert!(
result.contains("tˤ"),
"ط should become tˤ (emphatic t), got: {}",
result
);
let result = rules.apply("ظ");
assert!(
result.contains("ðˤ"),
"ظ should become ðˤ (emphatic dh), got: {}",
result
);
}
#[test]
fn test_pharyngeal_consonants() {
let rules = base();
let result = rules.apply("ح");
assert!(
result.contains('ħ'),
"ح should become ħ (voiceless pharyngeal), got: {}",
result
);
let result = rules.apply("ع");
assert!(
result.contains('ʕ'),
"ع should become ʕ (voiced pharyngeal), got: {}",
result
);
}
#[test]
fn test_hamza() {
let rules = base();
let result = rules.apply("أ");
assert!(result.contains('a'), "أ should become a, got: {}", result);
let result = rules.apply("إ");
assert!(result.contains('i'), "إ should become i, got: {}", result);
}
#[test]
fn test_special_forms() {
let rules = base();
let result = rules.apply("آ");
assert!(
result.contains("aː"),
"آ should become aː (long a), got: {}",
result
);
let result = rules.apply("ة");
assert!(result.contains('a'), "ة should become a, got: {}", result);
}
#[test]
fn test_numerals() {
let rules = base();
let result = rules.apply("٠");
assert!(result.contains('0'), "٠ should become 0, got: {}", result);
let result = rules.apply("٥");
assert!(result.contains('5'), "٥ should become 5, got: {}", result);
let result = rules.apply("٩");
assert!(result.contains('9'), "٩ should become 9, got: {}", result);
}
#[test]
fn test_word_marhaba() {
let rules = base();
let result = rules.apply("مرحبا");
assert!(
result.contains('m')
&& result.contains('r')
&& result.contains('ħ')
&& result.contains('b'),
"مرحبا should contain m, r, ħ, b, got: {}",
result
);
}
#[test]
fn test_word_salam() {
let rules = base();
let result = rules.apply("سلام");
assert!(
result.contains('s')
&& result.contains('l')
&& result.contains('a')
&& result.contains('m'),
"سلام should contain s, l, a, m, got: {}",
result
);
}
}