mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +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
|
@ -19,12 +19,14 @@ function meta:__newindex(name, value)
|
|||
return
|
||||
end
|
||||
local info = getinfo(2, "Sl")
|
||||
local desc = ("%s:%d"):format(info.short_src, info.currentline)
|
||||
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
|
||||
if not warned[warn_key] and info.what ~= "main" and info.what ~= "C" then
|
||||
core.log("warning", ("Assignment to undeclared global %q inside a function at %s.")
|
||||
:format(name, desc))
|
||||
warned[warn_key] = true
|
||||
if info ~= nil then
|
||||
local desc = ("%s:%d"):format(info.short_src, info.currentline)
|
||||
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
|
||||
if not warned[warn_key] and info.what ~= "main" and info.what ~= "C" then
|
||||
core.log("warning", ("Assignment to undeclared global %q inside a function at %s.")
|
||||
:format(name, desc))
|
||||
warned[warn_key] = true
|
||||
end
|
||||
end
|
||||
declared[name] = true
|
||||
end
|
||||
|
@ -35,6 +37,9 @@ function meta:__index(name)
|
|||
return
|
||||
end
|
||||
local info = getinfo(2, "Sl")
|
||||
if info == nil then
|
||||
return
|
||||
end
|
||||
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
|
||||
if not warned[warn_key] and info.what ~= "C" then
|
||||
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
|
||||
|
|
|
@ -67,18 +67,6 @@ local function test_dynamic_media(cb, player)
|
|||
end
|
||||
unittests.register("test_dynamic_media", test_dynamic_media, {async=true, player=true})
|
||||
|
||||
local function test_v3f_metatable(player)
|
||||
assert(vector.check(player:get_pos()))
|
||||
end
|
||||
unittests.register("test_v3f_metatable", test_v3f_metatable, {player=true})
|
||||
|
||||
local function test_v3s16_metatable(player, pos)
|
||||
local node = core.get_node(pos)
|
||||
local found_pos = core.find_node_near(pos, 0, node.name, true)
|
||||
assert(vector.check(found_pos))
|
||||
end
|
||||
unittests.register("test_v3s16_metatable", test_v3s16_metatable, {map=true})
|
||||
|
||||
local function test_clear_meta(_, pos)
|
||||
local ref = core.get_meta(pos)
|
||||
|
||||
|
|
|
@ -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