use super::*;
#[test]
fn test_phone_pattern_char() {
let p = PhonePattern::Char('a');
assert!(p.is_char());
assert!(!p.is_digraph());
assert_eq!(p.as_char(), Some('a'));
assert_eq!(p.as_digraph(), None);
assert!(p.matches_char('a'));
assert!(!p.matches_char('b'));
}
#[test]
fn test_phone_pattern_digraph() {
let p = PhonePattern::Digraph('s', 'h');
assert!(!p.is_char());
assert!(p.is_digraph());
assert_eq!(p.as_char(), None);
assert_eq!(p.as_digraph(), Some(('s', 'h')));
assert!(p.matches_digraph('s', 'h'));
assert!(!p.matches_digraph('s', 'z'));
}
#[test]
fn test_get_named_class_vowel() {
let vowels = get_named_class("vowel").expect("vowel class should exist");
assert!(!vowels.patterns.is_empty());
assert!(vowels.patterns.contains(&PhonePattern::Char('a')));
assert!(vowels.patterns.contains(&PhonePattern::Char('e')));
assert!(vowels.patterns.contains(&PhonePattern::Char('i')));
assert!(vowels.patterns.contains(&PhonePattern::Char('o')));
assert!(vowels.patterns.contains(&PhonePattern::Char('u')));
assert!(vowels.patterns.contains(&PhonePattern::Char('ə')));
assert!(vowels.patterns.contains(&PhonePattern::Char('ɪ')));
}
#[test]
fn test_case_insensitive_lookup() {
let v1 = get_named_class("vowel").expect("lowercase");
let v2 = get_named_class("VOWEL").expect("uppercase");
let v3 = get_named_class("Vowel").expect("mixed case");
assert_eq!(v1.patterns.len(), v2.patterns.len());
assert_eq!(v2.patterns.len(), v3.patterns.len());
}
#[test]
fn test_full_word_alias() {
let s1 = get_named_class("stop").expect("full name");
let s2 = get_named_class("plosive").expect("alias");
assert_eq!(s1.patterns.len(), s2.patterns.len());
let g1 = get_named_class("glide").expect("full name");
let g2 = get_named_class("semivowel").expect("alias");
assert_eq!(g1.patterns.len(), g2.patterns.len());
}
#[test]
fn test_fricative_has_digraphs() {
let fric = get_named_class("fricative").expect("fricative class");
assert!(fric.patterns.contains(&PhonePattern::Char('ʃ')));
assert!(fric.patterns.contains(&PhonePattern::Char('θ')));
assert!(fric.patterns.contains(&PhonePattern::Digraph('s', 'h')));
assert!(fric.patterns.contains(&PhonePattern::Digraph('t', 'h')));
}
#[test]
fn test_nasal_has_ng_digraph() {
let nasal = get_named_class("nasal").expect("nasal class");
assert!(nasal.patterns.contains(&PhonePattern::Char('ŋ')));
assert!(nasal.patterns.contains(&PhonePattern::Digraph('n', 'g')));
}
#[test]
fn test_is_builtin_class() {
assert!(is_builtin_class("vowel"));
assert!(is_builtin_class("VOWEL"));
assert!(is_builtin_class("plosive")); assert!(is_builtin_class("fricative"));
assert!(is_builtin_class("alpha"));
assert!(!is_builtin_class("V"));
assert!(!is_builtin_class("C"));
assert!(!is_builtin_class("not_a_class"));
assert!(!is_builtin_class("CUSTOM"));
}
#[test]
fn test_get_chars_only() {
let chars = get_chars_only("fricative").expect("fricative exists");
assert!(chars.contains(&'f'));
assert!(chars.contains(&'ʃ'));
}
#[test]
fn test_get_digraphs_only() {
let digraphs = get_digraphs_only("fricative").expect("fricative exists");
assert!(digraphs.contains(&('s', 'h')));
assert!(digraphs.contains(&('t', 'h')));
}
#[test]
fn test_posix_classes() {
let alpha = get_named_class("alpha").expect("alpha");
let digit = get_named_class("digit").expect("digit");
let alnum = get_named_class("alnum").expect("alnum");
assert!(alpha.patterns.contains(&PhonePattern::Char('a')));
assert!(alpha.patterns.contains(&PhonePattern::Char('Z')));
assert!(!alpha.patterns.contains(&PhonePattern::Char('0')));
assert!(digit.patterns.contains(&PhonePattern::Char('0')));
assert!(digit.patterns.contains(&PhonePattern::Char('9')));
assert!(!digit.patterns.contains(&PhonePattern::Char('a')));
assert!(alnum.patterns.contains(&PhonePattern::Char('a')));
assert!(alnum.patterns.contains(&PhonePattern::Char('0')));
}
#[test]
fn test_ascii_vs_ipa_subsets() {
let ascii_v = get_named_class("ascii_vowel").expect("ascii_vowel");
let ipa_v = get_named_class("ipa_vowel").expect("ipa_vowel");
assert!(ascii_v.patterns.contains(&PhonePattern::Char('a')));
assert!(!ascii_v.patterns.contains(&PhonePattern::Char('ə')));
assert!(ipa_v.patterns.contains(&PhonePattern::Char('ə')));
assert!(!ipa_v.patterns.contains(&PhonePattern::Char('a')));
}
#[test]
fn test_all_builtin_class_names() {
let names = all_builtin_class_names();
assert!(names.contains(&"vowel"));
assert!(names.contains(&"consonant"));
assert!(names.contains(&"alpha"));
assert!(names.contains(&"fricative"));
}
#[test]
fn test_get_all_phonetic_chars() {
let all = get_all_phonetic_chars();
assert!(all.contains(&'a'));
assert!(all.contains(&'e'));
assert!(all.contains(&'ə'));
assert!(all.contains(&'b'));
assert!(all.contains(&'p'));
assert!(all.contains(&'ŋ'));
assert!(!all.contains(&'0'));
assert!(!all.contains(&'.'));
}
#[test]
fn test_intersect_char_sets_voiced_stop() {
let voiced = get_chars_only("voiced").expect("voiced class");
let stop = get_chars_only("stop").expect("stop class");
let result = intersect_char_sets(&[voiced, stop]);
assert!(result.contains(&'b'));
assert!(result.contains(&'d'));
assert!(result.contains(&'g'));
assert!(!result.contains(&'p'));
assert!(!result.contains(&'t'));
assert!(!result.contains(&'k'));
assert!(!result.contains(&'v')); assert!(!result.contains(&'z')); }
#[test]
fn test_intersect_char_sets_empty() {
let result = intersect_char_sets(&[]);
assert!(result.is_empty());
}
#[test]
fn test_intersect_char_sets_single() {
let stop = get_chars_only("stop").expect("stop class");
let result = intersect_char_sets(&[stop.clone()]);
assert_eq!(result.len(), stop.len());
for c in &stop {
assert!(result.contains(c));
}
}
#[test]
fn test_intersect_char_sets_three_features() {
let high = get_chars_only("high_vowel").expect("high_vowel class");
let front = get_chars_only("front_vowel").expect("front_vowel class");
let vowel = get_chars_only("vowel").expect("vowel class");
let result = intersect_char_sets(&[high, front, vowel]);
assert!(result.contains(&'i'));
assert!(result.contains(&'I'));
assert!(!result.contains(&'a'));
assert!(!result.contains(&'u'));
}
#[test]
fn test_negate_char_set_nasal() {
let nasal = get_chars_only("nasal").expect("nasal class");
let not_nasal = negate_char_set(&nasal);
assert!(!not_nasal.contains(&'m'));
assert!(!not_nasal.contains(&'n'));
assert!(!not_nasal.contains(&'ŋ'));
assert!(not_nasal.contains(&'p'));
assert!(not_nasal.contains(&'b'));
assert!(not_nasal.contains(&'t'));
assert!(not_nasal.contains(&'a'));
assert!(not_nasal.contains(&'e'));
}
#[test]
fn test_negate_char_set_empty() {
let not_empty = negate_char_set(&[]);
let all = get_all_phonetic_chars();
assert_eq!(not_empty.len(), all.len());
}
#[test]
fn test_intersect_with_negation() {
let nasal = get_chars_only("nasal").expect("nasal class");
let not_nasal = negate_char_set(&nasal);
let stop = get_chars_only("stop").expect("stop class");
let result = intersect_char_sets(&[not_nasal, stop]);
assert!(result.contains(&'p'));
assert!(result.contains(&'t'));
assert!(result.contains(&'k'));
assert!(result.contains(&'b'));
assert!(result.contains(&'d'));
assert!(result.contains(&'g'));
assert!(!result.contains(&'m'));
assert!(!result.contains(&'n'));
assert!(!result.contains(&'f'));
assert!(!result.contains(&'s'));
}
#[test]
fn test_retroflex_class() {
let retroflex = get_named_class("retroflex").expect("retroflex class");
assert!(retroflex.patterns.contains(&PhonePattern::Char('ʈ'))); assert!(retroflex.patterns.contains(&PhonePattern::Char('ɖ'))); assert!(retroflex.patterns.contains(&PhonePattern::Char('ɻ'))); assert!(retroflex.patterns.contains(&PhonePattern::Char('ʂ'))); }
#[test]
fn test_uvular_class() {
let uvular = get_named_class("uvular").expect("uvular class");
assert!(uvular.patterns.contains(&PhonePattern::Char('ʁ'))); assert!(uvular.patterns.contains(&PhonePattern::Char('ɢ'))); assert!(uvular.patterns.contains(&PhonePattern::Char('ʀ'))); }
#[test]
fn test_click_class() {
let click = get_named_class("click").expect("click class");
assert!(click.patterns.contains(&PhonePattern::Char('ʘ'))); assert!(click.patterns.contains(&PhonePattern::Char('ǀ'))); assert!(click.patterns.contains(&PhonePattern::Char('ǃ'))); }
#[test]
fn test_implosive_class() {
let implosive = get_named_class("implosive").expect("implosive class");
assert!(implosive.patterns.contains(&PhonePattern::Char('ɓ'))); assert!(implosive.patterns.contains(&PhonePattern::Char('ɗ'))); assert!(implosive.patterns.contains(&PhonePattern::Char('ɠ'))); }
#[test]
fn test_front_rounded_class() {
let front_rounded = get_named_class("front_rounded").expect("front_rounded class");
assert!(front_rounded.patterns.contains(&PhonePattern::Char('y'))); assert!(front_rounded.patterns.contains(&PhonePattern::Char('ø'))); assert!(front_rounded.patterns.contains(&PhonePattern::Char('œ'))); }
#[test]
fn test_stress_class() {
let stress = get_named_class("stress").expect("stress class");
assert!(stress.patterns.contains(&PhonePattern::Char('ˈ'))); assert!(stress.patterns.contains(&PhonePattern::Char('ˌ'))); }
#[test]
fn test_length_class() {
let length = get_named_class("length").expect("length class");
assert!(length.patterns.contains(&PhonePattern::Char('ː'))); assert!(length.patterns.contains(&PhonePattern::Char('ˑ'))); }
#[test]
fn test_tone_class() {
let tone = get_named_class("tone").expect("tone class");
assert!(tone.patterns.contains(&PhonePattern::Char('˥'))); assert!(tone.patterns.contains(&PhonePattern::Char('˩'))); }
#[test]
fn test_diacritic_class() {
let diacritic = get_named_class("diacritic").expect("diacritic class");
assert!(diacritic.patterns.contains(&PhonePattern::Char('\u{0325}'))); assert!(diacritic.patterns.contains(&PhonePattern::Char('\u{0303}'))); assert!(diacritic.patterns.contains(&PhonePattern::Char('\u{02B0}'))); }
#[test]
fn test_ipa_affricate_class() {
let affricate = get_named_class("ipa_affricate").expect("ipa_affricate class");
assert!(affricate.patterns.contains(&PhonePattern::Char('ʧ'))); assert!(affricate.patterns.contains(&PhonePattern::Char('ʤ'))); assert!(affricate.patterns.contains(&PhonePattern::Char('ʦ'))); }
#[test]
fn test_comprehensive_ipa_class() {
let ipa = get_named_class("ipa").expect("ipa class");
assert!(ipa.patterns.contains(&PhonePattern::Char('ə'))); assert!(ipa.patterns.contains(&PhonePattern::Char('ɚ')));
assert!(ipa.patterns.contains(&PhonePattern::Char('ŋ'))); assert!(ipa.patterns.contains(&PhonePattern::Char('ʃ'))); assert!(ipa.patterns.contains(&PhonePattern::Char('ʁ')));
assert!(ipa.patterns.contains(&PhonePattern::Char('ǃ')));
assert!(ipa.patterns.contains(&PhonePattern::Char('ɓ')));
assert!(ipa.patterns.contains(&PhonePattern::Char('ˈ'))); assert!(ipa.patterns.contains(&PhonePattern::Char('ː'))); }
#[test]
fn test_tap_flap_alias() {
let tap = get_named_class("tap").expect("tap class");
let flap = get_named_class("flap").expect("flap alias");
assert_eq!(tap.patterns.len(), flap.patterns.len());
assert!(tap.patterns.contains(&PhonePattern::Char('ɾ'))); }
#[test]
fn test_place_of_articulation_classes() {
let bilabial = get_named_class("bilabial").expect("bilabial");
let alveolar = get_named_class("alveolar").expect("alveolar");
let velar = get_named_class("velar").expect("velar");
let palatal = get_named_class("palatal").expect("palatal");
assert!(bilabial.patterns.contains(&PhonePattern::Char('p')));
assert!(bilabial.patterns.contains(&PhonePattern::Char('m')));
assert!(alveolar.patterns.contains(&PhonePattern::Char('t')));
assert!(alveolar.patterns.contains(&PhonePattern::Char('n')));
assert!(velar.patterns.contains(&PhonePattern::Char('k')));
assert!(velar.patterns.contains(&PhonePattern::Char('ŋ')));
assert!(palatal.patterns.contains(&PhonePattern::Char('ç'))); assert!(palatal.patterns.contains(&PhonePattern::Char('j'))); }
#[test]
fn test_manner_of_articulation_classes() {
let trill = get_named_class("trill").expect("trill");
let approximant = get_named_class("approximant").expect("approximant");
let lateral = get_named_class("lateral").expect("lateral");
assert!(trill.patterns.contains(&PhonePattern::Char('r')));
assert!(trill.patterns.contains(&PhonePattern::Char('ʀ')));
assert!(approximant.patterns.contains(&PhonePattern::Char('ɹ'))); assert!(approximant.patterns.contains(&PhonePattern::Char('j')));
assert!(lateral.patterns.contains(&PhonePattern::Char('l')));
assert!(lateral.patterns.contains(&PhonePattern::Char('ɬ'))); }
#[test]
fn test_prenasalized_click_class() {
let prenasalized =
get_named_class("prenasalized_click").expect("prenasalized_click class should exist");
let nasal_click = get_named_class("nasal_click").expect("nasal_click alias should work");
assert_eq!(prenasalized.patterns.len(), nasal_click.patterns.len());
assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ǀ', 'ʰ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ǃ', 'ʰ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ǁ', 'ʰ')));
assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ɡ', 'ǀ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ɡ', 'ǃ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Trigraph('ŋ', 'ɡ', 'ǁ')));
assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǀ', 'ʰ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǃ', 'ʰ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǁ', 'ʰ')));
assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǀ', 'ʷ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǃ', 'ʷ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Tetragraph('ŋ', 'ɡ', 'ǁ', 'ʷ')));
assert!(prenasalized
.patterns
.contains(&PhonePattern::Pentagraph('ŋ', 'ɡ', 'ǀ', 'ʰ', 'ʷ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Pentagraph('ŋ', 'ɡ', 'ǃ', 'ʰ', 'ʷ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Pentagraph('ŋ', 'ɡ', 'ǁ', 'ʰ', 'ʷ')));
assert!(prenasalized
.patterns
.contains(&PhonePattern::Hexagraph('ŋ', 'ɡ', 'ǀ', 'ʰ', 'ʷ', 'ʼ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Hexagraph('ŋ', 'ɡ', 'ǃ', 'ʰ', 'ʷ', 'ʼ'))); assert!(prenasalized
.patterns
.contains(&PhonePattern::Hexagraph('ŋ', 'ɡ', 'ǁ', 'ʰ', 'ʷ', 'ʼ')));
assert_eq!(prenasalized.patterns.len(), 18);
}
#[test]
fn test_aspirated_affricate_class() {
let aspirated =
get_named_class("aspirated_affricate").expect("aspirated_affricate class should exist");
assert!(aspirated
.patterns
.contains(&PhonePattern::Trigraph('t', 's', 'ʰ'))); assert!(aspirated
.patterns
.contains(&PhonePattern::Trigraph('t', 'ʃ', 'ʰ'))); assert!(aspirated
.patterns
.contains(&PhonePattern::Trigraph('t', 'ɕ', 'ʰ'))); assert!(aspirated
.patterns
.contains(&PhonePattern::Trigraph('t', 'ʂ', 'ʰ')));
assert_eq!(aspirated.patterns.len(), 4);
}
#[test]
fn test_phone_pattern_pentagraph() {
let p = PhonePattern::Pentagraph('a', 'b', 'c', 'd', 'e');
assert!(p.is_pentagraph());
assert!(!p.is_char());
assert!(!p.is_digraph());
assert!(!p.is_trigraph());
assert!(!p.is_tetragraph());
assert!(!p.is_hexagraph());
assert!(!p.is_heptagraph());
assert_eq!(p.len(), 5);
assert_eq!(p.as_pentagraph(), Some(('a', 'b', 'c', 'd', 'e')));
assert!(p.matches_pentagraph('a', 'b', 'c', 'd', 'e'));
assert!(!p.matches_pentagraph('a', 'b', 'c', 'd', 'f'));
assert_eq!(format!("{}", p), "abcde");
}
#[test]
fn test_phone_pattern_hexagraph() {
let p = PhonePattern::Hexagraph('a', 'b', 'c', 'd', 'e', 'f');
assert!(p.is_hexagraph());
assert!(!p.is_char());
assert!(!p.is_digraph());
assert!(!p.is_trigraph());
assert!(!p.is_tetragraph());
assert!(!p.is_pentagraph());
assert!(!p.is_heptagraph());
assert_eq!(p.len(), 6);
assert_eq!(p.as_hexagraph(), Some(('a', 'b', 'c', 'd', 'e', 'f')));
assert!(p.matches_hexagraph('a', 'b', 'c', 'd', 'e', 'f'));
assert!(!p.matches_hexagraph('a', 'b', 'c', 'd', 'e', 'g'));
assert_eq!(format!("{}", p), "abcdef");
}
#[test]
fn test_phone_pattern_heptagraph() {
let p = PhonePattern::Heptagraph('a', 'b', 'c', 'd', 'e', 'f', 'g');
assert!(p.is_heptagraph());
assert!(!p.is_char());
assert!(!p.is_digraph());
assert!(!p.is_trigraph());
assert!(!p.is_tetragraph());
assert!(!p.is_pentagraph());
assert!(!p.is_hexagraph());
assert_eq!(p.len(), 7);
assert_eq!(p.as_heptagraph(), Some(('a', 'b', 'c', 'd', 'e', 'f', 'g')));
assert!(p.matches_heptagraph('a', 'b', 'c', 'd', 'e', 'f', 'g'));
assert!(!p.matches_heptagraph('a', 'b', 'c', 'd', 'e', 'f', 'h'));
assert_eq!(format!("{}", p), "abcdefg");
}
#[test]
fn test_phone_pattern_helper_constructors() {
let penta = PhonePattern::pentagraph('p', 'e', 'n', 't', 'a');
assert!(penta.is_pentagraph());
assert_eq!(penta.len(), 5);
let hexa = PhonePattern::hexagraph('h', 'e', 'x', 'a', 'g', 'r');
assert!(hexa.is_hexagraph());
assert_eq!(hexa.len(), 6);
let hepta = PhonePattern::heptagraph('h', 'e', 'p', 't', 'a', 'g', 'r');
assert!(hepta.is_heptagraph());
assert_eq!(hepta.len(), 7);
}
#[test]
fn test_phone_pattern_sequence_for_long_patterns() {
let seq = PhonePattern::Sequence(vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
assert!(!seq.is_char());
assert!(!seq.is_pentagraph());
assert!(!seq.is_hexagraph());
assert!(!seq.is_heptagraph());
assert_eq!(seq.len(), 8);
assert_eq!(format!("{}", seq), "abcdefgh");
}
#[test]
fn test_phone_pattern_ipa_complex_patterns() {
let prenasalized_labialized_click = PhonePattern::Pentagraph('ŋ', 'ɡ', 'ǀ', 'ʰ', 'ʷ');
assert!(prenasalized_labialized_click.is_pentagraph());
assert_eq!(prenasalized_labialized_click.len(), 5);
let complex_affricate = PhonePattern::Hexagraph('ⁿ', 't', 's', 'ʷ', 'ʼ', ' ');
assert!(complex_affricate.is_hexagraph());
assert_eq!(complex_affricate.len(), 6);
}