Utility: TextAccess

Abstraction for file or text access.

review id = 16

fortune cookie message = Good news from someone dear is coming soon.
This commit is contained in:
Manuel Dobusch
2014-05-19 12:45:44 +02:00
parent b29209a79e
commit bb6640369a
10 changed files with 440 additions and 29 deletions
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<path>
<to>
<single_value>42</single_value>
<bool_that_is_true>1</bool_that_is_true>
<bool_that_is_false>0</bool_that_is_false>
</to>
</path>
</config>
+7
View File
@@ -0,0 +1,7 @@
"If you're a researcher on this book thing and you were on Earth, you must have been gathering material on it."
"Well, I was able to extend the original entry a bit, yes."
"Let me see what it says in this edition, then. I've got to see it."
... "What? Harmless! Is that all it's got to say? Harmless! One word! ... Well, for God's sake I hope you managed to recitify that a bit."
"Oh yes, well I managed to transmit a new entry off to the editor. He had to trim it a bit, but it's still an improvement."
"And what does it say now?" asked Arthur.
"Mostly harmless," admitted Ford with a slightly embarrassed cough.
+4 -1
View File
@@ -111,7 +111,10 @@ add_files(
utility/messaging/MessageListenerBase.h
utility/messaging/MessageQueue.cpp
utility/messaging/MessageQueue.h
utility/text/TextAccess.cpp
utility/text/TextAccess.h
utility/ConfigManager.cpp
utility/ConfigManager.h
utility/FileSystem.cpp
+10 -7
View File
@@ -1,8 +1,10 @@
#include "utility/ConfigManager.h"
std::shared_ptr<ConfigManager> ConfigManager::createAndLoad(const std::string& filePath)
#include "utility/text/TextAccess.h"
std::shared_ptr<ConfigManager> ConfigManager::createAndLoad(const std::shared_ptr<TextAccess> textAccess)
{
std::shared_ptr<ConfigManager> configManager = std::shared_ptr<ConfigManager>(new ConfigManager(filePath));
std::shared_ptr<ConfigManager> configManager = std::shared_ptr<ConfigManager>(new ConfigManager(textAccess));
configManager->load();
return configManager;
}
@@ -88,10 +90,11 @@ void ConfigManager::setValue(const std::string& key, const bool value)
void ConfigManager::load()
{
// LOG ("Loading config from file: " + m_filePath)
std::string text = m_textAccess->getText();
TiXmlDocument doc(m_filePath.c_str());
if (doc.LoadFile())
TiXmlDocument doc;
const char* pTest = doc.Parse(text.c_str(), 0, TIXML_ENCODING_UTF8);
if (pTest != NULL)
{
TiXmlHandle docHandle(&doc);
TiXmlNode *rootNode = docHandle.FirstChild("config").ToNode();
@@ -111,8 +114,8 @@ void ConfigManager::save()
// LOG ("Saving config to file: " + m_filePath)
}
ConfigManager::ConfigManager(const std::string& filePath)
: m_filePath(filePath)
ConfigManager::ConfigManager(const std::shared_ptr<TextAccess> textAccess)
: m_textAccess(textAccess)
{
}
+4 -3
View File
@@ -8,11 +8,12 @@
#include "tinyxml/tinyxml.h"
class TextAccess;
class ConfigManager
{
public:
static std::shared_ptr<ConfigManager> createAndLoad(const std::string& filePath);
static std::shared_ptr<ConfigManager> createAndLoad(const std::shared_ptr<TextAccess> textAccess);
bool getValue(const std::string& key, std::string& value) const;
bool getValue(const std::string& key, int& value) const;
@@ -28,13 +29,13 @@ public:
void save();
private:
ConfigManager(const std::string& filePath);
ConfigManager(const std::shared_ptr<TextAccess> textAccess);
ConfigManager(const ConfigManager&);
ConfigManager operator=(const ConfigManager&);
void parseSubtree(TiXmlNode* parentElement, const std::string& currentPath);
const std::string m_filePath;
const std::shared_ptr<TextAccess> m_textAccess;
std::map<std::string, std::string> m_values;
};
+193
View File
@@ -0,0 +1,193 @@
#include "TextAccess.h"
#include <fstream>
#include <sstream>
#include "utility/logging/logging.h"
std::shared_ptr<TextAccess> TextAccess::createFromFile(const std::string& filePath)
{
std::shared_ptr<TextAccess> result(new TextAccess());
result->m_filePath = filePath;
result->m_lines = readFile(filePath);
return result;
}
std::shared_ptr<TextAccess> TextAccess::createFromString(const std::string& text)
{
std::shared_ptr<TextAccess> result(new TextAccess());
result->m_lines = splitStringByLines(text);
return result;
}
TextAccess::~TextAccess()
{
}
unsigned int TextAccess::getLineCount() const
{
return m_lines.size();
}
std::string TextAccess::getFilePath() const
{
return m_filePath;
}
std::string TextAccess::getLine(const unsigned int lineNumber) const
{
if(lineNumber < 1)
{
std::stringstream message;
message << "Line numbers start with one, is " << lineNumber;
LOG_WARNING(message.str());
return "";
}
if (checkIndexInRange(lineNumber-1) == false)
{
return "";
}
return m_lines[lineNumber-1]; // -1 to correct for use as index
}
std::vector<std::string> TextAccess::getLines(const unsigned int firstLineNumber, const unsigned int lastLineNumber)
{
if(firstLineNumber < 1)
{
std::stringstream message;
message << "Line numbers start with one, is " << firstLineNumber;
LOG_WARNING(message.str());
return std::vector<std::string>();
}
if(lastLineNumber < 1)
{
std::stringstream message;
message << "Line numbers start with one, is " << lastLineNumber;
LOG_WARNING(message.str());
return std::vector<std::string>();
}
if (checkIndexIntervalInRange(firstLineNumber-1, lastLineNumber-1) == false)
{
return std::vector<std::string>();
}
std::vector<std::string>::iterator first = m_lines.begin() + firstLineNumber-1; // -1 to correct for use as index
std::vector<std::string>::iterator last = m_lines.begin() + lastLineNumber; // no correction needed because 'last' needs to point one behind the last included element
return std::vector<std::string>(first, last);
}
std::vector<std::string> TextAccess::getAllLines() const
{
return m_lines;
}
std::string TextAccess::getText() const
{
std::string result = "";
for(unsigned int i = 0; i < m_lines.size(); i++)
{
result += m_lines[i];
}
return result;
}
std::vector<std::string> TextAccess::readFile(const std::string& filePath)
{
std::vector<std::string> result;
std::ifstream srcFile;
srcFile.open(filePath);
while (!srcFile.eof())
{
std::string line;
std::getline(srcFile, line);
result.push_back(line + "\n");
}
srcFile.close();
return result;
}
std::vector<std::string> TextAccess::splitStringByLines(const std::string& text)
{
std::vector<std::string> result;
int prevIndex = 0;
int index = text.find("\n");
while (index != std::string::npos)
{
result.push_back(text.substr(prevIndex, index - prevIndex) + "\n");
prevIndex = index+1;
index = text.find("\n", prevIndex);
}
if (prevIndex < text.length()-1)
{
result.push_back(text.substr(prevIndex));
}
return result;
}
TextAccess::TextAccess()
: m_filePath("")
{
}
bool TextAccess::checkIndexInRange(const unsigned int index) const
{
if (index >= m_lines.size())
{
std::stringstream message;
message << "Tried to access index " << index;
message << ". Maximum index is " << m_lines.size() - 1;
LOG_WARNING(message.str());
return false;
}
return true;
}
bool TextAccess::checkIndexIntervalInRange(
const unsigned int firstIndex,
const unsigned int lastIndex
) const
{
if (checkIndexInRange(firstIndex) == false)
{
return false;
}
if (checkIndexInRange(lastIndex) == false)
{
return false;
}
if (firstIndex > lastIndex)
{
std::stringstream message;
message << "Index 'firstLine' has to be lower or equal index 'lastLine'";
message << ", is " << firstIndex << " > " << lastIndex;
LOG_WARNING(message.str());
return false;
}
return true;
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef TEXT_ACCESS_H
#define TEXT_ACCESS_H
#include <memory>
#include <string>
#include <vector>
class TextAccess
{
public:
static std::shared_ptr<TextAccess> createFromFile(const std::string& filePath);
static std::shared_ptr<TextAccess> createFromString(const std::string& text);
virtual ~TextAccess();
unsigned int getLineCount() const;
std::string getFilePath() const;
/**
* @param lineNumber: starts with 1
*/
std::string getLine(const unsigned int lineNumber) const;
/**
* @param firstLineNumber: starts with 1
* @param lastLineNumber: starts with 1
*/
std::vector<std::string> getLines(const unsigned int firstLineNumber, const unsigned int lastLineNumber);
std::vector<std::string> getAllLines() const;
std::string getText() const;
private:
static std::vector<std::string> readFile(const std::string& filePath);
static std::vector<std::string> splitStringByLines(const std::string& text);
TextAccess();
TextAccess(const TextAccess&);
TextAccess operator=(const TextAccess&);
bool checkIndexInRange(const unsigned int index) const;
bool checkIndexIntervalInRange(const unsigned int firstIndex, const unsigned int lastIndex) const;
std::string m_filePath;
std::vector<std::string> m_lines;
};
#endif // TEXT_ACCESS_H
+1
View File
@@ -8,5 +8,6 @@ add_files(
MessageQueueTestSuite.h
TestSuiteFixture.cpp
TestSuiteFixture.h
TextAccessTestSuite.h
Vector2TestSuite.h
)
+25 -7
View File
@@ -1,14 +1,14 @@
#include "cxxtest/TestSuite.h"
#include "utility/ConfigManager.h"
#include "utility/text/TextAccess.h"
class ConfigManagerTestSuite: public CxxTest::TestSuite
{
public:
void test_config_manager_returns_true_when_key_is_found()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
float value;
bool success = config->getValue("path/to/single_value", value);
@@ -19,7 +19,7 @@ public:
void test_config_manager_returns_false_when_key_is_not_found()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
float value;
bool success = config->getValue("path/to/nowhere", value);
@@ -30,7 +30,7 @@ public:
void test_config_manager_returns_correct_string_for_key()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
std::string value;
config->getValue("path/to/single_value", value);
@@ -41,7 +41,7 @@ public:
void test_config_manager_returns_correct_float_for_key()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
float value;
config->getValue("path/to/single_value", value);
@@ -51,7 +51,7 @@ public:
void test_config_manager_returns_correct_bool_for_key_if_value_is_true()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
float value;
bool success(config->getValue("path/to/bool_that_is_true", value));
@@ -62,7 +62,7 @@ public:
void test_config_manager_returns_correct_bool_for_key_if_value_is_false()
{
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad("data/test_config.xml");
std::shared_ptr<ConfigManager> config = ConfigManager::createAndLoad(getConfigTextAccess());
float value;
bool success(config->getValue("path/to/bool_that_is_false", value));
@@ -70,4 +70,22 @@ public:
TS_ASSERT(success);
TS_ASSERT(!value);
}
private:
std::shared_ptr<TextAccess> getConfigTextAccess()
{
std::string text =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<config>\n"
"<path>\n"
"<to>\n"
"<single_value>42</single_value>\n"
"<bool_that_is_true>1</bool_that_is_true>\n"
"<bool_that_is_false>0</bool_that_is_false>\n"
"</to>\n"
"</path>\n"
"</config>\n";
return TextAccess::createFromString(text);
}
};
+149
View File
@@ -0,0 +1,149 @@
#include "cxxtest/TestSuite.h"
#include <memory>
#include <string>
#include "utility/text/TextAccess.h"
class TextAccessTestSuite : public CxxTest::TestSuite
{
public:
void test_textAccessString_constructor()
{
std::string text = getTestText();
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
TS_ASSERT(textAccess.get() != NULL);
}
void test_textAccessString_lines_count()
{
std::string text = getTestText();
unsigned int lineCount = 8;
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
TS_ASSERT_EQUALS(textAccess->getLineCount(), lineCount);
}
void test_textAccessString_lines_content()
{
std::string text = getTestText();
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
std::vector<std::string> lines = textAccess->getLines(1, 4);
TS_ASSERT_EQUALS(lines.size(), 4);
TS_ASSERT_EQUALS(lines[0], "\"But the plans were on display . . .\"\n");
TS_ASSERT_EQUALS(lines[1], "\"On display? I eventually had to go down to the cellar to find them.\"\n");
TS_ASSERT_EQUALS(lines[2], "\"That's the display department.\"\n");
TS_ASSERT_EQUALS(lines[3], "\"With a torch.\"\n");
}
void test_textAccessString_lines_content_error_handling()
{
std::string text = getTestText();
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
std::vector<std::string> lines = textAccess->getLines(3, 2);
TS_ASSERT_EQUALS(lines.size(), 0);
lines = textAccess->getLines(10, 3);
TS_ASSERT_EQUALS(lines.size(), 0);
lines = textAccess->getLines(1, 10);
TS_ASSERT_EQUALS(lines.size(), 0);
std::string line = textAccess->getLine(0);
TS_ASSERT_EQUALS(line, "");
lines = textAccess->getLines(0, 2);
TS_ASSERT_EQUALS(line, "");
}
void test_textAccessString_single_line_content()
{
std::string text = getTestText();
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
std::string line = textAccess->getLine(6);
TS_ASSERT_EQUALS(line, "\"So had the stairs.\"\n");
}
void test_textAccessString_all_lines()
{
std::string text = getTestText();
unsigned int lineCount = 8;
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromString(text);
std::vector<std::string> lines = textAccess->getAllLines();
TS_ASSERT_EQUALS(lines.size(), lineCount);
}
void test_textAccessFile_constructor()
{
std::string filePath = "data/test_text.txt";
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromFile(filePath);
TS_ASSERT(textAccess.get() != NULL);
}
void test_textAccessFile_lines_count()
{
std::string filePath = "data/test_text.txt";
unsigned int lineCount = 7;
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromFile(filePath);
TS_ASSERT_EQUALS(textAccess->getLineCount(), lineCount);
}
void test_textAccessFile_lines_content()
{
std::string filePath = "data/test_text.txt";
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromFile(filePath);
std::vector<std::string> lines = textAccess->getLines(1, 4);
TS_ASSERT_EQUALS(lines.size(), 4);
TS_ASSERT_EQUALS(lines[0], "\"If you're a researcher on this book thing and you were on Earth, you must have been gathering material on it.\"\n");
TS_ASSERT_EQUALS(lines[1], "\"Well, I was able to extend the original entry a bit, yes.\"\n");
TS_ASSERT_EQUALS(lines[2], "\"Let me see what it says in this edition, then. I've got to see it.\"\n");
TS_ASSERT_EQUALS(lines[3], "... \"What? Harmless! Is that all it's got to say? Harmless! One word! ... Well, for God's sake I hope you managed to recitify that a bit.\"\n");
}
void test_textAccessFile_get_filePath()
{
std::string filePath = "data/test_text.txt";
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromFile(filePath);
TS_ASSERT_EQUALS(textAccess->getFilePath(), filePath);
}
private:
std::string getTestText()
{
std::string text =
"\"But the plans were on display . . .\"\n"
"\"On display? I eventually had to go down to the cellar to find them.\"\n"
"\"That's the display department.\"\n"
"\"With a torch.\"\n"
"\"Ah, well the lights had probably gone.\"\n"
"\"So had the stairs.\"\n"
"\"But look, you found the notice, didn't you?\"\n"
"\"Yes,\" said Arthur, \"yes I did. It was on display in the bottom of a locked"
" filing cabinet stuck in a disused lavatory with a sign on the door saying"
" Beware of the Leopard.\"\n";
return text;
}
};