1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-22 06:23:53 +00:00
openmw/apps/openmw_test_suite/lua/test_configuration.cpp
florent.teppe 65cdd489fb create a specific esm reader function for RefID to avoid allocation for string and then again for RefId
Fixed some types

removed useless header

applied clang format

fixed compile tests

fixed clang tidy, and closer to logic before this MR

Removed hardcoded refids

unless there is a returned value we don't use static RefIds
can use == between RefId and hardcoded string

Fix clang format

Fixed a few instances where std::string was used, when only const std::string& was needed

removed unused variable
2022-12-27 19:15:57 +01:00

258 lines
12 KiB
C++

#include "gmock/gmock.h"
#include <gtest/gtest.h>
#include <fstream>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/lua/configuration.hpp>
#include <components/lua/serialization.hpp>
#include "../testing_util.hpp"
namespace
{
using testing::ElementsAre;
using testing::Pair;
std::vector<std::pair<int, std::string>> asVector(const LuaUtil::ScriptIdsWithInitializationData& d)
{
std::vector<std::pair<int, std::string>> res;
for (const auto& [k, v] : d)
res.emplace_back(k, std::string(v));
return res;
}
TEST(LuaConfigurationTest, ValidOMWScripts)
{
ESM::LuaScriptsCfg cfg;
LuaUtil::parseOMWScripts(cfg, R"X(
# Lines starting with '#' are comments
GLOBAL: my_mod/#some_global_script.lua
# Script that will be automatically attached to the player
PLAYER :my_mod/player.lua
CUSTOM : my_mod/some_other_script.lua
NPC , CREATURE PLAYER : my_mod/some_other_script.lua)X");
LuaUtil::parseOMWScripts(cfg, ":my_mod/player.LUA \r\nCREATURE,CUSTOM: my_mod/creature.lua\r\n");
ASSERT_EQ(cfg.mScripts.size(), 6);
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[0]), "GLOBAL : my_mod/#some_global_script.lua");
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[1]), "PLAYER : my_mod/player.lua");
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[2]), "CUSTOM : my_mod/some_other_script.lua");
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[3]), "PLAYER NPC CREATURE : my_mod/some_other_script.lua");
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[4]), ": my_mod/player.LUA");
EXPECT_EQ(LuaUtil::scriptCfgToString(cfg.mScripts[5]), "CUSTOM CREATURE : my_mod/creature.lua");
LuaUtil::ScriptsConfiguration conf;
conf.init(std::move(cfg));
ASSERT_EQ(conf.size(), 4);
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[0]), "GLOBAL : my_mod/#some_global_script.lua");
// cfg.mScripts[1] is overridden by cfg.mScripts[4]
// cfg.mScripts[2] is overridden by cfg.mScripts[3]
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[1]), "PLAYER NPC CREATURE : my_mod/some_other_script.lua");
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[2]), ": my_mod/player.LUA");
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[3]), "CUSTOM CREATURE : my_mod/creature.lua");
EXPECT_THAT(asVector(conf.getGlobalConf()), ElementsAre(Pair(0, "")));
EXPECT_THAT(asVector(conf.getPlayerConf()), ElementsAre(Pair(1, "")));
const ESM::RefId something = ESM::RefId::stringRefId("something");
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_CONT, something, ESM::RefNum())), ElementsAre());
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_NPC_, something, ESM::RefNum())), ElementsAre(Pair(1, "")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_CREA, something, ESM::RefNum())),
ElementsAre(Pair(1, ""), Pair(3, "")));
// Check that initialization cleans old data
cfg = ESM::LuaScriptsCfg();
conf.init(std::move(cfg));
EXPECT_EQ(conf.size(), 0);
}
TEST(LuaConfigurationTest, InvalidOMWScripts)
{
ESM::LuaScriptsCfg cfg;
EXPECT_ERROR(LuaUtil::parseOMWScripts(cfg, "GLOBAL: something"),
"Lua script should have suffix '.lua', got: GLOBAL: something");
EXPECT_ERROR(LuaUtil::parseOMWScripts(cfg, "something.lua"), "No flags found in: something.lua");
cfg.mScripts.clear();
EXPECT_NO_THROW(LuaUtil::parseOMWScripts(cfg, "GLOBAL, PLAYER: something.lua"));
LuaUtil::ScriptsConfiguration conf;
EXPECT_ERROR(conf.init(std::move(cfg)), "Global script can not have local flags");
}
TEST(LuaConfigurationTest, ConfInit)
{
ESM::LuaScriptsCfg cfg;
ESM::LuaScriptCfg& script1 = cfg.mScripts.emplace_back();
script1.mScriptPath = "Script1.lua";
script1.mInitializationData = "data1";
script1.mFlags = ESM::LuaScriptCfg::sPlayer;
script1.mTypes.push_back(ESM::REC_CREA);
script1.mRecords.push_back({ true, ESM::RefId::stringRefId("record1"), "dataRecord1" });
script1.mRefs.push_back({ true, 2, 3, "" });
script1.mRefs.push_back({ true, 2, 4, "" });
ESM::LuaScriptCfg& script2 = cfg.mScripts.emplace_back();
script2.mScriptPath = "Script2.lua";
script2.mFlags = ESM::LuaScriptCfg::sCustom;
script2.mTypes.push_back(ESM::REC_CONT);
ESM::LuaScriptCfg& script1Extra = cfg.mScripts.emplace_back();
script1Extra.mScriptPath = "script1.LUA";
script1Extra.mFlags = ESM::LuaScriptCfg::sCustom | ESM::LuaScriptCfg::sMerge;
script1Extra.mTypes.push_back(ESM::REC_NPC_);
script1Extra.mRecords.push_back({ false, ESM::RefId::stringRefId("rat"), "" });
script1Extra.mRecords.push_back({ true, ESM::RefId::stringRefId("record2"), "" });
script1Extra.mRefs.push_back({ true, 3, 5, "dataRef35" });
script1Extra.mRefs.push_back({ false, 2, 3, "" });
LuaUtil::ScriptsConfiguration conf;
conf.init(cfg);
ASSERT_EQ(conf.size(), 2);
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[0]),
"CUSTOM PLAYER CREATURE NPC : Script1.lua ; data 5 bytes ; 3 records ; 4 objects");
EXPECT_EQ(LuaUtil::scriptCfgToString(conf[1]), "CUSTOM CONTAINER : Script2.lua");
EXPECT_THAT(asVector(conf.getPlayerConf()), ElementsAre(Pair(0, "data1")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_CONT, ESM::RefId::stringRefId("something"), ESM::RefNum())),
ElementsAre(Pair(1, "")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_CREA, ESM::RefId::stringRefId("guar"), ESM::RefNum())),
ElementsAre(Pair(0, "data1")));
EXPECT_THAT(
asVector(conf.getLocalConf(ESM::REC_CREA, ESM::RefId::stringRefId("rat"), ESM::RefNum())), ElementsAre());
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_DOOR, ESM::RefId::stringRefId("record1"), ESM::RefNum())),
ElementsAre(Pair(0, "dataRecord1")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_DOOR, ESM::RefId::stringRefId("record2"), ESM::RefNum())),
ElementsAre(Pair(0, "data1")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_NPC_, ESM::RefId::stringRefId("record3"), { 1, 1 })),
ElementsAre(Pair(0, "data1")));
EXPECT_THAT(
asVector(conf.getLocalConf(ESM::REC_NPC_, ESM::RefId::stringRefId("record3"), { 2, 3 })), ElementsAre());
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_NPC_, ESM::RefId::stringRefId("record3"), { 3, 5 })),
ElementsAre(Pair(0, "dataRef35")));
EXPECT_THAT(asVector(conf.getLocalConf(ESM::REC_CONT, ESM::RefId::stringRefId("record4"), { 2, 4 })),
ElementsAre(Pair(0, "data1"), Pair(1, "")));
ESM::LuaScriptCfg& script3 = cfg.mScripts.emplace_back();
script3.mScriptPath = "script1.lua";
script3.mFlags = ESM::LuaScriptCfg::sGlobal;
EXPECT_ERROR(conf.init(cfg), "Flags mismatch for script1.lua");
}
TEST(LuaConfigurationTest, Serialization)
{
sol::state lua;
LuaUtil::BasicSerializer serializer;
ESM::ESMWriter writer;
writer.setAuthor("");
writer.setDescription("");
writer.setRecordCount(1);
writer.setFormat(ESM::Header::CurrentFormat);
writer.setVersion();
writer.addMaster("morrowind.esm", 0);
ESM::LuaScriptsCfg cfg;
std::string luaData;
{
sol::table data(lua, sol::create);
data["number"] = 5;
data["string"] = "some value";
data["fargoth"] = ESM::RefNum{ 128964, 1 };
luaData = LuaUtil::serialize(data, &serializer);
}
{
ESM::LuaScriptCfg& script = cfg.mScripts.emplace_back();
script.mScriptPath = "test_global.lua";
script.mFlags = ESM::LuaScriptCfg::sGlobal;
script.mInitializationData = luaData;
}
{
ESM::LuaScriptCfg& script = cfg.mScripts.emplace_back();
script.mScriptPath = "test_local.lua";
script.mFlags = ESM::LuaScriptCfg::sMerge;
script.mTypes.push_back(ESM::REC_DOOR);
script.mTypes.push_back(ESM::REC_MISC);
script.mRecords.push_back({ true, ESM::RefId::stringRefId("rat"), luaData });
script.mRecords.push_back({ false, ESM::RefId::stringRefId("chargendoorjournal"), "" });
script.mRefs.push_back({ true, 128964, 1, "" });
script.mRefs.push_back({ true, 128962, 1, luaData });
}
std::stringstream stream;
writer.save(stream);
writer.startRecord(ESM::REC_LUAL);
cfg.save(writer);
writer.endRecord(ESM::REC_LUAL);
writer.close();
std::string serializedOMWAddon = stream.str();
{
// Save for manual testing.
std::ofstream f(TestingOpenMW::outputFilePath("lua_conf_test.omwaddon"), std::ios::binary);
f << serializedOMWAddon;
f.close();
}
ESM::ESMReader reader;
reader.open(std::make_unique<std::istringstream>(serializedOMWAddon), "lua_conf_test.omwaddon");
ASSERT_EQ(reader.getRecordCount(), 1);
ASSERT_EQ(reader.getRecName().toInt(), ESM::REC_LUAL);
reader.getRecHeader();
ESM::LuaScriptsCfg loadedCfg;
loadedCfg.load(reader);
ASSERT_EQ(loadedCfg.mScripts.size(), cfg.mScripts.size());
for (size_t i = 0; i < cfg.mScripts.size(); ++i)
{
EXPECT_EQ(loadedCfg.mScripts[i].mScriptPath, cfg.mScripts[i].mScriptPath);
EXPECT_EQ(loadedCfg.mScripts[i].mFlags, cfg.mScripts[i].mFlags);
EXPECT_EQ(loadedCfg.mScripts[i].mInitializationData, cfg.mScripts[i].mInitializationData);
ASSERT_EQ(loadedCfg.mScripts[i].mTypes.size(), cfg.mScripts[i].mTypes.size());
for (size_t j = 0; j < cfg.mScripts[i].mTypes.size(); ++j)
EXPECT_EQ(loadedCfg.mScripts[i].mTypes[j], cfg.mScripts[i].mTypes[j]);
ASSERT_EQ(loadedCfg.mScripts[i].mRecords.size(), cfg.mScripts[i].mRecords.size());
for (size_t j = 0; j < cfg.mScripts[i].mRecords.size(); ++j)
{
EXPECT_EQ(loadedCfg.mScripts[i].mRecords[j].mAttach, cfg.mScripts[i].mRecords[j].mAttach);
EXPECT_EQ(loadedCfg.mScripts[i].mRecords[j].mRecordId, cfg.mScripts[i].mRecords[j].mRecordId);
EXPECT_EQ(loadedCfg.mScripts[i].mRecords[j].mInitializationData,
cfg.mScripts[i].mRecords[j].mInitializationData);
}
ASSERT_EQ(loadedCfg.mScripts[i].mRefs.size(), cfg.mScripts[i].mRefs.size());
for (size_t j = 0; j < cfg.mScripts[i].mRefs.size(); ++j)
{
EXPECT_EQ(loadedCfg.mScripts[i].mRefs[j].mAttach, cfg.mScripts[i].mRefs[j].mAttach);
EXPECT_EQ(loadedCfg.mScripts[i].mRefs[j].mRefnumIndex, cfg.mScripts[i].mRefs[j].mRefnumIndex);
EXPECT_EQ(
loadedCfg.mScripts[i].mRefs[j].mRefnumContentFile, cfg.mScripts[i].mRefs[j].mRefnumContentFile);
EXPECT_EQ(
loadedCfg.mScripts[i].mRefs[j].mInitializationData, cfg.mScripts[i].mRefs[j].mInitializationData);
}
}
{
ESM::ReadersCache readers(4);
readers.get(0)->openRaw(std::make_unique<std::istringstream>("dummyData"), "a.omwaddon");
readers.get(1)->openRaw(std::make_unique<std::istringstream>("dummyData"), "b.omwaddon");
readers.get(2)->openRaw(std::make_unique<std::istringstream>("dummyData"), "Morrowind.esm");
readers.get(3)->openRaw(std::make_unique<std::istringstream>("dummyData"), "c.omwaddon");
reader.setIndex(3);
reader.resolveParentFileIndices(readers);
}
loadedCfg.adjustRefNums(reader);
EXPECT_EQ(loadedCfg.mScripts[1].mRefs[0].mRefnumIndex, cfg.mScripts[1].mRefs[0].mRefnumIndex);
EXPECT_EQ(loadedCfg.mScripts[1].mRefs[0].mRefnumContentFile, 2);
{
sol::table data = LuaUtil::deserialize(
lua.lua_state(), loadedCfg.mScripts[1].mRefs[1].mInitializationData, &serializer);
ESM::RefNum adjustedRef = data["fargoth"].get<ESM::RefNum>();
EXPECT_EQ(adjustedRef.mIndex, 128964u);
EXPECT_EQ(adjustedRef.mContentFile, 2);
}
}
}