use sashite_sin::{Identifier, Letter, Side};
use std::collections::{HashMap, HashSet};
fn all_ids() -> Vec<Identifier> {
let mut ids = Vec::with_capacity(52);
for letter in Letter::ALL {
for side in [Side::First, Side::Second] {
ids.push(Identifier::new(letter, side));
}
}
ids
}
const STYLE_CASES: &[(&str, char, Side)] = &[
("W", 'W', Side::First), ("w", 'W', Side::Second), ("C", 'C', Side::First), ("c", 'C', Side::Second), ("J", 'J', Side::First), ("j", 'J', Side::Second), ("S", 'S', Side::First), ("s", 'S', Side::Second), ];
#[test]
fn documented_styles_decode_as_expected() {
for &(token, letter, side) in STYLE_CASES {
let id = Identifier::parse(token).unwrap_or_else(|e| panic!("{token:?}: {e:?}"));
assert_eq!(id.letter().as_char(), letter, "{token:?}");
assert_eq!(id.side(), side, "{token:?}");
assert_eq!(id.to_char().to_string(), token, "{token:?}");
assert_eq!(id.encode().as_str(), token, "{token:?} round-trip");
}
}
#[test]
fn equality_distinguishes_every_attribute() {
let base = Identifier::parse("W").unwrap();
assert_eq!(base, Identifier::parse("W").unwrap()); assert_ne!(base, Identifier::parse("w").unwrap()); assert_ne!(base, Identifier::parse("C").unwrap()); }
#[test]
fn parses_from_bytes() {
assert_eq!(
Identifier::try_from(&b"W"[..]).unwrap(),
Identifier::parse("W").unwrap(),
);
assert!(Identifier::try_from(&b"WW"[..]).is_err());
assert!(Identifier::try_from(&[0xFF_u8, 0xFE][..]).is_err());
}
#[test]
fn all_identifiers_are_distinct_and_hashable() {
let ids = all_ids();
let set: HashSet<Identifier> = ids.iter().copied().collect();
assert_eq!(
set.len(),
52,
"all 52 identifiers must be distinct under Hash + Eq"
);
let mut reinserted = set;
reinserted.extend(ids.iter().copied());
assert_eq!(reinserted.len(), 52);
}
#[test]
fn usable_as_map_keys() {
let mut map: HashMap<Identifier, &str> = HashMap::new();
map.insert(Identifier::parse("W").unwrap(), "first western");
map.insert(Identifier::parse("c").unwrap(), "second chinese");
assert_eq!(
map.get(&Identifier::parse("W").unwrap()),
Some(&"first western")
);
assert_eq!(map.get(&Identifier::parse("w").unwrap()), None);
assert_eq!(map.get(&Identifier::parse("C").unwrap()), None);
}
#[test]
fn sorting_yields_canonical_order() {
let canonical = all_ids(); assert!(
canonical.windows(2).all(|w| w[0] < w[1]),
"generation order must be strictly ascending and duplicate-free",
);
let mut scrambled = canonical.clone();
scrambled.reverse();
scrambled.sort();
assert_eq!(
scrambled, canonical,
"sorting must reproduce canonical order"
);
}
#[test]
fn debug_output_is_informative() {
let id = Identifier::parse("w").unwrap();
let rendered = format!("{id:?}");
assert!(rendered.contains("Letter('W')"), "{rendered}");
assert!(rendered.contains("Second"), "{rendered}");
assert_eq!(format!("{:?}", id.encode()), "EncodedSin(\"w\")");
}