From 2504538a3a164f27a96f413f5b389f8dad6b2cac Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 28 Aug 2019 08:29:02 +0200 Subject: Added a basic PalettedBlockArea implementation (#4377) --- tests/BlockTypeRegistry/BlockTypePaletteTest.cpp | 122 ++++++ tests/BlockTypeRegistry/CMakeLists.txt | 31 +- tests/BlockTypeRegistry/PalettedBlockAreaTest.cpp | 434 ++++++++++++++++++++++ 3 files changed, 586 insertions(+), 1 deletion(-) create mode 100644 tests/BlockTypeRegistry/BlockTypePaletteTest.cpp create mode 100644 tests/BlockTypeRegistry/PalettedBlockAreaTest.cpp (limited to 'tests/BlockTypeRegistry') diff --git a/tests/BlockTypeRegistry/BlockTypePaletteTest.cpp b/tests/BlockTypeRegistry/BlockTypePaletteTest.cpp new file mode 100644 index 000000000..ef79d8927 --- /dev/null +++ b/tests/BlockTypeRegistry/BlockTypePaletteTest.cpp @@ -0,0 +1,122 @@ +#include "Globals.h" +#include "../TestHelpers.h" +#include "BlockTypePalette.h" + + + + + +/** Tests the BlockTypePalette's basic APIs - creation, addition, querying. */ +static void testBasic() +{ + LOGD("Testing the basic BlockTypePalette's APIs..."); + + // Check inserting different block type names: + BlockTypePalette pal; + TEST_EQUAL(pal.index("testblock", BlockState()), 0); // Insert the first entry + TEST_EQUAL(pal.index("testblock", BlockState()), 0); // Check that it's not inserted again + TEST_EQUAL(pal.maybeIndex("testblock", BlockState()), (std::make_pair(0, true))); + TEST_EQUAL(pal.maybeIndex("nonexistent", BlockState()).second, false); + + TEST_EQUAL(pal.index("another", BlockState()), 1); // Insert the second entry + TEST_EQUAL(pal.index("another", BlockState()), 1); // Check that it's not inserted twice + TEST_EQUAL(pal.maybeIndex("another", BlockState()), (std::make_pair(1, true))); + TEST_EQUAL(pal.maybeIndex("testblock", BlockState()), (std::make_pair(0, true))); // The first one stayed + + // Check same block type name, different BlockState: + BlockState bs1; + BlockState bs2("key1", "value1"); + BlockState bs3({{"key1", "value1"}, {"key2", "value2"}}); + BlockState bs2Copy(bs2); + TEST_EQUAL(pal.index("multistate", bs1), 2); + TEST_EQUAL(pal.index("multistate", bs2), 3); + TEST_EQUAL(pal.index("multistate", bs3), 4); + TEST_EQUAL(pal.index("multistate", bs2Copy), 3); // Different BlockState instance, but same content + TEST_EQUAL(pal.count(), 5); + + // Check the entry() API: + TEST_EQUAL(pal.entry(0), (std::make_pair("testblock", BlockState()))); + TEST_EQUAL(pal.entry(1), (std::make_pair("another", BlockState()))); + TEST_EQUAL(pal.entry(2), (std::make_pair("multistate", BlockState(bs1)))); // make_pair requires a copy of the state + TEST_EQUAL(pal.entry(3), (std::make_pair("multistate", BlockState(bs2)))); + TEST_EQUAL(pal.entry(4), (std::make_pair("multistate", BlockState(bs3)))); +} + + + + + +/** Tests creating the transform map between two palettes. */ +static void testTransform() +{ + LOGD("Testing the createTransformMap API..."); + + // Create two palettes with some overlap: + BlockTypePalette pal1, pal2; + pal1.index("block1", BlockState()); + pal1.index("block2", BlockState()); + pal1.index("block3", BlockState()); + pal1.index("block4", BlockState()); + pal1.index("block5", BlockState("key1", "value1")); + pal2.index("block0", BlockState()); + pal2.index("block2", BlockState()); // overlap + pal2.index("block3", BlockState()); // overlap + pal2.index("block4", BlockState("key1", "value1")); + pal2.index("block5", BlockState("key1", "value1")); // overlap + pal2.index("block6", BlockState("key1", "value1")); + + // Check the transform map: + auto trans = pal1.createTransformMap(pal2); + TEST_EQUAL(pal1.maybeIndex("block1", BlockState()), (std::make_pair(0, true))); + TEST_EQUAL(pal1.maybeIndex("block2", BlockState()), (std::make_pair(1, true))); + TEST_EQUAL(pal1.maybeIndex("block3", BlockState()), (std::make_pair(2, true))); + TEST_EQUAL(pal1.maybeIndex("block4", BlockState()), (std::make_pair(3, true))); + TEST_EQUAL(pal1.maybeIndex("block5", BlockState("key1", "value1")), (std::make_pair(4, true))); + TEST_EQUAL(pal1.maybeIndex("block0", BlockState()), (std::make_pair(5, true))); + TEST_EQUAL(pal1.maybeIndex("block4", BlockState("key1", "value1")), (std::make_pair(6, true))); + TEST_EQUAL(pal1.maybeIndex("block6", BlockState("key1", "value1")), (std::make_pair(7, true))); + TEST_EQUAL(trans.size(), 6); + TEST_EQUAL(trans[0], 5); + TEST_EQUAL(trans[1], 1); + TEST_EQUAL(trans[2], 2); + TEST_EQUAL(trans[3], 6); + TEST_EQUAL(trans[4], 4); + TEST_EQUAL(trans[5], 7); +} + + + + + +int main() +{ + LOGD("BlockTypePaletteTest started"); + + try + { + testBasic(); + testTransform(); + } + catch (const TestException & exc) + { + LOGERROR("BlockTypePaletteTest has failed, an exception was thrown: %s", exc.mMessage.c_str()); + return 1; + } + catch (const std::exception & exc) + { + LOGERROR("BlockTypePaletteTest has failed, an exception was thrown: %s", exc.what()); + return 1; + } + catch (...) + { + LOGERROR("BlockTypePaletteTest has failed, an unhandled exception was thrown."); + return 1; + } + + LOGD("BlockTypePaletteTest finished"); + return 0; +} + + + + diff --git a/tests/BlockTypeRegistry/CMakeLists.txt b/tests/BlockTypeRegistry/CMakeLists.txt index c95c503dd..379158d5c 100644 --- a/tests/BlockTypeRegistry/CMakeLists.txt +++ b/tests/BlockTypeRegistry/CMakeLists.txt @@ -21,6 +21,16 @@ add_executable(BlockStateTest ) target_link_libraries(BlockStateTest fmt::fmt) +add_executable(BlockTypePaletteTest + BlockTypePaletteTest.cpp + ../TestHelpers.h + ${CMAKE_SOURCE_DIR}/src/BlockState.cpp + ${CMAKE_SOURCE_DIR}/src/BlockTypePalette.cpp + ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp +) +target_link_libraries(BlockTypePaletteTest fmt::fmt) + # BlockTypeRegistryTest: Verify that the BlockTypeRegistry class works as intended: add_executable(BlockTypeRegistryTest BlockTypeRegistryTest.cpp @@ -31,6 +41,21 @@ add_executable(BlockTypeRegistryTest ) target_link_libraries(BlockTypeRegistryTest fmt::fmt) +# PalettedBlockAreaTest: Verify that the PalettedBlockArea class works as intended: +add_executable(PalettedBlockAreaTest + PalettedBlockAreaTest.cpp + ../TestHelpers.h + ${CMAKE_SOURCE_DIR}/src/BlockState.cpp + ${CMAKE_SOURCE_DIR}/src/BlockTypeRegistry.cpp + ${CMAKE_SOURCE_DIR}/src/BlockTypePalette.cpp + ${CMAKE_SOURCE_DIR}/src/Cuboid.cpp + ${CMAKE_SOURCE_DIR}/src/PalettedBlockArea.cpp + ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp +) +target_link_libraries(PalettedBlockAreaTest fmt::fmt) + + @@ -38,8 +63,10 @@ target_link_libraries(BlockTypeRegistryTest fmt::fmt) # Define individual tests: -add_test(NAME BlockStateTest COMMAND BlockStateTest) +add_test(NAME BlockStateTest COMMAND BlockStateTest) add_test(NAME BlockTypeRegistryTest COMMAND BlockTypeRegistryTest) +add_test(NAME BlockTypePaletteTest COMMAND BlockTypePaletteTest) +add_test(NAME PalettedBlockAreaTest COMMAND PalettedBlockAreaTest) @@ -49,5 +76,7 @@ add_test(NAME BlockTypeRegistryTest COMMAND BlockTypeRegistryTest) set_target_properties( BlockStateTest BlockTypeRegistryTest + BlockTypePaletteTest + PalettedBlockAreaTest PROPERTIES FOLDER Tests/BlockTypeRegistry ) diff --git a/tests/BlockTypeRegistry/PalettedBlockAreaTest.cpp b/tests/BlockTypeRegistry/PalettedBlockAreaTest.cpp new file mode 100644 index 000000000..0fc7c9452 --- /dev/null +++ b/tests/BlockTypeRegistry/PalettedBlockAreaTest.cpp @@ -0,0 +1,434 @@ +#include "Globals.h" +#include +#include "PalettedBlockArea.h" +#include "../TestHelpers.h" + + + + + +/** Tests creating a PBA. */ +static void testCreation() +{ + LOG("Testing PBA creation..."); + + // Check failures: + TEST_ASSERTS(PalettedBlockArea::createFilled({-2, 3, 4}, "block", BlockState())); // Negative coords + TEST_THROWS(PalettedBlockArea::createFilled({4096, 4096, 4096}, "block", BlockState()), std::runtime_error); // Size too large for UInt32 + + // Check that a created area really is filled: + auto pba = PalettedBlockArea::createFilled({2, 3, 4}, "block", BlockState()); + TEST_EQUAL(pba.size(), Vector3i(2, 3, 4)); + TEST_EQUAL(pba.whole(), cCuboid({0, 0, 0}, {2, 3, 4})); + TEST_EQUAL(pba.palette().count(), 1); + TEST_EQUAL(pba.maybePaletteIndex("block", BlockState()), (std::make_pair(0, true))); + TEST_EQUAL(pba.maybePaletteIndex("nonexistentBlock", BlockState()).second, false); + for (int x = 0; x < 2; ++x) + { + for (int y = 0; y < 3; ++y) + { + for (int z = 0; z < 4; ++z) + { + TEST_EQUAL(pba.blockPaletteIndex({x, y, z}), 0); + } + } + } +} + + + + + +/** Tests setting and getting blocks. */ +static void testSetting() +{ + LOG("Testing PBA's set and get APIs..."); + auto pba = PalettedBlockArea::createFilled({2, 3, 4}, "block1", BlockState()); + pba.setBlock({0, 0, 0}, "block2", BlockState()); + pba.setBlock({1, 0, 0}, "block2", BlockState("key1", "value1")); + TEST_ASSERTS(pba.setBlock({2, 0, 0}, "block2", BlockState())); // Invalid coords + pba.setBlock({0, 1, 0}, 1); + TEST_ASSERTS(pba.setBlock({1, 1, 0}, 100)); // Invalid palette index + + // Check that the blocks have been set: + TEST_EQUAL(pba.palette().count(), 3); + TEST_EQUAL(pba.block({0, 0, 0}), (std::make_pair("block2", BlockState()))); + TEST_EQUAL(pba.block({1, 0, 0}), (std::make_pair("block2", BlockState("key1", "value1")))); + TEST_ASSERTS(pba.block({2, 0, 0})); // Invalid coords + TEST_EQUAL(pba.block({0, 1, 0}), (std::make_pair("block2", BlockState()))); + TEST_EQUAL(pba.block({1, 1, 0}), (std::make_pair("block1", BlockState()))); // Didn't overwrite with invalid palette index + TEST_EQUAL(pba.blockPaletteIndex({0, 0, 0}), 1); + TEST_EQUAL(pba.blockPaletteIndex({1, 0, 0}), 2); + TEST_ASSERTS(pba.blockPaletteIndex({2, 0, 0})); // Invalid coords + TEST_EQUAL(pba.blockPaletteIndex({0, 1, 0}), 1); + TEST_EQUAL(pba.blockPaletteIndex({1, 1, 0}), 0); // Didn't overwrite with invalid palette index + + // Test filling: + LOG("Testing PBA's fill API..."); + pba.fill("block3", BlockState("key1", "value1")); + TEST_EQUAL(pba.palette().count(), 1); + TEST_EQUAL(pba.paletteEntry(0), (std::make_pair("block3", BlockState("key1", "value1")))); + for (int x = 0; x < 2; ++x) + { + for (int y = 0; y < 2; ++y) + { + for (int z = 0; z < 2; ++z) + { + TEST_EQUAL(pba.blockPaletteIndex({x, y, z}), 0); + } + } + } +} + + + + + +/** Creates pbaA and pbaB that are pre-filled with known content. +The PBAs are then used for paste()-testing. +Used to be a function, but clang-3.5 didn't like it ("error: debug information for auto is not yet supported"). */ +#define PREPARE_PASTING_PBAS \ + auto pbaA = PalettedBlockArea::createFilled({5, 5, 5}, "blockA", BlockState()); \ + for (int x = 0; x < 5; ++x) \ + { \ + for (int y = 0; y < 5; ++y) \ + { \ + for (int z = 0; z < 5; ++z) \ + { \ + pbaA.setBlock({x, y, z}, Printf("A-%d-%d-%d", x, y, z), BlockState()); \ + } \ + } \ + } \ + auto pbaB = PalettedBlockArea::createFilled({6, 6, 6}, "blockB", BlockState()); \ + for (int x = 0; x < 6; ++x) \ + { \ + for (int y = 0; y < 6; ++y) \ + { \ + for (int z = 0; z < 6; ++z) \ + { \ + pbaB.setBlock({x, y, z}, Printf("B-%d-%d-%d", x, y, z), BlockState()); \ + } \ + } \ + } \ + do { } while (false) + + + + + +// This is the data for the original PBA, before the paste() operations. +// It is included here so that when adding new paste() tests we can simply copy it +// into the test function and modify for the test. +/* +static const AString expected[5][5][5] = +{ + { + {"A-0-0-0", "A-1-0-0", "A-2-0-0", "A-3-0-0", "A-4-0-0"}, + {"A-0-1-0", "A-1-1-0", "A-2-1-0", "A-3-1-0", "A-4-1-0"}, + {"A-0-2-0", "A-1-2-0", "A-2-2-0", "A-3-2-0", "A-4-2-0"}, + {"A-0-3-0", "A-1-3-0", "A-2-3-0", "A-3-3-0", "A-4-3-0"}, + {"A-0-4-0", "A-1-4-0", "A-2-4-0", "A-3-4-0", "A-4-4-0"}, + }, + { + {"A-0-0-1", "A-1-0-1", "A-2-0-1", "A-3-0-1", "A-4-0-1"}, + {"A-0-1-1", "A-1-1-1", "A-2-1-1", "A-3-1-1", "A-4-1-1"}, + {"A-0-2-1", "A-1-2-1", "A-2-2-1", "A-3-2-1", "A-4-2-1"}, + {"A-0-3-1", "A-1-3-1", "A-2-3-1", "A-3-3-1", "A-4-3-1"}, + {"A-0-4-1", "A-1-4-1", "A-2-4-1", "A-3-4-1", "A-4-4-1"}, + }, + { + {"A-0-0-2", "A-1-0-2", "A-2-0-2", "A-3-0-2", "A-4-0-2"}, + {"A-0-1-2", "A-1-1-2", "A-2-1-2", "A-3-1-2", "A-4-1-2"}, + {"A-0-2-2", "A-1-2-2", "A-2-2-2", "A-3-2-2", "A-4-2-2"}, + {"A-0-3-2", "A-1-3-2", "A-2-3-2", "A-3-3-2", "A-4-3-2"}, + {"A-0-4-2", "A-1-4-2", "A-2-4-2", "A-3-4-2", "A-4-4-2"}, + }, + { + {"A-0-0-3", "A-1-0-3", "A-2-0-3", "A-3-0-3", "A-4-0-3"}, + {"A-0-1-3", "A-1-1-3", "A-2-1-3", "A-3-1-3", "A-4-1-3"}, + {"A-0-2-3", "A-1-2-3", "A-2-2-3", "A-3-2-3", "A-4-2-3"}, + {"A-0-3-3", "A-1-3-3", "A-2-3-3", "A-3-3-3", "A-4-3-3"}, + {"A-0-4-3", "A-1-4-3", "A-2-4-3", "A-3-4-3", "A-4-4-3"}, + }, + { + {"A-0-0-4", "A-1-0-4", "A-2-0-4", "A-3-0-4", "A-4-0-4"}, + {"A-0-1-4", "A-1-1-4", "A-2-1-4", "A-3-1-4", "A-4-1-4"}, + {"A-0-2-4", "A-1-2-4", "A-2-2-4", "A-3-2-4", "A-4-2-4"}, + {"A-0-3-4", "A-1-3-4", "A-2-3-4", "A-3-3-4", "A-4-3-4"}, + {"A-0-4-4", "A-1-4-4", "A-2-4-4", "A-3-4-4", "A-4-4-4"}, + }, +}; +*/ + + + + + +/** Tests the "paste()" operation with the pasted region being completely inside the destination PBA. */ +static void testPastingCompletelyInside() +{ + LOG("Testing the paste() API with destination completely inside (with cropping)..."); + PREPARE_PASTING_PBAS; + pbaA.paste(pbaB, cCuboid({1, 1, 1}, {4, 4, 4}), {1, 0, 0}); // Paste the 3x3x3 inside area from pbaB to pbaA, starting at {1, 0, 0} + static const AString expected[5][5][5] = + { + { + {"A-0-0-0", "B-1-1-1", "B-2-1-1", "B-3-1-1", "A-4-0-0"}, + {"A-0-1-0", "B-1-2-1", "B-2-2-1", "B-3-2-1", "A-4-1-0"}, + {"A-0-2-0", "B-1-3-1", "B-2-3-1", "B-3-3-1", "A-4-2-0"}, + {"A-0-3-0", "A-1-3-0", "A-2-3-0", "A-3-3-0", "A-4-3-0"}, + {"A-0-4-0", "A-1-4-0", "A-2-4-0", "A-3-4-0", "A-4-4-0"}, + }, + { + {"A-0-0-1", "B-1-1-2", "B-2-1-2", "B-3-1-2", "A-4-0-1"}, + {"A-0-1-1", "B-1-2-2", "B-2-2-2", "B-3-2-2", "A-4-1-1"}, + {"A-0-2-1", "B-1-3-2", "B-2-3-2", "B-3-3-2", "A-4-2-1"}, + {"A-0-3-1", "A-1-3-1", "A-2-3-1", "A-3-3-1", "A-4-3-1"}, + {"A-0-4-1", "A-1-4-1", "A-2-4-1", "A-3-4-1", "A-4-4-1"}, + }, + { + {"A-0-0-2", "B-1-1-3", "B-2-1-3", "B-3-1-3", "A-4-0-2"}, + {"A-0-1-2", "B-1-2-3", "B-2-2-3", "B-3-2-3", "A-4-1-2"}, + {"A-0-2-2", "B-1-3-3", "B-2-3-3", "B-3-3-3", "A-4-2-2"}, + {"A-0-3-2", "A-1-3-2", "A-2-3-2", "A-3-3-2", "A-4-3-2"}, + {"A-0-4-2", "A-1-4-2", "A-2-4-2", "A-3-4-2", "A-4-4-2"}, + }, + { + {"A-0-0-3", "A-1-0-3", "A-2-0-3", "A-3-0-3", "A-4-0-3"}, + {"A-0-1-3", "A-1-1-3", "A-2-1-3", "A-3-1-3", "A-4-1-3"}, + {"A-0-2-3", "A-1-2-3", "A-2-2-3", "A-3-2-3", "A-4-2-3"}, + {"A-0-3-3", "A-1-3-3", "A-2-3-3", "A-3-3-3", "A-4-3-3"}, + {"A-0-4-3", "A-1-4-3", "A-2-4-3", "A-3-4-3", "A-4-4-3"}, + }, + { + {"A-0-0-4", "A-1-0-4", "A-2-0-4", "A-3-0-4", "A-4-0-4"}, + {"A-0-1-4", "A-1-1-4", "A-2-1-4", "A-3-1-4", "A-4-1-4"}, + {"A-0-2-4", "A-1-2-4", "A-2-2-4", "A-3-2-4", "A-4-2-4"}, + {"A-0-3-4", "A-1-3-4", "A-2-3-4", "A-3-3-4", "A-4-3-4"}, + {"A-0-4-4", "A-1-4-4", "A-2-4-4", "A-3-4-4", "A-4-4-4"}, + }, + }; + for (int x = 0; x < 5; ++x) + { + for (int y = 0; y < 5; ++y) + { + for (int z = 0; z < 5; ++z) + { + auto got = pbaA.block({x, y, z}).first; + TEST_EQUAL_MSG( + pbaA.block({x, y, z}).first, + expected[z][y][x], + Printf("{%d, %d, %d}, exp %s, got %s", x, y, z, expected[z][y][x].c_str(), pbaA.block({x, y, z}).first.c_str()).c_str() + ); + } + } + } +} + + + + + +/** Tests the "paste()" operation with the pasted region overflowing the destination PBA into the positive coords. */ +static void testPastingPositiveOverflow() +{ + LOG("Testing the paste() API with positive overflow..."); + PREPARE_PASTING_PBAS; + pbaA.paste(pbaB, Vector3i{3, 2, 1}); // Paste the entire pbaB to pbaA, starting at {3, 2, 1} + static const AString expected[5][5][5] = + { + { + {"A-0-0-0", "A-1-0-0", "A-2-0-0", "A-3-0-0", "A-4-0-0"}, + {"A-0-1-0", "A-1-1-0", "A-2-1-0", "A-3-1-0", "A-4-1-0"}, + {"A-0-2-0", "A-1-2-0", "A-2-2-0", "A-3-2-0", "A-4-2-0"}, + {"A-0-3-0", "A-1-3-0", "A-2-3-0", "A-3-3-0", "A-4-3-0"}, + {"A-0-4-0", "A-1-4-0", "A-2-4-0", "A-3-4-0", "A-4-4-0"}, + }, + { + {"A-0-0-1", "A-1-0-1", "A-2-0-1", "A-3-0-1", "A-4-0-1"}, + {"A-0-1-1", "A-1-1-1", "A-2-1-1", "A-3-1-1", "A-4-1-1"}, + {"A-0-2-1", "A-1-2-1", "A-2-2-1", "B-0-0-0", "B-1-0-0"}, + {"A-0-3-1", "A-1-3-1", "A-2-3-1", "B-0-1-0", "B-1-1-0"}, + {"A-0-4-1", "A-1-4-1", "A-2-4-1", "B-0-2-0", "B-1-2-0"}, + }, + { + {"A-0-0-2", "A-1-0-2", "A-2-0-2", "A-3-0-2", "A-4-0-2"}, + {"A-0-1-2", "A-1-1-2", "A-2-1-2", "A-3-1-2", "A-4-1-2"}, + {"A-0-2-2", "A-1-2-2", "A-2-2-2", "B-0-0-1", "B-1-0-1"}, + {"A-0-3-2", "A-1-3-2", "A-2-3-2", "B-0-1-1", "B-1-1-1"}, + {"A-0-4-2", "A-1-4-2", "A-2-4-2", "B-0-2-1", "B-1-2-1"}, + }, + { + {"A-0-0-3", "A-1-0-3", "A-2-0-3", "A-3-0-3", "A-4-0-3"}, + {"A-0-1-3", "A-1-1-3", "A-2-1-3", "A-3-1-3", "A-4-1-3"}, + {"A-0-2-3", "A-1-2-3", "A-2-2-3", "B-0-0-2", "B-1-0-2"}, + {"A-0-3-3", "A-1-3-3", "A-2-3-3", "B-0-1-2", "B-1-1-2"}, + {"A-0-4-3", "A-1-4-3", "A-2-4-3", "B-0-2-2", "B-1-2-2"}, + }, + { + {"A-0-0-4", "A-1-0-4", "A-2-0-4", "A-3-0-4", "A-4-0-4"}, + {"A-0-1-4", "A-1-1-4", "A-2-1-4", "A-3-1-4", "A-4-1-4"}, + {"A-0-2-4", "A-1-2-4", "A-2-2-4", "B-0-0-3", "B-1-0-3"}, + {"A-0-3-4", "A-1-3-4", "A-2-3-4", "B-0-1-3", "B-1-1-3"}, + {"A-0-4-4", "A-1-4-4", "A-2-4-4", "B-0-2-3", "B-1-2-3"}, + }, + }; + for (int x = 0; x < 5; ++x) + { + for (int y = 0; y < 5; ++y) + { + for (int z = 0; z < 5; ++z) + { + auto got = pbaA.block({x, y, z}).first; + TEST_EQUAL_MSG( + pbaA.block({x, y, z}).first, + expected[z][y][x], + Printf("{%d, %d, %d}, exp %s, got %s", x, y, z, expected[z][y][x].c_str(), pbaA.block({x, y, z}).first.c_str()).c_str() + ); + } + } + } +} + + + + + +/** Tests the "paste()" operation with the pasted region overflowing the destination PBA into the negative coords. */ +static void testPastingNegativeOverflow() +{ + LOG("Testing the paste() API with negative overflow..."); + PREPARE_PASTING_PBAS; + pbaA.paste(pbaB, Vector3i{-4, -3, -2}); // Paste the entire pbaB to pbaA, starting at {-4, -3, -2} + static const AString expected[5][5][5] = + { + { + {"B-4-3-2", "B-5-3-2", "A-2-0-0", "A-3-0-0", "A-4-0-0"}, + {"B-4-4-2", "B-5-4-2", "A-2-1-0", "A-3-1-0", "A-4-1-0"}, + {"B-4-5-2", "B-5-5-2", "A-2-2-0", "A-3-2-0", "A-4-2-0"}, + {"A-0-3-0", "A-1-3-0", "A-2-3-0", "A-3-3-0", "A-4-3-0"}, + {"A-0-4-0", "A-1-4-0", "A-2-4-0", "A-3-4-0", "A-4-4-0"}, + }, + { + {"B-4-3-3", "B-5-3-3", "A-2-0-1", "A-3-0-1", "A-4-0-1"}, + {"B-4-4-3", "B-5-4-3", "A-2-1-1", "A-3-1-1", "A-4-1-1"}, + {"B-4-5-3", "B-5-5-3", "A-2-2-1", "A-3-2-1", "A-4-2-1"}, + {"A-0-3-1", "A-1-3-1", "A-2-3-1", "A-3-3-1", "A-4-3-1"}, + {"A-0-4-1", "A-1-4-1", "A-2-4-1", "A-3-4-1", "A-4-4-1"}, + }, + { + {"B-4-3-4", "B-5-3-4", "A-2-0-2", "A-3-0-2", "A-4-0-2"}, + {"B-4-4-4", "B-5-4-4", "A-2-1-2", "A-3-1-2", "A-4-1-2"}, + {"B-4-5-4", "B-5-5-4", "A-2-2-2", "A-3-2-2", "A-4-2-2"}, + {"A-0-3-2", "A-1-3-2", "A-2-3-2", "A-3-3-2", "A-4-3-2"}, + {"A-0-4-2", "A-1-4-2", "A-2-4-2", "A-3-4-2", "A-4-4-2"}, + }, + { + {"B-4-3-5", "B-5-3-5", "A-2-0-3", "A-3-0-3", "A-4-0-3"}, + {"B-4-4-5", "B-5-4-5", "A-2-1-3", "A-3-1-3", "A-4-1-3"}, + {"B-4-5-5", "B-5-5-5", "A-2-2-3", "A-3-2-3", "A-4-2-3"}, + {"A-0-3-3", "A-1-3-3", "A-2-3-3", "A-3-3-3", "A-4-3-3"}, + {"A-0-4-3", "A-1-4-3", "A-2-4-3", "A-3-4-3", "A-4-4-3"}, + }, + { + {"A-0-0-4", "A-1-0-4", "A-2-0-4", "A-3-0-4", "A-4-0-4"}, + {"A-0-1-4", "A-1-1-4", "A-2-1-4", "A-3-1-4", "A-4-1-4"}, + {"A-0-2-4", "A-1-2-4", "A-2-2-4", "A-3-2-4", "A-4-2-4"}, + {"A-0-3-4", "A-1-3-4", "A-2-3-4", "A-3-3-4", "A-4-3-4"}, + {"A-0-4-4", "A-1-4-4", "A-2-4-4", "A-3-4-4", "A-4-4-4"}, + }, + }; + for (int x = 0; x < 5; ++x) + { + for (int y = 0; y < 5; ++y) + { + for (int z = 0; z < 5; ++z) + { + auto got = pbaA.block({x, y, z}).first; + TEST_EQUAL_MSG( + pbaA.block({x, y, z}).first, + expected[z][y][x], + Printf("{%d, %d, %d}, exp %s, got %s", x, y, z, expected[z][y][x].c_str(), pbaA.block({x, y, z}).first.c_str()).c_str() + ); + } + } + } +} + + + + + +/** Tests the "paste()" operation with the pasted region overflowing the destination PBA into mixed positive and negative coords. */ +static void testPastingMixedOverflow() +{ + LOG("Testing the paste() API with mixed positive and negative overflow..."); + PREPARE_PASTING_PBAS; + pbaA.paste(pbaB, Vector3i{-4, -3, 2}); // Paste the entire pbaB to pbaA, starting at {-4, -3, 2} + static const AString expected[5][5][5] = + { + { + {"A-0-0-0", "A-1-0-0", "A-2-0-0", "A-3-0-0", "A-4-0-0"}, + {"A-0-1-0", "A-1-1-0", "A-2-1-0", "A-3-1-0", "A-4-1-0"}, + {"A-0-2-0", "A-1-2-0", "A-2-2-0", "A-3-2-0", "A-4-2-0"}, + {"A-0-3-0", "A-1-3-0", "A-2-3-0", "A-3-3-0", "A-4-3-0"}, + {"A-0-4-0", "A-1-4-0", "A-2-4-0", "A-3-4-0", "A-4-4-0"}, + }, + { + {"A-0-0-1", "A-1-0-1", "A-2-0-1", "A-3-0-1", "A-4-0-1"}, + {"A-0-1-1", "A-1-1-1", "A-2-1-1", "A-3-1-1", "A-4-1-1"}, + {"A-0-2-1", "A-1-2-1", "A-2-2-1", "A-3-2-1", "A-4-2-1"}, + {"A-0-3-1", "A-1-3-1", "A-2-3-1", "A-3-3-1", "A-4-3-1"}, + {"A-0-4-1", "A-1-4-1", "A-2-4-1", "A-3-4-1", "A-4-4-1"}, + }, + { + {"B-4-3-0", "B-5-3-0", "A-2-0-2", "A-3-0-2", "A-4-0-2"}, + {"B-4-4-0", "B-5-4-0", "A-2-1-2", "A-3-1-2", "A-4-1-2"}, + {"B-4-5-0", "B-5-5-0", "A-2-2-2", "A-3-2-2", "A-4-2-2"}, + {"A-0-3-2", "A-1-3-2", "A-2-3-2", "A-3-3-2", "A-4-3-2"}, + {"A-0-4-2", "A-1-4-2", "A-2-4-2", "A-3-4-2", "A-4-4-2"}, + }, + { + {"B-4-3-1", "B-5-3-1", "A-2-0-3", "A-3-0-3", "A-4-0-3"}, + {"B-4-4-1", "B-5-4-1", "A-2-1-3", "A-3-1-3", "A-4-1-3"}, + {"B-4-5-1", "B-5-5-1", "A-2-2-3", "A-3-2-3", "A-4-2-3"}, + {"A-0-3-3", "A-1-3-3", "A-2-3-3", "A-3-3-3", "A-4-3-3"}, + {"A-0-4-3", "A-1-4-3", "A-2-4-3", "A-3-4-3", "A-4-4-3"}, + }, + { + {"B-4-3-2", "B-5-3-2", "A-2-0-4", "A-3-0-4", "A-4-0-4"}, + {"B-4-4-2", "B-5-4-2", "A-2-1-4", "A-3-1-4", "A-4-1-4"}, + {"B-4-5-2", "B-5-5-2", "A-2-2-4", "A-3-2-4", "A-4-2-4"}, + {"A-0-3-4", "A-1-3-4", "A-2-3-4", "A-3-3-4", "A-4-3-4"}, + {"A-0-4-4", "A-1-4-4", "A-2-4-4", "A-3-4-4", "A-4-4-4"}, + }, + }; + for (int x = 0; x < 5; ++x) + { + for (int y = 0; y < 5; ++y) + { + for (int z = 0; z < 5; ++z) + { + auto got = pbaA.block({x, y, z}).first; + TEST_EQUAL_MSG( + pbaA.block({x, y, z}).first, + expected[z][y][x], + Printf("{%d, %d, %d}, exp %s, got %s", x, y, z, expected[z][y][x].c_str(), pbaA.block({x, y, z}).first.c_str()).c_str() + ); + } + } + } +} + + + + + +IMPLEMENT_TEST_MAIN("PalettedBlockArea", + testCreation(); + testSetting(); + testPastingCompletelyInside(); + testPastingPositiveOverflow(); + testPastingNegativeOverflow(); + testPastingMixedOverflow(); +) -- cgit v1.2.3