diff --git a/src/tests.zig b/src/tests.zig index 83d8d951..f9e03822 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -99,9 +99,12 @@ test { _ = @import("world/persistence/save_manager.zig"); _ = @import("world/meshing/quadric_simplifier.zig"); _ = @import("world/chunk_storage_tests.zig"); + _ = @import("world/chunk_storage_extended_tests.zig"); _ = @import("world/block_tests.zig"); _ = @import("world/block_registry_tests.zig"); + _ = @import("world/block_biome_tests.zig"); _ = @import("world/chunk_tests.zig"); + _ = @import("world/chunk_mesh_tests.zig"); _ = @import("world/packed_light_tests.zig"); _ = @import("world/meshing/boundary_tests.zig"); } diff --git a/src/world/block_biome_tests.zig b/src/world/block_biome_tests.zig new file mode 100644 index 00000000..e2f48bd3 --- /dev/null +++ b/src/world/block_biome_tests.zig @@ -0,0 +1,154 @@ +const std = @import("std"); +const testing = std.testing; +const BlockType = @import("block.zig").BlockType; +const Biome = @import("block.zig").Biome; + +test "Biome.getSurfaceBlock deep ocean returns gravel" { + try testing.expectEqual(BlockType.gravel, Biome.deep_ocean.getSurfaceBlock()); + try testing.expectEqual(BlockType.gravel, Biome.ocean.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock beach returns sand" { + try testing.expectEqual(BlockType.sand, Biome.beach.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock plains and forest return grass" { + try testing.expectEqual(BlockType.grass, Biome.plains.getSurfaceBlock()); + try testing.expectEqual(BlockType.grass, Biome.forest.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock desert returns sand" { + try testing.expectEqual(BlockType.sand, Biome.desert.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock taiga returns grass" { + try testing.expectEqual(BlockType.grass, Biome.taiga.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock snow tundra returns snow block" { + try testing.expectEqual(BlockType.snow_block, Biome.snow_tundra.getSurfaceBlock()); + try testing.expectEqual(BlockType.snow_block, Biome.snowy_mountains.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock mountains returns stone" { + try testing.expectEqual(BlockType.stone, Biome.mountains.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock river returns sand" { + try testing.expectEqual(BlockType.sand, Biome.river.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock swamp returns grass" { + try testing.expectEqual(BlockType.grass, Biome.swamp.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock mangrove swamp returns mud" { + try testing.expectEqual(BlockType.mud, Biome.mangrove_swamp.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock jungle returns grass" { + try testing.expectEqual(BlockType.grass, Biome.jungle.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock savanna returns grass" { + try testing.expectEqual(BlockType.grass, Biome.savanna.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock badlands returns red sand" { + try testing.expectEqual(BlockType.red_sand, Biome.badlands.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock mushroom fields returns mycelium" { + try testing.expectEqual(BlockType.mycelium, Biome.mushroom_fields.getSurfaceBlock()); +} + +test "Biome.getSurfaceBlock transition biomes return grass" { + try testing.expectEqual(BlockType.grass, Biome.foothills.getSurfaceBlock()); + try testing.expectEqual(BlockType.grass, Biome.marsh.getSurfaceBlock()); + try testing.expectEqual(BlockType.grass, Biome.dry_plains.getSurfaceBlock()); + try testing.expectEqual(BlockType.grass, Biome.coastal_plains.getSurfaceBlock()); +} + +test "Biome.getFillerBlock deep ocean returns gravel" { + try testing.expectEqual(BlockType.gravel, Biome.deep_ocean.getFillerBlock()); +} + +test "Biome.getFillerBlock ocean returns sand" { + try testing.expectEqual(BlockType.sand, Biome.ocean.getFillerBlock()); +} + +test "Biome.getFillerBlock beach and desert return sand" { + try testing.expectEqual(BlockType.sand, Biome.beach.getFillerBlock()); + try testing.expectEqual(BlockType.sand, Biome.desert.getFillerBlock()); + try testing.expectEqual(BlockType.sand, Biome.river.getFillerBlock()); +} + +test "Biome.getFillerBlock plains and forest return dirt" { + try testing.expectEqual(BlockType.dirt, Biome.plains.getFillerBlock()); + try testing.expectEqual(BlockType.dirt, Biome.forest.getFillerBlock()); +} + +test "Biome.getFillerBlock taiga returns dirt" { + try testing.expectEqual(BlockType.dirt, Biome.taiga.getFillerBlock()); +} + +test "Biome.getFillerBlock swamp returns dirt" { + try testing.expectEqual(BlockType.dirt, Biome.swamp.getFillerBlock()); +} + +test "Biome.getFillerBlock jungle returns dirt" { + try testing.expectEqual(BlockType.dirt, Biome.jungle.getFillerBlock()); +} + +test "Biome.getFillerBlock snow tundra returns dirt" { + try testing.expectEqual(BlockType.dirt, Biome.snow_tundra.getFillerBlock()); +} + +test "Biome.getFillerBlock mountains returns stone" { + try testing.expectEqual(BlockType.stone, Biome.mountains.getFillerBlock()); + try testing.expectEqual(BlockType.stone, Biome.snowy_mountains.getFillerBlock()); +} + +test "Biome.getFillerBlock mangrove swamp returns mud" { + try testing.expectEqual(BlockType.mud, Biome.mangrove_swamp.getFillerBlock()); +} + +test "Biome.getFillerBlock badlands returns terracotta" { + try testing.expectEqual(BlockType.terracotta, Biome.badlands.getFillerBlock()); +} + +test "Biome.getFillerBlock mushroom fields returns dirt" { + try testing.expectEqual(BlockType.dirt, Biome.mushroom_fields.getFillerBlock()); +} + +test "Biome.getFillerBlock transition biomes return dirt" { + try testing.expectEqual(BlockType.dirt, Biome.foothills.getFillerBlock()); + try testing.expectEqual(BlockType.dirt, Biome.marsh.getFillerBlock()); + try testing.expectEqual(BlockType.dirt, Biome.dry_plains.getFillerBlock()); + try testing.expectEqual(BlockType.dirt, Biome.coastal_plains.getFillerBlock()); +} + +test "Biome.getOceanFloorBlock deep depth returns gravel" { + try testing.expectEqual(BlockType.gravel, Biome.ocean.getOceanFloorBlock(50.0)); + try testing.expectEqual(BlockType.gravel, Biome.deep_ocean.getOceanFloorBlock(50.0)); +} + +test "Biome.getOceanFloorBlock mid depth returns clay" { + try testing.expectEqual(BlockType.clay, Biome.ocean.getOceanFloorBlock(20.0)); + try testing.expectEqual(BlockType.clay, Biome.deep_ocean.getOceanFloorBlock(20.0)); +} + +test "Biome.getOceanFloorBlock shallow returns sand" { + try testing.expectEqual(BlockType.sand, Biome.ocean.getOceanFloorBlock(10.0)); + try testing.expectEqual(BlockType.sand, Biome.deep_ocean.getOceanFloorBlock(5.0)); +} + +test "Biome.getOceanFloorBlock boundary at depth 15" { + try testing.expectEqual(BlockType.clay, Biome.ocean.getOceanFloorBlock(15.0001)); + try testing.expectEqual(BlockType.sand, Biome.ocean.getOceanFloorBlock(15.0)); +} + +test "Biome.getOceanFloorBlock boundary at depth 30" { + try testing.expectEqual(BlockType.gravel, Biome.ocean.getOceanFloorBlock(30.0001)); + try testing.expectEqual(BlockType.clay, Biome.ocean.getOceanFloorBlock(30.0)); +} diff --git a/src/world/chunk_mesh_tests.zig b/src/world/chunk_mesh_tests.zig new file mode 100644 index 00000000..8d8d660c --- /dev/null +++ b/src/world/chunk_mesh_tests.zig @@ -0,0 +1,43 @@ +const std = @import("std"); +const testing = std.testing; +const ChunkMesh = @import("chunk_mesh.zig").ChunkMesh; + +test "ChunkMesh.init creates mesh with null allocations" { + var mesh = ChunkMesh.init(testing.allocator); + try testing.expectEqual(false, mesh.ready); + try testing.expectEqual(null, mesh.solid_allocation); + try testing.expectEqual(null, mesh.cutout_allocation); + try testing.expectEqual(null, mesh.fluid_allocation); + try testing.expectEqual(null, mesh.pending_solid); + try testing.expectEqual(null, mesh.pending_cutout); + try testing.expectEqual(null, mesh.pending_fluid); + mesh.deinitWithoutRHI(); +} + +test "ChunkMesh.init sets allocator" { + var mesh = ChunkMesh.init(testing.allocator); + try testing.expectEqual(testing.allocator, mesh.allocator); + mesh.deinitWithoutRHI(); +} + +test "ChunkMesh.deinitWithoutRHI can be called on fresh mesh" { + var mesh = ChunkMesh.init(testing.allocator); + mesh.deinitWithoutRHI(); +} + +test "ChunkMesh.deinitWithoutRHI can be called twice safely" { + var mesh = ChunkMesh.init(testing.allocator); + mesh.deinitWithoutRHI(); + mesh.deinitWithoutRHI(); +} + +test "ChunkMesh.subchunk arrays are initially null" { + const NUM_SUBCHUNKS = @import("chunk_mesh.zig").NUM_SUBCHUNKS; + var mesh = ChunkMesh.init(testing.allocator); + for (0..NUM_SUBCHUNKS) |i| { + try testing.expectEqual(null, mesh.subchunk_solid[i]); + try testing.expectEqual(null, mesh.subchunk_cutout[i]); + try testing.expectEqual(null, mesh.subchunk_fluid[i]); + } + mesh.deinitWithoutRHI(); +} diff --git a/src/world/chunk_storage_extended_tests.zig b/src/world/chunk_storage_extended_tests.zig new file mode 100644 index 00000000..16b86c73 --- /dev/null +++ b/src/world/chunk_storage_extended_tests.zig @@ -0,0 +1,100 @@ +const std = @import("std"); +const testing = std.testing; +const ChunkStorage = @import("chunk_storage.zig").ChunkStorage; +const IChunkStorage = @import("chunk_storage.zig").IChunkStorage; + +test "ChunkStorage.getOrCreate idempotent" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const data1 = try storage.getOrCreate(0, 0); + const data2 = try storage.getOrCreate(0, 0); + try testing.expect(data1 == data2); + try testing.expectEqual(@as(usize, 1), storage.count()); +} + +test "ChunkStorage.getOrCreate distinct positions" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const data1 = try storage.getOrCreate(0, 0); + const data2 = try storage.getOrCreate(1, 0); + const data3 = try storage.getOrCreate(0, 1); + try testing.expect(data1 != data2); + try testing.expect(data2 != data3); + try testing.expectEqual(@as(usize, 3), storage.count()); +} + +test "ChunkStorage.getOrCreate negative coordinates" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const data = try storage.getOrCreate(-5, -10); + try testing.expectEqual(@as(i32, -5), data.chunk.chunk_x); + try testing.expectEqual(@as(i32, -10), data.chunk.chunk_z); +} + +test "ChunkStorage interface returns wrapper" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const iface = storage.interface(); + try testing.expectEqual(@as(usize, 0), iface.count()); +} + +test "ChunkStorage interface.get returns null for missing" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const iface = storage.interface(); + try testing.expectEqual(null, iface.get(99, 99)); +} + +test "ChunkStorage interface.get returns data after create" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + _ = try storage.getOrCreate(42, -7); + const iface = storage.interface(); + const data = iface.get(42, -7); + try testing.expect(data != null); + try testing.expectEqual(@as(i32, 42), data.?.chunk.chunk_x); + try testing.expectEqual(@as(i32, -7), data.?.chunk.chunk_z); +} + +test "ChunkStorage interface.totalVertexCount with no meshes" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + _ = try storage.getOrCreate(0, 0); + _ = try storage.getOrCreate(1, 1); + const iface = storage.interface(); + try testing.expectEqual(@as(u64, 0), iface.totalVertexCount()); +} + +test "ChunkStorage interface.isChunkRenderable false for missing" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const iface = storage.interface(); + try testing.expectEqual(false, iface.isChunkRenderable(0, 0)); +} + +test "ChunkStorage interface.isChunkRenderable false for new chunk" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + _ = try storage.getOrCreate(0, 0); + const iface = storage.interface(); + try testing.expectEqual(false, iface.isChunkRenderable(0, 0)); +} + +test "ChunkStorage next_job_token increments on create" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + try testing.expectEqual(@as(u32, 1), storage.next_job_token); + _ = try storage.getOrCreate(0, 0); + try testing.expectEqual(@as(u32, 2), storage.next_job_token); + _ = try storage.getOrCreate(1, 0); + try testing.expectEqual(@as(u32, 3), storage.next_job_token); +} + +test "ChunkStorage created chunk has correct job_token" { + var storage = ChunkStorage.init(testing.allocator); + defer storage.deinitWithoutRHI(); + const data1 = try storage.getOrCreate(0, 0); + try testing.expectEqual(@as(u32, 1), data1.chunk.job_token); + const data2 = try storage.getOrCreate(1, 0); + try testing.expectEqual(@as(u32, 2), data2.chunk.job_token); +}