use crate::test::types::{
CompoundOnWideSeven, CompoundSeven, CompoundWideOnSeven, GoldenValues,
Seventeen, Sixteen, StructOne, StructThree, Three, ThreeHundred, WideThree,
};
use enumoid::{EnumIndex, EnumSize, Enumoid};
fn check_constants<T: GoldenValues>() {
assert_eq!(T::FIRST, *T::VALUES.first().unwrap());
assert_eq!(T::LAST, *T::VALUES.last().unwrap());
assert_eq!(T::SIZE, T::VALUES.len());
}
fn check_value_navigation<T: GoldenValues>() {
let values = T::VALUES;
for (i, &x) in values.iter().enumerate() {
if i == 0 {
assert_eq!(x.prev(), None, "prev({i})");
assert_eq!(x.prev_wrapped(), T::LAST, "prev_wrapped({i})");
} else {
assert_eq!(x.prev(), Some(values[i - 1]), "prev({i})");
assert_eq!(x.prev_wrapped(), values[i - 1], "prev_wrapped({i})");
}
if i == values.len() - 1 {
assert_eq!(x.next(), None, "next({i})");
assert_eq!(x.next_wrapped(), T::FIRST, "next_wrapped({i})");
} else {
assert_eq!(x.next(), Some(values[i + 1]), "next({i})");
assert_eq!(x.next_wrapped(), values[i + 1], "next_wrapped({i})");
}
}
}
fn check_index<T: GoldenValues>() {
let values = T::VALUES;
for (i, &x) in values.iter().enumerate() {
let index = EnumIndex::from_value(x);
assert_eq!(index.into_usize(), i, "into_usize({i})");
assert_eq!(
EnumIndex::<T>::from_usize(i),
Some(index),
"from_usize({i})"
);
assert_eq!(T::from_word(index.into_word()), Some(x), "into_word({i})");
if i == 0 {
assert_eq!(index.prev(), None, "EnumIndex::prev({i})");
assert_eq!(
index.prev_wrapped(),
EnumIndex::from_value(T::LAST),
"EnumIndex::prev_wrapped({i})"
);
} else {
assert_eq!(
index.prev(),
Some(EnumIndex::from_value(values[i - 1])),
"EnumIndex::prev({i})"
);
assert_eq!(
index.prev_wrapped(),
EnumIndex::from_value(values[i - 1]),
"EnumIndex::prev_wrapped({i})"
);
}
if i == values.len() - 1 {
assert_eq!(index.next(), None, "EnumIndex::next({i})");
assert_eq!(
index.next_wrapped(),
EnumIndex::from_value(T::FIRST),
"EnumIndex::next_wrapped({i})"
);
} else {
assert_eq!(
index.next(),
Some(EnumIndex::from_value(values[i + 1])),
"EnumIndex::next({i})"
);
assert_eq!(
index.next_wrapped(),
EnumIndex::from_value(values[i + 1]),
"EnumIndex::next_wrapped({i})"
);
}
}
assert_eq!(
EnumIndex::<T>::from_usize(T::SIZE),
None,
"EnumIndex::from_usize(SIZE)"
);
}
fn check_value_iterators<T: GoldenValues>() {
let values = T::VALUES;
assert_eq!(
T::iter().collect::<Vec<_>>(),
values.to_vec(),
"Enumoid::iter()"
);
for (i, &from) in values.iter().enumerate() {
assert_eq!(
T::iter_from(from).collect::<Vec<_>>(),
values[i..].to_vec(),
"Enumoid::iter_from({from:?})"
);
}
for (j, &until) in values.iter().enumerate() {
assert_eq!(
T::iter_until(until).collect::<Vec<_>>(),
values[..=j].to_vec(),
"Enumoid::iter_until({until:?})"
);
}
for (i, &from) in values.iter().enumerate() {
for (j, &until) in values.iter().enumerate() {
let expected: Vec<T> = if i <= j {
values[i..=j].to_vec()
} else {
Vec::new()
};
assert_eq!(
T::iter_from_until(from, until).collect::<Vec<_>>(),
expected,
"Enumoid::iter_from_until({from:?}, {until:?})"
);
}
}
}
fn check_size_conversions<T: GoldenValues>() {
let values = T::VALUES;
let sizes = all_sizes::<T>();
assert_eq!(
EnumSize::<T>::from_usize(T::SIZE + 1),
None,
"EnumSize::from_usize(SIZE + 1)"
);
for (s, &size) in sizes.iter().enumerate() {
assert_eq!(size.into_usize(), s, "EnumSize({s})::into_usize()");
assert_eq!(
EnumSize::from_word(size.into_word()),
Some(size),
"EnumSize({s})::from_word(into_word())"
);
if s == 0 {
assert_eq!(
size.into_last_index(),
None,
"EnumSize(0)::into_last_index()"
);
assert_eq!(size.into_last(), None, "EnumSize(0)::into_last()");
} else {
assert_eq!(
size.into_last_index(),
Some(EnumIndex::from_value(values[s - 1])),
"EnumSize({s})::into_last_index()"
);
assert_eq!(
size.into_last(),
Some(values[s - 1]),
"EnumSize({s})::into_last()"
);
}
if s < values.len() {
assert_eq!(
size.increase(),
Some(sizes[s + 1]),
"EnumSize({s})::increase()"
);
} else {
assert_eq!(size.increase(), None, "EnumSize(FULL)::increase()");
}
if s > 0 {
assert_eq!(
size.decrease(),
Some(sizes[s - 1]),
"EnumSize({s})::decrease()"
);
} else {
assert_eq!(size.decrease(), None, "EnumSize(0)::decrease()");
}
for (i, &v) in values.iter().enumerate() {
let expected = i < s;
assert_eq!(size.contains(v), expected, "EnumSize({s})::contains({v:?})");
assert_eq!(
size.contains_index(EnumIndex::from_value(v)),
expected,
"EnumSize({s})::contains_index({v:?})"
);
}
}
}
fn check_size_iterators<T: GoldenValues>() {
let values = T::VALUES;
let sizes = all_sizes::<T>();
for (s, &size) in sizes.iter().enumerate() {
assert_eq!(
size.iter().collect::<Vec<_>>(),
values[..s].to_vec(),
"EnumSize({s})::iter()"
);
for (i, &from) in values.iter().enumerate() {
let expected: Vec<T> = if i < s {
values[i..s].to_vec()
} else {
Vec::new()
};
assert_eq!(
size.iter_from(from).collect::<Vec<_>>(),
expected,
"EnumSize({s})::iter_from({from:?})"
);
}
for (j, &until) in values.iter().enumerate() {
let lim = (j + 1).min(s);
assert_eq!(
size.iter_until(until).collect::<Vec<_>>(),
values[..lim].to_vec(),
"EnumSize({s})::iter_until({until:?})"
);
}
for (i, &from) in values.iter().enumerate() {
for (j, &until) in values.iter().enumerate() {
let lim = (j + 1).min(s);
let expected: Vec<T> = if i < lim {
values[i..lim].to_vec()
} else {
Vec::new()
};
assert_eq!(
size.iter_from_until(from, until).collect::<Vec<_>>(),
expected,
"EnumSize({s})::iter_from_until({from:?}, {until:?})"
);
}
}
}
}
fn all_sizes<T: GoldenValues>() -> Vec<EnumSize<T>> {
(0..=T::SIZE)
.map(|s| EnumSize::<T>::from_usize(s).unwrap())
.collect()
}
macro_rules! order_tests {
($name:ident, $t:ty) => {
mod $name {
use super::*;
#[test]
fn constants() {
check_constants::<$t>();
}
#[test]
fn value_navigation() {
check_value_navigation::<$t>();
}
#[test]
fn index() {
check_index::<$t>();
}
#[test]
fn value_iterators() {
check_value_iterators::<$t>();
}
#[test]
fn size_conversions() {
check_size_conversions::<$t>();
}
#[test]
fn size_iterators() {
check_size_iterators::<$t>();
}
}
};
}
order_tests!(three, Three);
order_tests!(wide_three, WideThree);
order_tests!(struct_one, StructOne);
order_tests!(struct_three, StructThree);
order_tests!(compound_seven, CompoundSeven);
order_tests!(compound_on_wide_seven, CompoundOnWideSeven);
order_tests!(compound_wide_on_seven, CompoundWideOnSeven);
order_tests!(sixteen, Sixteen);
order_tests!(seventeen, Seventeen);
#[test]
fn test_three_hundred() {
assert_eq!(ThreeHundred::FIRST, ThreeHundred::A1);
assert_eq!(ThreeHundred::LAST, ThreeHundred::A300);
assert_eq!(ThreeHundred::SIZE, 300);
}
#[test]
fn test_from_word_out_of_bounds() {
assert_eq!(EnumSize::<Three>::from_word(3), Some(EnumSize::FULL));
assert_eq!(EnumSize::<Three>::from_word(4), None);
assert_eq!(EnumSize::<WideThree>::from_word(3), Some(EnumSize::FULL));
assert_eq!(EnumSize::<WideThree>::from_word(4), None);
assert_eq!(Three::from_word(2), Some(Three::C));
assert_eq!(Three::from_word(3), None);
assert_eq!(WideThree::from_word(2), Some(WideThree::C));
assert_eq!(WideThree::from_word(3), None);
}