mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-22 17:18:39 +00:00
Add unit tests for Lua vector reading
This commit is contained in:
parent
a5263dc7ed
commit
ec16fb33d0
5 changed files with 197 additions and 20 deletions
|
@ -36,6 +36,7 @@ set (UNITTEST_SRCS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/test_random.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_sao.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_schematic.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_scriptapi.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_serialization.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_serveractiveobjectmgr.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_server_shutdown_state.cpp
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
#define UTEST(x, fmt, ...) \
|
||||
if (!(x)) { \
|
||||
char utest_buf[1024]; \
|
||||
snprintf(utest_buf, sizeof(utest_buf), fmt, __VA_ARGS__); \
|
||||
porting::mt_snprintf(utest_buf, sizeof(utest_buf), fmt, __VA_ARGS__); \
|
||||
throw TestFailedException(utest_buf, __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ public:
|
|||
} catch (EType &e) { \
|
||||
exception_thrown = true; \
|
||||
} \
|
||||
UASSERT(exception_thrown); \
|
||||
UTEST(exception_thrown, "Exception %s not thrown", #EType); \
|
||||
}
|
||||
|
||||
class IGameDef;
|
||||
|
|
183
src/unittest/test_scriptapi.cpp
Normal file
183
src/unittest/test_scriptapi.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2022 Minetest core developers & community
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "script/cpp_api/s_base.h"
|
||||
#include "script/lua_api/l_util.h"
|
||||
#include "script/lua_api/l_settings.h"
|
||||
#include "script/common/c_converter.h"
|
||||
#include "irrlicht_changes/printing.h"
|
||||
#include "server.h"
|
||||
|
||||
namespace {
|
||||
class MyScriptApi : virtual public ScriptApiBase {
|
||||
public:
|
||||
MyScriptApi() : ScriptApiBase(ScriptingType::Async) {};
|
||||
void init();
|
||||
using ScriptApiBase::getStack;
|
||||
};
|
||||
}
|
||||
|
||||
class TestScriptApi : public TestBase
|
||||
{
|
||||
public:
|
||||
TestScriptApi() { TestManager::registerTestModule(this); }
|
||||
const char *getName() { return "TestScriptApi"; }
|
||||
|
||||
void runTests(IGameDef *gamedef);
|
||||
|
||||
void testVectorMetatable(MyScriptApi *script);
|
||||
void testVectorRead(MyScriptApi *script);
|
||||
void testVectorReadErr(MyScriptApi *script);
|
||||
void testVectorReadMix(MyScriptApi *script);
|
||||
};
|
||||
|
||||
static TestScriptApi g_test_instance;
|
||||
|
||||
void MyScriptApi::init()
|
||||
{
|
||||
lua_State *L = getStack();
|
||||
|
||||
lua_getglobal(L, "core");
|
||||
int top = lua_gettop(L);
|
||||
|
||||
// By creating an environment of 'async' type we have the fewest amount
|
||||
// of external classes needed.
|
||||
lua_pushstring(L, "async");
|
||||
lua_setglobal(L, "INIT");
|
||||
|
||||
LuaSettings::Register(L);
|
||||
ModApiUtil::InitializeAsync(L, top);
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
loadMod(Server::getBuiltinLuaPath() + DIR_DELIM + "init.lua", BUILTIN_MOD_NAME);
|
||||
checkSetByBuiltin();
|
||||
}
|
||||
|
||||
void TestScriptApi::runTests(IGameDef *gamedef)
|
||||
{
|
||||
MyScriptApi script;
|
||||
try {
|
||||
script.init();
|
||||
} catch (ModError &e) {
|
||||
rawstream << e.what() << std::endl;
|
||||
num_tests_failed = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
TEST(testVectorMetatable, &script);
|
||||
TEST(testVectorRead, &script);
|
||||
TEST(testVectorReadErr, &script);
|
||||
TEST(testVectorReadMix, &script);
|
||||
}
|
||||
|
||||
// Runs Lua code and leaves `nresults` return values on the stack
|
||||
static void run(lua_State *L, const char *code, int nresults)
|
||||
{
|
||||
if (luaL_loadstring(L, code) != 0) {
|
||||
rawstream << lua_tostring(L, -1) << std::endl;
|
||||
UASSERT(false);
|
||||
}
|
||||
if (lua_pcall(L, 0, nresults, 0) != 0) {
|
||||
throw LuaError(lua_tostring(L, -1));
|
||||
}
|
||||
}
|
||||
|
||||
void TestScriptApi::testVectorMetatable(MyScriptApi *script)
|
||||
{
|
||||
lua_State *L = script->getStack();
|
||||
StackUnroller unroller(L);
|
||||
|
||||
const auto &call_vector_check = [&] () -> bool {
|
||||
lua_setglobal(L, "tmp");
|
||||
run(L, "return vector.check(tmp)", 1);
|
||||
return lua_toboolean(L, -1);
|
||||
};
|
||||
|
||||
push_v3s16(L, {1, 2, 3});
|
||||
UASSERT(call_vector_check());
|
||||
|
||||
push_v3f(L, {1, 2, 3});
|
||||
UASSERT(call_vector_check());
|
||||
|
||||
// 2-component vectors must not have this metatable
|
||||
push_v2s32(L, {0, 0});
|
||||
UASSERT(!call_vector_check());
|
||||
|
||||
push_v2f(L, {0, 0});
|
||||
UASSERT(!call_vector_check());
|
||||
}
|
||||
|
||||
void TestScriptApi::testVectorRead(MyScriptApi *script)
|
||||
{
|
||||
lua_State *L = script->getStack();
|
||||
StackUnroller unroller(L);
|
||||
|
||||
// both methods should parse these
|
||||
const std::pair<const char*, v3s16> pairs1[] = {
|
||||
{"return {x=1, y=-2, z=3}", {1, -2, 3}},
|
||||
{"return {x=1.1, y=0, z=0}", {1, 0, 0}},
|
||||
{"return {x=1.5, y=0, z=0}", {2, 0, 0}},
|
||||
{"return {x=-1.1, y=0, z=0}", {-1, 0, 0}},
|
||||
{"return {x=-1.5, y=0, z=0}", {-2, 0, 0}},
|
||||
{"return vector.new(5, 6, 7)", {5, 6, 7}},
|
||||
{"return vector.new(32767, 0, -32768)", {S16_MAX, 0, S16_MIN}},
|
||||
};
|
||||
for (auto &it : pairs1) {
|
||||
run(L, it.first, 1);
|
||||
v3s16 v = read_v3s16(L, -1);
|
||||
UASSERTEQ(auto, v, it.second);
|
||||
v = check_v3s16(L, -1);
|
||||
UASSERTEQ(auto, v, it.second);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void TestScriptApi::testVectorReadErr(MyScriptApi *script)
|
||||
{
|
||||
lua_State *L = script->getStack();
|
||||
StackUnroller unroller(L);
|
||||
|
||||
// both methods should reject these
|
||||
const char *errs1[] = {
|
||||
"return {y=1, z=3}",
|
||||
"return {x=1, z=3}",
|
||||
"return {x=1, y=3}",
|
||||
"return {}",
|
||||
"return 'bamboo'",
|
||||
"return function() end",
|
||||
"return nil",
|
||||
};
|
||||
for (auto &it : errs1) {
|
||||
infostream << it << std::endl;
|
||||
run(L, it, 1);
|
||||
EXCEPTION_CHECK(LuaError, read_v3s16(L, -1));
|
||||
EXCEPTION_CHECK(LuaError, check_v3s16(L, -1));
|
||||
}
|
||||
}
|
||||
|
||||
void TestScriptApi::testVectorReadMix(MyScriptApi *script)
|
||||
{
|
||||
lua_State *L = script->getStack();
|
||||
StackUnroller unroller(L);
|
||||
|
||||
// read_v3s16 should allow these, but check_v3s16 should not
|
||||
const std::pair<const char*, v3s16> pairs2[] = {
|
||||
{"return {x='3', y='2.9', z=3}", {3, 3, 3}},
|
||||
{"return {x=false, y=0, z=0}", {0, 0, 0}},
|
||||
{"return {x='?', y=0, z=0}", {0, 0, 0}},
|
||||
{"return {x={'baguette'}, y=0, z=0}", {0, 0, 0}},
|
||||
};
|
||||
for (auto &it : pairs2) {
|
||||
infostream << it.first << std::endl;
|
||||
run(L, it.first, 1);
|
||||
v3s16 v = read_v3s16(L, -1);
|
||||
UASSERTEQ(auto, v, it.second);
|
||||
EXCEPTION_CHECK(LuaError, check_v3s16(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue