use sashite_sin::{Identifier, Letter, Side};
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
}
#[test]
fn flip_is_an_involution_and_changes_only_side() {
for id in all_ids() {
let flipped = id.flipped();
assert_ne!(flipped.side(), id.side());
assert_eq!(flipped.flipped(), id, "double flip must restore {id:?}");
assert_eq!(flipped.letter(), id.letter());
let expected = if id.is_first() {
id.to_char().to_ascii_lowercase()
} else {
id.to_char().to_ascii_uppercase()
};
assert_eq!(flipped.to_char(), expected);
}
assert_eq!(Side::First.flip().flip(), Side::First);
}
#[test]
fn with_setters_change_only_their_target() {
let chinese = Letter::try_from_char('C').unwrap();
for id in all_ids() {
for side in [Side::First, Side::Second] {
let changed = id.with_side(side);
assert_eq!(changed.side(), side);
assert_eq!(changed.letter(), id.letter());
}
let changed = id.with_letter(chinese);
assert_eq!(changed.letter(), chinese);
assert_eq!(changed.side(), id.side());
}
}
#[test]
fn queries_agree_with_accessors() {
for id in all_ids() {
assert_eq!(id.is_first(), id.side() == Side::First);
assert_eq!(id.is_second(), id.side() == Side::Second);
assert!(id.is_first() ^ id.is_second());
}
}
const WESTERN: Identifier = Identifier::new(Letter::ALL[22], Side::First); const WESTERN_SECOND: Identifier = WESTERN.flipped();
const CHINESE_FIRST: Identifier = WESTERN.with_letter(Letter::ALL[2]);
#[test]
fn transforms_work_in_const_context() {
assert_eq!(WESTERN.letter().as_char(), 'W');
assert_eq!(WESTERN.encode().as_str(), "W");
assert_eq!(WESTERN_SECOND.encode().as_str(), "w");
assert_eq!(CHINESE_FIRST.encode().as_str(), "C");
}
const PARSED: Result<Identifier, sashite_sin::ParseError> = Identifier::parse("W");
const WESTERN_IS_VALID: bool = Identifier::is_valid("W");
#[test]
fn parsing_works_in_const_context() {
assert_eq!(WESTERN_IS_VALID, Identifier::is_valid("W"));
assert_eq!(PARSED, Identifier::parse("W"));
}
#[test]
fn letter_helpers() {
let upper = Letter::try_from_char('C').unwrap();
let lower = Letter::try_from_char('c').unwrap();
assert_eq!(upper, lower);
assert_eq!(upper.as_char(), 'C');
assert_eq!(upper.as_ascii(), b'C');
assert_eq!(Letter::try_from('Z').unwrap().as_char(), 'Z');
assert!(Letter::try_from('!').is_err());
let letter_a = Letter::try_from_char('A').unwrap();
assert_eq!(Letter::from_ascii(b'A'), Some((letter_a, Side::First)));
assert_eq!(
Letter::from_ascii(b'a').map(|(letter, side)| (letter.as_char(), side)),
Some(('A', Side::Second)),
);
assert_eq!(Letter::from_ascii(b'0'), None);
let spelled: String = Letter::ALL.iter().map(|letter| letter.as_char()).collect();
assert_eq!(spelled, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
}
#[test]
fn derived_orderings_are_canonical() {
assert!(Side::First < Side::Second);
let less = |left: &str, right: &str| {
Identifier::parse(left).unwrap() < Identifier::parse(right).unwrap()
};
assert!(less("A", "B")); assert!(less("A", "a")); assert!(!less("Z", "a")); assert!(less("a", "B")); }