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/urdu/base.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded urdu/base.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Urdu 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(), "Urdu base rules should not be empty");
assert!(
rules.len() > 60,
"expected >60 base rules, got {}",
rules.len()
);
}
#[test]
fn test_arabic_inherited_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_persian_additions() {
let rules = base();
let result = rules.apply("پ");
assert!(result.contains('p'), "پ should become p, got: {}", result);
let result = rules.apply("چ");
assert!(
result.contains('C') || result.contains("t͡ʃ"),
"چ should become C or t͡ʃ, got: {}",
result
);
let result = rules.apply("گ");
assert!(result.contains('ɡ'), "گ should become g, got: {}", result);
let result = rules.apply("ژ");
assert!(result.contains("ʒ"), "ژ should become ʒ, got: {}", result);
}
#[test]
fn test_retroflex_consonants() {
let rules = base();
let result = rules.apply("ٹ");
assert!(result.contains("ʈ"), "ٹ should become ʈ, got: {}", result);
let result = rules.apply("ڈ");
assert!(result.contains("ɖ"), "ڈ should become ɖ, got: {}", result);
let result = rules.apply("ڑ");
assert!(
result.contains("r") || result.contains("ɽ"),
"ڑ should become r or ɽ, got: {}",
result
);
}
#[test]
fn test_special_letters() {
let rules = base();
let result = rules.apply("ں");
assert!(
result.contains('ŋ') || result.contains('\u{0303}') || result.contains('N'),
"ں should become nasalization marker, got: {}",
result
);
let result = rules.apply("ے");
assert!(result.contains('e'), "ے should become e, got: {}", result);
let result = rules.apply("ہ");
assert!(result.contains('h'), "ہ should become h, got: {}", result);
}
#[test]
fn test_aspirated_consonants() {
let rules = base();
let result = rules.apply("بھ");
assert!(
result.contains("bh"),
"بھ should become bh, got: {}",
result
);
let result = rules.apply("پھ");
assert!(
result.contains("ph"),
"پھ should become ph, got: {}",
result
);
let result = rules.apply("کھ");
assert!(
result.contains("kh") || result.contains("x"),
"کھ should become kh or x, got: {}",
result
);
let result = rules.apply("گھ");
assert!(
result.contains("gh") || result.contains("ɣ") || result.contains("ɡh"),
"گھ should become gh, ɡh, or ɣ, 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('ʃ') || result.contains("sˤ") || result.contains('S'),
"ص should become sˤ or S, got: {}",
result
);
let result = rules.apply("ض");
assert!(
result.contains('D') || result.contains("dˤ"),
"ض should become dˤ or D, got: {}",
result
);
let result = rules.apply("ط");
assert!(
result.contains('T') || result.contains("tˤ"),
"ط should become tˤ or T, got: {}",
result
);
let result = rules.apply("ظ");
assert!(
result.contains('Z') || result.contains("ðˤ"),
"ظ should become ðˤ or Z, got: {}",
result
);
}
#[test]
fn test_pharyngeal_consonants() {
let rules = base();
let result = rules.apply("ح");
assert!(
result.contains('H') || result.contains('ħ'),
"ح should become H or ħ, got: {}",
result
);
let result = rules.apply("ع");
assert!(
result.contains('E') || result.contains('ʕ'),
"ع should become E or ʕ, 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_pakistan() {
let rules = base();
let result = rules.apply("پاکستان");
assert!(
result.contains('p') && result.contains('k') && result.contains('s'),
"پاکستان should contain p, k, s, got: {}",
result
);
}
#[test]
fn test_word_urdu() {
let rules = base();
let result = rules.apply("اردو");
assert!(
result.contains('a') && result.contains('r') && result.contains('d'),
"اردو should contain a, r, d, got: {}",
result
);
}
}