Rework the tagfile library
After further experimentation, the previous template-heavy design turned out to cause issues with compilation. Thus, it has now been replaced with a simpler, dumber implementation that pushes more of the logic into the caller.
This commit is contained in:
234
test/tagfile.cpp
234
test/tagfile.cpp
@@ -7,60 +7,10 @@
|
||||
|
||||
#include "fileio/tagfile.hpp"
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& os, const tBasicTag<T>& tag) {
|
||||
return os << T(tag);
|
||||
}
|
||||
|
||||
class pSamplePage1 : public cTagFile_Page {
|
||||
public:
|
||||
DEFINE_TAGFILE_PAGE(pSamplePage1, cTagFile_Page);
|
||||
tBasicTag<int> a{*this, "A"}, b{*this, "B"}, c{*this, "C"};
|
||||
};
|
||||
|
||||
class pSamplePage2 : public cTagFile_Page {
|
||||
public:
|
||||
DEFINE_TAGFILE_PAGE(pSamplePage2, cTagFile_Page);
|
||||
tBasicTag<std::string> x{*this, "X"}, y{*this, "Y"}, z{*this, "Z"};
|
||||
};
|
||||
|
||||
class fSampleTagFile : public cTagFile {
|
||||
public:
|
||||
pSamplePage1 p1{*this};
|
||||
pSamplePage2 p2{*this};
|
||||
};
|
||||
|
||||
class pComplexPage : public cTagFile_Page {
|
||||
public:
|
||||
DEFINE_TAGFILE_PAGE(pComplexPage, cTagFile_Page);
|
||||
tBasicTag<int> id{*this, "ID"};
|
||||
tArrayTag<std::string> strings{*this, "STRING"};
|
||||
tArrayTag<std::pair<int, int>> locations{*this, "LOC"};
|
||||
tOptionalTag<int> filter{*this, "FILTER"};
|
||||
tOptionalTag<int> count{*this, "COUNT"};
|
||||
tOptionalTag<bool> yes{*this, "YES"};
|
||||
tOptionalTag<bool> no{*this, "NO"};
|
||||
tBasicTag<bool> enable{*this, "ENABLE"};
|
||||
};
|
||||
|
||||
class pSampleMultiPage : public pMultiPage<pSampleMultiPage> {
|
||||
public:
|
||||
DEFINE_TAGFILE_MULTIPAGE(pSampleMultiPage, pMultiPage);
|
||||
tBasicTag<char> id{*this, "ID"};
|
||||
tBasicTag<int> value{*this, "VALUE"};
|
||||
tBasicTag<std::string> comment{*this, "COMMENT"};
|
||||
};
|
||||
|
||||
class fComplexTagFile : public cTagFile {
|
||||
public:
|
||||
pSamplePage1 p1{*this};
|
||||
pComplexPage p2{*this};
|
||||
pSampleMultiPage p3{*this};
|
||||
};
|
||||
|
||||
TEST_CASE("Simple tag file") {
|
||||
static const std::string file_contents =
|
||||
"A 12\n"
|
||||
@@ -71,36 +21,40 @@ TEST_CASE("Simple tag file") {
|
||||
"Y foo\n"
|
||||
"Z Blah!\n"
|
||||
;
|
||||
fSampleTagFile content;
|
||||
cTagFile content;
|
||||
SECTION("output") {
|
||||
std::ostringstream file;
|
||||
content.p1.a = 12;
|
||||
content.p1.b = 22;
|
||||
content.p1.c = 45;
|
||||
content.p2.x = "Hello World";
|
||||
content.p2.y = "foo";
|
||||
content.p2.z = "Blah!";
|
||||
auto& p1 = content.add();
|
||||
p1["A"] << 12;
|
||||
p1["B"] << 22;
|
||||
p1["C"] << 45;
|
||||
auto& p2 = content.add();
|
||||
p2["X"] << "Hello World";
|
||||
p2["Y"] << "foo";
|
||||
p2["Z"] << "Blah!";
|
||||
content.writeTo(file);
|
||||
CHECK(file.str() == file_contents);
|
||||
}
|
||||
SECTION("input") {
|
||||
std::istringstream file(file_contents);
|
||||
content.readFrom(file);
|
||||
CHECK(content.p1.a == 12);
|
||||
CHECK(content.p1.b == 22);
|
||||
CHECK(content.p1.c == 45);
|
||||
CHECK(content.p2.x == std::string("Hello World"));
|
||||
CHECK(content.p2.y == std::string("foo"));
|
||||
CHECK(content.p2.z == std::string("Blah!"));
|
||||
CHECK(content[0]["A"][0] == 12);
|
||||
CHECK(content[0]["B"][0] == 22);
|
||||
CHECK(content[0]["C"][0] == 45);
|
||||
CHECK(content[1]["X"][0] == std::string("Hello World"));
|
||||
CHECK(content[1]["Y"][0] == std::string("foo"));
|
||||
CHECK(content[1]["Z"][0] == std::string("Blah!"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Complex tag file") {
|
||||
static const std::string file_contents =
|
||||
// Page 1, a simple page with 3 single tags
|
||||
"A 12\n"
|
||||
"B 22\n"
|
||||
"C 45\n"
|
||||
"\f"
|
||||
// Page 2, a complex page with some array-like values
|
||||
"ID 123\n"
|
||||
"STRING foo\n"
|
||||
"STRING bar\n"
|
||||
@@ -110,6 +64,7 @@ TEST_CASE("Complex tag file") {
|
||||
"COUNT 12\n"
|
||||
"YES\n"
|
||||
"ENABLE false\n"
|
||||
// Page 3 and onward, a series of identical pages
|
||||
"\f"
|
||||
"ID 12\n"
|
||||
"VALUE 400\n"
|
||||
@@ -123,66 +78,111 @@ TEST_CASE("Complex tag file") {
|
||||
"VALUE 90\n"
|
||||
"COMMENT \"It's great!\"\n"
|
||||
;
|
||||
fComplexTagFile content;
|
||||
cTagFile content;
|
||||
SECTION("output") {
|
||||
std::ostringstream file;
|
||||
content.p1.a = 12;
|
||||
content.p1.b = 22;
|
||||
content.p1.c = 45;
|
||||
content.p2.id = 123;
|
||||
content.p2.strings.add("foo");
|
||||
content.p2.strings.add("bar");
|
||||
content.p2.locations.add({1,5});
|
||||
content.p2.locations.add({12,22});
|
||||
content.p2.locations.add({143,9});
|
||||
content.p2.count = 12;
|
||||
content.p2.yes = true;
|
||||
content.p2.no = false;
|
||||
content.p2.enable = false;
|
||||
content.p3[0].id = 0x0c;
|
||||
content.p3[0].value = 400;
|
||||
content.p3[0].comment = "This is a comment!!!";
|
||||
content.p3[1].id = 0x0d;
|
||||
content.p3[1].value = 128;
|
||||
content.p3[1].comment = "Nope nope nope";
|
||||
auto& p3c = content.p3.add();
|
||||
p3c.id = 0x12;
|
||||
p3c.value = 90;
|
||||
p3c.comment = "It's great!";
|
||||
auto& p1 = content.add();
|
||||
p1["A"] << 12;
|
||||
p1["B"] << 22;
|
||||
p1["C"] << 45;
|
||||
auto& p2 = content.add();
|
||||
p2["ID"] << 123;
|
||||
p2["STRING"] << "foo";
|
||||
p2["STRING"] << "bar";
|
||||
p2["LOC"] << 1 << 5;
|
||||
p2["LOC"] << std::array<int,2>{{12,22}};
|
||||
p2["LOC"] << std::pair<int,int>{143,9};
|
||||
p2["COUNT"] << 12;
|
||||
p2.add("YES");
|
||||
p2["ENABLE"] << false;
|
||||
auto& p4a = content.add();
|
||||
p4a["ID"] << '\x0c';
|
||||
p4a["VALUE"] << 400;
|
||||
p4a["COMMENT"] << "This is a comment!!!";
|
||||
auto& p4b = content.add();
|
||||
p4b["ID"] << '\x0d';
|
||||
p4b["VALUE"] << 128;
|
||||
p4b["COMMENT"] << "Nope nope nope";
|
||||
auto& p4c = content.add();
|
||||
p4c["ID"] << '\x12';
|
||||
p4c["VALUE"] << 90;
|
||||
p4c["COMMENT"] << "It's great!";
|
||||
content.writeTo(file);
|
||||
CHECK(file.str() == file_contents);
|
||||
}
|
||||
SECTION("input") {
|
||||
std::istringstream file(file_contents);
|
||||
content.readFrom(file);
|
||||
CHECK(content.p1.a == 12);
|
||||
CHECK(content.p1.b == 22);
|
||||
CHECK(content.p1.c == 45);
|
||||
CHECK(content.p2.id == 123);
|
||||
REQUIRE(content.p2.strings.size() == 2);
|
||||
CHECK(content.p2.strings[0] == "foo");
|
||||
CHECK(content.p2.strings[1] == "bar");
|
||||
REQUIRE(content.p2.locations.size() == 3);
|
||||
CHECK(content.p2.locations[0].first == 1);
|
||||
CHECK(content.p2.locations[0].second == 5);
|
||||
CHECK(content.p2.locations[1].first == 12);
|
||||
CHECK(content.p2.locations[1].second == 22);
|
||||
CHECK(content.p2.locations[2].first == 143);
|
||||
CHECK(content.p2.locations[2].second == 9);
|
||||
CHECK(content.p2.filter == boost::none);
|
||||
CHECK(content.p2.count == 12);
|
||||
CHECK(content.p2.yes == true);
|
||||
CHECK(content.p2.no == false);
|
||||
CHECK(content.p2.enable == false);
|
||||
REQUIRE(content.p3.size() == 3);
|
||||
CHECK(content.p3[0].id == '\x0c');
|
||||
CHECK(content.p3[0].value == 400);
|
||||
CHECK(content.p3[0].comment == "This is a comment!!!");
|
||||
CHECK(content.p3[1].id == '\x0d');
|
||||
CHECK(content.p3[1].value == 128);
|
||||
CHECK(content.p3[1].comment == "Nope nope nope");
|
||||
CHECK(content.p3[2].id == '\x12');
|
||||
CHECK(content.p3[2].value == 90);
|
||||
CHECK(content.p3[2].comment == "It's great!");
|
||||
bool p1 = false, p2 = false;
|
||||
size_t p3 = 0;
|
||||
for(const auto& page : content) {
|
||||
if(!p1) {
|
||||
p1 = true;
|
||||
int a = 0, b = 0, c = 0;
|
||||
page["A"] >> a;
|
||||
page["B"] >> b;
|
||||
page["C"] >> c;
|
||||
CHECK(a == 12);
|
||||
CHECK(b == 22);
|
||||
CHECK(c == 45);
|
||||
} else if(!p2) {
|
||||
p2 = true;
|
||||
int id = 0, count = 0;
|
||||
page["ID"] >> id;
|
||||
page["COUNT"] >> count;
|
||||
CHECK(id == 123);
|
||||
CHECK(count == 12);
|
||||
std::vector<std::string> strings;
|
||||
page["STRING"].extract(strings);
|
||||
REQUIRE(strings.size() == 2);
|
||||
CHECK(strings[0] == "foo");
|
||||
CHECK(strings[1] == "bar");
|
||||
std::vector<std::pair<int,int>> locations;
|
||||
page["LOC"].extract(locations);
|
||||
REQUIRE(locations.size() == 3);
|
||||
CHECK(locations[0].first == 1);
|
||||
CHECK(locations[0].second == 5);
|
||||
CHECK(locations[1].first == 12);
|
||||
CHECK(locations[1].second == 22);
|
||||
CHECK(locations[2].first == 143);
|
||||
CHECK(locations[2].second == 9);
|
||||
bool yes = page.contains("YES"), no = page.contains("NO"), enable = true;
|
||||
page["ENABLE"] >> enable;
|
||||
CHECK(yes == true);
|
||||
CHECK(no == false);
|
||||
CHECK(enable == false);
|
||||
} else {
|
||||
p3++;
|
||||
char id;
|
||||
int value;
|
||||
std::string comment;
|
||||
page["ID"] >> id;
|
||||
page["VALUE"] >> value;
|
||||
page["COMMENT"] >> comment;
|
||||
switch(p3) {
|
||||
case 1:
|
||||
CHECK(id == '\x0c');
|
||||
CHECK(value == 400);
|
||||
CHECK(comment == "This is a comment!!!");
|
||||
break;
|
||||
case 2:
|
||||
CHECK(id == '\x0d');
|
||||
CHECK(value == 128);
|
||||
CHECK(comment == "Nope nope nope");
|
||||
break;
|
||||
case 3:
|
||||
CHECK(id == '\x12');
|
||||
CHECK(value == 90);
|
||||
CHECK(comment == "It's great!");
|
||||
break;
|
||||
default:
|
||||
FAIL("Too many extra pages!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(p1);
|
||||
CHECK(p2);
|
||||
CHECK(p3);
|
||||
CHECK(p3 == 3);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user