synvael/crates/server/src/tests/chunk_cache.rs

51 lines
1.9 KiB
Rust

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