use std::{
string::{String, ToString},
vec::Vec,
};
use smol_bytes::Utf8Bytes;
use super::{
Language, LanguageId, ParseLanguageError, ParseRegionError, ParseScriptSubtagError, Region,
ScriptSubtag, registry,
};
#[test]
fn the_text_out_is_the_canonical_text_for_all_three() {
let language = Language::new("GER").expect("a language subtag");
assert_eq!(language.as_ref() as &str, "de");
assert_eq!(String::from(language), "de");
assert_eq!(Utf8Bytes::from(language), Utf8Bytes::from("de"));
let script = ScriptSubtag::new("hans").expect("a script subtag");
assert_eq!(script.as_ref() as &str, "Hans");
assert_eq!(String::from(script), "Hans");
assert_eq!(Utf8Bytes::from(script), Utf8Bytes::from("Hans"));
let region = Region::new("bu").expect("a region subtag");
assert_eq!(region.as_ref() as &str, "MM");
assert_eq!(String::from(region), "MM");
assert_eq!(Utf8Bytes::from(region), Utf8Bytes::from("MM"));
}
const _: () = {
const fn is_copy<T: Copy>() {}
is_copy::<Language>();
is_copy::<ScriptSubtag>();
is_copy::<Region>();
};
#[test]
fn the_derived_order_is_the_texts_order_across_the_registry() {
fn agrees<T: Ord + Copy>(held: &[T], text: impl Fn(&T) -> &str) {
for (at, left) in held.iter().enumerate() {
for right in &held[at..] {
assert_eq!(
left.cmp(right),
text(left).cmp(text(right)),
"`{}` vs `{}`: the derived order and the text's part",
text(left),
text(right),
);
}
}
}
let mut languages: std::collections::BTreeMap<u8, Vec<Language>> =
std::collections::BTreeMap::new();
for (subtag, _) in registry::table::LANGUAGES {
let held = Language::new(subtag.as_str()).expect("a registered subtag is a subtag");
languages
.entry(held.as_str().as_bytes()[0])
.or_default()
.push(held);
}
for group in languages.values() {
agrees(group, |held| held.as_str());
}
let scripts: Vec<ScriptSubtag> = registry::table::SCRIPTS
.iter()
.map(|(subtag, _)| ScriptSubtag::new(subtag.as_str()).expect("a script"))
.collect();
agrees(&scripts, |held| held.as_str());
let regions: Vec<Region> = registry::table::REGIONS
.iter()
.map(|(subtag, _)| Region::new(subtag.as_str()).expect("a region"))
.collect();
agrees(®ions, |held| held.as_str());
}
#[test]
fn a_shorter_subtag_sorts_before_the_longer_one_it_prefixes() {
let short = Language::new("xy").expect("structurally a language subtag");
let long = Language::new("xyz").expect("structurally a language subtag");
assert_eq!(short.as_str(), "xy", "unregistered, so nothing folded it");
assert_eq!(long.as_str(), "xyz");
assert!(short < long, "the padding must sort below any real byte");
assert_eq!(short.cmp(&long), "xy".cmp("xyz"));
assert!(
Region::new("419").expect("a region") < Region::new("AA").expect("a region"),
"digits sort before letters, on both readings",
);
}
#[test]
fn the_text_in_is_the_door_for_all_three() {
assert_eq!(
Language::try_from("GER").expect("a language subtag"),
Language::new("de").expect("a language subtag"),
);
assert_eq!(
Language::try_from(Utf8Bytes::from("iw")).expect("a language subtag"),
Language::new("he").expect("a language subtag"),
);
assert_eq!(
ScriptSubtag::try_from("hans").expect("a script subtag"),
ScriptSubtag::new("Hans").expect("a script subtag"),
);
assert_eq!(
ScriptSubtag::try_from(Utf8Bytes::from("LATN")).expect("a script subtag"),
ScriptSubtag::new("Latn").expect("a script subtag"),
);
assert_eq!(
Region::try_from("bu").expect("a region subtag"),
Region::new("MM").expect("a region subtag"),
);
assert_eq!(
Region::try_from(Utf8Bytes::from("419")).expect("a region subtag"),
Region::new("419").expect("a region subtag"),
);
assert_eq!(Language::try_from("e"), Err(ParseLanguageError::TooShort));
assert_eq!(
ScriptSubtag::try_from(Utf8Bytes::from("Lat")),
Err(ParseScriptSubtagError::WrongWidth)
);
assert_eq!(
Region::try_from("DEU"),
Err(ParseRegionError::WrongLetterWidth)
);
}
#[test]
fn the_default_identity_is_the_undetermined_tag() {
let default = LanguageId::default();
assert_eq!(default.to_string(), "und");
assert!(default.language().is_undetermined());
assert_eq!(default.script(), None);
assert_eq!(default.region(), None);
assert_eq!(default.rest(), None);
assert_eq!(LanguageId::new("und").expect("a tag"), default);
assert_eq!(LanguageId::from(Language::UND), default);
let absent: Option<LanguageId> = None;
assert_ne!(absent, Some(default), "no tag is not the `und` tag");
}