mirror of https://github.com/Poikilos/b3view
parent
ff44991f55
commit
98ad5d1457
|
@ -279,6 +279,7 @@ s32 Engine::getNumberOfVertices()
|
|||
|
||||
Engine::Engine()
|
||||
{
|
||||
settings.set_int("max_recent", 10);
|
||||
// For monitoring single press: see
|
||||
// <http://irrlicht.sourceforge.net/forum/viewtopic.php?p=210744>
|
||||
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
|
||||
|
|
3
Engine.h
3
Engine.h
|
@ -13,6 +13,7 @@ class View;
|
|||
#include "EventHandler.h"
|
||||
#include "extlib/CGUITTFont.h"
|
||||
#include <irrlicht/irrlicht.h>
|
||||
#include "settings.h"
|
||||
|
||||
enum SceneItemID {
|
||||
SIID_LIGHT = 1,
|
||||
|
@ -66,7 +67,7 @@ private:
|
|||
bool KeyIsDown[irr::KEY_KEY_CODES_COUNT];
|
||||
irr::s32 keyState[irr::KEY_KEY_CODES_COUNT];
|
||||
irr::s32 LMouseState, RMouseState;
|
||||
|
||||
Settings settings;
|
||||
public:
|
||||
std::wstring m_LoadedMeshPath;
|
||||
std::wstring m_LoadedTexturePath;
|
||||
|
|
65
Utility.cpp
65
Utility.cpp
|
@ -17,6 +17,8 @@ using namespace irr::scene;
|
|||
using namespace irr::video;
|
||||
using namespace std;
|
||||
|
||||
const std::string Utility::WHITESPACE = " \n\r\t\f\v";
|
||||
|
||||
void Utility::dumpVectorToConsole(const vector3df& vector)
|
||||
{
|
||||
debug() << "X: " << vector.X << " Y: " << vector.Y << " Z: " << vector.Z << endl;
|
||||
|
@ -152,6 +154,36 @@ bool Utility::startsWith(const std::wstring& haystack, const std::wstring& needl
|
|||
return found;
|
||||
}
|
||||
|
||||
bool Utility::endsWith(const std::wstring& haystack, const std::wstring& needle) {
|
||||
bool found = false;
|
||||
if (haystack.length() >= needle.length()) {
|
||||
if (haystack.substr(haystack.length()-needle.length())==needle) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool Utility::startsWith(const std::string& haystack, const std::string& needle) {
|
||||
bool found = false;
|
||||
if (haystack.length() >= needle.length()) {
|
||||
if (haystack.substr(0, needle.length())==needle) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool Utility::endsWith(const std::string& haystack, const std::string& needle) {
|
||||
bool found = false;
|
||||
if (haystack.length() >= needle.length()) {
|
||||
if (haystack.substr(haystack.length()-needle.length())==needle) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
wstring Utility::replaceAll(const wstring &subject, const wstring &from, const wstring &to)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
@ -190,16 +222,6 @@ std::string Utility::replaceAll(const std::string &subject, const std::string &f
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Utility::endsWith(const std::wstring& haystack, const std::wstring& needle) {
|
||||
bool found = false;
|
||||
if (haystack.length() >= needle.length()) {
|
||||
if (haystack.substr(haystack.length()-needle.length())==needle) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool Utility::startsWithAny(const std::wstring& haystack, const std::vector<std::wstring>& needles, bool CI) {
|
||||
return getPrefix(haystack, needles, CI).length() > 0;
|
||||
}
|
||||
|
@ -447,6 +469,23 @@ std::string Utility::toString(irr::f32 val)
|
|||
return std::to_string(val);
|
||||
}
|
||||
|
||||
std::string Utility::ltrim(const std::string& s)
|
||||
{
|
||||
size_t start = s.find_first_not_of(Utility::WHITESPACE);
|
||||
return (start == std::string::npos) ? "" : s.substr(start);
|
||||
}
|
||||
|
||||
std::string Utility::rtrim(const std::string& s)
|
||||
{
|
||||
size_t end = s.find_last_not_of(Utility::WHITESPACE);
|
||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||
}
|
||||
|
||||
std::string Utility::trim(const std::string& s)
|
||||
{
|
||||
return rtrim(ltrim(s));
|
||||
}
|
||||
|
||||
// don't do late instantiation (see header file)
|
||||
// template<typename T>
|
||||
// bool Utility::equalsApprox(T f1, T f2)
|
||||
|
@ -477,17 +516,17 @@ void TestUtility::testReplaceAll(const std::string &subject, const std::string &
|
|||
void TestUtility::assertEqual(const wstring& subject, const wstring& expectedResult)
|
||||
{
|
||||
if (subject != expectedResult) {
|
||||
cerr << "The test expected \"" << Utility::toString(expectedResult) << "\" but got \"" << Utility::toString(subject) << std::endl;
|
||||
cerr << "The test expected \"" << Utility::toString(expectedResult) << "\" but got \"" << Utility::toString(subject) << "\"" << std::endl;
|
||||
}
|
||||
assert(subject == expectedResult);
|
||||
}
|
||||
void TestUtility::assertEqual(const std::string subject, const std::string expectedResult)
|
||||
{
|
||||
if (subject != expectedResult) {
|
||||
cerr << "The test expected \"" << expectedResult << "\" but got \"" << subject << std::endl;
|
||||
cerr << "The test expected \"" << expectedResult << "\" but got \"" << subject << "\"" << std::endl;
|
||||
}
|
||||
assert(subject == expectedResult);
|
||||
}
|
||||
|
||||
|
||||
static TestUtility testutility;
|
||||
static TestUtility testutility; // Run tests (Creating the first instance runs the static constructor).
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
class Utility {
|
||||
public:
|
||||
static const std::string WHITESPACE;
|
||||
static void dumpVectorToConsole(const irr::core::vector3df& vector);
|
||||
static int getTextureCount(const irr::video::SMaterial& material);
|
||||
static int getTextureCount(irr::scene::IAnimatedMeshSceneNode* node);
|
||||
|
@ -20,9 +21,11 @@ public:
|
|||
static std::wstring rightOf(const std::wstring& path, const std::wstring& delimiter, bool allIfNotFound);
|
||||
static std::wstring rightOfLast(const std::wstring& path, const std::wstring& delimiter, bool allIfNotFound);
|
||||
static bool startsWith(const std::wstring& haystack, const std::wstring& needle);
|
||||
static bool endsWith(const std::wstring& haystack, const std::wstring& needle);
|
||||
static bool startsWith(const std::string& haystack, const std::string& needle);
|
||||
static bool endsWith(const std::string& haystack, const std::string& needle);
|
||||
static std::wstring replaceAll(const std::wstring& subject, const std::wstring& from, const std::wstring& to);
|
||||
static std::string replaceAll(const std::string& subject, const std::string& from, const std::string& to);
|
||||
static bool endsWith(const std::wstring& haystack, const std::wstring& needle);
|
||||
static std::wstring getPrefix(const std::wstring& haystack, const std::vector<std::wstring>& needles, bool CI);
|
||||
static std::wstring getSuffix(const std::wstring& haystack, const std::vector<std::wstring>& needles, bool CI);
|
||||
static bool startsWithAny(const std::wstring& haystack, const std::vector<std::wstring>& needles, bool CI);
|
||||
|
@ -51,6 +54,10 @@ public:
|
|||
{
|
||||
return abs(f2 - f1) < .00000001; // TODO: kEpsilon? (see also <https://en.wikipedia.org/wiki/Machine_epsilon#How_to_determine_machine_epsilon>)
|
||||
}
|
||||
|
||||
static std::string ltrim(const std::string &s);
|
||||
static std::string rtrim(const std::string &s);
|
||||
static std::string trim(const std::string &s);
|
||||
};
|
||||
|
||||
class TestUtility {
|
||||
|
|
|
@ -9,14 +9,16 @@ SOURCES += main.cpp \
|
|||
Debug.cpp \
|
||||
View.cpp \
|
||||
extlib/CGUITTFont.cpp \
|
||||
Utility.cpp
|
||||
Utility.cpp \
|
||||
settings.cpp
|
||||
HEADERS += Engine.h \
|
||||
EventHandler.h \
|
||||
UserInterface.h \
|
||||
Debug.h \
|
||||
View.h \
|
||||
extlib/CGUITTFont.h \
|
||||
Utility.h
|
||||
Utility.h \
|
||||
settings.h
|
||||
CONFIG += warn_off
|
||||
|
||||
# Irrlicht
|
||||
|
|
|
@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [git] - 2021-02-17
|
||||
### Added
|
||||
- a settings system and related tests
|
||||
- more string functions in Utility
|
||||
|
||||
### Fixed
|
||||
- Add a missing quote in TestUtility output.
|
||||
|
||||
|
||||
## [git] - 2020-07-30
|
||||
(Poikilos)
|
||||
|
|
|
@ -0,0 +1,454 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm> // std::find
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "settings.h"
|
||||
#include "Utility.h"
|
||||
// #include "Debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Settings::init_default_symbols() {
|
||||
this->init(" = ", "# ");
|
||||
}
|
||||
|
||||
void Settings::init(std::string assignmentOperator, std::string commentMark)
|
||||
{
|
||||
this->ao_and_spacing = assignmentOperator;
|
||||
this->cm_and_spacing = commentMark;
|
||||
this->enable_autosave = true;
|
||||
}
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
this->init_default_symbols();
|
||||
}
|
||||
|
||||
Settings::Settings(std::string confPath)
|
||||
{
|
||||
this->init_default_symbols();
|
||||
this->path = confPath;
|
||||
this->load(confPath);
|
||||
}
|
||||
|
||||
void Settings::clear()
|
||||
{
|
||||
this->section = "";
|
||||
this->sections.clear();
|
||||
this->table.clear();
|
||||
}
|
||||
|
||||
void Settings::clear_types()
|
||||
{
|
||||
this->types.clear();
|
||||
}
|
||||
|
||||
bool Settings::load(std::string path)
|
||||
{
|
||||
this->section = "";
|
||||
this->path = path;
|
||||
fstream newfile;
|
||||
this->pre = "";
|
||||
newfile.open(path,ios::in);
|
||||
std::string ao = this->ao_trimmed();
|
||||
std::string cm = this->cm_trimmed();
|
||||
if (newfile.is_open()){
|
||||
std::string line;
|
||||
int lineN = 0; // Set this to 1 before use.
|
||||
while(getline(newfile, line)) {
|
||||
lineN += 1;
|
||||
this->pre = this->path + ":" + std::to_string(lineN) + ": "; // must end with space for outputinspector
|
||||
line = Utility::trim(line);
|
||||
std::size_t signPos = line.find(ao);
|
||||
std::string typeStr = "string";
|
||||
if ((line.length() >= cm.length()) && (line.substr(0, cm.length()) == cm)) {
|
||||
// comment
|
||||
}
|
||||
else if (line.length() == 0) {
|
||||
// blank
|
||||
}
|
||||
else if (signPos != std::string::npos) {
|
||||
std::string name = Utility::trim(line.substr(0, signPos));
|
||||
std::string value = Utility::trim(line.substr(signPos+1));
|
||||
std::string::size_type iSz;
|
||||
std::string::size_type fSz;
|
||||
int valueI = std::stoi(value, &iSz);
|
||||
float valueF = std::stof(value, &fSz);
|
||||
// ^ radix (3rd param) default is 10 (base-10 number system)
|
||||
cerr << name << std::endl;
|
||||
cerr << " valueI length: " << iSz << std::endl;
|
||||
cerr << " valueF length: " << fSz << std::endl;
|
||||
if (fSz > iSz) {
|
||||
typeStr = "float";
|
||||
}
|
||||
else if (iSz == value.length()) {
|
||||
typeStr = "int";
|
||||
}
|
||||
else if (iSz > 0) {
|
||||
cerr << this->pre << "WARNING: The file has a "
|
||||
<< typeStr << " for " << name << ", but "
|
||||
<< this->types[name] << " was expected."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
this->types[name] = typeStr;
|
||||
this->table[name] = value;
|
||||
if (this->types.find(name) != this->types.end()) {
|
||||
if (this->types[name] != typeStr) {
|
||||
cerr << this->pre << "WARNING: The file has a "
|
||||
<< typeStr << " for " << name << ", but "
|
||||
<< this->types[name] << " was expected."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (this->section.length() > 0) {
|
||||
this->sections[name] = this->section;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (
|
||||
(line.length() >= 3)
|
||||
&& Utility::startsWith(line, "[")
|
||||
&& Utility::endsWith(line, "]")
|
||||
) {
|
||||
std::string section = Utility::trim(line.substr(1, line.length()-2));
|
||||
if (section.length() > 0) {
|
||||
this->section = section;
|
||||
}
|
||||
else {
|
||||
cerr << this->pre << "WARNING: The file has a blank section \""
|
||||
<< line << "\" (expected section name)."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cerr << this->pre << "WARNING: \""
|
||||
<< line << "\" is not understood (expected comment with '"
|
||||
<< cm <<"' (settable via this->setCM(commentMark)),"
|
||||
<< " section enclosed in '[' and ']' or assignment containing '"
|
||||
<< ao << "' [settable via this->setAO(assignmentOperator)])."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
newfile.close();
|
||||
}
|
||||
this->section = "";
|
||||
this->pre = "";
|
||||
}
|
||||
|
||||
bool Settings::save(std::string path)
|
||||
{
|
||||
this->path = path;
|
||||
ofstream myfile;
|
||||
myfile.open(path, ios::out); // default is ios_base::out
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
std::vector<std::string> sectionNames;
|
||||
sectionNames.push_back(" ");
|
||||
for (it = this->sections.begin(); it != this->sections.end(); it++) {
|
||||
if (std::find(sectionNames.begin(), sectionNames.end(), it->second) == sectionNames.end())
|
||||
sectionNames.push_back(it->second);
|
||||
}
|
||||
// Save each section consecutively, starting with variables that have no section.
|
||||
for (std::vector<std::string>::iterator vIt = sectionNames.begin() ; vIt != sectionNames.end(); ++vIt) {
|
||||
if (*vIt != " ") {
|
||||
myfile << "[" << *vIt << "]" << std::endl;
|
||||
}
|
||||
for (it = table.begin(); it != table.end(); it++) {
|
||||
if (this->sections.find(it->first) != this->sections.end()) {
|
||||
if (*vIt == this->sections[it->first]) {
|
||||
myfile << it->first << this->ao_and_spacing << it->second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (*vIt == " ") {
|
||||
// ^ " " is the global section
|
||||
// (The variable is not in a section).
|
||||
myfile << it->first << this->ao_and_spacing << it->second << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
myfile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Settings::save()
|
||||
{
|
||||
if (this->path.length() == 0) {
|
||||
throw std::string("There is no path during save().");
|
||||
}
|
||||
this->save(this->path);
|
||||
}
|
||||
|
||||
string Settings::ao_trimmed()
|
||||
{
|
||||
Utility::trim(this->ao_and_spacing);
|
||||
}
|
||||
|
||||
string Settings::cm_trimmed()
|
||||
{
|
||||
Utility::trim(this->cm_and_spacing);
|
||||
}
|
||||
|
||||
bool Settings::check_type(std::string typeStr, std::string name)
|
||||
{
|
||||
std::string currentTypeStr = get_type_str(name);
|
||||
if ((currentTypeStr != "") && (typeStr != currentTypeStr)) {
|
||||
cerr << this->pre << "WARNING: settings.set got a(n) "
|
||||
<< typeStr << " (value \"" << this->table[name] << "\") for "
|
||||
<< name << ", but expected a(n) "
|
||||
<< currentTypeStr << "."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string Settings::get_type_str(string name)
|
||||
{
|
||||
std::string currentTypeStr = "";
|
||||
if (this->types.find(name) != this->types.end()) {
|
||||
currentTypeStr = this->types[name];
|
||||
}
|
||||
return currentTypeStr;
|
||||
}
|
||||
|
||||
bool Settings::exists(string name)
|
||||
{
|
||||
return (this->table.find(name) != this->table.end());
|
||||
}
|
||||
|
||||
void Settings::set_ao_and_spacing(std::string assignmentOperator)
|
||||
{
|
||||
this->ao_and_spacing = assignmentOperator;
|
||||
}
|
||||
|
||||
void Settings::set_cm_and_spacing(std::string commentMark)
|
||||
{
|
||||
this->cm_and_spacing = commentMark;
|
||||
}
|
||||
|
||||
bool Settings::set_all_auto(std::map<std::string, std::string> table)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
for (it = table.begin(); it != table.end(); it++) {
|
||||
this->set_auto(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::set_section(std::string sectionName)
|
||||
{
|
||||
this->section = sectionName;
|
||||
}
|
||||
|
||||
void Settings::set_raw(std::string name, std::string value) {
|
||||
std::string section = this->section;
|
||||
// In any case below, never change the section of a variable
|
||||
// that was already declared.
|
||||
if (this->sections.find(name) != this->sections.end()) {
|
||||
// Get use its section since it exists.
|
||||
section = this->sections[name];
|
||||
}
|
||||
else if (this->exists(name)) {
|
||||
section = "";
|
||||
}
|
||||
std::string previous = "";
|
||||
if (this->table.find(name) != this->table.end()) {
|
||||
previous = this->table[name];
|
||||
}
|
||||
this->table[name] = value;
|
||||
if (section.length() > 0) {
|
||||
this->sections[name] = section;
|
||||
}
|
||||
if (this->enable_autosave) {
|
||||
if (previous != value) {
|
||||
if (this->path.length() > 0) {
|
||||
this->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::set(std::string name, std::string value)
|
||||
{
|
||||
bool match = this->check_type("string", name);
|
||||
set_raw(name, value);
|
||||
if (this->types.find(name) == this->types.end()) {
|
||||
this->types[name] = "string";
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
bool Settings::set_int(std::string name, int value)
|
||||
{
|
||||
bool match = this->check_type("int", name);
|
||||
this->set_raw(name, std::to_string(value));
|
||||
if (this->types.find(name) == this->types.end()) {
|
||||
this->types[name] = "int";
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
bool Settings::set_float(std::string name, irr::f32 value)
|
||||
{
|
||||
bool match = this->check_type("float", name);
|
||||
this->set_raw(name, std::to_string(value));
|
||||
if (this->types.find(name) == this->types.end()) {
|
||||
this->types[name] = "float";
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
void Settings::set_auto(std::string name, std::string value)
|
||||
{
|
||||
std::string typeStr = "string";
|
||||
if (this->types.find(name) != this->types.end()) {
|
||||
std::string typeStr = this->types[name];
|
||||
}
|
||||
if (typeStr == "int") {
|
||||
std::string::size_type iSz;
|
||||
int valueI = std::stoi(value, &iSz);
|
||||
this->set_int(name, valueI);
|
||||
}
|
||||
else if (typeStr == "float") {
|
||||
std::string::size_type fSz;
|
||||
float valueF = std::stof(value, &fSz);
|
||||
this->set_float(name, valueF);
|
||||
}
|
||||
else {
|
||||
// Treat typeStr as string if blank
|
||||
// (implement more types above to avoid errors in
|
||||
// "set" which always assumes that string is the type).
|
||||
this->set(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
string Settings::get(string name, bool& found)
|
||||
{
|
||||
bool match = this->check_type("string", name);
|
||||
if (this->table.find(name) == this->table.end()) {
|
||||
found = false;
|
||||
return "";
|
||||
}
|
||||
found = true;
|
||||
return this->table[name];
|
||||
}
|
||||
|
||||
float Settings::get_float(string name, bool &found)
|
||||
{
|
||||
bool match = this->check_type("float", name);
|
||||
if (this->table.find(name) == this->table.end()) {
|
||||
found = false;
|
||||
return 0.0f;
|
||||
}
|
||||
found = true;
|
||||
size_t sz;
|
||||
std::string value = this->table[name];
|
||||
float v = std::stof(value, &sz);
|
||||
if (sz != name.length()) {
|
||||
cerr << this->pre << "WARNING: only \""
|
||||
<< value.substr(0, sz) << "\" part of \""
|
||||
<< value << "\" for the variable named \""
|
||||
<< name << "\" is a number."
|
||||
<< endl;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
int Settings::get_int(string name, bool &found)
|
||||
{
|
||||
bool match = this->check_type("int", name);
|
||||
if (this->table.find(name) == this->table.end()) {
|
||||
found = false;
|
||||
return 0;
|
||||
}
|
||||
found = true;
|
||||
size_t sz;
|
||||
std::string value = this->table[name];
|
||||
int v = std::stoi(value, &sz);
|
||||
if (sz != name.length()) {
|
||||
cerr << this->pre << "WARNING: only \""
|
||||
<< value.substr(0, sz) << "\" part of \""
|
||||
<< value << "\" for the variable named \""
|
||||
<< name << "\" is a number."
|
||||
<< endl;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////// TESTS /////////////////////////
|
||||
|
||||
TestSettings::TestSettings() {
|
||||
cerr << "TestSettings..." << std::flush;
|
||||
assert_type_warning_str_then_int();
|
||||
assert_set("what", "bluedragon");
|
||||
assert_set("what", "greendragon");
|
||||
assert_get("what", "greendragon");
|
||||
assert_section_set_on_create();
|
||||
cerr << "OK" << std::endl;
|
||||
}
|
||||
|
||||
void TestSettings::assert_equal(const std::string subject, const std::string expectedResult)
|
||||
{
|
||||
if (subject != expectedResult) {
|
||||
cerr << "The test expected \"" << expectedResult << "\" but got \"" << subject << "\"" << std::endl;
|
||||
}
|
||||
assert(subject == expectedResult);
|
||||
}
|
||||
|
||||
void TestSettings::assert_set(const std::string &name, const std::string &value)
|
||||
{
|
||||
settings.set(name, value);
|
||||
bool found = false;
|
||||
std::string result = settings.get(name, found);
|
||||
assert_equal(result, value);
|
||||
assert(found);
|
||||
}
|
||||
|
||||
void TestSettings::assert_get(const std::string &name, const std::string &expectedResult)
|
||||
{
|
||||
bool found = false;
|
||||
std::string result = settings.get(name, found);
|
||||
assert(found);
|
||||
assert_equal(result, expectedResult);
|
||||
}
|
||||
|
||||
void TestSettings::assert_type_warning_str_then_int()
|
||||
{
|
||||
settings.clear();
|
||||
settings.set("username", "Poikilos");
|
||||
bool match = settings.set_int("username", 1);
|
||||
assert(!match);
|
||||
cerr << "(The warning above is expected during the test: expected string, got int)" << endl;
|
||||
}
|
||||
|
||||
void TestSettings::assert_section_set_on_create()
|
||||
{
|
||||
std::string tmpPath = "test.conf";
|
||||
settings.clear();
|
||||
settings.set_int("a", 1);
|
||||
settings.set_section("more");
|
||||
settings.set_int("b", 2);
|
||||
settings.set_int("a", 3);
|
||||
settings.save(tmpPath);
|
||||
settings.clear();
|
||||
ifstream myfile(tmpPath);
|
||||
if (myfile.is_open())
|
||||
{
|
||||
std::string line;
|
||||
assert(getline(myfile,line));
|
||||
assert_equal(line, "a = 3");
|
||||
assert(getline(myfile,line));
|
||||
assert_equal(line, "[more]");
|
||||
assert(getline(myfile,line));
|
||||
assert_equal(line, "b = 2");
|
||||
myfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
static TestSettings testsettings; // Run tests (Creating the first instance runs the static constructor).
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <irrlicht/irrlicht.h>
|
||||
|
||||
class Settings
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
std::map<std::string, std::string> table;
|
||||
std::map<std::string, std::string> types;
|
||||
std::map<std::string, std::string> sections;
|
||||
std::string section;
|
||||
std::string ao_and_spacing; // assignment operator
|
||||
std::string cm_and_spacing; // comment mark
|
||||
std::string pre; // debug prefix such as "filename:lineNumber: " (must end with space for outputinspector)
|
||||
void init(std::string assignmentOperator, std::string commentMark);
|
||||
void init_default_symbols();
|
||||
|
||||
public:
|
||||
bool enable_autosave;
|
||||
|
||||
Settings();
|
||||
Settings(std::string confPath);
|
||||
void clear();
|
||||
void clear_types();
|
||||
bool load(std::string path);
|
||||
bool save(std::string path);
|
||||
bool save();
|
||||
std::string ao_trimmed();
|
||||
std::string cm_trimmed();
|
||||
bool check_type(std::string typeStr, std::string name);
|
||||
std::string get_type_str(std::string name);
|
||||
bool exists(std::string name);
|
||||
void set_ao_and_spacing(std::string assignmentOperator);
|
||||
void set_cm_and_spacing(std::string commentMark);
|
||||
bool set_all_auto(std::map<std::string, std::string> table);
|
||||
void set_section(std::string sectionName);
|
||||
void set_raw(std::string name, std::string value);
|
||||
bool set(std::string name, std::string value);
|
||||
bool set_float(std::string name, irr::f32 value);
|
||||
bool set_int(std::string name, int value);
|
||||
void set_auto(std::string name, std::string value);
|
||||
std::string get(std::string name, bool& found);
|
||||
float get_float(std::string name, bool& found);
|
||||
int get_int(std::string name, bool& found);
|
||||
};
|
||||
|
||||
class TestSettings {
|
||||
Settings settings;
|
||||
public:
|
||||
TestSettings();
|
||||
void assert_equal(const std::string subject, const std::string expectedResult);
|
||||
void assert_set(const std::string& name, const std::string& value);
|
||||
void assert_get(const std::string& name, const std::string& expectedResult);
|
||||
void assert_type_warning_str_then_int();
|
||||
void assert_section_set_on_create();
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
Loading…
Reference in New Issue