test: extend coverage of testSchematic
This commit is contained in:
1 parent
be77c57de3
commit
dcba0c8da0
1 file changed
+179
@@ -315,3 +315,182 @@ VF_TEST(aTruncatedBufferIsRejectedAtEveryCutPoint) {
|
|||||||
Schematic::capture(source, Selection::box({0, 0, 0}, {4, 4, 4}), "cut", "f", 1u).encode();
|
Schematic::capture(source, Selection::box({0, 0, 0}, {4, 4, 4}), "cut", "f", 1u).encode();
|
||||||
CHECK(bytes.size() > 40u);
|
CHECK(bytes.size() > 40u);
|
||||||
|
|
||||||
|
Schematic loaded;
|
||||||
|
for (std::size_t keep : {std::size_t(0), std::size_t(3), std::size_t(11), bytes.size() - 5u,
|
||||||
|
bytes.size() - 1u}) {
|
||||||
|
ByteBuffer cut(bytes.begin(), bytes.begin() + static_cast<std::ptrdiff_t>(keep));
|
||||||
|
SchematicError error = Schematic::decode(cut.data(), cut.size(), loaded);
|
||||||
|
CHECK(error == SchematicError::Truncated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A body length claiming more bytes than the buffer holds is truncation too.
|
||||||
|
ByteBuffer lying = bytes;
|
||||||
|
writeU32(lying, 8, readU32(lying, 8) + 64u);
|
||||||
|
CHECK(Schematic::decode(lying.data(), lying.size(), loaded) == SchematicError::Truncated);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aFlippedByteInTheBodyIsCaughtByTheChecksum) {
|
||||||
|
World source = terrainWorld(5, 5);
|
||||||
|
ByteBuffer bytes =
|
||||||
|
Schematic::capture(source, Selection::box({0, 0, 0}, {4, 4, 4}), "bit", "f", 1u).encode();
|
||||||
|
|
||||||
|
Schematic loaded;
|
||||||
|
for (std::size_t offset : {bodyOffset, bodyOffset + 20u, bytes.size() - 6u}) {
|
||||||
|
ByteBuffer damaged = bytes;
|
||||||
|
damaged[offset] = static_cast<uint8_t>(damaged[offset] ^ 0x40u);
|
||||||
|
CHECK(Schematic::decode(damaged.data(), damaged.size(), loaded) ==
|
||||||
|
SchematicError::BadChecksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer wrongChecksum = bytes;
|
||||||
|
writeU32(wrongChecksum, wrongChecksum.size() - 4u, 0xdeadbeefu);
|
||||||
|
CHECK(Schematic::decode(wrongChecksum.data(), wrongChecksum.size(), loaded) ==
|
||||||
|
SchematicError::BadChecksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(dimensionsThatDoNotMatchThePayloadAreRejected) {
|
||||||
|
World source = terrainWorld(5, 5);
|
||||||
|
ByteBuffer bytes =
|
||||||
|
Schematic::capture(source, Selection::box({0, 0, 0}, {4, 4, 4}), "dim", "f", 1u).encode();
|
||||||
|
|
||||||
|
Schematic control;
|
||||||
|
CHECK(Schematic::decode(bytes.data(), bytes.size(), control) == SchematicError::None);
|
||||||
|
CHECK(control.header().dims == Vec3i(5, 5, 5));
|
||||||
|
|
||||||
|
ByteBuffer widened = bytes;
|
||||||
|
patchBody(widened, 3u, 6u);
|
||||||
|
Schematic loaded;
|
||||||
|
CHECK(Schematic::decode(widened.data(), widened.size(), loaded) ==
|
||||||
|
SchematicError::DimensionMismatch);
|
||||||
|
|
||||||
|
ByteBuffer negative = bytes;
|
||||||
|
negative[bodyOffset] = 0xffu;
|
||||||
|
refreshChecksum(negative);
|
||||||
|
CHECK(Schematic::decode(negative.data(), negative.size(), loaded) ==
|
||||||
|
SchematicError::DimensionMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aPaletteThatDoesNotDescribeRealBlocksIsRejected) {
|
||||||
|
World source = terrainWorld(5, 5);
|
||||||
|
ByteBuffer bytes =
|
||||||
|
Schematic::capture(source, Selection::box({0, 0, 0}, {4, 4, 4}), "pal", "f", 1u).encode();
|
||||||
|
|
||||||
|
Schematic loaded;
|
||||||
|
ByteBuffer unknownBlock = bytes;
|
||||||
|
patchBody(unknownBlock, paletteOffsetInBody, 250u);
|
||||||
|
CHECK(Schematic::decode(unknownBlock.data(), unknownBlock.size(), loaded) ==
|
||||||
|
SchematicError::BadPalette);
|
||||||
|
|
||||||
|
ByteBuffer emptyPalette = bytes;
|
||||||
|
patchBody(emptyPalette, 25u, 0u);
|
||||||
|
CHECK(Schematic::decode(emptyPalette.data(), emptyPalette.size(), loaded) ==
|
||||||
|
SchematicError::BadPalette);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(pasteModesDecideWhichExistingBlocksSurvive) {
|
||||||
|
ClipboardBuffer stamp({3, 1, 3}, {0, 0, 0});
|
||||||
|
for (int z = 0; z < 3; ++z)
|
||||||
|
for (int x = 0; x < 3; ++x) stamp.put(x, 0, z, Block::Planks);
|
||||||
|
Schematic schematic = Schematic::fromBuffer(stamp, "floor", "foksiu", 2u);
|
||||||
|
|
||||||
|
World overwrite;
|
||||||
|
for (int z = 0; z < 3; ++z)
|
||||||
|
for (int x = 0; x < 3; ++x) overwrite.setBlock(x, 0, z, Block::Stone);
|
||||||
|
CHECK_EQ(schematic.pasteInto(overwrite, {0, 0, 0}, ClipboardBuffer::PasteMode::Overwrite), 9u);
|
||||||
|
CHECK(overwrite.blockAt(1, 0, 1) == Block::Planks);
|
||||||
|
|
||||||
|
World intoAir;
|
||||||
|
for (int z = 0; z < 3; ++z)
|
||||||
|
for (int x = 0; x < 3; ++x) intoAir.setBlock(x, 0, z, Block::Stone);
|
||||||
|
CHECK_EQ(schematic.pasteInto(intoAir, {0, 0, 0}, ClipboardBuffer::PasteMode::IntoAirOnly), 0u);
|
||||||
|
CHECK(intoAir.blockAt(1, 0, 1) == Block::Stone);
|
||||||
|
CHECK_EQ(schematic.pasteInto(intoAir, {0, 1, 0}, ClipboardBuffer::PasteMode::IntoAirOnly), 9u);
|
||||||
|
CHECK(intoAir.blockAt(1, 1, 1) == Block::Planks);
|
||||||
|
|
||||||
|
World replaceOnly;
|
||||||
|
replaceOnly.setBlock(0, 0, 0, Block::Stone);
|
||||||
|
replaceOnly.setBlock(2, 0, 2, Block::Stone);
|
||||||
|
CHECK_EQ(schematic.pasteInto(replaceOnly, {0, 0, 0},
|
||||||
|
ClipboardBuffer::PasteMode::ReplaceExisting),
|
||||||
|
2u);
|
||||||
|
CHECK(replaceOnly.blockAt(0, 0, 0) == Block::Planks);
|
||||||
|
CHECK(replaceOnly.blockAt(1, 0, 1) == Block::Air);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theAnchorDecidesWhereAPastedSchematicLands) {
|
||||||
|
ClipboardBuffer stamp({3, 3, 3}, {1, 1, 1});
|
||||||
|
for (int y = 0; y < 3; ++y)
|
||||||
|
for (int z = 0; z < 3; ++z)
|
||||||
|
for (int x = 0; x < 3; ++x) stamp.put(x, y, z, Block::Sandstone);
|
||||||
|
Schematic schematic = Schematic::fromBuffer(stamp, "cube", "foksiu", 4u);
|
||||||
|
|
||||||
|
World world;
|
||||||
|
schematic.pasteInto(world, {50, 50, 50}, ClipboardBuffer::PasteMode::Overwrite);
|
||||||
|
CHECK(world.blockAt(50, 50, 50) == Block::Sandstone);
|
||||||
|
CHECK(world.blockAt(49, 49, 49) == Block::Sandstone);
|
||||||
|
CHECK(world.blockAt(51, 51, 51) == Block::Sandstone);
|
||||||
|
CHECK(world.blockAt(52, 50, 50) == Block::Air);
|
||||||
|
CHECK(world.blockAt(48, 50, 50) == Block::Air);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(pastingThroughTheHistoryIsOneUndoableBatch) {
|
||||||
|
World world = terrainWorld(6, 6);
|
||||||
|
Selection region = Selection::box({0, 0, 0}, {5, 4, 5});
|
||||||
|
Schematic saved = Schematic::capture(world, region, "copy", "foksiu", 1u);
|
||||||
|
|
||||||
|
EditHistory history(1u << 20);
|
||||||
|
std::size_t before = 0;
|
||||||
|
for (int y = 0; y <= 4; ++y)
|
||||||
|
for (int z = 0; z <= 5; ++z)
|
||||||
|
for (int x = 0; x <= 5; ++x)
|
||||||
|
if (!isAir(world.blockAt(x, y, z))) ++before;
|
||||||
|
|
||||||
|
std::size_t written = saved.pasteInto(world, history, {20, 0, 20},
|
||||||
|
ClipboardBuffer::PasteMode::Overwrite, 5u);
|
||||||
|
CHECK(written > 0u);
|
||||||
|
CHECK_EQ(history.stats().batchCount, 1u);
|
||||||
|
CHECK(world.blockAt(20, 0, 20) == world.blockAt(0, 0, 0));
|
||||||
|
|
||||||
|
CHECK(history.undo(world));
|
||||||
|
for (int y = 0; y <= 4; ++y)
|
||||||
|
for (int z = 0; z <= 5; ++z)
|
||||||
|
for (int x = 0; x <= 5; ++x) CHECK(isAir(world.blockAt(20 + x, y, 20 + z)));
|
||||||
|
|
||||||
|
std::size_t after = 0;
|
||||||
|
for (int y = 0; y <= 4; ++y)
|
||||||
|
for (int z = 0; z <= 5; ++z)
|
||||||
|
for (int x = 0; x <= 5; ++x)
|
||||||
|
if (!isAir(world.blockAt(x, y, z))) ++after;
|
||||||
|
CHECK_EQ(after, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(anEmptySchematicSurvivesTheRoundTrip) {
|
||||||
|
Schematic nothing = Schematic::fromBuffer(ClipboardBuffer{}, "void", "foksiu", 9u);
|
||||||
|
CHECK(nothing.header().dims == Vec3i(0, 0, 0));
|
||||||
|
|
||||||
|
ByteBuffer bytes = nothing.encode();
|
||||||
|
Schematic loaded;
|
||||||
|
CHECK(Schematic::decode(bytes.data(), bytes.size(), loaded) == SchematicError::None);
|
||||||
|
CHECK(loaded.buffer().empty());
|
||||||
|
CHECK(loaded.header().name == std::string("void"));
|
||||||
|
|
||||||
|
World world;
|
||||||
|
CHECK_EQ(loaded.pasteInto(world, {0, 0, 0}, ClipboardBuffer::PasteMode::Overwrite), 0u);
|
||||||
|
CHECK_EQ(world.chunkCount(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(reEncodingADecodedSchematicProducesTheSameBytes) {
|
||||||
|
World source = terrainWorld(7, 7);
|
||||||
|
Schematic saved = Schematic::capture(source, Selection::sphere({3, 3, 3}, 3), "stable",
|
||||||
|
"foksiu", 42u);
|
||||||
|
ByteBuffer first = saved.encode();
|
||||||
|
|
||||||
|
Schematic loaded;
|
||||||
|
CHECK(Schematic::decode(first.data(), first.size(), loaded) == SchematicError::None);
|
||||||
|
ByteBuffer second = loaded.encode();
|
||||||
|
CHECK(first == second);
|
||||||
|
|
||||||
|
CHECK(std::string(Schematic::errorText(SchematicError::None)) == std::string("ok"));
|
||||||
|
CHECK(std::string(Schematic::errorText(SchematicError::BadPalette)) !=
|
||||||
|
std::string(Schematic::errorText(SchematicError::BadChecksum)));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user