mirror of
https://github.com/red0124/ssp.git
synced 2025-12-14 21:59:55 +01:00
WIP, added multiline restriction, fixed a few bugs for multiline, updated unit tests
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user