Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions library/LuaTools.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Regression test for https://github.com/DFHack/dfhack/issues/5450
// (fixed by https://github.com/DFHack/dfhack/pull/5451)
//
// df::identity_traits<T>::get() returns a pointer to a *const* instance of
// a type_identity subclass for most types. When the df_object constraint
// required a pointer to non-const type_identity, Lua::Push rejected those
// types and fell back to the bool overload, so e.g. a pointer to a vector
// arrived in Lua as a boolean.

#include "LuaTools.h"
#include "LuaWrapper.h"

#include <gtest/gtest.h>
#include <lualib.h>

#include <cstdint>
#include <vector>

// The constraint must accept types whose identity is exposed through a
// pointer-to-const. This is the compile-time half of the regression check:
// it fails to build if df_object ever becomes too strict again.
static_assert(DFHack::Lua::df_object<std::vector<int32_t>>);
static_assert(DFHack::Lua::df_object<int32_t>);
static_assert(DFHack::Lua::df_object<df::coord>);

class LuaPushTest : public testing::Test {
protected:
lua_State *L = nullptr;

void SetUp() override
{
L = luaL_newstate();
ASSERT_NE(nullptr, L);
luaL_openlibs(L);
DFHack::LuaWrapper::AttachDFGlobals(L);
}

void TearDown() override
{
if (L)
lua_close(L);
}
};

TEST_F(LuaPushTest, PushVectorPointer)
{
std::vector<int32_t> vec{ 7, 42 };

// NB: intentionally avoids df_object-constrained calls below so that
// this test still compiles if the constraint regresses - in that case
// Push() falls back to the bool overload and the checks fail at runtime
DFHack::Lua::Push(L, &vec);

// the pointer must arrive as a wrapped DF object, not a boolean
ASSERT_EQ(LUA_TUSERDATA, lua_type(L, -1));
ASSERT_EQ(DFHack::Lua::OBJ_REF, DFHack::Lua::IsDFObject(L, -1));

// the same pointer must round-trip back out of Lua
EXPECT_EQ(static_cast<void*>(&vec),
DFHack::Lua::GetDFObject(L, df::identity_traits<std::vector<int32_t>>::get(), -1));

// and the pushed object must behave like the vector it wraps
lua_len(L, -1);
EXPECT_EQ(lua_Integer(vec.size()), lua_tointeger(L, -1));
lua_pop(L, 1);

lua_geti(L, -1, 0);
EXPECT_EQ(7, lua_tointeger(L, -1));
lua_pop(L, 1);

lua_geti(L, -1, 1);
EXPECT_EQ(42, lua_tointeger(L, -1));
lua_pop(L, 1);
}
2 changes: 1 addition & 1 deletion library/include/LuaWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ namespace LuaWrapper {

void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct);

void AttachDFGlobals(lua_State *state);
DFHACK_EXPORT void AttachDFGlobals(lua_State *state);

DFHACK_EXPORT void notify_deprecated(lua_State* state, std::string_view name, std::string_view message);
}}
Loading