test_moveaction.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. Minetest
  3. Copyright (C) 2022 Minetest core developers & community
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "test.h"
  17. #include "mock_inventorymanager.h"
  18. #include "mock_server.h"
  19. #include "mock_serveractiveobject.h"
  20. class TestMoveAction : public TestBase
  21. {
  22. public:
  23. TestMoveAction() { TestManager::registerTestModule(this); }
  24. const char *getName() { return "TestMoveAction"; }
  25. void runTests(IGameDef *gamedef);
  26. void testMove(ServerActiveObject *obj, IGameDef *gamedef);
  27. void testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef);
  28. void testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef);
  29. void testMoveSomewherePartial(ServerActiveObject *obj, IGameDef *gamedef);
  30. void testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
  31. void testMovePartial(ServerActiveObject *obj, IGameDef *gamedef);
  32. void testSwap(ServerActiveObject *obj, IGameDef *gamedef);
  33. void testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
  34. void testSwapToUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
  35. void testCallbacks(ServerActiveObject *obj, Server *server);
  36. void testCallbacksSwap(ServerActiveObject *obj, Server *server);
  37. };
  38. static TestMoveAction g_test_instance;
  39. void TestMoveAction::runTests(IGameDef *gamedef)
  40. {
  41. MockServer server(getTestTempDirectory());
  42. server.createScripting();
  43. try {
  44. std::string builtin = Server::getBuiltinLuaPath() + DIR_DELIM;
  45. auto script = server.getScriptIface();
  46. script->loadBuiltin();
  47. script->loadMod(builtin + "game" DIR_DELIM "tests" DIR_DELIM "test_moveaction.lua", BUILTIN_MOD_NAME);
  48. } catch (ModError &e) {
  49. rawstream << e.what() << std::endl;
  50. num_tests_failed = 1;
  51. return;
  52. }
  53. MetricsBackend mb;
  54. auto null_map = std::unique_ptr<ServerMap>();
  55. ServerEnvironment server_env(std::move(null_map), &server, &mb);
  56. MockServerActiveObject obj(&server_env);
  57. TEST(testMove, &obj, gamedef);
  58. TEST(testMoveFillStack, &obj, gamedef);
  59. TEST(testMoveSomewhere, &obj, gamedef);
  60. TEST(testMoveSomewherePartial, &obj, gamedef);
  61. TEST(testMoveUnallowed, &obj, gamedef);
  62. TEST(testMovePartial, &obj, gamedef);
  63. TEST(testSwap, &obj, gamedef);
  64. TEST(testSwapFromUnallowed, &obj, gamedef);
  65. TEST(testSwapToUnallowed, &obj, gamedef);
  66. TEST(testCallbacks, &obj, &server);
  67. TEST(testCallbacksSwap, &obj, &server);
  68. }
  69. static ItemStack parse_itemstack(const char *s)
  70. {
  71. ItemStack item;
  72. item.deSerialize(s, nullptr);
  73. return item;
  74. }
  75. static void apply_action(const char *s, InventoryManager *inv, ServerActiveObject *obj, IGameDef *gamedef)
  76. {
  77. std::istringstream str(s);
  78. InventoryAction *action = InventoryAction::deSerialize(str);
  79. action->apply(inv, obj, gamedef);
  80. delete action;
  81. }
  82. void TestMoveAction::testMove(ServerActiveObject *obj, IGameDef *gamedef)
  83. {
  84. MockInventoryManager inv(gamedef);
  85. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:stone 50"));
  86. inv.p2.addList("main", 10);
  87. apply_action("Move 20 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  88. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:stone 30");
  89. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 20");
  90. }
  91. void TestMoveAction::testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef)
  92. {
  93. MockInventoryManager inv(gamedef);
  94. auto list = inv.p1.addList("main", 10);
  95. list->changeItem(0, parse_itemstack("default:stone 209"));
  96. list->changeItem(1, parse_itemstack("default:stone 90")); // 9 free slots
  97. apply_action("Move 209 player:p1 main 0 player:p1 main 1", &inv, obj, gamedef);
  98. UASSERT(list->getItem(0).getItemString() == "default:stone 200");
  99. UASSERT(list->getItem(1).getItemString() == "default:stone 99");
  100. // Trigger stack swap
  101. apply_action("Move 200 player:p1 main 0 player:p1 main 1", &inv, obj, gamedef);
  102. UASSERT(list->getItem(0).getItemString() == "default:stone 99");
  103. UASSERT(list->getItem(1).getItemString() == "default:stone 200");
  104. }
  105. void TestMoveAction::testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef)
  106. {
  107. MockInventoryManager inv(gamedef);
  108. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:stone 50"));
  109. InventoryList *list = inv.p2.addList("main", 10);
  110. list->addItem(0, parse_itemstack("default:brick 10"));
  111. list->addItem(2, parse_itemstack("default:stone 85"));
  112. apply_action("MoveSomewhere 50 player:p1 main 0 player:p2 main", &inv, obj, gamedef);
  113. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:brick 10");
  114. UASSERT(inv.p2.getList("main")->getItem(1).getItemString() == "default:stone 36");
  115. // Partially moved
  116. UASSERT(inv.p2.getList("main")->getItem(2).getItemString() == "default:stone 99");
  117. }
  118. void TestMoveAction::testMoveSomewherePartial(ServerActiveObject *obj, IGameDef *gamedef)
  119. {
  120. // "Fail" because the destination list is full.
  121. MockInventoryManager inv(gamedef);
  122. InventoryList *src = inv.p1.addList("main", 3);
  123. src->addItem(0, parse_itemstack("default:brick 10"));
  124. src->changeItem(1, parse_itemstack("default:stone 111")); // oversized
  125. InventoryList *dst = inv.p2.addList("main", 1);
  126. dst->addItem(0, parse_itemstack("default:stone 98"));
  127. // No free slots to fit
  128. apply_action("MoveSomewhere 10 player:p1 main 0 player:p2 main", &inv, obj, gamedef);
  129. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:brick 10");
  130. // Only 1 item fits
  131. apply_action("MoveSomewhere 111 player:p1 main 1 player:p2 main", &inv, obj, gamedef);
  132. UASSERT(inv.p1.getList("main")->getItem(1).getItemString() == "default:stone 110");
  133. }
  134. void TestMoveAction::testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef)
  135. {
  136. MockInventoryManager inv(gamedef);
  137. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 50"));
  138. inv.p2.addList("main", 10);
  139. apply_action("Move 20 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  140. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_deny 50");
  141. UASSERT(inv.p2.getList("main")->getItem(0).empty())
  142. }
  143. void TestMoveAction::testMovePartial(ServerActiveObject *obj, IGameDef *gamedef)
  144. {
  145. MockInventoryManager inv(gamedef);
  146. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_max_5 50"));
  147. inv.p2.addList("main", 10);
  148. // Lua: limited to 5 per transaction
  149. apply_action("Move 20 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  150. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 45");
  151. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 5");
  152. }
  153. void TestMoveAction::testSwap(ServerActiveObject *obj, IGameDef *gamedef)
  154. {
  155. MockInventoryManager inv(gamedef);
  156. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:stone 50"));
  157. inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:brick 60"));
  158. apply_action("Move 50 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  159. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:brick 60");
  160. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 50");
  161. }
  162. void TestMoveAction::testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *gamedef)
  163. {
  164. MockInventoryManager inv(gamedef);
  165. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 50"));
  166. inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:brick 60"));
  167. apply_action("Move 50 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  168. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_deny 50");
  169. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:brick 60");
  170. }
  171. void TestMoveAction::testSwapToUnallowed(ServerActiveObject *obj, IGameDef *gamedef)
  172. {
  173. MockInventoryManager inv(gamedef);
  174. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:stone 50"));
  175. inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 60"));
  176. apply_action("Move 50 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);
  177. UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:stone 50");
  178. UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_deny 60");
  179. }
  180. static bool check_function(lua_State *L, bool expect_swap)
  181. {
  182. bool ok = false;
  183. int error_handler = PUSH_ERROR_HANDLER(L);
  184. lua_getglobal(L, "core");
  185. lua_getfield(L, -1, "__helper_check_callbacks");
  186. lua_pushboolean(L, expect_swap);
  187. int result = lua_pcall(L, 1, 1, error_handler);
  188. if (result == 0)
  189. ok = lua_toboolean(L, -1);
  190. else
  191. errorstream << lua_tostring(L, -1) << std::endl; // Error msg
  192. lua_settop(L, 0);
  193. return ok;
  194. }
  195. void TestMoveAction::testCallbacks(ServerActiveObject *obj, Server *server)
  196. {
  197. server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
  198. MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();
  199. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_cb_1 10"));
  200. inv.p2.addList("main", 10);
  201. apply_action("Move 10 player:p1 main 0 player:p2 main 1", &inv, obj, server);
  202. // Expecting no swap. 4 callback executions in total. See Lua file for details.
  203. UASSERT(check_function(server->getScriptIface()->getStack(), false));
  204. server->m_inventory_mgr.reset();
  205. }
  206. void TestMoveAction::testCallbacksSwap(ServerActiveObject *obj, Server *server)
  207. {
  208. server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
  209. MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();
  210. inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_cb_2 50"));
  211. inv.p2.addList("main", 10)->addItem(1, parse_itemstack("default:takeput_cb_1 10"));
  212. apply_action("Move 10 player:p1 main 0 player:p2 main 1", &inv, obj, server);
  213. // Expecting swap. 8 callback executions in total. See Lua file for details.
  214. UASSERT(check_function(server->getScriptIface()->getStack(), true));
  215. server->m_inventory_mgr.reset();
  216. }