2016-05-20 03:09:22 +02:00
|
|
|
#include <GameConfig.hpp>
|
2017-02-17 01:17:50 +01:00
|
|
|
|
|
|
|
#include <boost/filesystem.hpp>
|
2016-09-09 22:13:22 +02:00
|
|
|
#include <boost/test/unit_test.hpp>
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2016-05-20 03:09:22 +02:00
|
|
|
#include <fstream>
|
2017-02-17 01:17:50 +01:00
|
|
|
#include <map>
|
|
|
|
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
|
2017-02-17 01:58:49 +01:00
|
|
|
typedef std::map<std::string, std::map<std::string, std::string>> simpleConfig_t;
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2017-02-17 01:58:49 +01:00
|
|
|
simpleConfig_t getValidConfig() {
|
|
|
|
simpleConfig_t result;
|
2017-02-18 02:35:28 +01:00
|
|
|
// Some values and subkeys are surrounded by whitespace
|
|
|
|
// to test the robustness of the INI parser.
|
2017-02-17 01:58:49 +01:00
|
|
|
// 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.";
|
2017-02-17 01:17:50 +01:00
|
|
|
result["input"]["invert_y"] = "1 #values != 0 enable input inversion. Optional.";
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
std::ostream &operator<<(std::ostream &os, const simpleConfig_t &config) {
|
2017-02-17 01:17:50 +01:00
|
|
|
for (auto §ion : config) {
|
|
|
|
os << "[" << section.first << "]" << "\n";
|
|
|
|
for (auto &keyValue : section.second) {
|
|
|
|
os << keyValue.first << "=" << keyValue.second << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
class TempFile {
|
|
|
|
// A TempFile file will be removed on destruction
|
|
|
|
public:
|
|
|
|
TempFile() : m_path(getRandomFilePath()) {
|
|
|
|
}
|
|
|
|
~TempFile() {
|
|
|
|
this->remove();
|
|
|
|
}
|
|
|
|
void remove() {
|
|
|
|
fs::remove(this->m_path);
|
|
|
|
}
|
|
|
|
void touch() {
|
2017-02-18 02:35:28 +01:00
|
|
|
std::ofstream ofs(this->path(), std::ios::out | std::ios::app);
|
2017-02-17 14:00:02 +01:00
|
|
|
ofs.close();
|
|
|
|
}
|
|
|
|
bool exists() {
|
|
|
|
return fs::exists(this->m_path);
|
|
|
|
}
|
|
|
|
std::string path() {
|
|
|
|
return this->m_path.string();
|
|
|
|
}
|
|
|
|
std::string filename() {
|
|
|
|
return this->m_path.filename().string();
|
|
|
|
}
|
|
|
|
std::string dirname() {
|
|
|
|
return this->m_path.parent_path().string();
|
|
|
|
}
|
2017-02-18 07:33:53 +01:00
|
|
|
void change_perms_readonly() {
|
|
|
|
fs::permissions(this->m_path, fs::perms::owner_read
|
|
|
|
| fs::perms::group_read | fs::perms::others_read);
|
|
|
|
}
|
2017-02-17 14:00:02 +01:00
|
|
|
template<typename T>
|
2017-02-18 07:33:53 +01:00
|
|
|
bool append(T t) {
|
2017-02-18 02:35:28 +01:00
|
|
|
// Append argument at the end of the file.
|
|
|
|
// File is open/closes repeatedly. Not optimal.
|
|
|
|
std::ofstream ofs(this->path(), std::ios::out | std::ios::app);
|
2017-02-17 14:00:02 +01:00
|
|
|
ofs << t;
|
|
|
|
ofs.close();
|
2017-02-18 07:33:53 +01:00
|
|
|
return ofs.good();
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
|
|
bool write(T t) {
|
|
|
|
// Write the argument to the file, discarding all contents.
|
|
|
|
// File is open/closes repeatedly. Not optimal.
|
|
|
|
std::ofstream ofs(this->path(), std::ios::out | std::ios::trunc);
|
|
|
|
ofs << t;
|
|
|
|
ofs.close();
|
|
|
|
return ofs.good();
|
2017-02-17 14:00:02 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
static fs::path getRandomFilePath() {
|
|
|
|
return fs::unique_path(fs::temp_directory_path() / "openrw_test_%%%%%%%%%%%%%%%%");
|
|
|
|
}
|
|
|
|
fs::path m_path;
|
|
|
|
};
|
|
|
|
|
2016-05-20 03:09:22 +02:00
|
|
|
BOOST_AUTO_TEST_SUITE(ConfigTests)
|
|
|
|
|
2017-02-18 02:35:28 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_TempFile) {
|
|
|
|
// Check the behavior of TempFile
|
|
|
|
TempFile tempFile;
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.exists(), false);
|
|
|
|
tempFile.touch();
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.exists(), true);
|
|
|
|
tempFile.remove();
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.exists(), false);
|
|
|
|
|
|
|
|
tempFile.touch();
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.exists(), true);
|
|
|
|
tempFile.remove();
|
|
|
|
|
2017-02-18 07:33:53 +01:00
|
|
|
BOOST_CHECK_EQUAL(tempFile.append("abc"), true);
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.append("def"), true);
|
2017-02-18 02:35:28 +01:00
|
|
|
BOOST_CHECK_EQUAL(tempFile.exists(), true);
|
|
|
|
tempFile.touch();
|
|
|
|
std::ifstream ifs(tempFile.path());
|
|
|
|
std::string line;
|
|
|
|
std::getline(ifs, line);
|
|
|
|
BOOST_CHECK_EQUAL(line, "abcdef");
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
tempFile.change_perms_readonly();
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.write("abc"), false);
|
|
|
|
BOOST_CHECK_EQUAL(tempFile.append("def"), false);
|
2017-02-18 02:35:28 +01:00
|
|
|
}
|
|
|
|
|
2017-02-17 01:17:50 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_valid) {
|
2017-02-17 01:58:49 +01:00
|
|
|
// Test reading a valid configuration file
|
2017-02-17 01:17:50 +01:00
|
|
|
auto cfg = getValidConfig();
|
2017-01-15 03:16:46 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2016-05-20 03:09:22 +02:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2016-05-20 03:09:22 +02:00
|
|
|
|
2016-09-09 22:13:22 +02:00
|
|
|
BOOST_CHECK(config.isValid());
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
2017-02-18 07:33:53 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
2016-05-20 03:09:22 +02:00
|
|
|
|
2016-09-09 22:13:22 +02:00
|
|
|
BOOST_CHECK_EQUAL(config.getGameDataPath(), "/dev/test");
|
2017-01-06 22:45:25 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getGameLanguage(), "american");
|
2017-02-17 01:17:50 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getInputInvertY(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_config_valid_modified) {
|
2017-02-17 01:58:49 +01:00
|
|
|
// Test reading a valid modified configuration file
|
2017-02-17 01:17:50 +01:00
|
|
|
auto cfg = getValidConfig();
|
2017-02-17 01:58:49 +01:00
|
|
|
cfg["game"]["path"] = "Liberty City";
|
2017-02-17 01:17:50 +01:00
|
|
|
cfg["input"]["invert_y"] = "0";
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:17:50 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(config.isValid());
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
2017-02-18 07:33:53 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
|
|
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2017-01-15 03:16:46 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getInputInvertY(), false);
|
2017-02-17 01:58:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(config.getGameDataPath(), "Liberty City");
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_config_save) {
|
|
|
|
// Test saving a configuration file
|
|
|
|
auto cfg = getValidConfig();
|
|
|
|
cfg["game"]["path"] = "Liberty City";
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2017-02-17 01:58:49 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:58:49 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
tempFile.remove();
|
|
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
|
2017-02-18 07:33:53 +01:00
|
|
|
auto writeResult = config.saveConfig();
|
|
|
|
BOOST_CHECK(writeResult.isValid());
|
2017-02-17 14:00:02 +01:00
|
|
|
BOOST_CHECK(tempFile.exists());
|
|
|
|
|
|
|
|
GameConfig config2(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:58:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(config2.getGameDataPath(), "Liberty City");
|
2016-05-20 03:09:22 +02:00
|
|
|
}
|
|
|
|
|
2017-02-18 07:33:53 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
|
|
|
|
// Test whether saving to a readonly INI file fails
|
|
|
|
auto cfg = getValidConfig();
|
|
|
|
|
|
|
|
TempFile tempFile;
|
|
|
|
tempFile.append(cfg);
|
|
|
|
tempFile.change_perms_readonly();
|
|
|
|
|
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
|
|
|
BOOST_CHECK_EQUAL(config.isValid(), true);
|
|
|
|
|
|
|
|
auto writeResult = config.saveConfig();
|
|
|
|
BOOST_CHECK(!writeResult.isValid());
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(writeResult.type(), GameConfig::ParseResult::ErrorType::INVALIDOUTPUTFILE);
|
2017-02-18 07:33:53 +01:00
|
|
|
}
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_valid_default) {
|
|
|
|
// Test whether the default INI string is valid
|
|
|
|
TempFile tempFile;
|
|
|
|
BOOST_CHECK(!tempFile.exists());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
|
|
|
BOOST_CHECK(!config.isValid());
|
|
|
|
|
|
|
|
auto defaultINI = config.getDefaultINIString();
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(defaultINI);
|
2017-02-17 14:00:02 +01:00
|
|
|
|
|
|
|
config = GameConfig(tempFile.filename(), tempFile.dirname());
|
|
|
|
BOOST_CHECK(config.isValid());
|
|
|
|
}
|
|
|
|
|
2017-02-17 01:17:50 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
|
2017-02-17 01:58:49 +01:00
|
|
|
// Test duplicate keys in invalid configuration file
|
2017-02-17 01:17:50 +01:00
|
|
|
auto cfg = getValidConfig();
|
|
|
|
cfg["input"]["invert_y "] = "0";
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:17:50 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(!config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
const auto &parseResult = config.getParseResult();
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
|
2017-02-17 01:17:50 +01:00
|
|
|
}
|
|
|
|
|
2017-02-17 01:58:49 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
|
|
|
|
// Test missing required keys in invalid configuration file
|
|
|
|
auto cfg = getValidConfig();
|
|
|
|
cfg["game"].erase("path");
|
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2017-02-17 01:58:49 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:58:49 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(!config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
const auto &parseResult = config.getParseResult();
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 1);
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing()[0], "game.path");
|
2017-02-17 01:58:49 +01:00
|
|
|
}
|
|
|
|
|
2017-02-17 19:19:02 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
|
|
|
|
// Test wrong data type
|
|
|
|
auto cfg = getValidConfig();
|
|
|
|
cfg["input"]["invert_y"]="d";
|
|
|
|
|
|
|
|
TempFile tempFile;
|
2017-02-18 07:33:53 +01:00
|
|
|
tempFile.append(cfg);
|
2017-02-17 19:19:02 +01:00
|
|
|
|
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
|
|
|
|
|
|
|
BOOST_CHECK(!config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
const auto &parseResult = config.getParseResult();
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 0);
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 1);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData()[0], "input.invert_y");
|
2017-02-17 19:19:02 +01:00
|
|
|
}
|
|
|
|
|
2017-02-17 01:17:50 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
|
2017-02-17 01:58:49 +01:00
|
|
|
// Test reading empty configuration file
|
2017-02-18 07:33:53 +01:00
|
|
|
// An empty file has a valid data structure, but has missing keys and is thus invalid.
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
|
|
|
tempFile.touch();
|
|
|
|
BOOST_CHECK(tempFile.exists());
|
2017-02-17 01:17:50 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:17:50 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(!config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
const auto &parseResult = config.getParseResult();
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
2017-02-18 07:33:53 +01:00
|
|
|
BOOST_CHECK_GE(parseResult.getKeysRequiredMissing().size(), 1);
|
2017-02-17 01:17:50 +01:00
|
|
|
}
|
2017-01-06 22:45:25 +01:00
|
|
|
|
2017-02-17 01:58:49 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(test_config_invalid_nonexisting) {
|
|
|
|
// Test reading non-existing configuration file
|
2017-02-17 14:00:02 +01:00
|
|
|
TempFile tempFile;
|
2017-02-17 01:58:49 +01:00
|
|
|
|
2017-02-17 14:00:02 +01:00
|
|
|
BOOST_CHECK(!tempFile.exists());
|
|
|
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
2017-02-17 01:58:49 +01:00
|
|
|
|
|
|
|
BOOST_CHECK(!config.isValid());
|
2017-02-18 07:33:53 +01:00
|
|
|
|
|
|
|
const auto &parseResult = config.getParseResult();
|
2017-02-18 16:46:40 +01:00
|
|
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
|
2017-02-17 01:58:49 +01:00
|
|
|
}
|
|
|
|
|
2016-05-20 03:09:22 +02:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|