test: add tests for prefab structure templates and block stamping

This commit is contained in:
dualfroz committed 2026-08-27 11:52:27 +02:00
1 parent 38fdc60006
commit f802dd8ea6
1 file changed
+123
+123
View File
@@ -0,0 +1,123 @@
#include "testHarness.h"
#include "vf/Structures.h"
#include "vf/WorldGen.h"
using namespace vf;
namespace {
bool sameEdits(const std::vector<StructureEdit>& a, const std::vector<StructureEdit>& b) {
if (a.size() != b.size()) return false;
for (std::size_t i = 0; i < a.size(); ++i) {
if (!(a[i].offset == b[i].offset) || a[i].block != b[i].block) return false;
}
return true;
}
std::size_t countBlock(const World& world, Block target) {
std::size_t total = 0;
for (const auto& entry : world.allChunks())
for (Block b : entry.second->raw())
if (b == target) ++total;
return total;
}
bool worldsEqual(const World& a, const World& b) {
if (a.chunkCount() != b.chunkCount()) return false;
for (const auto& entry : a.allChunks()) {
const Chunk* other = b.chunkAt(entry.first);
if (!other) return false;
if (entry.second->raw() != other->raw()) return false;
}
return true;
}
} // namespace
VF_TEST(structureBuildIsDeterministicPerSeed) {
std::vector<StructureEdit> oakA = buildStructure(StructureKind::OakTree, 12345u);
std::vector<StructureEdit> oakB = buildStructure(StructureKind::OakTree, 12345u);
CHECK(sameEdits(oakA, oakB)); // same seed, same tree
std::vector<StructureEdit> oakC = buildStructure(StructureKind::OakTree, 999u);
CHECK(!sameEdits(oakA, oakC)); // different seed, different tree
CHECK(!oakA.empty());
}
VF_TEST(structureHutHasLanternFloorAndDoor) {
std::vector<StructureEdit> hut = buildStructure(StructureKind::Hut, 7u);
bool lantern = false, floorCentre = false, doorOpen = true;
for (const StructureEdit& e : hut) {
if (e.block == Block::Glowstone) lantern = true;
if (e.offset == Vec3i(0, 0, 0) && e.block == Block::Wood) floorCentre = true;
if (e.offset == Vec3i(0, 1, -2)) doorOpen = false; // doorway cell must stay empty
}
CHECK(lantern);
CHECK(floorCentre);
CHECK(doorOpen);
}
VF_TEST(structureStampWritesBlocks) {
World world;
std::vector<StructureEdit> oak = buildStructure(StructureKind::OakTree, 42u);
stampStructure(world, {100, 40, 100}, oak, 128);
CHECK(world.blockAt(100, 40, 100) == Block::Wood); // trunk base
CHECK(countBlock(world, Block::Leaves) > 0); // canopy present
}
VF_TEST(structureLeavesDoNotOverwriteSolids) {
World world;
world.setBlock(100, 41, 100, Block::Stone); // pre-existing solid where a leaf would go
std::vector<StructureEdit> oak = buildStructure(StructureKind::OakTree, 42u);
stampStructure(world, {100, 40, 100}, oak, 128);
CHECK(world.blockAt(100, 41, 100) == Block::Wood || world.blockAt(100, 41, 100) == Block::Stone);
// trunk (wood) may overwrite, but no leaf replaced the stone
}
VF_TEST(worldGenWithStructuresIsDeterministic) {
WorldGenParams params;
params.structures = true;
WorldGen genA(params), genB(params);
World a, b;
for (int cx = 0; cx < 5; ++cx)
for (int cz = 0; cz < 5; ++cz) {
genA.generateColumn(a, cx, cz);
genB.generateColumn(b, cx, cz);
}
CHECK(worldsEqual(a, b)); // same seed -> identical structures and terrain
}
VF_TEST(worldGenDifferentSeedDiffersWithStructures) {
WorldGenParams pa;
pa.seed = 1337u;
WorldGenParams pb;
pb.seed = 2024u;
WorldGen genA(pa), genB(pb);
World a, b;
for (int cx = 0; cx < 5; ++cx)
for (int cz = 0; cz < 5; ++cz) {
genA.generateColumn(a, cx, cz);
genB.generateColumn(b, cx, cz);
}
CHECK(!worldsEqual(a, b));
}
VF_TEST(worldGenStampsHutsWhenEnabled) {
WorldGenParams on;
on.structures = true;
WorldGen gen(on);
World world;
for (int cx = 0; cx < 16; ++cx)
for (int cz = 0; cz < 16; ++cz)
gen.generateColumn(world, cx, cz);
CHECK(countBlock(world, Block::Glowstone) > 0); // lantern proves a hut was stamped
WorldGenParams off;
off.structures = false;
WorldGen bare(off);
World plain;
for (int cx = 0; cx < 16; ++cx)
for (int cz = 0; cz < 16; ++cz)
bare.generateColumn(plain, cx, cz);
CHECK_EQ(countBlock(plain, Block::Glowstone), static_cast<std::size_t>(0));
}