#include #include static int counter(lua_State* L) { Nz::LuaInstance& luaInstance = Nz::LuaInstance::GetInstance(L); double val = luaInstance.ToNumber(luaInstance.GetIndexOfUpValue(1)); luaInstance.PushNumber(++val); luaInstance.PushValue(-1); luaInstance.Replace(luaInstance.GetIndexOfUpValue(1)); return 1; } struct TestLuaState { int a = 3; float b = 5.f; }; struct TestMetaTable { float x = 1.f; float y = 2.f; }; inline int LuaImplReplyVal(const Nz::LuaState& state, TestLuaState&& val, Nz::TypeTag) { state.PushTable(); state.PushField("a", val.a); state.PushField("b", val.b); return 1; } inline unsigned int LuaImplQueryArg(const Nz::LuaState& state, int index, TestLuaState* arg, Nz::TypeTag) { state.CheckType(index, Nz::LuaType_Table); arg->a = state.CheckField("a", index); arg->b = state.CheckField("b", index); return 1; } SCENARIO("LuaState", "[LUA][LUASTATE]") { GIVEN("One lua instance") { Nz::LuaInstance luaInstance; luaInstance.LoadLibraries(Nz::LuaLib_Math); WHEN("We push different primitive types") { bool booleanValue = true; long long integerValue = 5LL; double doubleValue = -55.0; const char* stringValue = "test"; Nz::String nazaraValue = "Nazara"; luaInstance.PushBoolean(booleanValue); luaInstance.PushInteger(integerValue); luaInstance.PushNil(); luaInstance.PushNumber(doubleValue); luaInstance.PushString(stringValue); luaInstance.PushString(nazaraValue); THEN("We should be able to retrieve them") { CHECK(luaInstance.CheckBoolean(1) == booleanValue); CHECK(luaInstance.CheckInteger(2) == integerValue); bool succeeded = false; CHECK(luaInstance.ToInteger(2, &succeeded) == integerValue); CHECK(succeeded); CHECK(luaInstance.ToPointer(3) == nullptr); CHECK(luaInstance.CheckNumber(4) == Approx(doubleValue)); succeeded = false; CHECK(luaInstance.ToNumber(4, &succeeded) == Approx(doubleValue)); CHECK(succeeded); CHECK(luaInstance.CheckString(5) == std::string(stringValue)); CHECK(luaInstance.CheckString(6) == nazaraValue); std::size_t length = 0; CHECK(luaInstance.ToString(6, &length) == nazaraValue); CHECK(length == nazaraValue.GetSize()); } } WHEN("We use basic operations") { luaInstance.PushInteger(1); luaInstance.PushInteger(2); THEN("We should behave normally") { CHECK(luaInstance.Compare(1, 2, Nz::LuaComparison_Less)); luaInstance.Compute(Nz::LuaOperation_Substraction); CHECK(luaInstance.ToInteger(1) == -1); } } WHEN("We manipulate the stack") { Nz::String stringValue = "hello"; luaInstance.PushBoolean(true); luaInstance.PushNumber(10.0); luaInstance.PushNil(); luaInstance.PushString(stringValue); /* true 10.0 nil hello */ THEN("These effects are expected") { luaInstance.PushValue(-4); /* true 10.0 nil hello true */ CHECK(luaInstance.CheckBoolean(5)); luaInstance.Replace(3); /* true 10.0 true hello */ CHECK(luaInstance.CheckBoolean(3)); luaInstance.Remove(-2); /* true 10.0 hello */ CHECK(luaInstance.CheckString(3) == stringValue); luaInstance.Pop(2); /* true */ CHECK_FALSE(luaInstance.IsValid(2)); } } WHEN("We try the CFunction") { double counterValue = 55.0; luaInstance.PushFunction([=](Nz::LuaState& s) -> int { s.PushNumber(counterValue); s.PushCFunction(&counter, 1); return 1; }); THEN("We can call them") { luaInstance.Call(0); // We call our counter creator luaInstance.Call(0); // We call our counter, which increments the value CHECK(luaInstance.ToNumber(0) == Approx(counterValue + 1.0)); } } WHEN("We push our user type locally") { luaInstance.Push(TestLuaState()); THEN("We can retrieve it") { int index = 1; TestLuaState popped = luaInstance.Check(&index); CHECK(popped.a == 3); CHECK(popped.b == Approx(5.0)); } } WHEN("We push our user type globally") { luaInstance.PushGlobal("TestLuaState", TestLuaState()); THEN("We can retrieve it") { TestLuaState popped = luaInstance.CheckGlobal("TestLuaState"); CHECK(popped.a == 3); CHECK(popped.b == Approx(5.0)); } } WHEN("We define a lua function") { luaInstance.Execute(R"( function f (x, y) return (x^2 * math.sin(y))/(1 - x) end )"); THEN("We can call it from the code") { REQUIRE(luaInstance.GetGlobal("f") == Nz::LuaType_Function); luaInstance.Push(3.0, 2.0); luaInstance.Call(2, 1); CHECK(luaInstance.ToNumber(1) == Approx(-4.09).margin(0.1)); } } } }