From 50e91b882c2ccf979d13843a780778c9a8ed19c4 Mon Sep 17 00:00:00 2001 From: Desour Date: Mon, 10 Apr 2023 23:40:33 +0200 Subject: [PATCH] Add some simple unittests for shapeless recipes Note: devtest also has craft unittests (see devtest/mods/unittests/crafting.lua), but those aren't run at load-time. --- src/unittest/CMakeLists.txt | 1 + src/unittest/test_craft.cpp | 275 ++++++++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 src/unittest/test_craft.cpp diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt index 0f80bcf1a..c43a7dbd3 100644 --- a/src/unittest/CMakeLists.txt +++ b/src/unittest/CMakeLists.txt @@ -8,6 +8,7 @@ set (UNITTEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_collision.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_compression.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_connection.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_craft.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_filepath.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_irrptr.cpp diff --git a/src/unittest/test_craft.cpp b/src/unittest/test_craft.cpp new file mode 100644 index 000000000..5b546f709 --- /dev/null +++ b/src/unittest/test_craft.cpp @@ -0,0 +1,275 @@ +/* +Minetest +Copyright (C) 2023 DS + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "test.h" + +#include "craftdef.h" + +class TestCraft : public TestBase +{ +public: + TestCraft() { TestManager::registerTestModule(this); } + const char *getName() { return "TestCraft"; } + + void runTests(IGameDef *gamedef); + + static std::string getDumpedCraftResult(CraftInput input, IGameDef *gamedef); + static void registerItemWithGroups(const std::string &itemname, + const std::vector &groups, IGameDef *gamedef); + + void testShapeless(IGameDef *gamedef); +}; + +static TestCraft g_test_instance; + +void TestCraft::runTests(IGameDef *gamedef) +{ + TEST(testShapeless, gamedef); +} + +std::string TestCraft::getDumpedCraftResult(CraftInput input, IGameDef *gamedef) +{ + // (input is passed by value, because getCraftResult needs a non-const ref + // for decrementing input) + + IWritableCraftDefManager *cdef = (IWritableCraftDefManager *)gamedef->getCraftDefManager(); + + CraftOutput output{}; + std::vector output_replacements; + + cdef->getCraftResult(input, output, output_replacements, false, gamedef); + + return output.dump(); +} + +void TestCraft::registerItemWithGroups(const std::string &itemname, + const std::vector &groups, IGameDef *gamedef) +{ + IWritableItemDefManager *idef = (IWritableItemDefManager *)gamedef->getItemDefManager(); + + if (idef->isKnown(itemname)) { + // already registered. check that the groups match + const ItemDefinition &itemdef = idef->get(itemname); + + SANITY_CHECK(itemdef.groups.size() == groups.size()); + for (const auto &g : groups) { + auto it = itemdef.groups.find(g); + SANITY_CHECK(it != itemdef.groups.end()); + SANITY_CHECK(it->second == 1); + } + + } else { + // register it + ItemDefinition itemdef{}; + + itemdef.type = ITEM_CRAFT; + itemdef.name = itemname; + itemdef.description = itemname; + for (const auto &g : groups) + itemdef.groups[g] = 1; + idef->registerItem(itemdef); + } +} + +void TestCraft::testShapeless(IGameDef *gamedef) +{ + IWritableItemDefManager *idef = (IWritableItemDefManager *)gamedef->getItemDefManager(); + IWritableCraftDefManager *cdef = (IWritableCraftDefManager *)gamedef->getCraftDefManager(); + + auto to_item = [&](const std::string &itemstring) -> ItemStack { + ItemStack item; + item.deSerialize(itemstring, idef); + return item; + }; + + cdef->clear(); + + idef->registerAlias("crafttest:a1", "crafttest:i1"); + registerItemWithGroups("crafttest:i1", {}, gamedef); + registerItemWithGroups("crafttest:i2", {}, gamedef); + registerItemWithGroups("crafttest:i3", {}, gamedef); + registerItemWithGroups("crafttest:i4", {}, gamedef); + registerItemWithGroups("crafttest:g1g2", {"crafttest_g1", "crafttest_g2"}, gamedef); + + cdef->registerCraft(new CraftDefinitionShapeless( + "crafttest:i1", + { + "crafttest:i1", + "crafttest:a1", + }, + CraftReplacements{} + ), gamedef); + + cdef->registerCraft(new CraftDefinitionShapeless( + "crafttest:i2", + { + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "crafttest:i1", + }, + CraftReplacements{} + ), gamedef); + + cdef->registerCraft(new CraftDefinitionShapeless( + "crafttest:i3", + { + "crafttest:i2", + "crafttest:i1", + "crafttest:i2", + "group:crafttest_g1", + }, + CraftReplacements{} + ), gamedef); + + cdef->registerCraft(new CraftDefinitionShapeless( + "crafttest:i4", + { + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g2", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + "group:crafttest_g1", + }, + CraftReplacements{} + ), gamedef); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:i1"), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i1\", time=0)"); + + cdef->initHashes(gamedef); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:i1"), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i1\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:i1"), + to_item(""), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i1\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 4, + { + to_item("crafttest:i1"), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i1\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i2\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 4, + { + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i1"), + }), gamedef), + "(item=\"crafttest:i2\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:i2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:g1g2"), + }), gamedef), + "(item=\"crafttest:i3\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:g1g2"), + to_item("crafttest:i1"), + to_item("crafttest:i2"), + to_item("crafttest:i2"), + }), gamedef), + "(item=\"crafttest:i3\", time=0)"); + + UASSERTEQ(std::string, getDumpedCraftResult(CraftInput(CRAFT_METHOD_NORMAL, 3, + { + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + to_item("crafttest:g1g2"), + }), gamedef), + "(item=\"crafttest:i4\", time=0)"); +}