use sashite_epin::{Identifier, Letter, Side, State};
use sashite_pin::Identifier as Pin;
fn all_pins() -> Vec<Pin> {
let mut pins = Vec::with_capacity(312);
for letter in Letter::ALL {
for side in [Side::First, Side::Second] {
for state in [State::Diminished, State::Normal, State::Enhanced] {
for terminal in [false, true] {
pins.push(Pin::new(letter, side, state, terminal));
}
}
}
}
pins
}
fn all_epins() -> Vec<Identifier> {
let mut epins = Vec::with_capacity(624);
for pin in all_pins() {
epins.push(Identifier::new(pin, false));
epins.push(Identifier::new(pin, true));
}
epins
}
#[test]
fn native_and_derive_set_only_the_flag() {
for id in all_epins() {
let n = id.native();
let d = id.derive();
assert!(n.is_native());
assert!(d.is_derived());
assert_eq!(n.pin(), id.pin());
assert_eq!(d.pin(), id.pin());
}
}
#[test]
fn native_and_derive_are_idempotent_and_compose() {
for id in all_epins() {
assert_eq!(id.native(), id.native().native());
assert_eq!(id.derive(), id.derive().derive());
assert_eq!(id.native().derive(), id.derive());
assert_eq!(id.derive().native(), id.native());
}
}
#[test]
fn with_pin_replaces_core_and_keeps_flag() {
for id in all_epins() {
let flipped_core = id.pin().flipped();
let swapped = id.with_pin(flipped_core);
assert_eq!(swapped.pin(), flipped_core);
assert_eq!(swapped.is_derived(), id.is_derived());
assert_eq!(swapped.with_pin(swapped.pin().flipped()), id);
}
}
#[test]
fn accessors_delegate_to_the_inner_pin() {
for id in all_epins() {
let pin = id.pin();
assert_eq!(id.letter().as_char(), pin.letter().as_char());
assert_eq!(id.side(), pin.side());
assert_eq!(id.state(), pin.state());
assert_eq!(id.is_terminal(), pin.is_terminal());
assert_eq!(id.is_first(), pin.is_first());
assert_eq!(id.is_second(), pin.is_second());
assert_eq!(id.is_native(), !id.is_derived());
}
}
#[test]
fn encoding_reflects_the_derivation_flag() {
for id in all_epins() {
let encoded = id.encode();
assert_eq!(encoded.as_str().ends_with('\''), id.is_derived());
assert_eq!(id.native().encode().as_str(), id.pin().encode().as_str());
}
}
#[test]
fn native_orders_before_derived_for_the_same_core() {
for pin in all_pins() {
assert!(Identifier::new(pin, false) < Identifier::new(pin, true));
}
}
#[test]
fn sorting_yields_canonical_order() {
let canonical = all_epins();
let mut scrambled = canonical.clone();
scrambled.reverse();
scrambled.sort();
assert_eq!(
scrambled, canonical,
"sorting must reproduce the canonical order"
);
}
#[test]
fn transforms_work_in_const_context() {
const CORE: Pin = match Pin::parse("+K^") {
Ok(pin) => pin,
Err(_) => panic!("\"+K^\" is a valid PIN token"),
};
const DERIVED: Identifier = Identifier::new(CORE, true);
const NATIVE: Identifier = DERIVED.native();
const FLIPPED: Identifier = DERIVED.with_pin(CORE.flipped());
assert_eq!(DERIVED, Identifier::new(Pin::parse("+K^").unwrap(), true));
assert_eq!(NATIVE, Identifier::new(Pin::parse("+K^").unwrap(), false));
assert_eq!(FLIPPED, Identifier::new(Pin::parse("+k^").unwrap(), true));
}