1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-21 09:39:56 +00:00

Fix the tests

This commit is contained in:
Evil Eye 2024-08-23 22:40:39 +02:00
parent c9783344a0
commit 4529af9b7f
7 changed files with 224 additions and 197 deletions

View File

@ -13,12 +13,14 @@ namespace
{
void SetUp() override
{
mLua.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback {
sol::table hiddenData(mLua.sol(), sol::create);
hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
return LuaUtil::Callback{ std::move(fn), hiddenData };
};
mLua.sol()["pass"] = [this](LuaUtil::Callback callback) { mCb = callback; };
mLua.protectedCall([&](LuaUtil::LuaView& view) {
view.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback {
sol::table hiddenData(view.sol(), sol::create);
hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
return LuaUtil::Callback{ std::move(fn), hiddenData };
};
view.sol()["pass"] = [&](LuaUtil::Callback callback) { mCb = callback; };
});
}
LuaUtil::LuaState mLua{ nullptr, nullptr };
@ -28,25 +30,29 @@ namespace
TEST_F(LuaCoroutineCallbackTest, CoroutineCallbacks)
{
internal::CaptureStdout();
mLua.sol().safe_script(R"X(
mLua.protectedCall([&](LuaUtil::LuaView& view) {
view.sol().safe_script(R"X(
local s = 'test'
coroutine.wrap(function()
pass(callback(function(v) print(s) end))
end)()
)X");
mLua.sol().collect_garbage();
mCb.call();
view.sol().collect_garbage();
mCb.call();
});
EXPECT_THAT(internal::GetCapturedStdout(), "test\n");
}
TEST_F(LuaCoroutineCallbackTest, ErrorInCoroutineCallbacks)
{
mLua.sol().safe_script(R"X(
mLua.protectedCall([&](LuaUtil::LuaView& view) {
view.sol().safe_script(R"X(
coroutine.wrap(function()
pass(callback(function() error('COROUTINE CALLBACK') end))
end)()
)X");
mLua.sol().collect_garbage();
view.sol().collect_garbage();
});
EXPECT_ERROR(mCb.call(), "COROUTINE CALLBACK");
}
}

View File

@ -81,84 +81,87 @@ you_have_arrows: "Arrows count: {count}"
TEST_F(LuaL10nTest, L10n)
{
LuaUtil::LuaState lua{ mVFS.get(), &mCfg };
sol::state_view& l = lua.sol();
internal::CaptureStdout();
l10n::Manager l10nManager(mVFS.get());
l10nManager.setPreferredLocales({ "de", "en" });
EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n");
lua.protectedCall([&](LuaUtil::LuaView& view) {
sol::state_view& l = view.sol();
internal::CaptureStdout();
l10n::Manager l10nManager(mVFS.get());
l10nManager.setPreferredLocales({ "de", "en" });
EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n");
l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager);
l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager);
internal::CaptureStdout();
l.safe_script("t1 = l10n('Test1')");
EXPECT_THAT(internal::GetCapturedStdout(),
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n");
internal::CaptureStdout();
l.safe_script("t1 = l10n('Test1')");
EXPECT_THAT(internal::GetCapturedStdout(),
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n");
internal::CaptureStdout();
l.safe_script("t2 = l10n('Test2')");
{
std::string output = internal::GetCapturedStdout();
EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled"));
}
internal::CaptureStdout();
l.safe_script("t2 = l10n('Test2')");
{
std::string output = internal::GetCapturedStdout();
EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled"));
}
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Guten Morgen.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile.");
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Guten Morgen.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile.");
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
internal::CaptureStdout();
l10nManager.setPreferredLocales({ "en", "de" });
EXPECT_THAT(internal::GetCapturedStdout(),
"Preferred locales: gmst en de\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
internal::CaptureStdout();
l10nManager.setPreferredLocales({ "en", "de" });
EXPECT_THAT(internal::GetCapturedStdout(),
"Preferred locales: gmst en de\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Good morning.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "You have one arrow.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete.");
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete.");
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=1})"), "You came in 1st place.");
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=100})"), "You came in 100th place.");
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=1})"), "There is one thing.");
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=100})"), "There are one hundred things.");
EXPECT_EQ(get<std::string>(l, "t1('duration', {num=100})"), "It took 1:40");
EXPECT_EQ(get<std::string>(l, "t1('numbers', {int=123, double=123.456})"),
"123 and 123 are integers, but 123.456 is a double");
EXPECT_EQ(get<std::string>(l, "t1('rounding', {value=123.456789})"), "123.46");
// Check that failed messages display the key instead of an empty string
EXPECT_EQ(get<std::string>(l, "t1('{mismatched_braces')"), "{mismatched_braces");
EXPECT_EQ(get<std::string>(l, "t1('{unknown_arg}')"), "{unknown_arg}");
EXPECT_EQ(get<std::string>(l, "t1('{num, integer}', {num=1})"), "{num, integer}");
// Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency.
l10nManager.setPreferredLocales({ "en-US", "de" });
EXPECT_EQ(get<std::string>(l, "t1('currency', {money=10000.10})"), "You have $10,000.10");
// Note: Not defined in English localisation file, so we fall back to the German before falling back to the key
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Good morning.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "You have one arrow.");
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us.");
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete.");
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete.");
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=1})"), "You came in 1st place.");
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=100})"), "You came in 100th place.");
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=1})"), "There is one thing.");
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=100})"), "There are one hundred things.");
EXPECT_EQ(get<std::string>(l, "t1('duration', {num=100})"), "It took 1:40");
EXPECT_EQ(get<std::string>(l, "t1('numbers', {int=123, double=123.456})"),
"123 and 123 are integers, but 123.456 is a double");
EXPECT_EQ(get<std::string>(l, "t1('rounding', {value=123.456789})"), "123.46");
// Check that failed messages display the key instead of an empty string
EXPECT_EQ(get<std::string>(l, "t1('{mismatched_braces')"), "{mismatched_braces");
EXPECT_EQ(get<std::string>(l, "t1('{unknown_arg}')"), "{unknown_arg}");
EXPECT_EQ(get<std::string>(l, "t1('{num, integer}', {num=1})"), "{num, integer}");
// Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency.
l10nManager.setPreferredLocales({ "en-US", "de" });
EXPECT_EQ(get<std::string>(l, "t1('currency', {money=10000.10})"), "You have $10,000.10");
// Note: Not defined in English localisation file, so we fall back to the German before falling back to the
// key
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
// Test that locales with variants and country codes fall back to more generic locales
internal::CaptureStdout();
l10nManager.setPreferredLocales({ "en-GB-oed", "de" });
EXPECT_THAT(internal::GetCapturedStdout(),
"Preferred locales: gmst en_GB_OED de\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
// Test that locales with variants and country codes fall back to more generic locales
internal::CaptureStdout();
l10nManager.setPreferredLocales({ "en-GB-oed", "de" });
EXPECT_THAT(internal::GetCapturedStdout(),
"Preferred locales: gmst en_GB_OED de\n"
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
// Test setting fallback language
l.safe_script("t3 = l10n('Test3', 'de')");
l10nManager.setPreferredLocales({ "en" });
EXPECT_EQ(get<std::string>(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!");
// Test setting fallback language
l.safe_script("t3 = l10n('Test3', 'de')");
l10nManager.setPreferredLocales({ "en" });
EXPECT_EQ(get<std::string>(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!");
});
}
}

View File

@ -97,26 +97,26 @@ return {
TEST_F(LuaStateTest, ToString)
{
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), 3.14)), "3.14");
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), true)), "true");
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), 3.14)), "3.14");
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), true)), "true");
EXPECT_EQ(LuaUtil::toString(sol::nil), "nil");
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), "something")), "\"something\"");
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), "something")), "\"something\"");
}
TEST_F(LuaStateTest, Cast)
{
EXPECT_EQ(LuaUtil::cast<int>(sol::make_object(mLua.sol(), 3.14)), 3);
EXPECT_ERROR(
LuaUtil::cast<int>(sol::make_object(mLua.sol(), "3.14")), "Value \"\"3.14\"\" can not be casted to int");
EXPECT_ERROR(LuaUtil::cast<std::string_view>(sol::make_object(mLua.sol(), sol::nil)),
EXPECT_EQ(LuaUtil::cast<int>(sol::make_object(mLua.unsafeState(), 3.14)), 3);
EXPECT_ERROR(LuaUtil::cast<int>(sol::make_object(mLua.unsafeState(), "3.14")),
"Value \"\"3.14\"\" can not be casted to int");
EXPECT_ERROR(LuaUtil::cast<std::string_view>(sol::make_object(mLua.unsafeState(), sol::nil)),
"Value \"nil\" can not be casted to string");
EXPECT_ERROR(LuaUtil::cast<std::string>(sol::make_object(mLua.sol(), sol::nil)),
EXPECT_ERROR(LuaUtil::cast<std::string>(sol::make_object(mLua.unsafeState(), sol::nil)),
"Value \"nil\" can not be casted to string");
EXPECT_ERROR(LuaUtil::cast<sol::table>(sol::make_object(mLua.sol(), sol::nil)),
EXPECT_ERROR(LuaUtil::cast<sol::table>(sol::make_object(mLua.unsafeState(), sol::nil)),
"Value \"nil\" can not be casted to sol::table");
EXPECT_ERROR(LuaUtil::cast<sol::function>(sol::make_object(mLua.sol(), "3.14")),
EXPECT_ERROR(LuaUtil::cast<sol::function>(sol::make_object(mLua.unsafeState(), "3.14")),
"Value \"\"3.14\"\" can not be casted to sol::function");
EXPECT_ERROR(LuaUtil::cast<sol::protected_function>(sol::make_object(mLua.sol(), "3.14")),
EXPECT_ERROR(LuaUtil::cast<sol::protected_function>(sol::make_object(mLua.unsafeState(), "3.14")),
"Value \"\"3.14\"\" can not be casted to sol::function");
}
@ -186,21 +186,22 @@ return {
TEST_F(LuaStateTest, ProvideAPI)
{
LuaUtil::LuaState lua(mVFS.get(), &mCfg);
lua.protectedCall([&](LuaUtil::LuaView& view) {
sol::table api1 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api1"));
sol::table api2 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api2"));
sol::table api1 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api1"));
sol::table api2 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api2"));
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } });
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } });
lua.addCommonPackage("sqrlib", view.sol().create_table_with("sqr", [](int x) { return x * x; }));
lua.addCommonPackage("sqrlib", lua.sol().create_table_with("sqr", [](int x) { return x * x; }));
sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } });
sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } });
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
EXPECT_EQ(LuaUtil::call(script1["apiName"]).get<std::string>(), "api1");
EXPECT_EQ(LuaUtil::call(script2["apiName"]).get<std::string>(), "api2");
EXPECT_EQ(LuaUtil::call(script1["apiName"]).get<std::string>(), "api1");
EXPECT_EQ(LuaUtil::call(script2["apiName"]).get<std::string>(), "api2");
});
}
TEST_F(LuaStateTest, GetLuaVersion)
@ -212,7 +213,7 @@ return {
{
auto getMem = [&] {
for (int i = 0; i < 5; ++i)
lua_gc(mLua.sol(), LUA_GCCOLLECT, 0);
lua_gc(mLua.unsafeState(), LUA_GCCOLLECT, 0);
return mLua.getTotalMemoryUsage();
};
int64_t memWithScript;

View File

@ -198,8 +198,9 @@ CUSTOM, PLAYER: useInterface.lua
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua")));
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua")));
std::string X0 = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5));
std::string X1 = LuaUtil::serialize(mLua.sol().create_table_with("x", 1.5));
sol::state_view sol = mLua.unsafeState();
std::string X0 = LuaUtil::serialize(sol.create_table_with("x", 0.5));
std::string X1 = LuaUtil::serialize(sol.create_table_with("x", 1.5));
{
testing::internal::CaptureStdout();
@ -243,7 +244,8 @@ CUSTOM, PLAYER: useInterface.lua
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test1.lua")));
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua")));
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua")));
std::string X = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5));
sol::state_view sol = mLua.unsafeState();
std::string X = LuaUtil::serialize(sol.create_table_with("x", 0.5));
{
testing::internal::CaptureStdout();
@ -334,8 +336,9 @@ CUSTOM, PLAYER: useInterface.lua
scripts1.addAutoStartedScripts();
EXPECT_TRUE(scripts1.addCustomScript(*mCfg.findId("test1.lua")));
scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 1, "x", 0.5, "y", 3.5)));
scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 2, "x", 2.5, "y", 1.5)));
sol::state_view sol = mLua.unsafeState();
scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 1, "x", 0.5, "y", 3.5)));
scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 2, "x", 2.5, "y", 1.5)));
ESM::LuaScripts data;
scripts1.save(data);
@ -379,10 +382,10 @@ CUSTOM, PLAYER: useInterface.lua
EXPECT_EQ(internal::GetCapturedStdout(), "");
int counter1 = 0, counter2 = 0, counter3 = 0, counter4 = 0;
sol::function fn1 = sol::make_object(mLua.sol(), [&]() { counter1++; });
sol::function fn2 = sol::make_object(mLua.sol(), [&]() { counter2++; });
sol::function fn3 = sol::make_object(mLua.sol(), [&](int d) { counter3 += d; });
sol::function fn4 = sol::make_object(mLua.sol(), [&](int d) { counter4 += d; });
sol::function fn1 = sol::make_object(mLua.unsafeState(), [&]() { counter1++; });
sol::function fn2 = sol::make_object(mLua.unsafeState(), [&]() { counter2++; });
sol::function fn3 = sol::make_object(mLua.unsafeState(), [&](int d) { counter3 += d; });
sol::function fn4 = sol::make_object(mLua.unsafeState(), [&](int d) { counter4 += d; });
scripts.registerTimerCallback(test1Id, "A", fn3);
scripts.registerTimerCallback(test1Id, "B", fn4);
@ -391,12 +394,16 @@ CUSTOM, PLAYER: useInterface.lua
scripts.processTimers(1, 2);
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.sol(), 3));
scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.sol(), 4));
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.sol(), 1));
scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.sol(), 2));
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.sol(), 10));
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.sol(), 20));
scripts.setupSerializableTimer(
TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.unsafeState(), 3));
scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.unsafeState(), 4));
scripts.setupSerializableTimer(
TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.unsafeState(), 1));
scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.unsafeState(), 2));
scripts.setupSerializableTimer(
TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.unsafeState(), 10));
scripts.setupSerializableTimer(
TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.unsafeState(), 20));
scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 10, test2Id, fn2);
scripts.setupUnsavableTimer(TimerType::GAME_TIME, 10, test1Id, fn2);
@ -446,7 +453,8 @@ CUSTOM, PLAYER: useInterface.lua
TEST_F(LuaScriptsContainerTest, CallbackWrapper)
{
LuaUtil::Callback callback{ mLua.sol()["print"], mLua.newTable() };
sol::state_view view = mLua.unsafeState();
LuaUtil::Callback callback{ view["print"], sol::table(view, sol::create) };
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptDebugNameKey] = "some_script.lua";
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{ nullptr, 0 };

