WIP, added multiline restriction, fixed a few bugs for multiline, updated unit tests

This commit is contained in:
ado
2021-02-20 15:53:18 +01:00
parent 2985027505
commit 2dbc21780f
8 changed files with 288 additions and 98 deletions

View File

@@ -1,9 +1,9 @@
test_sources = files([
'test_main.cpp',
'test_splitter.cpp',
'test_converter.cpp',
#'test_splitter.cpp',
#'test_converter.cpp',
'test_parser.cpp',
'test_extractions.cpp',
#'test_extractions.cpp',
])
doctest_proj = subproject('doctest')

View File

@@ -8,10 +8,9 @@
#include <doctest.h>
#endif
class buffer {
struct buffer {
char* data_{nullptr};
public:
char* operator()(const char* data) {
if (data_) {
delete[] data_;

View File

@@ -66,7 +66,7 @@ TEST_CASE("parser test various cases") {
i.emplace_back(ss::to_object<X>(a));
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
}
{
@@ -80,7 +80,7 @@ TEST_CASE("parser test various cases") {
i.emplace_back(ss::to_object<X>(a));
}
CHECK(std::equal(i.begin(), i.end(), data.begin() + 1));
CHECK_EQ(i, data);
}
{
@@ -91,7 +91,7 @@ TEST_CASE("parser test various cases") {
i.push_back(p.get_object<X, int, double, std::string>());
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
}
{
@@ -103,7 +103,7 @@ TEST_CASE("parser test various cases") {
i.push_back(p.get_object<X, tup>());
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
}
{
@@ -114,7 +114,7 @@ TEST_CASE("parser test various cases") {
i.push_back(p.get_next<X>());
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
}
{
@@ -132,7 +132,7 @@ TEST_CASE("parser test various cases") {
std::vector<X> expected = data;
std::remove_if(expected.begin(), expected.end(),
[](const X& x) { return x.i == excluded; });
CHECK(std::equal(i.begin(), i.end(), expected.begin()));
CHECK_EQ(i, data);
}
{
@@ -146,7 +146,7 @@ TEST_CASE("parser test various cases") {
}
}
std::vector<X> expected = {{3, 4, "y"}};
CHECK(std::equal(i.begin(), i.end(), expected.begin()));
CHECK_EQ(i, data);
}
{
@@ -194,7 +194,7 @@ TEST_CASE("parser test composite conversion") {
auto expect_error = [](auto error) { CHECK(!error.empty()); };
REQUIRE(p.valid());
REQUIRE(!p.eof());
REQUIRE_FALSE(p.eof());
{
constexpr static auto expectedData = std::tuple{10, 'a', 11.1};
@@ -209,11 +209,11 @@ TEST_CASE("parser test composite conversion") {
.values();
REQUIRE(p.valid());
REQUIRE(!d1);
REQUIRE(!d2);
REQUIRE_FALSE(d1);
REQUIRE_FALSE(d2);
REQUIRE(d3);
REQUIRE(!d4);
CHECK(*d3 == expectedData);
REQUIRE_FALSE(d4);
CHECK_EQ(*d3, expectedData);
}
{
@@ -234,10 +234,10 @@ TEST_CASE("parser test composite conversion") {
REQUIRE(p.valid());
REQUIRE(d1);
REQUIRE(!d2);
REQUIRE(!d3);
REQUIRE(!d4);
CHECK(*d1 == expectedData);
REQUIRE_FALSE(d2);
REQUIRE_FALSE(d3);
REQUIRE_FALSE(d4);
CHECK_EQ(*d1 ,expectedData);
}
{
@@ -252,12 +252,12 @@ TEST_CASE("parser test composite conversion") {
.or_else<int, char, double>(fail)
.values();
REQUIRE(!p.valid());
REQUIRE(!d1);
REQUIRE(!d2);
REQUIRE(!d3);
REQUIRE(!d4);
REQUIRE(!d5);
REQUIRE_FALSE(p.valid());
REQUIRE_FALSE(d1);
REQUIRE_FALSE(d2);
REQUIRE_FALSE(d3);
REQUIRE_FALSE(d4);
REQUIRE_FALSE(d5);
}
{
@@ -272,7 +272,7 @@ TEST_CASE("parser test composite conversion") {
REQUIRE(p.valid());
REQUIRE(d1);
REQUIRE(!d2);
REQUIRE_FALSE(d2);
}
{
@@ -283,9 +283,9 @@ TEST_CASE("parser test composite conversion") {
.values();
REQUIRE(p.valid());
REQUIRE(!d1);
REQUIRE_FALSE(d1);
REQUIRE(d2);
CHECK(d2->tied() == std::tuple{1, 11.1, 'a'});
CHECK_EQ(d2->tied(), std::tuple{1, 11.1, 'a'});
}
{
@@ -300,12 +300,12 @@ TEST_CASE("parser test composite conversion") {
.on_error(expect_error)
.values();
REQUIRE(!p.valid());
REQUIRE(!d1);
REQUIRE(!d2);
REQUIRE(!d3);
REQUIRE(!d4);
REQUIRE(!d5);
REQUIRE_FALSE(p.valid());
REQUIRE_FALSE(d1);
REQUIRE_FALSE(d2);
REQUIRE_FALSE(d3);
REQUIRE_FALSE(d4);
REQUIRE_FALSE(d5);
}
{
@@ -319,12 +319,12 @@ TEST_CASE("parser test composite conversion") {
REQUIRE(p.valid());
REQUIRE(d1);
REQUIRE(!d2);
CHECK(*d1 == std::tuple{10, std::nullopt});
REQUIRE_FALSE(d2);
CHECK_EQ(*d1, std::tuple{10, std::nullopt});
}
{
REQUIRE(!p.eof());
REQUIRE_FALSE(p.eof());
auto [d1, d2] = p.try_next<int, std::variant<int, std::string>>()
.on_error(fail)
@@ -334,8 +334,8 @@ TEST_CASE("parser test composite conversion") {
REQUIRE(p.valid());
REQUIRE(d1);
REQUIRE(!d2);
CHECK(*d1 == std::tuple{11, std::variant<int, std::string>{"junk"}});
REQUIRE_FALSE(d2);
CHECK_EQ(*d1, std::tuple{11, std::variant<int, std::string>{"junk"}});
}
{
@@ -346,12 +346,12 @@ TEST_CASE("parser test composite conversion") {
.values();
REQUIRE(p.valid());
REQUIRE(d1);
REQUIRE(!d2);
CHECK(d1->tied() == std::tuple{10, 11.1, 'c'});
REQUIRE_FALSE(d2);
CHECK_EQ(d1->tied(), std::tuple{10, 11.1, 'c'});
}
{
REQUIRE(!p.eof());
REQUIRE_FALSE(p.eof());
auto [d1, d2, d3, d4] =
p.try_next<int, int>([] { return false; })
@@ -361,11 +361,11 @@ TEST_CASE("parser test composite conversion") {
.values();
REQUIRE(p.valid());
REQUIRE(!d1);
REQUIRE(!d2);
REQUIRE_FALSE(d1);
REQUIRE_FALSE(d2);
REQUIRE(d3);
REQUIRE(!d4);
CHECK(d3.value() == std::tuple{10, 20});
REQUIRE_FALSE(d4);
CHECK_EQ(d3.value(), std::tuple{10, 20});
}
{
@@ -379,11 +379,11 @@ TEST_CASE("parser test composite conversion") {
.values();
REQUIRE(p.valid());
REQUIRE(!d1);
REQUIRE(!d2);
REQUIRE_FALSE(d1);
REQUIRE_FALSE(d2);
REQUIRE(d3);
REQUIRE(!d4);
CHECK(d3->tied() == std::tuple{10, 22.2, 'f'});
REQUIRE_FALSE(d4);
CHECK_EQ(d3->tied(), std::tuple{10, 22.2, 'f'});
}
CHECK(p.eof());
@@ -446,7 +446,7 @@ TEST_CASE("parser test the moving of parsed values") {
ss::parser p{f.name, ","};
auto x = p.get_next<my_string>();
CHECK(move_called < 3);
CHECK_LT(move_called, 3);
move_called_one_col = move_called;
move_called = 0;
}
@@ -461,21 +461,21 @@ TEST_CASE("parser test the moving of parsed values") {
ss::parser p{f.name, ","};
auto x = p.get_next<my_string, my_string, my_string>();
CHECK(move_called <= 3 * move_called_one_col);
CHECK_LE(move_called, 3 * move_called_one_col);
move_called = 0;
}
{
ss::parser p{f.name, ","};
auto x = p.get_object<xyz, my_string, my_string, my_string>();
CHECK(move_called <= 6 * move_called_one_col);
CHECK_LE(move_called, 6 * move_called_one_col);
move_called = 0;
}
{
ss::parser p{f.name, ","};
auto x = p.get_next<xyz>();
CHECK(move_called <= 6 * move_called_one_col);
CHECK_LE(move_called, 6 * move_called_one_col);
move_called = 0;
}
}
@@ -503,10 +503,10 @@ TEST_CASE("parser test error mode") {
ss::parser<ss::string_error> p(f.name, ",");
REQUIRE(!p.eof());
REQUIRE_FALSE(p.eof());
p.get_next<int>();
CHECK(!p.valid());
CHECK(!p.error_msg().empty());
CHECK_FALSE(p.valid());
CHECK_FALSE(p.error_msg().empty());
}
std::string no_quote(const std::string& s) {
@@ -516,7 +516,7 @@ std::string no_quote(const std::string& s) {
return s;
}
TEST_CASE("parser test csv on multiple lines with quotes") {
TEST_CASE("parser test csv on multiple lines with quotes zzz") {
unique_file_name f;
std::vector<X> data = {{1, 2, "\"x\nx\nx\""}, {3, 4, "\"y\ny\ny\""},
{5, 6, "\"z\nz\""}, {7, 8, "\"u\"\"\""},
@@ -537,7 +537,7 @@ TEST_CASE("parser test csv on multiple lines with quotes") {
i.emplace_back(ss::to_object<X>(a));
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
ss::parser<ss::quote<'"'>> p_no_multiline{f.name, ","};
while (!p.eof()) {
@@ -551,10 +551,10 @@ std::string no_escape(std::string& s) {
return s;
}
TEST_CASE("parser test csv on multiple lines with escapes") {
TEST_CASE("parser test csv on multiple lines with escapes xxx") {
unique_file_name f;
std::vector<X> data = {{1, 2, "x\\\nx\\\nx"}, {3, 4, "y\\\ny\\\ny"},
{5, 6, "z\\\nz"}, {7, 8, "u"},
std::vector<X> data = {{1, 2, "x\\\nx\\\nx"}, {5, 6, "z\\\nz\\\nz"},
{7, 8, "u"}, {3, 4, "y\\\ny\\\ny"},
{9, 10, "v\\\\"}, {11, 12, "w\\\n"}};
make_and_write(f.name, data);
@@ -571,13 +571,78 @@ TEST_CASE("parser test csv on multiple lines with escapes") {
while (!p.eof()) {
auto a = p.get_next<int, double, std::string>();
i.emplace_back(ss::to_object<X>(a));
// std::cout << i.back().s << std::endl;
}
CHECK(std::equal(i.begin(), i.end(), data.begin()));
CHECK_EQ(i, data);
ss::parser<ss::escape<'\\'>> p_no_multiline{f.name, ","};
while (!p.eof()) {
auto a = p_no_multiline.get_next<int, double, std::string>();
CHECK(!p.valid());
CHECK_FALSE(p.valid());
}
}
TEST_CASE("parser test csv on multiple lines with quotes and escapes yyy") {
unique_file_name f;
{
std::ofstream out{f.name};
// out << "1,2,\"just\\\n\nstrings\"" << std::endl;
out << "3,4,\"j\\\ns\n\\\nx\\\ny\ng\"" << std::endl;
// out << "5,6,\"just\\\n\\\n\n\nstrings" << std::endl;
// out << "7,8,\"just strings\"" << std::endl;
// out << "9,10,just strings" << std::endl;
}
ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>> p{f.name};
std::vector<X> i;
while (!p.eof()) {
auto a = p.get_next<int, double, std::string>();
if (p.valid()) {
i.emplace_back(ss::to_object<X>(a));
}
}
std::vector<X> data = {{1, 2, "just\n\nstrings"},
{3, 4, "just\nsome\n\n\nstrings"},
{9, 10, "just strings"}};
CHECK_EQ(i, data);
}
/*
TEST_CASE("parser test multiline restricted") {
unique_file_name f;
{
std::ofstream out{f.name};
//out << "1,2,\"just\n\nstrings\"" << std::endl;
//out << "3,4,\"ju\n\n\nnk\"" << std::endl;
//out << "5,6,just\\\n\\\nstrings" << std::endl;
//out << "7,8,ju\\\n\\\n\\\nnk" << std::endl;
//out << "9,10,\"just\\\n\nstrings\"" << std::endl;
out << "11,12,\"ju\\\n|\n\n\n\n\nk\"" << std::endl;
// out << "13,14,\"ju\\\n\\\n15,16\"\\\n\\\\\n\nnk\"" << std::endl;
// out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
out << "19,20,just strings" << std::endl;
}
ss::parser<ss::multiline_restricted<120>, ss::quote<'"'>, ss::escape<'\\'>>
p{f.name, ","};
std::vector<X> i;
while (!p.eof()) {
std::cout << "==========================" << std::endl;
auto a = p.get_next<int, double, std::string>();
if (p.valid()) {
i.emplace_back(ss::to_object<X>(a));
}
}
std::vector<X> data = {{1, 2, "just\n\nstrings"},
{5, 6, "just\n\nstrings"},
{9, 10, "just\n\nstrings"},
{19, 20, "just strings"}};
CHECK(std::equal(i.begin(), i.end(), data.begin()));
}
*/

View File

@@ -541,7 +541,7 @@ public:
};
} /* ss */
TEST_CASE("splitter test unterminated quote") {
TEST_CASE("splitter test resplit unterminated quote") {
{
ss::converter<ss::quote<'"'>> c;
auto& s = c.splitter;
@@ -578,6 +578,7 @@ TEST_CASE("splitter test unterminated quote") {
std::vector<std::string> expected{"just", "some", R"("just","some",")"};
CHECK(words(vec) == expected);
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0';
auto new_line = buff.append(R"(,dom","strings")");
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid());
@@ -629,6 +630,27 @@ TEST_CASE("splitter test unterminated quote") {
}
}
{
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c;
auto& s = c.splitter;
auto vec =
expect_unterminated_quote(s, "3,4,"
"\"just0\\\n1\\\n22\\\n33333x\\\n4");
std::vector<std::string> expected{"3", "4"};
auto w = words(vec);
w.pop_back();
CHECK(w == expected);
{
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0';
auto new_line = buff.append("\nx5strings\"");
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid());
CHECK(!s.unterminated_quote());
expected = {"3", "4", "just0\n1\n22\n33333x\n4\nx5strings"};
CHECK(words(vec) == expected);
}
}
{
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c;
auto& s = c.splitter;
@@ -638,6 +660,7 @@ TEST_CASE("splitter test unterminated quote") {
w.pop_back();
CHECK(w == expected);
{
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0';
auto new_line = buff.append(R"(n,dom",str\"ings)");
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid());
@@ -650,17 +673,18 @@ TEST_CASE("splitter test unterminated quote") {
{
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c;
auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just\"some","ra\")");
auto vec = expect_unterminated_quote(s, R"("just\"some","r\a\a\\\a\")");
std::vector<std::string> expected{"just\"some"};
auto w = words(vec);
w.pop_back();
CHECK(w == expected);
{
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0';
auto new_line = buff.append(R"(n,dom",str\"ings)");
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid());
CHECK(!s.unterminated_quote());
expected = {"just\"some", "ra\"n,dom", "str\"ings"};
expected = {"just\"some", "raa\\a\"n,dom", "str\"ings"};
CHECK(words(vec) == expected);
}
}
@@ -692,6 +716,7 @@ TEST_CASE("splitter test unterminated quote") {
w.pop_back();
CHECK(w == expected);
{
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0';
auto new_line = buff.append(R"( n,dom" , strings )");
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid());