// SPDX-License-Identifier: AGPL-3.0-only use super::*; use shared::generator::{VoxelGenerator, WorldGenConfig}; use shared::world::{BlockId, ChunkPos}; use std::num::NonZeroUsize; /// Builds a generator with a small, cheap terrain configuration for cache tests. fn test_generator() -> VoxelGenerator { let config = WorldGenConfig { base_height: 8, noise_scale: 0.05, surface_block: BlockId(1), subsurface_block: BlockId(2), stone_block: BlockId(3), }; VoxelGenerator::new(config, 42) } /// A second lookup of the same position must be served from the store, not regenerated. #[test] fn repeated_lookup_is_a_cache_hit() { let generator = test_generator(); let cache = ChunkCache::new(NonZeroUsize::new(4).unwrap_or(NonZeroUsize::MIN)); let pos = ChunkPos::new(0, 0, 0); let first = cache.get_or_generate(pos, &generator); let second = cache.get_or_generate(pos, &generator); // Determinism guarantees identical output, and a single resident entry can only hold if the second call was a hit rather than a fresh generation-and-insert of a distinct value. assert_eq!(first.blocks, second.blocks); assert_eq!(cache.len(), 1); } /// Inserting beyond capacity evicts the least-recently-used entry. #[test] fn exceeding_capacity_evicts_oldest() { let generator = test_generator(); let cache = ChunkCache::new(NonZeroUsize::new(2).unwrap_or(NonZeroUsize::MIN)); let _ = cache.get_or_generate(ChunkPos::new(0, 0, 0), &generator); let _ = cache.get_or_generate(ChunkPos::new(1, 0, 0), &generator); // Touch the first so the second becomes the least-recently-used before the overflow. let _ = cache.get_or_generate(ChunkPos::new(0, 0, 0), &generator); let _ = cache.get_or_generate(ChunkPos::new(2, 0, 0), &generator); assert_eq!(cache.len(), 2); assert!(cache.contains(ChunkPos::new(0, 0, 0))); assert!(!cache.contains(ChunkPos::new(1, 0, 0))); }