From 41651c73172cc90c9e1bccb5a705bf97954bbff1 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 25 May 2025 13:31:16 +0200 Subject: [PATCH] Add C++-side unit tests for MMVManip --- src/dummymap.h | 7 +- src/map.cpp | 4 +- src/unittest/test_voxelmanipulator.cpp | 122 +++++++++++++++++-------- 3 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/dummymap.h b/src/dummymap.h index 2da371884..408f91341 100644 --- a/src/dummymap.h +++ b/src/dummymap.h @@ -27,12 +27,13 @@ public: void fill(v3s16 bpmin, v3s16 bpmax, MapNode n) { for (s16 z = bpmin.Z; z <= bpmax.Z; z++) - for (s16 y = bpmin.Y; y <= bpmax.Y; y++) - for (s16 x = bpmin.X; x <= bpmax.X; x++) { + for (s16 x = bpmin.X; x <= bpmax.X; x++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) { MapBlock *block = getBlockNoCreateNoEx({x, y, z}); if (block) { + auto *data = block->getData(); for (size_t i = 0; i < MapBlock::nodecount; i++) - block->getData()[i] = n; + data[i] = n; block->expireIsAirCache(); } } diff --git a/src/map.cpp b/src/map.cpp index d88200846..b04376de3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -772,7 +772,7 @@ void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent) infostream<emergeBlock(p, true); + assert(block); block->copyTo(*this); } else { flags |= VMANIP_BLOCK_DATA_INEXIST; diff --git a/src/unittest/test_voxelmanipulator.cpp b/src/unittest/test_voxelmanipulator.cpp index 09d4b5781..d677ac5e0 100644 --- a/src/unittest/test_voxelmanipulator.cpp +++ b/src/unittest/test_voxelmanipulator.cpp @@ -4,11 +4,13 @@ #include "test.h" -#include +#include #include "gamedef.h" #include "log.h" #include "voxel.h" +#include "dummymap.h" +#include "irrlicht_changes/printing.h" class TestVoxelManipulator : public TestBase { public: @@ -17,59 +19,30 @@ public: void runTests(IGameDef *gamedef); - void testVoxelArea(); - void testVoxelManipulator(const NodeDefManager *nodedef); + void testBasic(const NodeDefManager *nodedef); + void testEmerge(IGameDef *gamedef); + void testBlitBack(IGameDef *gamedef); }; static TestVoxelManipulator g_test_instance; void TestVoxelManipulator::runTests(IGameDef *gamedef) { - TEST(testVoxelArea); - TEST(testVoxelManipulator, gamedef->getNodeDefManager()); + TEST(testBasic, gamedef->ndef()); + TEST(testEmerge, gamedef); + TEST(testBlitBack, gamedef); } //////////////////////////////////////////////////////////////////////////////// -void TestVoxelManipulator::testVoxelArea() -{ - VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1)); - UASSERT(a.index(0,0,0) == 1*3*3 + 1*3 + 1); - UASSERT(a.index(-1,-1,-1) == 0); - - VoxelArea c(v3s16(-2,-2,-2), v3s16(2,2,2)); - // An area that is 1 bigger in x+ and z- - VoxelArea d(v3s16(-2,-2,-3), v3s16(3,2,2)); - - std::list aa; - d.diff(c, aa); - - // Correct results - std::vector results; - results.emplace_back(v3s16(-2,-2,-3), v3s16(3,2,-3)); - results.emplace_back(v3s16(3,-2,-2), v3s16(3,2,2)); - - UASSERT(aa.size() == results.size()); - - infostream<<"Result of diff:"<print(infostream); - infostream << std::endl; - - auto j = std::find(results.begin(), results.end(), *it); - UASSERT(j != results.end()); - results.erase(j); - } -} - - -void TestVoxelManipulator::testVoxelManipulator(const NodeDefManager *nodedef) +void TestVoxelManipulator::testBasic(const NodeDefManager *nodedef) { VoxelManipulator v; v.print(infostream, nodedef); + UASSERT(v.m_area.hasEmptyExtent()); - infostream << "*** Setting (-1,0,-1)=2 ***" << std::endl; + infostream << "*** Setting (-1,0,-1) ***" << std::endl; v.setNode(v3s16(-1,0,-1), MapNode(t_CONTENT_GRASS)); v.print(infostream, nodedef); @@ -89,3 +62,74 @@ void TestVoxelManipulator::testVoxelManipulator(const NodeDefManager *nodedef) UASSERT(v.getNode(v3s16(-1,0,-1)).getContent() == t_CONTENT_GRASS); EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1))); } + +void TestVoxelManipulator::testEmerge(IGameDef *gamedef) +{ + constexpr int bs = MAP_BLOCKSIZE; + + DummyMap map(gamedef, {0,0,0}, {1,1,1}); + map.fill({0,0,0}, {1,1,1}, CONTENT_AIR); + + MMVManip vm(&map); + UASSERT(!vm.isOrphan()); + + // emerge something + vm.initialEmerge({0,0,0}, {0,0,0}); + UASSERTEQ(auto, vm.m_area.MinEdge, v3s16(0)); + UASSERTEQ(auto, vm.m_area.MaxEdge, v3s16(bs-1)); + UASSERTEQ(auto, vm.getNodeNoExNoEmerge({0,0,0}).getContent(), CONTENT_AIR); + + map.setNode({0, 1,0}, t_CONTENT_BRICK); + map.setNode({0,bs+1,0}, t_CONTENT_BRICK); + + // emerge top block: this should not re-read the first one + vm.initialEmerge({0,0,0}, {0,1,0}); + UASSERTEQ(auto, vm.m_area.getExtent(), v3s32(bs,2*bs,bs)); + + UASSERTEQ(auto, vm.getNodeNoExNoEmerge({0, 1,0}).getContent(), CONTENT_AIR); + UASSERTEQ(auto, vm.getNodeNoExNoEmerge({0,bs+1,0}).getContent(), t_CONTENT_BRICK); + + // emerge out of bounds: should produce empty data + vm.initialEmerge({0,0,0}, {0,2,0}, false); + UASSERTEQ(auto, vm.m_area.getExtent(), v3s32(bs,3*bs,bs)); + + UASSERTEQ(auto, vm.getNodeNoExNoEmerge({0,2*bs,0}).getContent(), CONTENT_IGNORE); + UASSERT(!vm.exists({0,2*bs,0})); + + // clear + vm.clear(); + UASSERT(vm.m_area.hasEmptyExtent()); +} + +void TestVoxelManipulator::testBlitBack(IGameDef *gamedef) +{ + DummyMap map(gamedef, {-1,-1,-1}, {1,1,1}); + map.fill({0,0,0}, {0,0,0}, CONTENT_AIR); + + std::unique_ptr vm2; + + { + MMVManip vm(&map); + vm.initialEmerge({0,0,0}, {0,0,0}); + UASSERT(vm.exists({0,0,0})); + vm.setNodeNoEmerge({0,0,0}, t_CONTENT_STONE); + vm.setNodeNoEmerge({1,1,1}, t_CONTENT_GRASS); + vm.setNodeNoEmerge({2,2,2}, CONTENT_IGNORE); + // test out clone and reparent too + vm2.reset(vm.clone()); + } + + UASSERT(vm2); + UASSERT(vm2->isOrphan()); + vm2->reparent(&map); + + std::map modified; + vm2->blitBackAll(&modified); + UASSERTEQ(size_t, modified.size(), 1); + UASSERTEQ(auto, modified.begin()->first, v3s16(0,0,0)); + + UASSERTEQ(auto, map.getNode({0,0,0}).getContent(), t_CONTENT_STONE); + UASSERTEQ(auto, map.getNode({1,1,1}).getContent(), t_CONTENT_GRASS); + // ignore nodes are not written (is this an intentional feature?) + UASSERTEQ(auto, map.getNode({2,2,2}).getContent(), CONTENT_AIR); +}