test: extend coverage of testDataPack

This commit is contained in:
dualfroz committed 2026-09-11 16:34:09 +02:00
1 parent 157b6e5207
commit c3d658be63
1 file changed
+158
+158
View File
@@ -318,3 +318,161 @@ VF_TEST(aTagMarkedReplaceWipesWhatCameBeforeIt) {
CHECK_EQ(logs.size(), static_cast<std::size_t>(1));
if (!logs.empty()) CHECK(logs[0] == Block::Cactus);
const BlockTag* tag = loader.blockTags().find(id("voxelforge:logs"));
CHECK(tag != nullptr);
CHECK(tag->replace);
CHECK(tag->contains(id("voxelforge:cactus")));
CHECK(!tag->contains(id("voxelforge:wood")));
}
VF_TEST(tagReferencesFlattenIntoTheirMembersWithoutDuplicates) {
DataPackLoader loader;
loader.addPack(basePack());
CHECK(loader.load());
std::vector<ResourceId> members;
CHECK(loader.blockTags().resolve(id("voxelforge:mineable"), members));
CHECK_EQ(members.size(), static_cast<std::size_t>(3));
if (members.size() == 3u) {
CHECK(members[0] == id("voxelforge:wood"));
CHECK(members[1] == id("voxelforge:stone"));
CHECK(members[2] == id("voxelforge:sand"));
}
CHECK(loader.blockTags().contains(id("voxelforge:mineable"), id("voxelforge:wood")));
CHECK(!loader.blockTags().contains(id("voxelforge:mineable"), id("voxelforge:cactus")));
std::vector<Block> blocks;
CHECK(loader.blocksInTag(id("voxelforge:mineable"), blocks));
CHECK_EQ(blocks.size(), static_cast<std::size_t>(3));
if (!blocks.empty()) CHECK(blocks[0] == Block::Wood);
std::vector<ItemId> fuel;
CHECK(loader.itemsInTag(id("voxelforge:fuel"), fuel));
CHECK_EQ(fuel.size(), static_cast<std::size_t>(2));
if (fuel.size() == 2u) {
CHECK(fuel[0] == ItemId::CoalLump);
CHECK(fuel[1] == ItemId::Planks);
}
// A tag that names a tag nobody defined resolves to nothing, loudly.
std::vector<ResourceId> unresolved;
std::string problem;
TagRegistry registry;
BlockTag dangling;
dangling.id = id("voxelforge:dangling");
dangling.entries.push_back({id("voxelforge:absent"), true});
registry.define(dangling);
CHECK(!registry.resolve(dangling.id, unresolved, problem));
CHECK(problem.find("unknown tag") != std::string::npos);
CHECK(!registry.hasCycle(dangling.id));
}
VF_TEST(aTagThatReferencesItselfIsReportedAsACycleInsteadOfLoopingForever) {
DataPackMeta meta;
meta.name = "looping";
DataPack pack(meta);
pack.addFile("data/voxelforge/tags/blocks/first.json",
R"json({"values": ["voxelforge:stone", "#voxelforge:second"]})json");
pack.addFile("data/voxelforge/tags/blocks/second.json",
R"json({"values": ["voxelforge:sand", "#voxelforge:third"]})json");
pack.addFile("data/voxelforge/tags/blocks/third.json",
R"json({"values": ["#voxelforge:first"]})json");
pack.addFile("data/voxelforge/tags/blocks/selfish.json",
R"json({"values": ["#voxelforge:selfish"]})json");
DataPackLoader loader;
loader.addPack(pack);
CHECK(loader.load());
const TagRegistry& tags = loader.blockTags();
std::vector<ResourceId> members;
std::string problem;
CHECK(!tags.resolve(id("voxelforge:first"), members, problem));
CHECK(problem.find("tag cycle") != std::string::npos);
CHECK(members.empty());
CHECK(tags.hasCycle(id("voxelforge:first")));
CHECK(tags.hasCycle(id("voxelforge:second")));
CHECK(tags.hasCycle(id("voxelforge:selfish")));
std::vector<Block> blocks;
CHECK(!loader.blocksInTag(id("voxelforge:first"), blocks));
CHECK(blocks.empty());
// A diamond is not a cycle: two paths onto the same tag still resolve.
DataPackMeta diamondMeta;
diamondMeta.name = "diamond";
DataPack diamond(diamondMeta);
diamond.addFile("data/voxelforge/tags/blocks/leaf.json",
R"json({"values": ["voxelforge:stone"]})json");
diamond.addFile("data/voxelforge/tags/blocks/left.json",
R"json({"values": ["#voxelforge:leaf"]})json");
diamond.addFile("data/voxelforge/tags/blocks/right.json",
R"json({"values": ["#voxelforge:leaf"]})json");
diamond.addFile("data/voxelforge/tags/blocks/top.json",
R"json({"values": ["#voxelforge:left", "#voxelforge:right"]})json");
DataPackLoader diamondLoader;
diamondLoader.addPack(diamond);
CHECK(diamondLoader.load());
CHECK(diamondLoader.blockTags().resolve(id("voxelforge:top"), members));
CHECK_EQ(members.size(), static_cast<std::size_t>(1));
CHECK(!diamondLoader.blockTags().hasCycle(id("voxelforge:top")));
}
VF_TEST(oneRottenFileCostsItselfAndNothingElseInThePack) {
DataPackMeta meta;
meta.name = "mixed";
DataPack pack(meta);
pack.addFile("data/voxelforge/recipes/good.json", appleBread);
pack.addFile("data/voxelforge/recipes/torn.json", "{\"type\": \"craftingShapeless\",");
pack.addFile("data/voxelforge/recipes/ghost_item.json",
R"json({"type": "craftingShapeless", "ingredients": ["voxelforge:cheese"],
"result": {"item": "voxelforge:bread"}})json");
pack.addFile("data/voxelforge/recipes/nonsense.json",
R"json({"type": "alchemy", "result": {"item": "voxelforge:bread"}})json");
pack.addFile("data/voxelforge/nowhere/lost.json", R"json({"values": []})json");
pack.addFile("data/voxelforge/lootTables/empty.json", R"json({"pools": []})json");
pack.addFile("data/voxelforge/tags/blocks/bad_entry.json",
R"json({"values": ["Not An Id"]})json");
pack.addFile("data/voxelforge/tags/blocks/fine.json",
R"json({"values": ["voxelforge:stone"]})json");
pack.addFile("data/voxelforge/recipes/ShoutyName.json", appleBread);
DataPackLoader loader;
loader.addPack(pack);
CHECK(!loader.load());
CHECK_EQ(loader.errors().size(), static_cast<std::size_t>(7));
for (const DataPackError& failure : loader.errors()) {
CHECK(!failure.file.empty());
CHECK(!failure.reason.empty());
CHECK_EQ(failure.pack, std::string("mixed"));
CHECK(failure.text().find("mixed/data/") != std::string::npos);
}
// The healthy files in the very same pack still landed.
CHECK_EQ(loader.recipes().size(), static_cast<std::size_t>(1));
CHECK(loader.recipe(id("voxelforge:good")) != nullptr);
CHECK_EQ(loader.blockTags().size(), static_cast<std::size_t>(1));
CHECK(loader.blockTags().has(id("voxelforge:fine")));
bool sawParseError = false;
bool sawUnknownItem = false;
bool sawUnknownFolder = false;
bool sawUppercaseId = false;
for (const DataPackError& failure : loader.errors()) {
if (failure.file == "data/voxelforge/recipes/torn.json") {
sawParseError = failure.line > 0;
}
if (failure.file == "data/voxelforge/recipes/ghost_item.json")
sawUnknownItem = failure.reason.find("no such item") != std::string::npos;
if (failure.file == "data/voxelforge/nowhere/lost.json")
sawUnknownFolder = failure.reason.find("known folder") != std::string::npos;
if (failure.file == "data/voxelforge/recipes/ShoutyName.json")
sawUppercaseId = failure.reason.find("valid resource id") != std::string::npos;
}
CHECK(sawParseError);
CHECK(sawUnknownItem);
CHECK(sawUnknownFolder);
CHECK(sawUppercaseId);
}