summaryrefslogtreecommitdiff
path: root/datatest.cpp
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2018-11-05 20:40:39 -0500
committerJeffrey Walton <noloader@gmail.com>2018-11-05 20:40:39 -0500
commit93c75189003b6f94e92bada07cfc86605d6c71dc (patch)
tree7410131e97ba23ca2b5ca2ff1eb89b2c3b23da7a /datatest.cpp
parent7c0be4ea8f75eab3862d4b564bd30ac2ff2beb78 (diff)
downloadcryptopp-git-93c75189003b6f94e92bada07cfc86605d6c71dc.tar.gz
Improve datatest parser
This switches to line oriented parsing for the test files. Previously we we using streams for names, and lines for values. We can now use whitespace and make the tests a bit more readable by grouping similar tests. AlgorithmType will clear the current accumlated values.
Diffstat (limited to 'datatest.cpp')
-rw-r--r--datatest.cpp139
1 files changed, 80 insertions, 59 deletions
diff --git a/datatest.cpp b/datatest.cpp
index 2caa35fd..5169cab0 100644
--- a/datatest.cpp
+++ b/datatest.cpp
@@ -51,6 +51,34 @@ public:
static const TestData *s_currentTestData = NULLPTR;
+std::string TrimComment(std::string str)
+{
+ if (str.empty()) return "";
+
+ std::string::size_type first = str.find("#");
+
+ if (first != std::string::npos)
+ return str.substr(0, first);
+ else
+ return str;
+}
+
+std::string TrimSpace(std::string str)
+{
+ if (str.empty()) return "";
+
+ const std::string whitespace(" \r\t\n");
+ std::string::size_type beg = str.find_first_not_of(whitespace);
+ std::string::size_type end = str.find_last_not_of(whitespace);
+
+ if (beg != std::string::npos && end != std::string::npos)
+ return str.substr(beg, end+1);
+ else if (beg != std::string::npos)
+ return str.substr(beg);
+ else
+ return "";
+}
+
static void OutputTestData(const TestData &v)
{
for (TestData::const_iterator i = v.begin(); i != v.end(); ++i)
@@ -771,78 +799,74 @@ inline char LastChar(const std::string& str) {
// For istream.fail() see https://stackoverflow.com/q/34395801/608639.
bool GetField(std::istream &is, std::string &name, std::string &value)
{
- // ***** Name *****
- name: name.clear();
- if ((is >> name).fail() == true)
- return false;
-
- // Eat whitespace and comments gracefully
- if (name.empty() || name[0] =='#')
- goto name;
+ std::string line;
+ name.clear(); value.clear();
- if (LastChar(name) != ':')
+ // ***** Name *****
+ while (is >> std::ws && std::getline(is, line))
{
- char c;
- if ((is >> std::skipws >> c).fail() == true || c != ':')
+ // Eat whitespace and comments gracefully
+ if (line.empty() || line[0] == '#')
+ continue;
+
+ std::string::size_type pos = line.find(':');
+ if (pos == std::string::npos)
SignalTestError();
- }
- else
- name.erase(name.size()-1);
- while (is.peek() == ' ')
- is.ignore(1);
+ name = TrimSpace(line.substr(0, pos));
+ line = TrimSpace(line.substr(pos + 1));
+
+ // Empty name is bad
+ if (name.empty())
+ return false;
+
+ // Empty value is ok
+ if (line.empty())
+ return true;
+
+ break;
+ }
// ***** Value *****
- value.clear();
- std::string line;
bool continueLine = true;
- while (continueLine && std::getline(is, line))
+ do
{
- // Unix and Linux may have a stray \r because of Windows
- if (!line.empty() && (LastChar(line) == '\r' || LastChar(line) == '\n')) {
- line.erase(line.size()-1);
- }
+ // Trim leading and trailing whitespace, including OS X and Windows
+ // new lines. Don't parse comments here because there may be a line
+ // continuation at the end.
+ line = TrimSpace(line);
continueLine = false;
- if (!line.empty())
- {
- // Early out for immediate line continuation
- if (line[0] == '\\') {
- continueLine = true;
- continue;
- }
- // Check end of line. It must be last character
- if (LastChar(line) == '\\') {
- continueLine = true;
- }
- // Check for comment. It can be first character
- if (line[0] == '#') {
- continue;
- }
+ if (line.empty())
+ continue;
+
+ // Early out for immediate line continuation
+ if (line[0] == '\\') {
+ continueLine = true;
+ continue;
+ }
+ // Check end of line. It must be last character
+ if (LastChar(line) == '\\') {
+ continueLine = true;
+ line.erase(line.end()-1);
+ line = TrimSpace(line);
}
- // Leading and trailing position. The leading position moves right, and
- // trailing position moves left. The sub-string in the middle is the value
- // for the name. We leave one space when line continuation is in effect.
- // The value can be an empty string. One Plaintext value is often empty
- // for algorithm testing.
- std::string::size_type l=0, t=std::string::npos;
- const std::string whitespace = "\t \r\n";
+ // Re-trim after parsing
+ line = TrimComment(line);
+ line = TrimSpace(line);
- l = line.find_first_not_of(whitespace, l);
- if (l == std::string::npos) { l = 0; }
- t = line.find('#', l);
- if (t != std::string::npos) { t--; }
- t = line.find_last_not_of(whitespace+"\\", t);
- if (t != std::string::npos) { t++; }
+ if (line.empty())
+ continue;
- CRYPTOPP_ASSERT(t >= l);
- value += line.substr(l, t - l);
+ // Finally... the value
+ value += line;
if (continueLine)
value += ' ';
}
+ while (continueLine && is >> std::ws && std::getline(is, line));
return true;
}
@@ -897,15 +921,12 @@ void TestDataFile(std::string filename, const NameValuePairs &overrideParameters
while (file)
{
- while (file.peek() == '#')
- file.ignore((std::numeric_limits<std::streamsize>::max)(), '\n');
-
- if (file.peek() == '\n' || file.peek() == '\r')
- v.clear();
-
if (!GetField(file, name, value))
break;
+ if (name == "AlgorithmType")
+ v.clear();
+
// Can't assert value. Plaintext is sometimes empty.
// CRYPTOPP_ASSERT(!value.empty());
v[name] = value;