mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 06:52:34 +02:00
config: unknown data will be kept in memory and saved onto disk
This commit is contained in:
parent
7a86c199b0
commit
a92f24cbb4
@ -1,16 +1,16 @@
|
|||||||
#include "GameConfig.hpp"
|
#include "GameConfig.hpp"
|
||||||
#include <cstdlib>
|
#include <algorithm>
|
||||||
#include <cstring>
|
|
||||||
#include <rw/defines.hpp>
|
#include <rw/defines.hpp>
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
#include <boost/property_tree/ini_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
namespace pt = boost::property_tree;
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
const std::string kConfigDirectoryName("OpenRW");
|
const std::string kConfigDirectoryName("OpenRW");
|
||||||
|
|
||||||
GameConfig::GameConfig(const std::string& configName,
|
GameConfig::GameConfig(const std::string &configName,
|
||||||
const std::string& configPath)
|
const std::string &configPath)
|
||||||
: m_configName(configName)
|
: m_configName(configName)
|
||||||
, m_configPath(configPath)
|
, m_configPath(configPath)
|
||||||
, m_parseResult()
|
, m_parseResult()
|
||||||
@ -23,7 +23,8 @@ GameConfig::GameConfig(const std::string& configName,
|
|||||||
auto configFile = getConfigFile();
|
auto configFile = getConfigFile();
|
||||||
|
|
||||||
std::string dummy;
|
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 {
|
std::string GameConfig::getConfigFile() const {
|
||||||
@ -41,17 +42,17 @@ const GameConfig::ParseResult &GameConfig::getParseResult() const {
|
|||||||
std::string GameConfig::getDefaultConfigPath() {
|
std::string GameConfig::getDefaultConfigPath() {
|
||||||
#if defined(RW_LINUX) || defined(RW_FREEBSD) || defined(RW_NETBSD) || \
|
#if defined(RW_LINUX) || defined(RW_FREEBSD) || defined(RW_NETBSD) || \
|
||||||
defined(RW_OPENBSD)
|
defined(RW_OPENBSD)
|
||||||
char* config_home = getenv("XDG_CONFIG_HOME");
|
char *config_home = getenv("XDG_CONFIG_HOME");
|
||||||
if (config_home != nullptr) {
|
if (config_home != nullptr) {
|
||||||
return std::string(config_home) + "/" + kConfigDirectoryName;
|
return std::string(config_home) + "/" + kConfigDirectoryName;
|
||||||
}
|
}
|
||||||
char* home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (home != nullptr) {
|
if (home != nullptr) {
|
||||||
return std::string(home) + "/.config/" + kConfigDirectoryName;
|
return std::string(home) + "/.config/" + kConfigDirectoryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(RW_OSX)
|
#elif defined(RW_OSX)
|
||||||
char* home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (home)
|
if (home)
|
||||||
return std::string(home) + "/Library/Preferences/" +
|
return std::string(home) + "/Library/Preferences/" +
|
||||||
kConfigDirectoryName;
|
kConfigDirectoryName;
|
||||||
@ -67,7 +68,7 @@ std::string GameConfig::getDefaultConfigPath() {
|
|||||||
|
|
||||||
std::string stripComments(const std::string &str) {
|
std::string stripComments(const std::string &str) {
|
||||||
auto s = std::string(str, 0, str.find_first_of(";#"));
|
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 {
|
struct StringTranslator {
|
||||||
@ -83,7 +84,7 @@ struct StringTranslator {
|
|||||||
|
|
||||||
struct BoolTranslator {
|
struct BoolTranslator {
|
||||||
typedef std::string internal_type;
|
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> get_value(const internal_type &str) {
|
||||||
boost::optional<external_type> res;
|
boost::optional<external_type> res;
|
||||||
try {
|
try {
|
||||||
@ -99,7 +100,7 @@ struct BoolTranslator {
|
|||||||
|
|
||||||
struct IntTranslator {
|
struct IntTranslator {
|
||||||
typedef std::string internal_type;
|
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> get_value(const internal_type &str) {
|
||||||
boost::optional<external_type> res;
|
boost::optional<external_type> res;
|
||||||
try {
|
try {
|
||||||
@ -115,8 +116,7 @@ struct IntTranslator {
|
|||||||
|
|
||||||
GameConfig::ParseResult GameConfig::saveConfig() {
|
GameConfig::ParseResult GameConfig::saveConfig() {
|
||||||
auto filename = getConfigFile();
|
auto filename = getConfigFile();
|
||||||
return parseConfig(ParseType::CONFIG, "",
|
return parseConfig(ParseType::CONFIG, "", ParseType::FILE, filename);
|
||||||
ParseType::FILE, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GameConfig::getDefaultINIString() {
|
std::string GameConfig::getDefaultINIString() {
|
||||||
@ -125,10 +125,11 @@ std::string GameConfig::getDefaultINIString() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameConfig::ParseResult GameConfig::parseConfig(
|
GameConfig::ParseResult GameConfig::parseConfig(GameConfig::ParseType srcType,
|
||||||
GameConfig::ParseType srcType, const std::string &source,
|
const std::string &source,
|
||||||
ParseType destType, std::string &destination)
|
ParseType destType,
|
||||||
{
|
std::string &destination) {
|
||||||
|
// srcTree: holds all key/value pairs
|
||||||
pt::ptree srcTree;
|
pt::ptree srcTree;
|
||||||
ParseResult parseResult(srcType, source, destType, destination);
|
ParseResult parseResult(srcType, source, destType, destination);
|
||||||
|
|
||||||
@ -152,12 +153,16 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
return parseResult;
|
return parseResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// knownKeys: holds all known keys
|
||||||
|
std::vector<std::string> knownKeys;
|
||||||
|
|
||||||
auto read_config = [&](const std::string &key, auto &target,
|
auto read_config = [&](const std::string &key, auto &target,
|
||||||
const auto &defaultValue, auto &translator,
|
const auto &defaultValue, auto &translator,
|
||||||
bool optional=true) {
|
bool optional = true) {
|
||||||
typedef typename std::remove_reference<decltype(target)>::type config_t;
|
typedef typename std::remove_reference<decltype(target)>::type config_t;
|
||||||
|
|
||||||
config_t sourceValue;
|
config_t sourceValue;
|
||||||
|
knownKeys.push_back(key);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case ParseType::DEFAULT:
|
case ParseType::DEFAULT:
|
||||||
@ -210,13 +215,50 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
// Additionally, add them to the unit test.
|
// Additionally, add them to the unit test.
|
||||||
|
|
||||||
// @todo Don't allow path separators and relative directories
|
// @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("game.language", this->m_gameLanguage, "american", deft);
|
||||||
|
|
||||||
read_config("input.invert_y", this->m_inputInvertY, false, boolt);
|
read_config("input.invert_y", this->m_inputInvertY, false, boolt);
|
||||||
|
|
||||||
if (!parseResult.isValid())
|
if (!parseResult.isValid()) return parseResult;
|
||||||
return parseResult;
|
|
||||||
|
// Build the unknown key/value map from the correct source
|
||||||
|
switch (srcType) {
|
||||||
|
case ParseType::FILE:
|
||||||
|
case ParseType::STRING:
|
||||||
|
for (const auto §ion : 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 {
|
try {
|
||||||
if (destType == ParseType::STRING) {
|
if (destType == ParseType::STRING) {
|
||||||
@ -234,8 +276,8 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
return parseResult;
|
return parseResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GameConfig::extractFilenameParseTypeData(ParseType type, const std::string &data)
|
std::string GameConfig::extractFilenameParseTypeData(ParseType type,
|
||||||
{
|
const std::string &data) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ParseType::CONFIG:
|
case ParseType::CONFIG:
|
||||||
return "<configuration>";
|
return "<configuration>";
|
||||||
@ -249,16 +291,19 @@ std::string GameConfig::extractFilenameParseTypeData(ParseType type, const std::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameConfig::ParseResult::ParseResult(
|
GameConfig::ParseResult::ParseResult(GameConfig::ParseType srcType,
|
||||||
GameConfig::ParseType srcType, const std::string &source,
|
const std::string &source,
|
||||||
GameConfig::ParseType destType, const std::string &destination)
|
GameConfig::ParseType destType,
|
||||||
|
const std::string &destination)
|
||||||
: m_result(ErrorType::GOOD)
|
: m_result(ErrorType::GOOD)
|
||||||
, m_inputfilename(GameConfig::extractFilenameParseTypeData(srcType, source))
|
, m_inputfilename(GameConfig::extractFilenameParseTypeData(srcType, source))
|
||||||
, m_outputfilename(GameConfig::extractFilenameParseTypeData(destType, destination))
|
, m_outputfilename(
|
||||||
|
GameConfig::extractFilenameParseTypeData(destType, destination))
|
||||||
, m_line(0)
|
, m_line(0)
|
||||||
, m_message()
|
, m_message()
|
||||||
, m_keys_requiredMissing()
|
, m_keys_requiredMissing()
|
||||||
, m_keys_invalidData() {
|
, m_keys_invalidData()
|
||||||
|
, m_unknownData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
GameConfig::ParseResult::ParseResult()
|
GameConfig::ParseResult::ParseResult()
|
||||||
@ -280,7 +325,7 @@ bool GameConfig::ParseResult::isValid() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameConfig::ParseResult::failInputFile(size_t line,
|
void GameConfig::ParseResult::failInputFile(size_t line,
|
||||||
const std::string &message) {
|
const std::string &message) {
|
||||||
this->m_result = ParseResult::ErrorType::INVALIDINPUTFILE;
|
this->m_result = ParseResult::ErrorType::INVALIDINPUTFILE;
|
||||||
this->m_line = line;
|
this->m_line = line;
|
||||||
this->m_message = message;
|
this->m_message = message;
|
||||||
@ -301,17 +346,19 @@ void GameConfig::ParseResult::failInvalidData(const std::string &key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameConfig::ParseResult::failOutputFile(size_t line,
|
void GameConfig::ParseResult::failOutputFile(size_t line,
|
||||||
const std::string &message) {
|
const std::string &message) {
|
||||||
this->m_result = ParseResult::ErrorType::INVALIDOUTPUTFILE;
|
this->m_result = ParseResult::ErrorType::INVALIDOUTPUTFILE;
|
||||||
this->m_line = line;
|
this->m_line = line;
|
||||||
this->m_message = message;
|
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;
|
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;
|
return this->m_keys_invalidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,27 +368,23 @@ std::string GameConfig::ParseResult::what() const {
|
|||||||
return "Good";
|
return "Good";
|
||||||
case ErrorType::INVALIDARGUMENT:
|
case ErrorType::INVALIDARGUMENT:
|
||||||
return "Invalid argument: destination cannot be the default config";
|
return "Invalid argument: destination cannot be the default config";
|
||||||
case ErrorType::INVALIDINPUTFILE:
|
case ErrorType::INVALIDINPUTFILE: {
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error while reading \""
|
oss << "Error while reading \"" << this->m_inputfilename
|
||||||
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
|
<< "\":" << this->m_line << ":\n"
|
||||||
<< this->m_message;
|
<< this->m_message;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
case ErrorType::INVALIDOUTPUTFILE:
|
case ErrorType::INVALIDOUTPUTFILE: {
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error while writing \""
|
oss << "Error while writing \"" << this->m_inputfilename
|
||||||
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
|
<< "\":" << this->m_line << ":\n"
|
||||||
<< this->m_message;
|
<< this->m_message;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
case ErrorType::INVALIDCONTENT:
|
case ErrorType::INVALIDCONTENT: {
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error while parsing \""
|
oss << "Error while parsing \"" << this->m_inputfilename << "\".";
|
||||||
<< this->m_inputfilename << "\".";
|
|
||||||
if (this->m_keys_requiredMissing.size()) {
|
if (this->m_keys_requiredMissing.size()) {
|
||||||
oss << "\nRequired keys that are missing:";
|
oss << "\nRequired keys that are missing:";
|
||||||
for (auto &key : this->m_keys_requiredMissing) {
|
for (auto &key : this->m_keys_requiredMissing) {
|
||||||
@ -360,3 +403,18 @@ std::string GameConfig::ParseResult::what() const {
|
|||||||
return "Unknown error";
|
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;
|
||||||
|
}
|
||||||
|
@ -1,47 +1,50 @@
|
|||||||
#ifndef RWGAME_GAMECONFIG_HPP
|
#ifndef RWGAME_GAMECONFIG_HPP
|
||||||
#define RWGAME_GAMECONFIG_HPP
|
#define RWGAME_GAMECONFIG_HPP
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class GameConfig {
|
class GameConfig {
|
||||||
private:
|
private:
|
||||||
enum ParseType {
|
enum ParseType { DEFAULT, CONFIG, FILE, STRING };
|
||||||
DEFAULT,
|
|
||||||
CONFIG,
|
|
||||||
FILE,
|
|
||||||
STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief extractFilenameParseTypeData Get a human readable filename string
|
* @brief extractFilenameParseTypeData Get a human readable filename string
|
||||||
* @return file path or a description of the data type
|
* @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:
|
public:
|
||||||
class ParseResult {
|
class ParseResult {
|
||||||
public:
|
public:
|
||||||
enum ErrorType {
|
enum ErrorType {
|
||||||
/// GOOD: Input file/string was good
|
/// GOOD: Input file/string was good
|
||||||
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,
|
INVALIDINPUTFILE,
|
||||||
/// INVALIDARGUMENT: The parser received impossible arguments
|
/// INVALIDARGUMENT: The parser received impossible arguments
|
||||||
INVALIDARGUMENT,
|
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,
|
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
|
INVALIDOUTPUTFILE
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
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 srcType Type of the source
|
||||||
* @param source The source of the parser
|
* @param source The source of the parser
|
||||||
* @param destType Type of the destination
|
* @param destType Type of the destination
|
||||||
* @param destination The destination
|
* @param destination The destination
|
||||||
*/
|
*/
|
||||||
ParseResult(ParseType srcType, const std::string &source,
|
ParseResult(ParseType srcType, const std::string &source,
|
||||||
ParseType destType, const std::string &destination);
|
ParseType destType, const std::string &destination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ParseResult Create empty ParseResult
|
* @brief ParseResult Create empty ParseResult
|
||||||
@ -93,7 +96,8 @@ public:
|
|||||||
void failInvalidData(const std::string &key);
|
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 line Line number where the error is located
|
||||||
* @param message Description of the error
|
* @param message Description of the error
|
||||||
*/
|
*/
|
||||||
@ -110,6 +114,20 @@ public:
|
|||||||
* @return String with the error description
|
* @return String with the error description
|
||||||
*/
|
*/
|
||||||
std::string what() const;
|
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:
|
private:
|
||||||
/// Type of the failure
|
/// Type of the failure
|
||||||
ErrorType m_result;
|
ErrorType m_result;
|
||||||
@ -120,7 +138,8 @@ public:
|
|||||||
/// Filename of the output file
|
/// Filename of the output file
|
||||||
std::string m_outputfilename;
|
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;
|
size_t m_line;
|
||||||
|
|
||||||
/// Description of the failure (on invalid input or output file)
|
/// Description of the failure (on invalid input or output file)
|
||||||
@ -132,6 +151,15 @@ public:
|
|||||||
/// All keys that contain invalid data
|
/// All keys that contain invalid data
|
||||||
std::vector<std::string> m_keys_invalidData;
|
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;
|
friend class GameConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,8 +168,8 @@ public:
|
|||||||
* @param configName The configuration filename to load
|
* @param configName The configuration filename to load
|
||||||
* @param configPath Where to look.
|
* @param configPath Where to look.
|
||||||
*/
|
*/
|
||||||
GameConfig(const std::string& configName,
|
GameConfig(const std::string &configName,
|
||||||
const std::string& configPath = getDefaultConfigPath());
|
const std::string &configPath = getDefaultConfigPath());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getFilePath Returns the system file path for the configuration
|
* @brief getFilePath Returns the system file path for the configuration
|
||||||
@ -166,15 +194,16 @@ public:
|
|||||||
const ParseResult &getParseResult() const;
|
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
|
* @return INI string
|
||||||
*/
|
*/
|
||||||
std::string getDefaultINIString();
|
std::string getDefaultINIString();
|
||||||
|
|
||||||
const std::string& getGameDataPath() const {
|
const std::string &getGameDataPath() const {
|
||||||
return m_gamePath;
|
return m_gamePath;
|
||||||
}
|
}
|
||||||
const std::string& getGameLanguage() const {
|
const std::string &getGameLanguage() const {
|
||||||
return m_gameLanguage;
|
return m_gameLanguage;
|
||||||
}
|
}
|
||||||
bool getInputInvertY() const {
|
bool getInputInvertY() const {
|
||||||
@ -186,6 +215,7 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parseConfig Load data from source and write it to destination.
|
* @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 srcType Can be DEFAULT | CONFIG | FILE | STRING
|
||||||
* @param source don't care if srcType == (DEFAULT | CONFIG),
|
* @param source don't care if srcType == (DEFAULT | CONFIG),
|
||||||
* path of INI file if srcType == FILE
|
* path of INI file if srcType == FILE
|
||||||
@ -197,7 +227,7 @@ private:
|
|||||||
* @return True if the parsing succeeded
|
* @return True if the parsing succeeded
|
||||||
*/
|
*/
|
||||||
ParseResult parseConfig(ParseType srcType, const std::string &source,
|
ParseResult parseConfig(ParseType srcType, const std::string &source,
|
||||||
ParseType destType, std::string &destination);
|
ParseType destType, std::string &destination);
|
||||||
|
|
||||||
/* Config State */
|
/* Config State */
|
||||||
std::string m_configName;
|
std::string m_configName;
|
||||||
|
@ -3,12 +3,39 @@
|
|||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <boost/property_tree/ini_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "rw/defines.hpp"
|
||||||
|
|
||||||
|
namespace pt = boost::property_tree;
|
||||||
namespace fs = boost::filesystem;
|
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 §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 getValidConfig() {
|
||||||
simpleConfig_t result;
|
simpleConfig_t result;
|
||||||
@ -16,14 +43,17 @@ simpleConfig_t getValidConfig() {
|
|||||||
// to test the robustness of the INI parser.
|
// to test the robustness of the INI parser.
|
||||||
// Don't change game.path and input.invert_y keys. Tests depend on them.
|
// 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"]["path"] = "\t/dev/test \t \r\n";
|
||||||
result["game"]["\tlanguage\t "] = " american ;american english french german italian spanish.";
|
result["game"]["\tlanguage\t "] =
|
||||||
result["input"]["invert_y"] = "1 #values != 0 enable input inversion. Optional.";
|
" american ;american english french german italian spanish.";
|
||||||
|
result["input"]["invert_y"] =
|
||||||
|
"1 #values != 0 enable input inversion. Optional.";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const simpleConfig_t &config) {
|
std::ostream &operator<<(std::ostream &os, const simpleConfig_t &config) {
|
||||||
for (auto §ion : config) {
|
for (auto §ion : config) {
|
||||||
os << "[" << section.first << "]" << "\n";
|
os << "[" << section.first << "]"
|
||||||
|
<< "\n";
|
||||||
for (auto &keyValue : section.second) {
|
for (auto &keyValue : section.second) {
|
||||||
os << keyValue.first << "=" << keyValue.second << "\n";
|
os << keyValue.first << "=" << keyValue.second << "\n";
|
||||||
}
|
}
|
||||||
@ -59,10 +89,11 @@ public:
|
|||||||
return this->m_path.parent_path().string();
|
return this->m_path.parent_path().string();
|
||||||
}
|
}
|
||||||
void change_perms_readonly() {
|
void change_perms_readonly() {
|
||||||
fs::permissions(this->m_path, fs::perms::owner_read
|
fs::permissions(this->m_path, fs::perms::owner_read |
|
||||||
| fs::perms::group_read | fs::perms::others_read);
|
fs::perms::group_read |
|
||||||
|
fs::perms::others_read);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool append(T t) {
|
bool append(T t) {
|
||||||
// Append argument at the end of the file.
|
// Append argument at the end of the file.
|
||||||
// File is open/closes repeatedly. Not optimal.
|
// File is open/closes repeatedly. Not optimal.
|
||||||
@ -71,7 +102,7 @@ public:
|
|||||||
ofs.close();
|
ofs.close();
|
||||||
return ofs.good();
|
return ofs.good();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool write(T t) {
|
bool write(T t) {
|
||||||
// Write the argument to the file, discarding all contents.
|
// Write the argument to the file, discarding all contents.
|
||||||
// File is open/closes repeatedly. Not optimal.
|
// File is open/closes repeatedly. Not optimal.
|
||||||
@ -80,15 +111,31 @@ public:
|
|||||||
ofs.close();
|
ofs.close();
|
||||||
return ofs.good();
|
return ofs.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static fs::path getRandomFilePath() {
|
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;
|
fs::path m_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(ConfigTests)
|
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) {
|
BOOST_AUTO_TEST_CASE(test_TempFile) {
|
||||||
// Check the behavior of TempFile
|
// Check the behavior of TempFile
|
||||||
TempFile tempFile;
|
TempFile tempFile;
|
||||||
@ -126,8 +173,10 @@ BOOST_AUTO_TEST_CASE(test_config_valid) {
|
|||||||
GameConfig config(tempFile.filename(), tempFile.dirname());
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
||||||
|
|
||||||
BOOST_CHECK(config.isValid());
|
BOOST_CHECK(config.isValid());
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
BOOST_CHECK_EQUAL(config.getParseResult().type(),
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
GameConfig::ParseResult::ErrorType::GOOD);
|
||||||
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(),
|
||||||
|
0);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(config.getGameDataPath(), "/dev/test");
|
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());
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
||||||
|
|
||||||
BOOST_CHECK(config.isValid());
|
BOOST_CHECK(config.isValid());
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
BOOST_CHECK_EQUAL(config.getParseResult().type(),
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
GameConfig::ParseResult::ErrorType::GOOD);
|
||||||
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(),
|
||||||
|
0);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(config.getInputInvertY(), false);
|
BOOST_CHECK_EQUAL(config.getInputInvertY(), false);
|
||||||
@ -176,6 +227,55 @@ BOOST_AUTO_TEST_CASE(test_config_save) {
|
|||||||
|
|
||||||
GameConfig config2(tempFile.filename(), tempFile.dirname());
|
GameConfig config2(tempFile.filename(), tempFile.dirname());
|
||||||
BOOST_CHECK_EQUAL(config2.getGameDataPath(), "Liberty City");
|
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) {
|
BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
|
||||||
@ -191,7 +291,8 @@ BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
|
|||||||
|
|
||||||
auto writeResult = config.saveConfig();
|
auto writeResult = config.saveConfig();
|
||||||
BOOST_CHECK(!writeResult.isValid());
|
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) {
|
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_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) {
|
BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
|
||||||
// Test duplicate keys in invalid configuration file
|
// Test duplicate keys in invalid configuration file
|
||||||
auto cfg = getValidConfig();
|
auto cfg = getValidConfig();
|
||||||
@ -221,7 +338,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
|
|||||||
|
|
||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
const auto &parseResult = config.getParseResult();
|
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) {
|
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());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
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.getKeysRequiredMissing().size(), 1);
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
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) {
|
BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
|
||||||
// Test wrong data type
|
// Test wrong data type
|
||||||
auto cfg = getValidConfig();
|
auto cfg = getValidConfig();
|
||||||
cfg["input"]["invert_y"]="d";
|
cfg["input"]["invert_y"] = "d";
|
||||||
|
|
||||||
TempFile tempFile;
|
TempFile tempFile;
|
||||||
tempFile.append(cfg);
|
tempFile.append(cfg);
|
||||||
@ -258,7 +377,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
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.getKeysRequiredMissing().size(), 0);
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 1);
|
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) {
|
BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
|
||||||
// Test reading empty configuration file
|
// 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 tempFile;
|
||||||
tempFile.touch();
|
tempFile.touch();
|
||||||
BOOST_CHECK(tempFile.exists());
|
BOOST_CHECK(tempFile.exists());
|
||||||
@ -278,7 +399,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
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);
|
BOOST_CHECK_GE(parseResult.getKeysRequiredMissing().size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +414,8 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_nonexisting) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user