use std::vec::Vec;
use super::{
GRANDFATHERED_COUNT, LANGUAGE_COUNT, LANGUAGE_PRIVATE_USE, REGION_COUNT, REGION_PRIVATE_USE,
SCRIPT_COUNT, SCRIPT_PRIVATE_USE, alpha3, grandfathered_preferred, is_grandfathered,
language_is_deprecated, language_is_private_use, language_name, language_preferred,
language_suppress_script, region_is_deprecated, region_is_private_use, region_name,
region_preferred, script_is_private_use, script_name, table,
};
#[test]
fn every_pair_table_is_sorted() {
for (name, table) in [
("LANGUAGES", table::LANGUAGES),
("LANGUAGE_PREFERRED", table::LANGUAGE_PREFERRED),
("LANGUAGE_SUPPRESS_SCRIPT", table::LANGUAGE_SUPPRESS_SCRIPT),
("ALPHA3", table::ALPHA3),
] {
assert!(
table.windows(2).all(|pair| pair[0].0 < pair[1].0),
"{name} is not sorted, so its lookups are not lookups"
);
}
assert!(
table::SCRIPTS.windows(2).all(|pair| pair[0].0 < pair[1].0),
"SCRIPTS is not sorted, so its lookups are not lookups"
);
for (name, table) in [
("REGIONS", table::REGIONS),
("REGION_PREFERRED", table::REGION_PREFERRED),
] {
assert!(
table.windows(2).all(|pair| pair[0].0 < pair[1].0),
"{name} is not sorted, so its lookups are not lookups"
);
}
assert!(
table::GRANDFATHERED
.windows(2)
.all(|pair| pair[0].0 < pair[1].0),
"GRANDFATHERED is not sorted, so its lookups are not lookups"
);
for (name, table) in [
("LANGUAGE_DEPRECATED", table::LANGUAGE_DEPRECATED),
("REGION_DEPRECATED", table::REGION_DEPRECATED),
("GRANDFATHERED_KEPT", table::GRANDFATHERED_KEPT),
] {
assert!(
table.windows(2).all(|pair| pair[0] < pair[1]),
"{name} is not sorted"
);
}
}
#[test]
fn every_registered_subtag_is_found_by_its_own_subtag() {
for (subtag, name) in table::LANGUAGES {
let subtag = subtag.as_str();
assert_eq!(language_name(subtag), Some(*name), "language `{subtag}`");
}
for (subtag, name) in table::SCRIPTS {
let subtag = subtag.as_str();
assert_eq!(script_name(subtag), Some(*name), "script `{subtag}`");
}
for (subtag, name) in table::REGIONS {
let subtag = subtag.as_str();
assert_eq!(region_name(subtag), Some(*name), "region `{subtag}`");
}
assert_eq!(LANGUAGE_COUNT, table::LANGUAGES.len());
assert_eq!(SCRIPT_COUNT, table::SCRIPTS.len());
assert_eq!(REGION_COUNT, table::REGIONS.len());
assert_eq!(
GRANDFATHERED_COUNT, 26,
"BCP 47 grandfathered twenty-six tags"
);
}
#[test]
fn a_preferred_value_prefers_nothing_itself() {
for (subtag, preferred) in table::LANGUAGE_PREFERRED {
let subtag = subtag.as_str();
assert!(
language_name(preferred).is_some(),
"`{subtag}` prefers `{preferred}`, which is not registered"
);
assert_eq!(
language_preferred(preferred),
None,
"`{subtag}` prefers `{preferred}`, which prefers something else"
);
}
for (subtag, preferred) in table::REGION_PREFERRED {
let subtag = subtag.as_str();
assert!(
region_name(preferred).is_some(),
"`{subtag}` prefers `{preferred}`, which is not registered"
);
assert_eq!(
region_preferred(preferred),
None,
"`{subtag}` prefers `{preferred}`, which prefers something else"
);
}
}
#[test]
fn the_alpha3_fold_supplies_only_what_bcp47_omits() {
for (code, shortest) in table::ALPHA3 {
let code = code.as_str();
assert_eq!(
language_name(code),
None,
"ISO 639-2 folds `{code}` onto `{shortest}` and BCP 47 registers `{code}` itself"
);
assert!(
language_name(shortest).is_some(),
"ISO 639-2 folds `{code}` onto `{shortest}`, which BCP 47 does not register"
);
}
}
#[test]
fn every_suppressed_script_is_a_registered_script() {
for (subtag, script) in table::LANGUAGE_SUPPRESS_SCRIPT {
let subtag = subtag.as_str();
assert!(
script_name(script).is_some(),
"`{subtag}` suppresses `{script}`, which is not a registered script"
);
}
}
#[test]
fn the_bibliographic_and_terminological_codes_both_reach_the_shortest_one() {
assert_eq!(alpha3("ger"), Some("de"));
assert_eq!(alpha3("deu"), Some("de"));
assert_eq!(language_name("ger"), None, "BCP 47 has no `ger`");
assert_eq!(language_name("deu"), None, "BCP 47 has no `deu`");
assert_eq!(language_name("de"), Some("German"));
assert_eq!(alpha3("fre"), Some("fr"));
assert_eq!(alpha3("fra"), Some("fr"));
assert_eq!(alpha3("spa"), Some("es"));
assert_eq!(alpha3("haw"), None);
assert_eq!(language_name("haw"), Some("Hawaiian"));
assert_eq!(alpha3("yue"), None);
assert_eq!(language_name("yue"), Some("Yue Chinese"));
assert_eq!(alpha3("fil"), None);
assert_eq!(language_name("fil"), Some("Filipino"));
}
#[test]
fn a_deprecated_subtag_reaches_the_one_that_replaced_it() {
assert_eq!(language_preferred("iw"), Some("he"));
assert!(language_is_deprecated("iw"));
assert_eq!(language_name("he"), Some("Hebrew"));
assert!(!language_is_deprecated("he"));
assert_eq!(language_preferred("in"), Some("id"));
assert_eq!(language_preferred("ji"), Some("yi"));
assert_eq!(language_preferred("mo"), Some("ro"));
}
#[test]
fn a_deprecated_subtag_without_a_replacement_stays_itself() {
let orphaned: Vec<&str> = table::LANGUAGE_DEPRECATED
.iter()
.copied()
.filter(|subtag| language_preferred(subtag).is_none())
.collect();
assert_eq!(orphaned.len(), 120);
for subtag in orphaned {
assert!(
language_name(subtag).is_some(),
"`{subtag}` is deprecated and still registered"
);
}
for subtag in ["AN", "CS", "NT", "SU", "YU"] {
assert!(region_is_deprecated(subtag), "`{subtag}`");
assert_eq!(region_preferred(subtag), None, "`{subtag}`");
assert!(region_name(subtag).is_some(), "`{subtag}`");
}
}
#[test]
fn a_deprecated_region_reaches_the_one_that_replaced_it() {
assert_eq!(region_preferred("BU"), Some("MM"));
assert!(region_is_deprecated("BU"));
assert_eq!(region_name("MM"), Some("Myanmar"));
assert_eq!(region_preferred("ZR"), Some("CD"));
assert_eq!(region_preferred("TP"), Some("TL"));
assert_eq!(region_preferred("DD"), Some("DE"));
assert_eq!(region_preferred("FX"), Some("FR"));
assert_eq!(region_preferred("YD"), Some("YE"));
}
#[test]
fn a_suppressed_script_is_implied_and_chinese_suppresses_none() {
assert_eq!(language_suppress_script("en"), Some("Latn"));
assert_eq!(language_suppress_script("fr"), Some("Latn"));
assert_eq!(language_suppress_script("he"), Some("Hebr"));
assert_eq!(
language_suppress_script("zh"),
None,
"Chinese implies no script"
);
assert!(script_name("Hans").is_some());
assert!(script_name("Hant").is_some());
}
#[test]
fn a_grandfathered_tag_folds_where_the_registry_names_a_successor() {
assert_eq!(grandfathered_preferred("i-klingon"), Some("tlh"));
assert_eq!(grandfathered_preferred("zh-guoyu"), Some("cmn"));
assert_eq!(grandfathered_preferred("art-lojban"), Some("jbo"));
assert_eq!(grandfathered_preferred("no-bok"), Some("nb"));
for tag in [
"cel-gaulish",
"i-default",
"i-enochian",
"i-mingo",
"zh-min",
] {
assert!(is_grandfathered(tag), "`{tag}`");
assert_eq!(grandfathered_preferred(tag), None, "`{tag}`");
}
assert!(!is_grandfathered("en-GB"), "an ordinary composition");
assert_eq!(table::GRANDFATHERED_KEPT.len(), 5);
}
#[test]
fn the_undetermined_sentinels_are_ordinary_registered_subtags() {
assert_eq!(language_name("und"), Some("Undetermined"));
assert_eq!(script_name("Zxxx"), Some("Code for unwritten documents"));
assert_eq!(script_name("Zzzz"), Some("Code for uncoded script"));
assert_eq!(region_name("ZZ"), Some("Private use"));
for sentinel in ["und", "Zxxx", "Zzzz", "ZZ"] {
assert!(!sentinel.is_empty());
}
assert!(!language_is_deprecated("und"));
}
#[test]
fn a_private_use_subtag_is_in_range_and_out_of_the_roster() {
assert_eq!(LANGUAGE_PRIVATE_USE, ("qaa", "qtz"));
for subtag in ["qaa", "qtz", "qmm"] {
assert!(language_is_private_use(subtag), "`{subtag}`");
assert_eq!(language_name(subtag), None, "`{subtag}` carries no name");
}
assert!(!language_is_private_use("qua"), "past the range's top");
assert!(!language_is_private_use("de"));
assert_eq!(SCRIPT_PRIVATE_USE, ("Qaaa", "Qabx"));
assert!(script_is_private_use("Qaaa"));
assert!(script_is_private_use("Qabx"));
assert!(!script_is_private_use("Qaby"));
assert!(!script_is_private_use("Latn"));
assert_eq!(REGION_PRIVATE_USE, [("QM", "QZ"), ("XA", "XZ")]);
for subtag in ["QM", "QZ", "QR", "XA", "XZ", "XK"] {
assert!(region_is_private_use(subtag), "`{subtag}`");
}
assert!(!region_is_private_use("QL"), "below the first range");
assert!(!region_is_private_use("DE"));
}
#[test]
fn a_range_admits_only_subtags_of_its_own_width() {
assert!(
!language_is_private_use("qq"),
"two letters, inside the bounds as text"
);
assert!(!language_is_private_use("qaaa"), "four letters");
assert!(!region_is_private_use("Q"), "one letter");
assert!(!script_is_private_use("Qaa"), "three letters");
}
#[test]
fn a_lookup_is_case_sensitive_and_says_so() {
assert_eq!(language_name("DE"), None);
assert_eq!(language_name("de"), Some("German"));
assert_eq!(script_name("latn"), None);
assert_eq!(script_name("LATN"), None);
assert_eq!(script_name("Latn"), Some("Latin"));
assert_eq!(region_name("de"), None);
assert_eq!(region_name("DE"), Some("Germany"));
}
#[test]
fn the_region_roster_holds_both_grammars() {
let digits = table::REGIONS
.iter()
.filter(|(subtag, _)| subtag.as_str().bytes().all(|byte| byte.is_ascii_digit()))
.count();
assert_eq!(digits, 31, "the M.49 areas");
assert_eq!(region_name("419"), Some("Latin America and the Caribbean"));
assert_eq!(region_name("001"), Some("World"));
assert_eq!(REGION_COUNT - digits, table::REGIONS.len() - 31);
}