Skip to content

Commit

Permalink
Unittest: Add inventory callback tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SmallJoker committed Jan 20, 2024
1 parent ec9f2e0 commit 1b300ec
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/script/cpp_api/s_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class ScriptApiBase : protected LuaHelper {
friend class ModApiBase;
friend class ModApiEnv;
friend class LuaVoxelManip;
friend class TestMoveAction; // needs getStack()

/*
Subtle edge case with coroutines: If for whatever reason you have a
Expand Down
3 changes: 3 additions & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,10 @@ class Server : public con::PeerHandler, public MapEventReceiver,
private:
friend class EmergeThread;
friend class RemoteClient;

// unittest classes
friend class TestServerShutdownState;
friend class TestMoveAction;

struct ShutdownState {
friend class TestServerShutdownState;
Expand Down
7 changes: 4 additions & 3 deletions src/server/serverinventorymgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ class ServerInventoryManager : public InventoryManager
m_env = env;
}

Inventory *getInventory(const InventoryLocation &loc);
void setInventoryModified(const InventoryLocation &loc);
// virtual: Overwritten by MockInventoryManager for the unittests
virtual Inventory *getInventory(const InventoryLocation &loc);
virtual void setInventoryModified(const InventoryLocation &loc);

// Creates or resets inventory
Inventory *createDetachedInventory(const std::string &name, IItemDefManager *idef,
Expand All @@ -52,7 +53,7 @@ class ServerInventoryManager : public InventoryManager
void sendDetachedInventories(const std::string &peer_name, bool incremental,
std::function<void(const std::string &, Inventory *)> apply_cb);

private:
protected:
struct DetachedInventory
{
std::unique_ptr<Inventory> inventory;
Expand Down
17 changes: 12 additions & 5 deletions src/unittest/mock_inventorymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <gamedef.h>
#include <inventory.h>
#include <inventorymanager.h>
#pragma once

class MockInventoryManager : public InventoryManager
#include "gamedef.h"
#include "inventory.h"
#include "server/serverinventorymgr.h"

class ServerEnvironment;

class MockInventoryManager : public ServerInventoryManager
{
public:
MockInventoryManager(IGameDef *gamedef) :
p1(gamedef->getItemDefManager()),
p2(gamedef->getItemDefManager())
{};

virtual Inventory* getInventory(const InventoryLocation &loc){
Inventory *getInventory(const InventoryLocation &loc) override
{
if (loc.type == InventoryLocation::PLAYER && loc.name == "p1")
return &p1;
if (loc.type == InventoryLocation::PLAYER && loc.name == "p2")
return &p2;
return nullptr;
}
void setInventoryModified(const InventoryLocation &loc) override {}

Inventory p1;
Inventory p2;

};
2 changes: 2 additions & 0 deletions src/unittest/mock_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include <server.h>

class MockServer : public Server
Expand Down
112 changes: 79 additions & 33 deletions src/unittest/test_moveaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mock_serveractiveobject.h"

#include "scripting_server.h"
#include "server/mods.h"


class TestMoveAction : public TestBase
Expand All @@ -39,50 +40,39 @@ class TestMoveAction : public TestBase
void testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef);
void testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
void testMovePartial(ServerActiveObject *obj, IGameDef *gamedef);

void testSwap(ServerActiveObject *obj, IGameDef *gamedef);
void testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
void testSwapToUnallowed(ServerActiveObject *obj, IGameDef *gamedef);

void testCallbacks(ServerActiveObject *obj, Server *server);
void testCallbacksSwap(ServerActiveObject *obj, Server *server);
};

static TestMoveAction g_test_instance;

const static char *helper_lua_src = R"(
core.register_allow_player_inventory_action(function(player, action, inventory, info)
if action == "move" then
return info.count
end
if info.stack:get_name() == "default:water" then
return 0
end
if info.stack:get_name() == "default:lava" then
return 5
end
return info.stack:get_count()
end)
)";

void TestMoveAction::runTests(IGameDef *gamedef)
{
MockServer server(getTestTempDirectory());

const auto helper_lua = getTestTempFile();
std::ofstream ofs(helper_lua, std::ios::out | std::ios::binary);
ofs << helper_lua_src;
ofs.close();

ServerScripting server_scripting(&server);
try {
server_scripting.loadMod(Server::getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
server_scripting.loadMod(helper_lua, BUILTIN_MOD_NAME);
// FIXME: When removing the line below, the unittest does NOT crash
// (but it should) when running all unittests in order or registration.
server.m_modmgr = std::make_unique<ServerModManager>(server.m_path_world);

std::string builtin = Server::getBuiltinLuaPath() + DIR_DELIM;
server_scripting.loadMod(builtin + "init.lua", BUILTIN_MOD_NAME);
server_scripting.loadMod(builtin + "game" DIR_DELIM "tests" DIR_DELIM "test_moveaction.lua", BUILTIN_MOD_NAME);
} catch (ModError &e) {
// Print backtrace in case of syntax errors
rawstream << e.what() << std::endl;
num_tests_failed = 1;
return;
}

server.m_script = &server_scripting;

MetricsBackend mb;
ServerEnvironment server_env(nullptr, &server_scripting, &server, "", &mb);
MockServerActiveObject obj(&server_env);
Expand All @@ -92,9 +82,15 @@ void TestMoveAction::runTests(IGameDef *gamedef)
TEST(testMoveSomewhere, &obj, gamedef);
TEST(testMoveUnallowed, &obj, gamedef);
TEST(testMovePartial, &obj, gamedef);

TEST(testSwap, &obj, gamedef);
TEST(testSwapFromUnallowed, &obj, gamedef);
TEST(testSwapToUnallowed, &obj, gamedef);

TEST(testCallbacks, &obj, &server);
TEST(testCallbacksSwap, &obj, &server);

server.m_script = nullptr; // Do not free stack memory
}

static ItemStack parse_itemstack(const char *s)
Expand Down Expand Up @@ -165,26 +161,27 @@ void TestMoveAction::testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamede
{
MockInventoryManager inv(gamedef);

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:water 50"));
inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 50"));
inv.p2.addList("main", 10);

apply_action("Move 20 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);

UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:water 50");
UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_deny 50");
UASSERT(inv.p2.getList("main")->getItem(0).empty())
}

void TestMoveAction::testMovePartial(ServerActiveObject *obj, IGameDef *gamedef)
{
MockInventoryManager inv(gamedef);

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:lava 50"));
inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_max_5 50"));
inv.p2.addList("main", 10);

// Lua: limited to 5 per transaction
apply_action("Move 20 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);

UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:lava 45");
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:lava 5");
UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 45");
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 5");
}

void TestMoveAction::testSwap(ServerActiveObject *obj, IGameDef *gamedef)
Expand All @@ -204,12 +201,12 @@ void TestMoveAction::testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *ga
{
MockInventoryManager inv(gamedef);

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:water 50"));
inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 50"));
inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:brick 60"));

apply_action("Move 50 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);

UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:water 50");
UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:takeput_deny 50");
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:brick 60");
}

Expand All @@ -218,10 +215,59 @@ void TestMoveAction::testSwapToUnallowed(ServerActiveObject *obj, IGameDef *game
MockInventoryManager inv(gamedef);

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:stone 50"));
inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:water 60"));
inv.p2.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_deny 60"));

apply_action("Move 50 player:p1 main 0 player:p2 main 0", &inv, obj, gamedef);

UASSERT(inv.p1.getList("main")->getItem(0).getItemString() == "default:stone 50");
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:water 60");
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_deny 60");
}

static bool check_function(lua_State *L)
{
bool ok = false;
int error_handler = PUSH_ERROR_HANDLER(L);

lua_getglobal(L, "minetest");
lua_getfield(L, -1, "__helper_check_callbacks");
int result = lua_pcall(L, 0, 1, error_handler);
if (result == 0)
ok = lua_toboolean(L, -1);
else
puts(lua_tostring(L, -1)); // Error msg

lua_settop(L, 0);
return ok;
}

void TestMoveAction::testCallbacks(ServerActiveObject *obj, Server *server)
{
server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_cb_1 10"));
inv.p2.addList("main", 10);

apply_action("Move 10 player:p1 main 0 player:p2 main 1", &inv, obj, server);

// Expecting 4 callback executions. See Lua file for details.
UASSERT(check_function(server->getScriptIface()->getStack()));

delete server->m_inventory_mgr.release();
}

void TestMoveAction::testCallbacksSwap(ServerActiveObject *obj, Server *server)
{
server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();

inv.p1.addList("main", 10)->addItem(0, parse_itemstack("default:takeput_cb_2 50"));
inv.p2.addList("main", 10)->addItem(1, parse_itemstack("default:takeput_cb_1 10"));

apply_action("Move 10 player:p1 main 0 player:p2 main 1", &inv, obj, server);

// Expecting 8 callback executions run. See Lua file for details.
UASSERT(check_function(server->getScriptIface()->getStack()));

delete server->m_inventory_mgr.release();
}

0 comments on commit 1b300ec

Please sign in to comment.