mod common;
use std::collections::HashSet;
use o192::{is_valid, OrionIdError, OrionIdGenerator, ID_SIZE_CHARS};
#[test]
fn basic_generation_emits_canonical_32_char_string() {
let mut gen = OrionIdGenerator::new();
let id = gen.next().unwrap();
assert_eq!(id.len(), ID_SIZE_CHARS);
assert!(is_valid(&id));
}
#[test]
fn single_generator_is_strictly_monotonic_over_50k_iterations() {
let mut gen = OrionIdGenerator::new();
let mut prev = gen.next().unwrap();
for index in 0..50_000 {
let id = gen.next().unwrap();
assert!(prev < id, "non-monotonic at {index}");
prev = id;
}
}
#[test]
fn single_generator_emits_no_duplicates_over_50k_iterations() {
let mut gen = OrionIdGenerator::new();
let mut seen = HashSet::with_capacity(50_000);
for index in 0..50_000 {
let id = gen.next().unwrap();
assert!(seen.insert(id), "duplicate at {index}");
}
}
#[test]
fn clock_rollback_never_breaks_local_monotonicity() {
let mut gen = OrionIdGenerator::new().with_random_fill(|out| {
out.fill(0);
Ok(())
});
gen.set_physical_time_key_for_test(123_456_789u128 << 12);
let a = gen.next().unwrap();
gen.set_physical_time_key_for_test((123_456_789u128 << 12) - 1_000);
let b = gen.next().unwrap();
gen.set_physical_time_key_for_test((123_456_789u128 << 12) - 2_000);
let c = gen.next().unwrap();
assert!(a < b && b < c, "IDs must remain strictly increasing");
assert!(gen.clock_rollbacks() >= 2, "must observe ≥ 2 rollbacks");
}
#[test]
fn invalid_random_pool_options_are_rejected() {
assert!(matches!(
OrionIdGenerator::with_options(0, 1),
Err(OrionIdError::InvalidOption("random_pool_bytes"))
));
assert!(matches!(
OrionIdGenerator::with_options(0, 100 * 1024 * 1024),
Err(OrionIdError::InvalidOption("random_pool_bytes"))
));
}
#[test]
fn epoch_ms_shifts_relative_timestamp() {
let epoch_ms: u128 = 1_735_689_600_000;
let mut gen = OrionIdGenerator::with_epoch_ms(epoch_ms).unwrap();
let id = gen.next().unwrap();
let view = gen.parse(&id).unwrap();
assert!(view.unix_ms >= epoch_ms);
}