View File

@ -19,102 +19,110 @@ namespace
{
// Note: LuaUtil::Callback can be used only if Lua is initialized via LuaUtil::LuaState
LuaUtil::LuaState luaState{ nullptr, nullptr };
sol::state_view& mLua = luaState.sol();
LuaUtil::LuaStorage::initLuaBindings(mLua);
LuaUtil::LuaStorage storage(mLua);
storage.setActive(true);
luaState.protectedCall([](LuaUtil::LuaView& view) {
sol::state_view& lua = view.sol();
LuaUtil::LuaStorage::initLuaBindings(view);
LuaUtil::LuaStorage storage;
storage.setActive(true);
sol::table callbackHiddenData(mLua, sol::create);
callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
LuaUtil::getAsyncPackageInitializer(
mLua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData);
mLua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData };
sol::table callbackHiddenData(lua, sol::create);
callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
LuaUtil::getAsyncPackageInitializer(
lua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData);
lua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData };
mLua["mutable"] = storage.getMutableSection("test");
mLua["ro"] = storage.getReadOnlySection("test");
lua["mutable"] = storage.getMutableSection(lua, "test");
lua["ro"] = storage.getReadOnlySection(lua, "test");
mLua.safe_script(R"(
callbackCalls = {}
ro:subscribe(async:callback(function(section, key)
table.insert(callbackCalls, section .. '_' .. (key or '*'))
end))
)");
lua.safe_script(R"(
callbackCalls = {}
ro:subscribe(async:callback(function(section, key)
table.insert(callbackCalls, section .. '_' .. (key or '*'))
end))
)");
mLua.safe_script("mutable:set('x', 5)");
EXPECT_EQ(get<int>(mLua, "mutable:get('x')"), 5);
EXPECT_EQ(get<int>(mLua, "ro:get('x')"), 5);
lua.safe_script("mutable:set('x', 5)");
EXPECT_EQ(get<int>(lua, "mutable:get('x')"), 5);
EXPECT_EQ(get<int>(lua, "ro:get('x')"), 5);
EXPECT_THROW(mLua.safe_script("ro:set('y', 3)"), std::exception);
EXPECT_THROW(lua.safe_script("ro:set('y', 3)"), std::exception);
mLua.safe_script("t1 = mutable:asTable()");
mLua.safe_script("t2 = ro:asTable()");
EXPECT_EQ(get<int>(mLua, "t1.x"), 5);
EXPECT_EQ(get<int>(mLua, "t2.x"), 5);
lua.safe_script("t1 = mutable:asTable()");
lua.safe_script("t2 = ro:asTable()");
EXPECT_EQ(get<int>(lua, "t1.x"), 5);
EXPECT_EQ(get<int>(lua, "t2.x"), 5);
mLua.safe_script("mutable:reset()");
EXPECT_TRUE(get<bool>(mLua, "ro:get('x') == nil"));
lua.safe_script("mutable:reset()");
EXPECT_TRUE(get<bool>(lua, "ro:get('x') == nil"));
mLua.safe_script("mutable:reset({x=4, y=7})");
EXPECT_EQ(get<int>(mLua, "ro:get('x')"), 4);
EXPECT_EQ(get<int>(mLua, "ro:get('y')"), 7);
lua.safe_script("mutable:reset({x=4, y=7})");
EXPECT_EQ(get<int>(lua, "ro:get('x')"), 4);
EXPECT_EQ(get<int>(lua, "ro:get('y')"), 7);
EXPECT_THAT(get<std::string>(mLua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*");
EXPECT_THAT(get<std::string>(lua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*");
});
}
TEST(LuaUtilStorageTest, Table)
{
sol::state mLua;
LuaUtil::LuaStorage::initLuaBindings(mLua);
LuaUtil::LuaStorage storage(mLua);
storage.setActive(true);
mLua["mutable"] = storage.getMutableSection("test");
mLua["ro"] = storage.getReadOnlySection("test");
LuaUtil::LuaState luaState{ nullptr, nullptr };
luaState.protectedCall([](LuaUtil::LuaView& view) {
LuaUtil::LuaStorage::initLuaBindings(view);
LuaUtil::LuaStorage storage;
auto& lua = view.sol();
storage.setActive(true);
lua["mutable"] = storage.getMutableSection(lua, "test");
lua["ro"] = storage.getReadOnlySection(lua, "test");
mLua.safe_script("mutable:set('x', { y = 'abc', z = 7 })");
EXPECT_EQ(get<int>(mLua, "mutable:get('x').z"), 7);
EXPECT_THROW(mLua.safe_script("mutable:get('x').z = 3"), std::exception);
EXPECT_NO_THROW(mLua.safe_script("mutable:getCopy('x').z = 3"));
EXPECT_EQ(get<int>(mLua, "mutable:get('x').z"), 7);
EXPECT_EQ(get<int>(mLua, "ro:get('x').z"), 7);
EXPECT_EQ(get<std::string>(mLua, "ro:get('x').y"), "abc");
lua.safe_script("mutable:set('x', { y = 'abc', z = 7 })");
EXPECT_EQ(get<int>(lua, "mutable:get('x').z"), 7);
EXPECT_THROW(lua.safe_script("mutable:get('x').z = 3"), std::exception);
EXPECT_NO_THROW(lua.safe_script("mutable:getCopy('x').z = 3"));
EXPECT_EQ(get<int>(lua, "mutable:get('x').z"), 7);
EXPECT_EQ(get<int>(lua, "ro:get('x').z"), 7);
EXPECT_EQ(get<std::string>(lua, "ro:get('x').y"), "abc");
});
}
TEST(LuaUtilStorageTest, Saving)
{
sol::state mLua;
LuaUtil::LuaStorage::initLuaBindings(mLua);
LuaUtil::LuaStorage storage(mLua);
storage.setActive(true);
LuaUtil::LuaState luaState{ nullptr, nullptr };
luaState.protectedCall([](LuaUtil::LuaView& view) {
LuaUtil::LuaStorage::initLuaBindings(view);
LuaUtil::LuaStorage storage;
auto& lua = view.sol();
storage.setActive(true);
mLua["permanent"] = storage.getMutableSection("permanent");
mLua["temporary"] = storage.getMutableSection("temporary");
mLua.safe_script("temporary:removeOnExit()");
mLua.safe_script("permanent:set('x', 1)");
mLua.safe_script("temporary:set('y', 2)");
lua["permanent"] = storage.getMutableSection(lua, "permanent");
lua["temporary"] = storage.getMutableSection(lua, "temporary");
lua.safe_script("temporary:removeOnExit()");
lua.safe_script("permanent:set('x', 1)");
lua.safe_script("temporary:set('y', 2)");
const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin";
storage.save(tmpFile);
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
EXPECT_EQ(get<int>(mLua, "temporary:get('y')"), 2);
const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin";
storage.save(lua, tmpFile);
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
EXPECT_EQ(get<int>(lua, "temporary:get('y')"), 2);
storage.clearTemporaryAndRemoveCallbacks();
mLua["permanent"] = storage.getMutableSection("permanent");
mLua["temporary"] = storage.getMutableSection("temporary");
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
EXPECT_TRUE(get<bool>(mLua, "temporary:get('y') == nil"));
storage.clearTemporaryAndRemoveCallbacks();
lua["permanent"] = storage.getMutableSection(lua, "permanent");
lua["temporary"] = storage.getMutableSection(lua, "temporary");
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
EXPECT_TRUE(get<bool>(lua, "temporary:get('y') == nil"));
mLua.safe_script("permanent:set('x', 3)");
mLua.safe_script("permanent:set('z', 4)");
lua.safe_script("permanent:set('x', 3)");
lua.safe_script("permanent:set('z', 4)");
LuaUtil::LuaStorage storage2(mLua);
storage2.setActive(true);
storage2.load(tmpFile);
mLua["permanent"] = storage2.getMutableSection("permanent");
mLua["temporary"] = storage2.getMutableSection("temporary");
LuaUtil::LuaStorage storage2;
storage2.setActive(true);
storage2.load(lua, tmpFile);
lua["permanent"] = storage2.getMutableSection(lua, "permanent");
lua["temporary"] = storage2.getMutableSection(lua, "temporary");
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
EXPECT_TRUE(get<bool>(mLua, "permanent:get('z') == nil"));
EXPECT_TRUE(get<bool>(mLua, "temporary:get('y') == nil"));
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
EXPECT_TRUE(get<bool>(lua, "permanent:get('z') == nil"));
EXPECT_TRUE(get<bool>(lua, "temporary:get('y') == nil"));
});
}
}

View File

@ -27,7 +27,7 @@ namespace
return LuaUi::ContentView(result.get<sol::table>());
}
sol::table makeTable() { return sol::table(mLuaState.sol(), sol::create); }
sol::table makeTable() { return sol::table(mLuaState.unsafeState(), sol::create); }
sol::table makeTable(std::string name)
{
@ -39,13 +39,14 @@ namespace
TEST_F(LuaUiContentTest, ProtectedMetatable)
{
mLuaState.sol()["makeContent"] = mNew;
mLuaState.sol()["M"] = makeContent(makeTable()).getMetatable();
sol::state_view sol = mLuaState.unsafeState();
sol["makeContent"] = mNew;
sol["M"] = makeContent(makeTable()).getMetatable();
std::string testScript = R"(
assert(not pcall(function() setmetatable(makeContent{}, {}) end), 'Metatable is not protected')
assert(getmetatable(makeContent{}) == false, 'Metatable is not protected')
)";
EXPECT_NO_THROW(mLuaState.sol().safe_script(testScript));
EXPECT_NO_THROW(sol.safe_script(testScript));
}
TEST_F(LuaUiContentTest, Create)

View File

@ -95,7 +95,7 @@ namespace MWLua
sol::table initMWScriptBindings(const Context& context)
{
sol::state_view lua = lua;
sol::state_view lua = context.sol();
sol::table api(lua, sol::create);
api["getGlobalScript"]