mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-25 11:52:40 +01:00
753 lines
24 KiB
C++
753 lines
24 KiB
C++
#include <RWConfig.hpp>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <boost/property_tree/ini_parser.hpp>
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <map>
|
|
#include <random>
|
|
|
|
#include <rw/debug.hpp>
|
|
|
|
namespace pt = boost::property_tree;
|
|
|
|
typedef std::map<std::string, std::map<std::string, std::string>>
|
|
simpleConfig_t;
|
|
|
|
simpleConfig_t readConfig(const std::filesystem::path &path) {
|
|
simpleConfig_t cfg;
|
|
pt::ptree tree;
|
|
pt::read_ini(path.string(), tree);
|
|
|
|
for (const auto §ion : tree) {
|
|
for (const auto &subKey : section.second) {
|
|
cfg[section.first][subKey.first] = subKey.second.data();
|
|
}
|
|
}
|
|
return cfg;
|
|
}
|
|
|
|
std::string stripWhitespace(const std::string &in) {
|
|
static const std::string whitespace = " \n\r\t";
|
|
auto start = in.find_first_not_of(whitespace);
|
|
auto end = in.find_last_not_of(whitespace) + 1;
|
|
return std::string(in, start, end - start);
|
|
}
|
|
|
|
simpleConfig_t getValidConfig() {
|
|
simpleConfig_t result;
|
|
// Some values and subkeys are surrounded by whitespace
|
|
// to test the robustness of the INI parser.
|
|
// Don't change game.path and input.invert_y keys. Tests depend on them.
|
|
result["game"]["path"] = "\t/dev/test \t \r\n";
|
|
result["game"]["\tlanguage\t "] =
|
|
" american ;american english french german italian spanish.";
|
|
result["input"]["invert_y"] =
|
|
"1 #values != 0 enable input inversion. Optional.";
|
|
result["game"]["hud_scale"] = "2.0\t;HUD scale";
|
|
return result;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const simpleConfig_t &config) {
|
|
for (auto §ion : config) {
|
|
os << "[" << section.first << "]"
|
|
<< "\n";
|
|
for (auto &keyValue : section.second) {
|
|
os << keyValue.first << "=" << keyValue.second << "\n";
|
|
}
|
|
}
|
|
return os;
|
|
}
|
|
|
|
class Temp {
|
|
// An object of type Temp file will be removed on destruction
|
|
public:
|
|
virtual ~Temp() {
|
|
}
|
|
bool exists() const {
|
|
return std::filesystem::exists(this->m_path);
|
|
}
|
|
const std::filesystem::path &path() const {
|
|
return this->m_path;
|
|
}
|
|
std::string filename() const {
|
|
return this->m_path.filename().string();
|
|
}
|
|
std::string dirname() const {
|
|
return this->m_path.parent_path().string();
|
|
}
|
|
virtual void change_perms_normal() const = 0;
|
|
virtual void change_perms_readonly() const = 0;
|
|
virtual void remove() const = 0;
|
|
virtual void touch() const = 0;
|
|
|
|
protected:
|
|
Temp(const Temp &) = delete;
|
|
Temp() : m_path(getRandomFilePath()) {
|
|
}
|
|
Temp(const std::filesystem::path &dirname) : m_path(getRandomFilePath(dirname)) {
|
|
}
|
|
|
|
private:
|
|
static std::default_random_engine& getRandomEngine() {
|
|
static std::default_random_engine defaultRandomEngine = std::default_random_engine(std::random_device{}());
|
|
return defaultRandomEngine;
|
|
}
|
|
static std::string gen_random(size_t len) {
|
|
constexpr std::string_view alphanum =
|
|
"0123456789"
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz";
|
|
std::uniform_int_distribution<size_t> dist(0u, alphanum.size() - 1);
|
|
std::string res;
|
|
res.reserve(len);
|
|
std::generate_n(std::back_inserter(res), len, [&]() {
|
|
return alphanum[dist(getRandomEngine())];
|
|
});
|
|
return res;
|
|
}
|
|
static std::filesystem::path getRandomFilePath(const std::filesystem::path &dirname) {
|
|
const std::string name = "openrw_test_" + gen_random(16);
|
|
return dirname / name;
|
|
}
|
|
static std::filesystem::path getRandomFilePath() {
|
|
return getRandomFilePath(std::filesystem::temp_directory_path());
|
|
}
|
|
std::filesystem::path m_path;
|
|
};
|
|
|
|
class TempFile;
|
|
|
|
class TempDir : public Temp {
|
|
public:
|
|
TempDir() : Temp() {
|
|
}
|
|
TempDir(const TempDir &dirname) : Temp(dirname.path()) {
|
|
}
|
|
virtual ~TempDir() {
|
|
this->remove();
|
|
}
|
|
virtual void change_perms_normal() const override {
|
|
std::filesystem::permissions(this->path(),
|
|
std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | std::filesystem::perms::owner_exec |
|
|
std::filesystem::perms::group_read | std::filesystem::perms::group_exec |
|
|
std::filesystem::perms::others_read | std::filesystem::perms::others_exec);
|
|
}
|
|
virtual void change_perms_readonly() const override {
|
|
std::filesystem::permissions(this->path(),
|
|
std::filesystem::perms::owner_read | std::filesystem::perms::owner_exec |
|
|
std::filesystem::perms::group_read | std::filesystem::perms::group_exec |
|
|
std::filesystem::perms::others_read | std::filesystem::perms::others_exec);
|
|
}
|
|
virtual void remove() const override {
|
|
// Remove may fail if this directory contains a read-only entry. Ignore.
|
|
std::error_code ec;
|
|
std::filesystem::remove_all(this->path(), ec);
|
|
}
|
|
void touch() const override {
|
|
std::filesystem::create_directories(this->path());
|
|
}
|
|
friend class TempFile;
|
|
};
|
|
|
|
class TempFile : public Temp {
|
|
public:
|
|
TempFile() : Temp() {
|
|
}
|
|
TempFile(const TempDir &dirname) : Temp(dirname.path()) {
|
|
}
|
|
virtual ~TempFile() {
|
|
this->remove();
|
|
}
|
|
virtual void change_perms_normal() const override {
|
|
std::filesystem::permissions(this->path(),
|
|
std::filesystem::perms::owner_read | std::filesystem::perms::owner_write |
|
|
std::filesystem::perms::group_read |
|
|
std::filesystem::perms::others_read);
|
|
}
|
|
virtual void change_perms_readonly() const override {
|
|
std::filesystem::permissions(this->path(),
|
|
std::filesystem::perms::owner_read |
|
|
std::filesystem::perms::group_read |
|
|
std::filesystem::perms::others_read);
|
|
}
|
|
virtual void remove() const override {
|
|
std::error_code ec;
|
|
std::filesystem::remove_all(this->path(), ec);
|
|
}
|
|
virtual void touch() const override {
|
|
std::ofstream ofs(this->path().string(), std::ios::out | std::ios::app);
|
|
ofs.close();
|
|
}
|
|
template <typename T>
|
|
bool append(T t) const {
|
|
// Append argument at the end of the file.
|
|
// File is open/closes repeatedly. Not optimal.
|
|
std::ofstream ofs(this->path().string(), std::ios::out | std::ios::app);
|
|
ofs << t;
|
|
ofs.close();
|
|
return ofs.good();
|
|
}
|
|
template <typename T>
|
|
bool write(T t) const {
|
|
// Write the argument to the file, discarding all contents.
|
|
// File is open/closes repeatedly. Not optimal.
|
|
std::ofstream ofs(this->path().string(), std::ios::out | std::ios::trunc);
|
|
ofs << t;
|
|
ofs.close();
|
|
return ofs.good();
|
|
}
|
|
};
|
|
|
|
BOOST_AUTO_TEST_SUITE(ConfigTests)
|
|
|
|
BOOST_AUTO_TEST_CASE(test_stripWhitespace) {
|
|
std::map<std::string, std::string> map;
|
|
map["abc"] = "abc";
|
|
map["\tabc"] = "abc";
|
|
map["abc\t"] = "abc";
|
|
map[" abc"] = "abc";
|
|
map["abc "] = "abc";
|
|
map[" abc "] = "abc";
|
|
map[" abc "] = "abc";
|
|
for (const auto &keyValue : map) {
|
|
BOOST_CHECK_EQUAL(keyValue.second, stripWhitespace(keyValue.first));
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_TempDir) {
|
|
// Check the behavior of TempFile
|
|
TempDir tempDir;
|
|
BOOST_CHECK(!tempDir.exists());
|
|
tempDir.touch();
|
|
BOOST_CHECK(tempDir.exists());
|
|
tempDir.remove();
|
|
BOOST_CHECK(!tempDir.exists());
|
|
|
|
tempDir.touch();
|
|
BOOST_CHECK(tempDir.exists());
|
|
|
|
TempDir tempChildDir(tempDir);
|
|
BOOST_CHECK(!tempChildDir.exists());
|
|
|
|
tempChildDir.touch();
|
|
BOOST_CHECK(tempChildDir.exists());
|
|
|
|
tempDir.remove();
|
|
BOOST_CHECK(!tempChildDir.exists());
|
|
BOOST_CHECK(!tempDir.exists());
|
|
|
|
tempChildDir.touch();
|
|
BOOST_CHECK(tempChildDir.exists());
|
|
|
|
std::filesystem::path path;
|
|
{
|
|
TempDir tempLocal;
|
|
tempLocal.touch();
|
|
BOOST_CHECK(tempLocal.exists());
|
|
path = tempLocal.path();
|
|
}
|
|
BOOST_CHECK(!std::filesystem::exists(path));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_TempFile) {
|
|
// Check the behavior of TempFile
|
|
TempFile tempFile;
|
|
BOOST_CHECK(!tempFile.exists());
|
|
tempFile.touch();
|
|
BOOST_CHECK(tempFile.exists());
|
|
tempFile.remove();
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
tempFile.touch();
|
|
BOOST_CHECK(tempFile.exists());
|
|
tempFile.remove();
|
|
|
|
BOOST_CHECK(tempFile.append("abc"));
|
|
BOOST_CHECK(tempFile.append("def"));
|
|
BOOST_CHECK(tempFile.exists());
|
|
tempFile.touch();
|
|
std::ifstream ifs(tempFile.path().string());
|
|
std::string line;
|
|
std::getline(ifs, line);
|
|
BOOST_CHECK_EQUAL(line, "abcdef");
|
|
|
|
tempFile.change_perms_readonly();
|
|
BOOST_CHECK(!tempFile.write("abc"));
|
|
BOOST_CHECK(!tempFile.append("def"));
|
|
|
|
std::filesystem::path path;
|
|
{
|
|
TempFile tempLocal;
|
|
tempLocal.touch();
|
|
BOOST_CHECK(tempLocal.exists());
|
|
path = tempLocal.path();
|
|
}
|
|
BOOST_CHECK(!std::filesystem::exists(path));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_initial) {
|
|
// Test an initial config
|
|
[[maybe_unused]] RWConfigParser cfgParser;
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_valid) {
|
|
// Test reading a valid configuration file
|
|
auto cfg = getValidConfig();
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(parseResult.isValid());
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::GOOD);
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
|
|
|
BOOST_REQUIRE(cfgLayer.gamedataPath.has_value());
|
|
BOOST_REQUIRE(cfgLayer.gameLanguage.has_value());
|
|
BOOST_REQUIRE(cfgLayer.invertY.has_value());
|
|
BOOST_REQUIRE(cfgLayer.hudScale.has_value());
|
|
|
|
BOOST_CHECK_EQUAL(*cfgLayer.gamedataPath, "/dev/test");
|
|
BOOST_CHECK_EQUAL(*cfgLayer.gameLanguage, "american");
|
|
BOOST_CHECK(*cfgLayer.invertY);
|
|
BOOST_CHECK_EQUAL(*cfgLayer.hudScale, 2.f);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_valid_modified) {
|
|
// Test reading a valid modified configuration file
|
|
auto cfg = getValidConfig();
|
|
cfg["game"]["path"] = "Liberty City";
|
|
cfg["input"]["invert_y"] = "0";
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(parseResult.isValid());
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::GOOD);
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
|
|
|
BOOST_REQUIRE(cfgLayer.invertY.has_value());
|
|
BOOST_REQUIRE(cfgLayer.gamedataPath.has_value());
|
|
BOOST_CHECK(!*cfgLayer.invertY);
|
|
BOOST_CHECK_EQUAL(*cfgLayer.gamedataPath, "Liberty City");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_save) {
|
|
// Test saving a configuration file
|
|
auto cfg = getValidConfig();
|
|
cfg["game"]["path"] = "Liberty City";
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
{
|
|
RWConfigLayer cfgLayer;
|
|
{
|
|
RWConfigParser cfgParser;
|
|
RWConfigParser::ParseResult parseResult;
|
|
std::tie(cfgLayer, parseResult) = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
BOOST_REQUIRE(cfgLayer.gamedataPath.has_value());
|
|
}
|
|
|
|
tempFile.remove();
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
{
|
|
RWConfigParser cfgParser;
|
|
auto parseResult = cfgParser.saveFile(tempFile.path(), cfgLayer);
|
|
BOOST_CHECK(parseResult.isValid());
|
|
BOOST_CHECK(tempFile.exists());
|
|
}
|
|
}
|
|
|
|
{
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
|
|
BOOST_REQUIRE(cfgLayer.gamedataPath.has_value());
|
|
BOOST_CHECK_EQUAL(*cfgLayer.gamedataPath, "Liberty City");
|
|
}
|
|
|
|
simpleConfig_t cfg2 = readConfig(tempFile.path());
|
|
BOOST_CHECK_EQUAL(cfg2["game"]["path"], "Liberty City");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_valid_unknown_keys) {
|
|
// Test reading a valid modified configuration file with unknown data
|
|
auto cfg = getValidConfig();
|
|
cfg["game"]["unknownkey"] = "descartes";
|
|
cfg["dontknow"]["dontcare"] = "\t$%!$8847 %%$ ";
|
|
|
|
std::map<std::string, std::string> globalUnknownData;
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
{
|
|
RWConfigParser cfgParser;
|
|
RWConfigLayer cfgLayer;
|
|
{
|
|
RWConfigParser::ParseResult parseResult;
|
|
std::tie(cfgLayer, parseResult) = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(parseResult.isValid());
|
|
|
|
const auto &unknownData = parseResult.getUnknownData();
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.size(), 2);
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("game.unknownkey"), 1);
|
|
BOOST_CHECK_EQUAL(unknownData.at("game.unknownkey"),
|
|
stripWhitespace(cfg["game"]["unknownkey"]));
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("dontknow.dontcare"), 1);
|
|
BOOST_CHECK_EQUAL(unknownData.at("dontknow.dontcare"),
|
|
stripWhitespace(cfg["dontknow"]["dontcare"]));
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("game.path"), 0);
|
|
globalUnknownData = unknownData;
|
|
}
|
|
|
|
tempFile.remove();
|
|
|
|
{
|
|
auto parseResult = cfgParser.saveFile(tempFile.path(), cfgLayer, globalUnknownData);
|
|
BOOST_CHECK(parseResult.isValid());
|
|
}
|
|
}
|
|
|
|
{
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
const auto &unknownData = parseResult.getUnknownData();
|
|
|
|
BOOST_REQUIRE_EQUAL(unknownData.size(), 2);
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("game.unknownkey"), 1);
|
|
BOOST_CHECK_EQUAL(unknownData.at("game.unknownkey"),
|
|
stripWhitespace(cfg["game"]["unknownkey"]));
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("dontknow.dontcare"), 1);
|
|
BOOST_CHECK_EQUAL(unknownData.at("dontknow.dontcare"),
|
|
stripWhitespace(cfg["dontknow"]["dontcare"]));
|
|
|
|
BOOST_CHECK_EQUAL(unknownData.count("game.path"), 0);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_valid_empty_file) {
|
|
// An empty config file is valid
|
|
TempFile tempFile;
|
|
tempFile.touch();
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_save_readonly) {
|
|
// Test whether saving to a readonly INI file fails
|
|
auto cfg = getValidConfig();
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
tempFile.change_perms_readonly();
|
|
|
|
RWConfigParser cfgParser;
|
|
RWConfigLayer cfgLayer;
|
|
{
|
|
RWConfigParser::ParseResult parseResult;
|
|
std::tie(cfgLayer, parseResult) = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
}
|
|
|
|
{
|
|
auto parseResult = cfgParser.saveFile(tempFile.path(), cfgLayer);
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDOUTPUTFILE);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_valid_default) {
|
|
// Test whether the default INI string is valid
|
|
TempFile tempFile;
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
RWConfigParser cfgParser;
|
|
{
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
}
|
|
|
|
{
|
|
auto defaultLayer = buildDefaultConfigLayer();
|
|
auto parseResult = cfgParser.saveFile(tempFile.path(), defaultLayer);
|
|
BOOST_CHECK(parseResult.isValid());
|
|
}
|
|
|
|
BOOST_CHECK(tempFile.exists());
|
|
|
|
{
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
BOOST_CHECK(parseResult.isValid());
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_invalid_emptykey) {
|
|
// Test duplicate keys in invalid configuration file
|
|
auto cfg = getValidConfig();
|
|
cfg["game"][""] = "0";
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDINPUTFILE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_invalid_duplicate) {
|
|
// Test duplicate keys in invalid configuration file
|
|
auto cfg = getValidConfig();
|
|
cfg["input"]["invert_y "] = "0";
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDINPUTFILE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_invalid_wrong_type) {
|
|
// Test wrong data type
|
|
auto cfg = getValidConfig();
|
|
cfg["input"]["invert_y"] = "d";
|
|
|
|
TempFile tempFile;
|
|
tempFile.append(cfg);
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDCONTENT);
|
|
|
|
BOOST_REQUIRE_EQUAL(parseResult.getKeysInvalidData().size(), 1);
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData()[0], "input.invert_y");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_invalid_nodir) {
|
|
// Test reading non-existing configuration file in non-existing directory
|
|
TempDir tempDir;
|
|
TempFile tempFile(tempDir);
|
|
|
|
BOOST_CHECK(!tempDir.exists());
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDINPUTFILE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_configParser_invalid_nonexisting) {
|
|
// Test reading non-existing configuration file
|
|
TempFile tempFile;
|
|
|
|
BOOST_CHECK(!tempFile.exists());
|
|
RWConfigParser cfgParser;
|
|
auto [cfgLayer, parseResult] = cfgParser.loadFile(tempFile.path());
|
|
|
|
BOOST_CHECK(!parseResult.isValid());
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(),
|
|
RWConfigParser::ParseResult::INVALIDINPUTFILE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_nullptr) {
|
|
RWArgumentParser argParser;
|
|
argParser.parseArguments(0, nullptr);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_one) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {""};
|
|
argParser.parseArguments(1, args);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_optional_nonexisting) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {"", "--nonexistingoptional"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
BOOST_CHECK(!optLayer.has_value());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_positional_nonexisting) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {"", "nonexistingpositional"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
BOOST_CHECK(!optLayer.has_value());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_bool) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {"", "--help"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_CHECK(optLayer->help);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_string) {
|
|
RWArgumentParser argParser;
|
|
{
|
|
const auto path = "/some/path";
|
|
const char *args[] = {"", "-c", path};
|
|
auto optLayer = argParser.parseArguments(3, args);
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_REQUIRE(optLayer->configPath.has_value());
|
|
BOOST_CHECK_EQUAL(*optLayer->configPath, path);
|
|
}
|
|
{
|
|
const auto path = "/some/path";
|
|
const char *args[] = {"", "-b", path};
|
|
auto optLayer = argParser.parseArguments(3, args);
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_REQUIRE(optLayer->benchmarkPath.has_value());
|
|
BOOST_CHECK_EQUAL(*optLayer->benchmarkPath, path);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_int) {
|
|
RWArgumentParser argParser;
|
|
|
|
const int width = 1920;
|
|
const auto widthStr = std::to_string(width);
|
|
const char *args[] = {"", "-w", widthStr.c_str()};
|
|
auto optLayer = argParser.parseArguments(3, args);
|
|
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_REQUIRE(optLayer->width.has_value());
|
|
BOOST_CHECK_EQUAL(*optLayer->width, width);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_incomplete_optional) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {"", "--hel"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
BOOST_CHECK(!optLayer.has_value());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_case_sensitive) {
|
|
RWArgumentParser argParser;
|
|
const char *args[] = {"", "--HELP"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
BOOST_CHECK(!optLayer.has_value());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_int_invalid) {
|
|
RWArgumentParser argParser;
|
|
|
|
const auto widthStr = "1920d";
|
|
const char *args[] = {"", "-w", widthStr};
|
|
auto optLayer = argParser.parseArguments(3, args);
|
|
|
|
BOOST_CHECK(!optLayer.has_value());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_bool_newgame) {
|
|
RWArgumentParser argParser;
|
|
{
|
|
const char *args[] = {""};
|
|
auto optLayer = argParser.parseArguments(1, args);
|
|
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_CHECK(!optLayer->newGame);
|
|
}
|
|
{
|
|
const char *args[] = {"", "-n"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_CHECK(optLayer->newGame);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_argParser_bool_invert_y) {
|
|
RWArgumentParser argParser;
|
|
{
|
|
const char *args[] = {""};
|
|
auto optLayer = argParser.parseArguments(1, args);
|
|
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_CHECK(!optLayer->invertY.has_value());
|
|
}
|
|
{
|
|
const char *args[] = {"", "--invert_y"};
|
|
auto optLayer = argParser.parseArguments(2, args);
|
|
|
|
BOOST_REQUIRE(optLayer.has_value());
|
|
BOOST_REQUIRE(optLayer->invertY.has_value());
|
|
BOOST_CHECK(*optLayer->invertY);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_rwconfig_initial) {
|
|
RWConfig config;
|
|
auto missingKeys = config.missingKeys();
|
|
BOOST_CHECK_NE(missingKeys.size(), 0u);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_rwconfig_defaultLayer) {
|
|
auto defaultLayer = buildDefaultConfigLayer();
|
|
RWConfig config;
|
|
|
|
config.setLayer(RWConfig::LAYER_DEFAULT, defaultLayer);
|
|
BOOST_CHECK_NE(config.missingKeys().size(), 0u);
|
|
BOOST_CHECK_EQUAL(config.missingKeys().size(), 1u);
|
|
|
|
defaultLayer.gamedataPath = "/path/to/gamedata";
|
|
config.setLayer(RWConfig::LAYER_DEFAULT, defaultLayer);
|
|
|
|
BOOST_REQUIRE(config.layers[RWConfig::LAYER_DEFAULT].gamedataPath.has_value());
|
|
BOOST_CHECK_EQUAL(*config.layers[RWConfig::LAYER_DEFAULT].gamedataPath, "/path/to/gamedata");
|
|
BOOST_CHECK_EQUAL(config.gamedataPath(), "/path/to/gamedata");
|
|
BOOST_CHECK_EQUAL(config.missingKeys().size(), 0u);
|
|
|
|
config.layers[RWConfig::LAYER_USER].gamedataPath = "/some/other/path/to/gamedata";
|
|
BOOST_REQUIRE(config.layers[RWConfig::LAYER_DEFAULT].gamedataPath.has_value());
|
|
BOOST_CHECK_EQUAL(*config.layers[RWConfig::LAYER_DEFAULT].gamedataPath, "/path/to/gamedata");
|
|
BOOST_REQUIRE(config.layers[RWConfig::LAYER_USER].gamedataPath.has_value());
|
|
BOOST_CHECK_EQUAL(*config.layers[RWConfig::LAYER_USER].gamedataPath, "/some/other/path/to/gamedata");
|
|
BOOST_CHECK_EQUAL(config.gamedataPath(), "/some/other/path/to/gamedata");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|