o192 0.2.2

ORION-192: ordered, resilient, independent, URL-safe 192-bit IDs for distributed systems.
Documentation
//! Generator unit tests.

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);
}