cranpose-core 0.1.164

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
use super::*;

#[test]
fn group_anchor_registry_lifecycle_reuses_invalidated_id_with_generation_bump() {
    let mut registry = AnchorRegistry::new();
    let stale_anchor = registry.allocate();

    assert_eq!(registry.state(stale_anchor), Some(AnchorState::Invalidated));
    assert_eq!(registry.active_len(), 0);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 1);
    assert_eq!(registry.free_len(), 0);

    registry.set_active(stale_anchor, 12);
    assert_eq!(registry.active_index(stale_anchor), Some(12));
    assert_eq!(registry.active_len(), 1);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 0);

    registry.mark_detached(stale_anchor);
    assert_eq!(registry.state(stale_anchor), Some(AnchorState::Detached));
    assert_eq!(registry.active_len(), 0);
    assert_eq!(registry.detached_len(), 1);
    assert_eq!(registry.free_len(), 0);

    assert!(registry.invalidate_state(stale_anchor));
    assert_eq!(registry.state(stale_anchor), None);
    assert_eq!(registry.active_index(stale_anchor), None);
    assert_eq!(registry.active_len(), 0);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 0);
    assert_eq!(registry.free_len(), 1);
    assert_eq!(registry.validate_integrity(), Ok(()));

    let reused_anchor = registry.allocate();
    assert_eq!(reused_anchor.id, stale_anchor.id);
    assert_eq!(reused_anchor.generation, stale_anchor.generation + 1);
    assert_eq!(registry.state(stale_anchor), None);
    assert_eq!(
        registry.state(reused_anchor),
        Some(AnchorState::Invalidated)
    );
    assert_eq!(registry.free_len(), 0);
    assert_eq!(registry.invalidated_len(), 1);

    registry.set_active(stale_anchor, 99);
    assert_eq!(
        registry.state(reused_anchor),
        Some(AnchorState::Invalidated),
        "stale generation must not reactivate a reused anchor id"
    );
    registry.mark_detached(stale_anchor);
    assert_eq!(
        registry.state(reused_anchor),
        Some(AnchorState::Invalidated),
        "stale generation must not detach a reused anchor id"
    );

    registry.set_active(reused_anchor, 7);
    assert_eq!(registry.active_index(reused_anchor), Some(7));
    assert_eq!(registry.active_index(stale_anchor), None);
    assert_eq!(registry.active_len(), 1);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 0);
    assert_eq!(registry.free_len(), 0);
    assert_eq!(registry.validate_integrity(), Ok(()));
}

#[test]
fn group_anchor_disposal_keeps_dense_storage_for_hot_path_reuse() {
    let mut registry = AnchorRegistry::new();
    let anchors = (0..32)
        .map(|index| {
            let anchor = registry.allocate();
            registry.set_active(anchor, index);
            anchor
        })
        .collect::<Vec<_>>();
    let dense_capacity_before = registry.storage.dense_capacity();
    assert!(dense_capacity_before >= anchors.len());

    for anchor in &anchors {
        registry.mark_detached(*anchor);
        assert!(registry.invalidate_state(*anchor));
    }

    assert_eq!(registry.active_len(), 0);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 0);
    assert_eq!(registry.free_len(), anchors.len());
    assert_eq!(
        registry.storage.dense_capacity(),
        dense_capacity_before,
        "group anchor disposal must not compact dense storage on the mutation hot path"
    );
    assert_eq!(registry.validate_integrity(), Ok(()));
}

#[test]
fn sparse_group_anchor_ids_do_not_grow_dense_registry_storage() {
    let mut registry = AnchorRegistry::new();
    let anchor = AnchorId {
        id: 2_500_000,
        generation: 1,
    };
    registry.next_anchor = anchor.id as usize + 1;

    assert!(
        registry
            .set_state(anchor, AnchorState::Invalidated)
            .is_none()
    );
    registry.set_active(anchor, 4);

    assert_eq!(registry.active_index(anchor), Some(4));
    assert_eq!(registry.slot_len(), 1);
    assert_eq!(registry.active_len(), 1);
    assert_eq!(registry.detached_len(), 0);
    assert_eq!(registry.invalidated_len(), 0);
    assert!(
        registry.capacity() < 128,
        "sparse group ids must not allocate dense registry storage: capacity={}",
        registry.capacity()
    );
    assert_eq!(registry.validate_integrity(), Ok(()));
}

#[test]
fn registry_integrity_rejects_free_active_anchor_id() {
    let mut registry = AnchorRegistry::new();
    let anchor = registry.allocate();
    registry.set_active(anchor, 0);
    registry.free_ids.push(Reverse(anchor.id));

    assert_eq!(
        registry.validate_integrity(),
        Err(SlotInvariantError::AnchorRegistryInternalMismatch {
            detail: "free anchor id must not be active or detached",
            anchor_id: Some(anchor.id),
            expected: 0,
            actual: 1,
        })
    );
}

#[test]
fn registry_integrity_rejects_reused_generation_without_free_id() {
    let mut registry = AnchorRegistry::new();
    let anchor = AnchorId {
        id: 7,
        generation: 2,
    };
    registry.reused_generations.insert(anchor.id, 3);

    assert_eq!(
        registry.validate_integrity(),
        Err(SlotInvariantError::AnchorRegistryInternalMismatch {
            detail: "reused anchor generation must belong to a free id",
            anchor_id: Some(anchor.id),
            expected: 1,
            actual: 0,
        })
    );
}