diff --git a/tests/testSaveMigration.cpp b/tests/testSaveMigration.cpp index 8313d3c..414ba8f 100644 --- a/tests/testSaveMigration.cpp +++ b/tests/testSaveMigration.cpp @@ -313,3 +313,110 @@ VF_TEST(peekVersionReadsTheHeaderWithoutTheBody) { ByteBuffer buffer = writeSaveContainer(original); ByteBuffer headerOnly(buffer.begin(), buffer.begin() + saveHeaderBytes); + SaveVersion version = SaveVersion::V1; + CHECK(SaveMigrator::peekVersion(headerOnly.data(), headerOnly.size(), version)); + CHECK(version == SaveVersion::V3); + + ByteBuffer shorter(buffer.begin(), buffer.begin() + 12); + CHECK(!SaveMigrator::peekVersion(shorter.data(), shorter.size(), version)); +} + +VF_TEST(defaultLightIsBlockedByOpaqueBlocksAndLitByEmitters) { + Chunk chunk; + chunk.set(0, 0, 0, Block::Air); + chunk.set(1, 0, 0, Block::Stone); + chunk.set(2, 0, 0, Block::Glowstone); + + std::vector plane = defaultChunkLight(chunk, saveDefaultSkyLight); + CHECK_EQ(plane.size(), static_cast(chunkVolume)); + + uint8_t openCell = plane[static_cast(localIndex(0, 0, 0))]; + uint8_t stoneCell = plane[static_cast(localIndex(1, 0, 0))]; + uint8_t lampCell = plane[static_cast(localIndex(2, 0, 0))]; + + CHECK_EQ(static_cast(openCell >> 4), 15); + CHECK_EQ(static_cast(openCell & 0x0F), 0); + CHECK_EQ(static_cast(stoneCell >> 4), 0); + CHECK_EQ(static_cast(lampCell & 0x0F), blockLightEmission(Block::Glowstone)); + + std::vector dim = defaultChunkLight(chunk, 4); + CHECK_EQ(static_cast(dim[static_cast(localIndex(0, 0, 0))] >> 4), 4); +} + +VF_TEST(worldImportKeepsOnlyTheChunksOfTheAskedForRegion) { + World world; + world.ensureChunk({1, 0, 1}) = texturedChunk(1); + world.ensureChunk({2, 3, 4}) = texturedChunk(2); + world.ensureChunk({20, 0, 0}) = texturedChunk(3); + world.ensureChunk({5, 0, 5}); + + SaveContainer container = saveContainerFromWorld(world, RegionCoord{0, 0}, currentSaveVersion); + CHECK_EQ(container.chunks.size(), static_cast(2)); + CHECK(container.find({1, 0, 1}) != nullptr); + CHECK(container.find({2, 3, 4}) != nullptr); + CHECK(container.find({20, 0, 0}) == nullptr); + CHECK(container.find({5, 0, 5}) == nullptr); + + SaveContainer neighbour = saveContainerFromWorld(world, RegionCoord{1, 0}, currentSaveVersion); + CHECK_EQ(neighbour.chunks.size(), static_cast(1)); + CHECK(neighbour.find({20, 0, 0}) != nullptr); +} + +VF_TEST(applyingAContainerBackToAWorldRestoresTheBlocks) { + World source; + source.ensureChunk({1, 0, 1}) = texturedChunk(11); + source.ensureChunk({2, 1, 3}) = texturedChunk(12); + + SaveContainer container = saveContainerFromWorld(source, RegionCoord{0, 0}, currentSaveVersion); + ByteBuffer buffer = writeSaveContainer(container); + + SaveContainer reloaded; + CHECK(readSaveContainer(buffer.data(), buffer.size(), reloaded)); + World rebuilt; + applySaveContainerToWorld(reloaded, rebuilt); + + CHECK_EQ(rebuilt.chunkCount(), static_cast(2)); + CHECK(sameBlocks(*source.chunkAt({1, 0, 1}), *rebuilt.chunkAt({1, 0, 1}))); + CHECK(sameBlocks(*source.chunkAt({2, 1, 3}), *rebuilt.chunkAt({2, 1, 3}))); +} + +VF_TEST(payloadBytesCanBePulledOutOfAContainerVerbatim) { + SaveContainer container = buildContainer(SaveVersion::V4, 3); + ByteBuffer buffer = writeSaveContainer(container); + + ByteBuffer payload; + CHECK(readChunkPayloadBytes(buffer.data(), buffer.size(), Vec3i{1, 0, 3}, payload)); + CHECK(!payload.empty()); + + SaveChunkRecord decoded; + CHECK(decodeChunkPayload(SaveVersion::V4, payload.data(), payload.size(), decoded)); + const SaveChunkRecord* original = container.find({1, 0, 3}); + CHECK(original != nullptr); + if (original != nullptr) CHECK(sameBlocks(original->blocks, decoded.blocks)); + + ByteBuffer missing; + CHECK(!readChunkPayloadBytes(buffer.data(), buffer.size(), Vec3i{9, 9, 9}, missing)); +} + +VF_TEST(recordChecksumCoversTheBodyAndNotItsFraming) { + SaveContainer container = buildContainer(SaveVersion::V4, 1); + const SaveChunkRecord& record = container.chunks[0]; + + ByteBuffer loose = encodeChunkPayload(SaveVersion::V4, record, false); + ByteBuffer tight = encodeChunkPayload(SaveVersion::V4, record, true); + CHECK(tight.size() < loose.size()); + + uint32_t looseStored = 0, looseComputed = 0, tightStored = 0, tightComputed = 0; + CHECK(verifyChunkPayloadChecksum(SaveVersion::V4, loose.data(), loose.size(), looseStored, + looseComputed)); + CHECK(verifyChunkPayloadChecksum(SaveVersion::V4, tight.data(), tight.size(), tightStored, + tightComputed)); + CHECK_EQ(looseStored, looseComputed); + CHECK_EQ(tightStored, tightComputed); + CHECK_EQ(looseStored, tightStored); + + uint32_t stored = 0, computed = 0; + ByteBuffer ancient = encodeChunkPayload(SaveVersion::V1, record, false); + CHECK(!verifyChunkPayloadChecksum(SaveVersion::V1, ancient.data(), ancient.size(), stored, + computed)); +}