1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-03 00:59:47 +02:00

config: unknown data will be kept in memory and saved onto disk

This commit is contained in:
Anonymous Maarten 2017-02-20 20:57:36 +01:00 committed by Daniel Evans
parent 7a86c199b0
commit a92f24cbb4
3 changed files with 298 additions and 87 deletions

View File

@ -1,16 +1,16 @@
#include "GameConfig.hpp"
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <rw/defines.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
namespace pt = boost::property_tree;
const std::string kConfigDirectoryName("OpenRW");
GameConfig::GameConfig(const std::string& configName,
const std::string& configPath)
GameConfig::GameConfig(const std::string &configName,
const std::string &configPath)
: m_configName(configName)
, m_configPath(configPath)
, m_parseResult()
@ -23,7 +23,8 @@ GameConfig::GameConfig(const std::string& configName,
auto configFile = getConfigFile();
std::string dummy;
m_parseResult = parseConfig(ParseType::FILE, configFile, ParseType::CONFIG, dummy);
m_parseResult =
parseConfig(ParseType::FILE, configFile, ParseType::CONFIG, dummy);
}
std::string GameConfig::getConfigFile() const {
@ -41,17 +42,17 @@ const GameConfig::ParseResult &GameConfig::getParseResult() const {
std::string GameConfig::getDefaultConfigPath() {
#if defined(RW_LINUX) || defined(RW_FREEBSD) || defined(RW_NETBSD) || \
defined(RW_OPENBSD)
char* config_home = getenv("XDG_CONFIG_HOME");
char *config_home = getenv("XDG_CONFIG_HOME");
if (config_home != nullptr) {
return std::string(config_home) + "/" + kConfigDirectoryName;
}
char* home = getenv("HOME");
char *home = getenv("HOME");
if (home != nullptr) {
return std::string(home) + "/.config/" + kConfigDirectoryName;
}
#elif defined(RW_OSX)
char* home = getenv("HOME");
char *home = getenv("HOME");
if (home)
return std::string(home) + "/Library/Preferences/" +
kConfigDirectoryName;
@ -67,7 +68,7 @@ std::string GameConfig::getDefaultConfigPath() {
std::string stripComments(const std::string &str) {
auto s = std::string(str, 0, str.find_first_of(";#"));
return s.erase(s.find_last_not_of(" \n\r\t")+1);
return s.erase(s.find_last_not_of(" \n\r\t") + 1);
}
struct StringTranslator {
@ -83,7 +84,7 @@ struct StringTranslator {
struct BoolTranslator {
typedef std::string internal_type;
typedef bool external_type;
typedef bool external_type;
boost::optional<external_type> get_value(const internal_type &str) {
boost::optional<external_type> res;
try {
@ -99,7 +100,7 @@ struct BoolTranslator {
struct IntTranslator {
typedef std::string internal_type;
typedef int external_type;
typedef int external_type;
boost::optional<external_type> get_value(const internal_type &str) {
boost::optional<external_type> res;
try {
@ -115,8 +116,7 @@ struct IntTranslator {
GameConfig::ParseResult GameConfig::saveConfig() {
auto filename = getConfigFile();
return parseConfig(ParseType::CONFIG, "",
ParseType::FILE, filename);
return parseConfig(ParseType::CONFIG, "", ParseType::FILE, filename);
}
std::string GameConfig::getDefaultINIString() {
@ -125,10 +125,11 @@ std::string GameConfig::getDefaultINIString() {
return result;
}
GameConfig::ParseResult GameConfig::parseConfig(
GameConfig::ParseType srcType, const std::string &source,
ParseType destType, std::string &destination)
{
GameConfig::ParseResult GameConfig::parseConfig(GameConfig::ParseType srcType,
const std::string &source,
ParseType destType,
std::string &destination) {
// srcTree: holds all key/value pairs
pt::ptree srcTree;
ParseResult parseResult(srcType, source, destType, destination);
@ -152,12 +153,16 @@ GameConfig::ParseResult GameConfig::parseConfig(
return parseResult;
}
// knownKeys: holds all known keys
std::vector<std::string> knownKeys;
auto read_config = [&](const std::string &key, auto &target,
const auto &defaultValue, auto &translator,
bool optional=true) {
const auto &defaultValue, auto &translator,
bool optional = true) {
typedef typename std::remove_reference<decltype(target)>::type config_t;
config_t sourceValue;
knownKeys.push_back(key);
switch (srcType) {
case ParseType::DEFAULT:
@ -210,13 +215,50 @@ GameConfig::ParseResult GameConfig::parseConfig(
// Additionally, add them to the unit test.
// @todo Don't allow path separators and relative directories
read_config("game.path", this->m_gamePath, "/opt/games/Grand Theft Auto 3", deft, false);
read_config("game.path", this->m_gamePath, "/opt/games/Grand Theft Auto 3",
deft, false);
read_config("game.language", this->m_gameLanguage, "american", deft);
read_config("input.invert_y", this->m_inputInvertY, false, boolt);
if (!parseResult.isValid())
return parseResult;
if (!parseResult.isValid()) return parseResult;
// Build the unknown key/value map from the correct source
switch (srcType) {
case ParseType::FILE:
case ParseType::STRING:
for (const auto &section : srcTree) {
for (const auto &subKey : section.second) {
std::string key = section.first + "." + subKey.first;
if (std::find(knownKeys.begin(), knownKeys.end(), key) ==
knownKeys.end()) {
RW_MESSAGE("Unknown configuration key: " << key);
parseResult.addUnknownData(key, subKey.second.data());
}
}
}
break;
case ParseType::CONFIG:
parseResult.setUnknownData(m_parseResult.getUnknownData());
break;
case ParseType::DEFAULT:
break;
}
// Store the unknown key/value map to the correct destination
switch (destType) {
case ParseType::CONFIG:
m_parseResult.setUnknownData(parseResult.getUnknownData());
break;
case ParseType::STRING:
case ParseType::FILE:
for (const auto &keyvalue : parseResult.getUnknownData()) {
srcTree.put(keyvalue.first, keyvalue.second);
}
break;
default:
break;
}
try {
if (destType == ParseType::STRING) {
@ -234,8 +276,8 @@ GameConfig::ParseResult GameConfig::parseConfig(
return parseResult;
}
std::string GameConfig::extractFilenameParseTypeData(ParseType type, const std::string &data)
{
std::string GameConfig::extractFilenameParseTypeData(ParseType type,
const std::string &data) {
switch (type) {
case ParseType::CONFIG:
return "<configuration>";
@ -249,16 +291,19 @@ std::string GameConfig::extractFilenameParseTypeData(ParseType type, const std::
}
}
GameConfig::ParseResult::ParseResult(
GameConfig::ParseType srcType, const std::string &source,
GameConfig::ParseType destType, const std::string &destination)
GameConfig::ParseResult::ParseResult(GameConfig::ParseType srcType,
const std::string &source,
GameConfig::ParseType destType,
const std::string &destination)
: m_result(ErrorType::GOOD)
, m_inputfilename(GameConfig::extractFilenameParseTypeData(srcType, source))
, m_outputfilename(GameConfig::extractFilenameParseTypeData(destType, destination))
, m_outputfilename(
GameConfig::extractFilenameParseTypeData(destType, destination))
, m_line(0)
, m_message()
, m_keys_requiredMissing()
, m_keys_invalidData() {
, m_keys_invalidData()
, m_unknownData() {
}
GameConfig::ParseResult::ParseResult()
@ -280,7 +325,7 @@ bool GameConfig::ParseResult::isValid() const {
}
void GameConfig::ParseResult::failInputFile(size_t line,
const std::string &message) {
const std::string &message) {
this->m_result = ParseResult::ErrorType::INVALIDINPUTFILE;
this->m_line = line;
this->m_message = message;
@ -301,17 +346,19 @@ void GameConfig::ParseResult::failInvalidData(const std::string &key) {
}
void GameConfig::ParseResult::failOutputFile(size_t line,
const std::string &message) {
const std::string &message) {
this->m_result = ParseResult::ErrorType::INVALIDOUTPUTFILE;
this->m_line = line;
this->m_message = message;
}
const std::vector<std::string> &GameConfig::ParseResult::getKeysRequiredMissing() const {
const std::vector<std::string>
&GameConfig::ParseResult::getKeysRequiredMissing() const {
return this->m_keys_requiredMissing;
}
const std::vector<std::string> &GameConfig::ParseResult::getKeysInvalidData() const {
const std::vector<std::string> &GameConfig::ParseResult::getKeysInvalidData()
const {
return this->m_keys_invalidData;
}
@ -321,27 +368,23 @@ std::string GameConfig::ParseResult::what() const {
return "Good";
case ErrorType::INVALIDARGUMENT:
return "Invalid argument: destination cannot be the default config";
case ErrorType::INVALIDINPUTFILE:
{
case ErrorType::INVALIDINPUTFILE: {
std::ostringstream oss;
oss << "Error while reading \""
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
oss << "Error while reading \"" << this->m_inputfilename
<< "\":" << this->m_line << ":\n"
<< this->m_message;
return oss.str();
}
case ErrorType::INVALIDOUTPUTFILE:
{
case ErrorType::INVALIDOUTPUTFILE: {
std::ostringstream oss;
oss << "Error while writing \""
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
oss << "Error while writing \"" << this->m_inputfilename
<< "\":" << this->m_line << ":\n"
<< this->m_message;
return oss.str();
}
case ErrorType::INVALIDCONTENT:
{
case ErrorType::INVALIDCONTENT: {
std::ostringstream oss;
oss << "Error while parsing \""
<< this->m_inputfilename << "\".";
oss << "Error while parsing \"" << this->m_inputfilename << "\".";
if (this->m_keys_requiredMissing.size()) {
oss << "\nRequired keys that are missing:";
for (auto &key : this->m_keys_requiredMissing) {
@ -360,3 +403,18 @@ std::string GameConfig::ParseResult::what() const {
return "Unknown error";
}
}
void GameConfig::ParseResult::addUnknownData(const std::string &key,
const std::string &value) {
this->m_unknownData[key] = value;
}
const std::map<std::string, std::string>
&GameConfig::ParseResult::getUnknownData() const {
return this->m_unknownData;
}
void GameConfig::ParseResult::setUnknownData(
const std::map<std::string, std::string> &unknownData) {
this->m_unknownData = unknownData;
}

View File

@ -1,47 +1,50 @@
#ifndef RWGAME_GAMECONFIG_HPP
#define RWGAME_GAMECONFIG_HPP
#include <map>
#include <string>
#include <vector>
class GameConfig {
private:
enum ParseType {
DEFAULT,
CONFIG,
FILE,
STRING
};
enum ParseType { DEFAULT, CONFIG, FILE, STRING };
/**
* @brief extractFilenameParseTypeData Get a human readable filename string
* @return file path or a description of the data type
*/
static std::string extractFilenameParseTypeData(ParseType type, const std::string &data);
static std::string extractFilenameParseTypeData(ParseType type,
const std::string &data);
public:
class ParseResult {
public:
enum ErrorType {
/// GOOD: Input file/string was good
GOOD,
/// INVALIDINPUTFILE: There was some error while reading from a file or string or the input was ambiguous (e.g. duplicate keys)
/// INVALIDINPUTFILE: There was some error while reading from a file
/// or string or the input was ambiguous (e.g. duplicate keys)
INVALIDINPUTFILE,
/// INVALIDARGUMENT: The parser received impossible arguments
INVALIDARGUMENT,
/// INVALIDCONTENT: Some required keys were missing or some values were of incorrect type
/// INVALIDCONTENT: Some required keys were missing or some values
/// were of incorrect type
INVALIDCONTENT,
/// INVALIDOUTPUTFILE: There was some error while writing to a file or string
/// INVALIDOUTPUTFILE: There was some error while writing to a file
/// or string
INVALIDOUTPUTFILE
};
private:
/**
* @brief ParseResult Holds the issues occurred while parsing of a config file.
* @brief ParseResult Holds the issues occurred while parsing of a
* config file.
* @param srcType Type of the source
* @param source The source of the parser
* @param destType Type of the destination
* @param destination The destination
*/
ParseResult(ParseType srcType, const std::string &source,
ParseType destType, const std::string &destination);
ParseType destType, const std::string &destination);
/**
* @brief ParseResult Create empty ParseResult
@ -93,7 +96,8 @@ public:
void failInvalidData(const std::string &key);
/**
* @brief failOutputFile Fail because an error occurred while while writing to the output
* @brief failOutputFile Fail because an error occurred while while
* writing to the output
* @param line Line number where the error is located
* @param message Description of the error
*/
@ -110,6 +114,20 @@ public:
* @return String with the error description
*/
std::string what() const;
/**
* @brief addUnknownData Add unknown key value pairs
* @param key The unknown key
* @param value The associated data
*/
void addUnknownData(const std::string &key, const std::string &value);
/**
* @brief addUnknownData Get all the unknown key value pairs
* @return Mapping of the unknown keys with associated data
*/
const std::map<std::string, std::string> &getUnknownData() const;
private:
/// Type of the failure
ErrorType m_result;
@ -120,7 +138,8 @@ public:
/// Filename of the output file
std::string m_outputfilename;
/// Line number where the failure occurred (on invalid input or output file)
/// Line number where the failure occurred (on invalid input or output
/// file)
size_t m_line;
/// Description of the failure (on invalid input or output file)
@ -132,6 +151,15 @@ public:
/// All keys that contain invalid data
std::vector<std::string> m_keys_invalidData;
// Mapping of unknown keys and associated data
std::map<std::string, std::string> m_unknownData;
/**
* @brief setUnknownData Replace the the unknown key value pairs
*/
void setUnknownData(
const std::map<std::string, std::string> &unknownData);
friend class GameConfig;
};
@ -140,8 +168,8 @@ public:
* @param configName The configuration filename to load
* @param configPath Where to look.
*/
GameConfig(const std::string& configName,
const std::string& configPath = getDefaultConfigPath());
GameConfig(const std::string &configName,
const std::string &configPath = getDefaultConfigPath());
/**
* @brief getFilePath Returns the system file path for the configuration
@ -166,15 +194,16 @@ public:
const ParseResult &getParseResult() const;
/**
* @brief getConfigString Returns the content of the default INI configuration.
* @brief getConfigString Returns the content of the default INI
* configuration.
* @return INI string
*/
std::string getDefaultINIString();
const std::string& getGameDataPath() const {
const std::string &getGameDataPath() const {
return m_gamePath;
}
const std::string& getGameLanguage() const {
const std::string &getGameLanguage() const {
return m_gameLanguage;
}
bool getInputInvertY() const {
@ -186,6 +215,7 @@ private:
/**
* @brief parseConfig Load data from source and write it to destination.
* Whitespace will be stripped from unknown data.
* @param srcType Can be DEFAULT | CONFIG | FILE | STRING
* @param source don't care if srcType == (DEFAULT | CONFIG),
* path of INI file if srcType == FILE
@ -197,7 +227,7 @@ private:
* @return True if the parsing succeeded
*/
ParseResult parseConfig(ParseType srcType, const std::string &source,
ParseType destType, std::string &destination);
ParseType destType, std::string &destination);
/* Config State */
std::string m_configName;

View File

@ -3,12 +3,39 @@
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fstream>
#include <map>
#include "rw/defines.hpp"
namespace pt = boost::property_tree;
namespace fs = boost::filesystem;
typedef std::map<std::string, std::map<std::string, std::string>> simpleConfig_t;
typedef std::map<std::string, std::map<std::string, std::string>>
simpleConfig_t;
simpleConfig_t readConfig(const std::string &filename) {
simpleConfig_t cfg;
pt::ptree tree;
pt::read_ini(filename, tree);
for (const auto &section : 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;
@ -16,14 +43,17 @@ simpleConfig_t getValidConfig() {
// 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"]["\tlanguage\t "] =
" american ;american english french german italian spanish.";
result["input"]["invert_y"] =
"1 #values != 0 enable input inversion. Optional.";
return result;
}
std::ostream &operator<<(std::ostream &os, const simpleConfig_t &config) {
for (auto &section : config) {
os << "[" << section.first << "]" << "\n";
os << "[" << section.first << "]"
<< "\n";
for (auto &keyValue : section.second) {
os << keyValue.first << "=" << keyValue.second << "\n";
}
@ -59,10 +89,11 @@ public:
return this->m_path.parent_path().string();
}
void change_perms_readonly() {
fs::permissions(this->m_path, fs::perms::owner_read
| fs::perms::group_read | fs::perms::others_read);
fs::permissions(this->m_path, fs::perms::owner_read |
fs::perms::group_read |
fs::perms::others_read);
}
template<typename T>
template <typename T>
bool append(T t) {
// Append argument at the end of the file.
// File is open/closes repeatedly. Not optimal.
@ -71,7 +102,7 @@ public:
ofs.close();
return ofs.good();
}
template<typename T>
template <typename T>
bool write(T t) {
// Write the argument to the file, discarding all contents.
// File is open/closes repeatedly. Not optimal.
@ -80,15 +111,31 @@ public:
ofs.close();
return ofs.good();
}
private:
static fs::path getRandomFilePath() {
return fs::unique_path(fs::temp_directory_path() / "openrw_test_%%%%%%%%%%%%%%%%");
return fs::unique_path(fs::temp_directory_path() /
"openrw_test_%%%%%%%%%%%%%%%%");
}
fs::path m_path;
};
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_TempFile) {
// Check the behavior of TempFile
TempFile tempFile;
@ -126,8 +173,10 @@ BOOST_AUTO_TEST_CASE(test_config_valid) {
GameConfig config(tempFile.filename(), tempFile.dirname());
BOOST_CHECK(config.isValid());
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
BOOST_CHECK_EQUAL(config.getParseResult().type(),
GameConfig::ParseResult::ErrorType::GOOD);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(),
0);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
BOOST_CHECK_EQUAL(config.getGameDataPath(), "/dev/test");
@ -147,8 +196,10 @@ BOOST_AUTO_TEST_CASE(test_config_valid_modified) {
GameConfig config(tempFile.filename(), tempFile.dirname());
BOOST_CHECK(config.isValid());
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
BOOST_CHECK_EQUAL(config.getParseResult().type(),
GameConfig::ParseResult::ErrorType::GOOD);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(),
0);
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
BOOST_CHECK_EQUAL(config.getInputInvertY(), false);
@ -176,6 +227,55 @@ BOOST_AUTO_TEST_CASE(test_config_save) {
GameConfig config2(tempFile.filename(), tempFile.dirname());
BOOST_CHECK_EQUAL(config2.getGameDataPath(), "Liberty City");
simpleConfig_t cfg2 = readConfig(tempFile.path());
BOOST_CHECK_EQUAL(cfg2["game"]["path"], "Liberty City");
}
BOOST_AUTO_TEST_CASE(test_config_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 %%$ ";
TempFile tempFile;
tempFile.append(cfg);
GameConfig config(tempFile.filename(), tempFile.dirname());
BOOST_CHECK(config.isValid());
const auto &unknownData = config.getParseResult().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);
tempFile.remove();
config.saveConfig();
GameConfig config2(tempFile.filename(), tempFile.dirname());
const auto &unknownData2 = config2.getParseResult().getUnknownData();
BOOST_CHECK_EQUAL(unknownData2.size(), 2);
BOOST_CHECK_EQUAL(unknownData2.count("game.unknownkey"), 1);
BOOST_CHECK_EQUAL(unknownData2.at("game.unknownkey"),
stripWhitespace(cfg["game"]["unknownkey"]));
BOOST_CHECK_EQUAL(unknownData2.count("dontknow.dontcare"), 1);
BOOST_CHECK_EQUAL(unknownData2.at("dontknow.dontcare"),
stripWhitespace(cfg["dontknow"]["dontcare"]));
BOOST_CHECK_EQUAL(unknownData2.count("game.path"), 0);
}
BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
@ -191,7 +291,8 @@ BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
auto writeResult = config.saveConfig();
BOOST_CHECK(!writeResult.isValid());
BOOST_CHECK_EQUAL(writeResult.type(), GameConfig::ParseResult::ErrorType::INVALIDOUTPUTFILE);
BOOST_CHECK_EQUAL(writeResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDOUTPUTFILE);
}
BOOST_AUTO_TEST_CASE(test_config_valid_default) {
@ -209,6 +310,22 @@ BOOST_AUTO_TEST_CASE(test_config_valid_default) {
BOOST_CHECK(config.isValid());
}
BOOST_AUTO_TEST_CASE(test_config_invalid_emptykey) {
// Test duplicate keys in invalid configuration file
auto cfg = getValidConfig();
cfg["game"][""] = "0";
TempFile tempFile;
tempFile.append(cfg);
GameConfig config(tempFile.filename(), tempFile.dirname());
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
}
BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
// Test duplicate keys in invalid configuration file
auto cfg = getValidConfig();
@ -221,7 +338,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
}
BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
@ -237,7 +355,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 1);
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
@ -248,7 +367,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
// Test wrong data type
auto cfg = getValidConfig();
cfg["input"]["invert_y"]="d";
cfg["input"]["invert_y"] = "d";
TempFile tempFile;
tempFile.append(cfg);
@ -258,7 +377,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 0);
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 1);
@ -268,7 +388,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
// Test reading empty configuration file
// An empty file has a valid data structure, but has missing keys and is thus invalid.
// An empty file has a valid data structure, but has missing keys and is
// thus invalid.
TempFile tempFile;
tempFile.touch();
BOOST_CHECK(tempFile.exists());
@ -278,7 +399,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
BOOST_CHECK_GE(parseResult.getKeysRequiredMissing().size(), 1);
}
@ -292,7 +414,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_nonexisting) {
BOOST_CHECK(!config.isValid());
const auto &parseResult = config.getParseResult();
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
BOOST_CHECK_EQUAL(parseResult.type(),
GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
}
BOOST_AUTO_TEST_SUITE_END()