use aozora_encoding::DecodeError;
use aozora_encoding::gaiji::{Resolved, lookup, table_sizes};
#[test]
fn gatekeeper_decode_error_is_non_exhaustive_with_one_pinned_variant() {
let err = DecodeError::ShiftJisInvalid;
assert_eq!(
format!("{err}"),
"Shift_JIS からの変換に失敗しました (不正なバイト列)",
"user-facing error message must remain in Japanese; \
changing the wording is a user-visible UX change",
);
}
#[test]
fn gatekeeper_resolved_variant_inventory() {
fn assert_copy<T: Copy>() {}
fn assert_eq_<T: Eq>() {}
assert_copy::<Resolved>();
assert_eq_::<Resolved>();
assert_eq!(Resolved::Char('A'), Resolved::Char('A'));
assert_eq!(Resolved::Multi("か゚"), Resolved::Multi("か゚"));
assert_ne!(Resolved::Char('A'), Resolved::Multi("A"));
}
#[test]
fn gatekeeper_table_sizes_match_jisx0213_2004_spec() {
let (single, combo, description) = table_sizes();
assert_eq!(
single, 4329,
"JIS X 0213 plane-1 + plane-2 single-char count"
);
assert_eq!(combo, 25, "JIS X 0213 plane-1 combining-sequence cells");
assert!(
description >= 8_000,
"description fallback table dropped below the 8K floor: {description}",
);
}
#[test]
fn gatekeeper_every_combo_entry_is_exactly_two_scalars() {
let representative = [
"第3水準1-4-87", "第3水準1-4-88", "第3水準1-4-89", "第3水準1-4-90", "第3水準1-4-91", "第3水準1-5-87", "第3水準1-5-88", ];
for mencode in representative {
let r = lookup(None, Some(mencode), "")
.unwrap_or_else(|| panic!("combo mencode {mencode} must resolve"));
let s = match r {
Resolved::Multi(s) => s,
Resolved::Char(c) => panic!("expected Multi for {mencode}, got Char({c:?})"),
};
assert_eq!(
s.chars().count(),
2,
"combo cell {mencode} must be exactly 2 scalars; got {s:?}",
);
let last = s.chars().next_back().unwrap();
assert!(
(0x0300..=0x036F).contains(&(last as u32))
|| (0x3099..=0x309A).contains(&(last as u32)),
"second scalar of {mencode} ({s:?}) is not a combining mark",
);
}
}
#[test]
fn gatekeeper_lookup_tier_dispatch_order_is_pinned() {
assert_eq!(
lookup(Some('Z'), Some("第3水準1-85-54"), "木+吶のつくり"),
Some(Resolved::Char('Z')),
);
assert!(matches!(
lookup(None, Some("第3水準1-4-87"), "anything"),
Some(Resolved::Multi(_))
));
assert_eq!(
lookup(None, Some("第3水準1-85-54"), "〓"),
Some(Resolved::Char('\u{6798}')),
"single-char table must beat the description-table 〓 entry",
);
assert_eq!(
lookup(None, Some("U+304B"), "anything"),
Some(Resolved::Char('か')),
);
assert_eq!(lookup(None, None, "〓"), Some(Resolved::Char('\u{3013}')));
assert_eq!(lookup(None, None, "〻"), Some(Resolved::Char('\u{303B}')));
assert_eq!(lookup(None, None, "畺"), Some(Resolved::Char('\u{757A}')));
assert_eq!(lookup(None, None, "未知の字"), None);
}
#[test]
fn gatekeeper_resolved_utf8_len_is_consistent_with_write_to() {
let cases: &[(Resolved, usize)] = &[
(Resolved::Char('A'), 1),
(Resolved::Char('あ'), 3),
(Resolved::Char('𠂉'), 4),
(Resolved::Multi("\u{304B}\u{309A}"), 6),
];
for (r, want) in cases {
let mut s = String::new();
r.write_to(&mut s).expect("write to String");
assert_eq!(s.len(), *want, "byte len mismatch for {r:?}");
assert_eq!(r.utf8_len(), *want, "utf8_len mismatch for {r:?}");
}
}