test: cover testWorldBackup

This commit is contained in:
dualfroz committed 2026-09-14 03:04:15 +02:00
1 parent 7b06ebd943
commit 8fab041683
1 file changed
+156
+156
View File
@@ -158,3 +158,159 @@ VF_TEST(anIncrementalKeepsOnlyTheChunksThatMoved) {
CHECK_EQ(full->state.size(), static_cast<std::size_t>(3)); CHECK_EQ(full->state.size(), static_cast<std::size_t>(3));
CHECK_EQ(full->parentId, static_cast<uint32_t>(0)); CHECK_EQ(full->parentId, static_cast<uint32_t>(0));
CHECK(first->kind == BackupKind::Incremental);
CHECK_EQ(first->parentId, id0);
CHECK_EQ(first->stored.size(), static_cast<std::size_t>(1));
CHECK(first->findStored({1, 0, 0}) != nullptr);
CHECK(first->findStored({0, 0, 0}) == nullptr);
CHECK(first->removed.empty());
CHECK_EQ(second->stored.size(), static_cast<std::size_t>(2));
CHECK(second->findStored({2, 0, 0}) != nullptr);
CHECK(second->findStored({3, 0, 0}) != nullptr);
CHECK_EQ(second->state.size(), static_cast<std::size_t>(4));
CHECK(third->stored.empty());
CHECK_EQ(third->removed.size(), static_cast<std::size_t>(1));
CHECK(third->removed[0] == Vec3i(0, 0, 0));
CHECK(first->storedBytes() < full->storedBytes());
CHECK_EQ(third->storedBytes(), static_cast<std::size_t>(0));
CHECK_EQ(store.storedBytes(),
full->storedBytes() + first->storedBytes() + second->storedBytes());
}
VF_TEST(aChainMissingALinkIsReportedInsteadOfRestored) {
SaveContainer container = baseContainer();
ByteBuffer save0 = writeSaveContainer(container);
replaceChunk(container, {1, 0, 0}, texturedChunk(3));
ByteBuffer save1 = writeSaveContainer(container);
replaceChunk(container, {2, 0, 0}, texturedChunk(4));
ByteBuffer save2 = writeSaveContainer(container);
BackupStore store;
uint32_t id0 = store.capture(BackupKind::Full, save0, 0);
uint32_t id1 = store.capture(BackupKind::Incremental, save1, 1000);
uint32_t id2 = store.capture(BackupKind::Incremental, save2, 2000);
CHECK(store.restore(id2).ok);
CHECK(store.drop(id1));
CHECK(!store.drop(id1));
CHECK_EQ(store.index().count(), static_cast<std::size_t>(2));
RestoreResult broken = store.restore(id2);
CHECK(!broken.ok);
CHECK(broken.save.empty());
CHECK(broken.failure.find("chain broken") != std::string::npos);
CHECK(broken.failure.find("#" + std::to_string(id1)) != std::string::npos);
bool complete = true;
std::string walkFailure;
std::vector<uint32_t> walk = store.index().chainTo(id2, complete, walkFailure);
CHECK(!complete);
CHECK(walk.empty());
CHECK(!walkFailure.empty());
RestoreResult stillGood = store.restore(id0);
CHECK(stillGood.ok);
CHECK(stillGood.save == save0);
RestoreResult unknown = store.restore(9999);
CHECK(!unknown.ok);
CHECK(unknown.failure.find("not in the index") != std::string::npos);
}
VF_TEST(chainWalkListsTheFullBackupFirstAndTheAskedForEntryLast) {
SaveContainer container = baseContainer();
ByteBuffer save0 = writeSaveContainer(container);
replaceChunk(container, {1, 0, 0}, texturedChunk(3));
ByteBuffer save1 = writeSaveContainer(container);
replaceChunk(container, {2, 0, 0}, texturedChunk(4));
ByteBuffer save2 = writeSaveContainer(container);
BackupStore store;
uint32_t id0 = store.capture(BackupKind::Full, save0, 0);
uint32_t id1 = store.capture(BackupKind::Incremental, save1, 1000);
uint32_t id2 = store.capture(BackupKind::Incremental, save2, 2000);
bool complete = false;
std::string walkFailure;
std::vector<uint32_t> walk = store.index().chainTo(id2, complete, walkFailure);
CHECK(complete);
CHECK(walkFailure.empty());
CHECK_EQ(walk.size(), static_cast<std::size_t>(3));
if (walk.size() != 3) return;
CHECK_EQ(walk[0], id0);
CHECK_EQ(walk[1], id1);
CHECK_EQ(walk[2], id2);
CHECK_EQ(store.index().latestId(), id2);
}
VF_TEST(captureRefusesAFragmentedContainerAndPointsAtTheCompactor) {
ByteBuffer save = writeSaveContainer(baseContainer());
CHECK(updateChunkInPlace(save, buildRecord({1, 0, 0}, texturedChunk(8), SaveVersion::V4),
false));
CHECK(!isCanonicalSaveLayout(save.data(), save.size()));
BackupStore store;
CHECK_EQ(store.capture(BackupKind::Full, save, 0), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("compact") != std::string::npos);
CHECK_EQ(store.index().count(), static_cast<std::size_t>(0));
RegionCompactor compactor;
ByteBuffer tidy;
CompactionStats stats;
CHECK(compactor.compact(save, tidy, stats));
uint32_t id = store.capture(BackupKind::Full, tidy, 0);
CHECK(id != 0u);
CHECK(store.restore(id).save == tidy);
}
VF_TEST(captureRefusesASaveTheScannerCallsDamaged) {
ByteBuffer save = writeSaveContainer(baseContainer());
SaveHeader header;
CHECK(readSaveHeader(save.data(), save.size(), header));
std::vector<SaveTableEntry> entries;
CHECK(readSaveTable(save.data(), save.size(), header, entries));
std::size_t payloadAt = static_cast<std::size_t>(entries[1].sectorOffset) * header.sectorBytes;
saveWriteU32At(save.data(), save.size(), payloadAt + 8, 0u);
BackupStore store;
CHECK_EQ(store.capture(BackupKind::Full, save, 0), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("integrity") != std::string::npos);
ByteBuffer rubbish(30, 0);
CHECK_EQ(store.capture(BackupKind::Full, rubbish, 0), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("readable container") != std::string::npos);
}
VF_TEST(anIncrementalWithoutAFullBehindItIsRefused) {
ByteBuffer save = writeSaveContainer(baseContainer());
BackupStore store;
CHECK_EQ(store.capture(BackupKind::Incremental, save, 0), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("no full backup") != std::string::npos);
CHECK(store.capture(BackupKind::Full, save, 100) != 0u);
CHECK_EQ(store.capture(BackupKind::Incremental, save, 50), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("runs behind") != std::string::npos);
SaveContainer elsewhere = baseContainer();
elsewhere.regionX = 4;
for (SaveChunkRecord& record : elsewhere.chunks) record.coord.x += 64;
ByteBuffer other = writeSaveContainer(elsewhere);
CHECK_EQ(store.capture(BackupKind::Incremental, other, 200), static_cast<uint32_t>(0));
CHECK(store.lastFailure().find("chain covers region") != std::string::npos);
RestoreResult empty = BackupStore{}.restoreLatest();
CHECK(!empty.ok);
CHECK(empty.failure.find("empty") != std::string::npos);
}
VF_TEST(captureMigratedLiftsAnOldSaveBeforeStoringIt) {
SaveContainer legacy;
legacy.version = SaveVersion::V1;
legacy.chunks.push_back(buildRecord({0, 0, 0}, texturedChunk(1), SaveVersion::V1));
legacy.chunks.push_back(buildRecord({1, 0, 0}, texturedChunk(2), SaveVersion::V1));
ByteBuffer ancient = writeSaveContainer(legacy);