update all unit tests, fix bug with unterminated escape, updated multiline parsing, refactored some code, removed unused code

This commit is contained in:
ado 2021-02-21 02:49:23 +01:00
parent 2dbc21780f
commit 1af0e75788
9 changed files with 422 additions and 281 deletions

View File

@ -198,6 +198,10 @@ private:
return splitter_.resplit(new_line, new_size, delim); return splitter_.resplit(new_line, new_size, delim);
} }
size_t size_shifted() {
return splitter_.size_shifted();
}
//////////////// ////////////////
// error // error
//////////////// ////////////////

View File

@ -9,9 +9,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
// TODO remove
#include <iostream>
namespace ss { namespace ss {
template <typename... Matchers> template <typename... Matchers>
@ -21,6 +18,12 @@ class parser {
using multiline = typename setup<Matchers...>::multiline; using multiline = typename setup<Matchers...>::multiline;
using error_type = ss::ternary_t<string_error, std::string, bool>; using error_type = ss::ternary_t<string_error, std::string, bool>;
constexpr static bool escaped_multiline_enabled =
multiline::enabled && setup<Matchers...>::escape::enabled;
constexpr static bool quoted_multiline_enabled =
multiline::enabled && setup<Matchers...>::quote::enabled;
public: public:
parser(const std::string& file_name, parser(const std::string& file_name,
const std::string& delim = ss::default_delimiter) const std::string& delim = ss::default_delimiter)
@ -385,13 +388,12 @@ private:
size_t size = remove_eol(next_line_buffer_, ssize); size_t size = remove_eol(next_line_buffer_, ssize);
size_t limit = 0; size_t limit = 0;
if constexpr (multiline::enabled && if constexpr (escaped_multiline_enabled) {
setup<Matchers...>::escape::enabled) {
while (escaped_eol(size)) { while (escaped_eol(size)) {
if (multiline_limit_reached(limit)) { if (multiline_limit_reached(limit)) {
return true; return true;
} }
if (!append_line(next_line_buffer_, size)) { if (!append_next_line_to_buffer(next_line_buffer_, size)) {
return false; return false;
} }
} }
@ -399,15 +401,27 @@ private:
next_line_converter_.split(next_line_buffer_, delim_); next_line_converter_.split(next_line_buffer_, delim_);
if constexpr (multiline::enabled && if constexpr (quoted_multiline_enabled) {
setup<Matchers...>::quote::enabled) {
while (unterminated_quote()) { while (unterminated_quote()) {
if (multiline_limit_reached(limit)) { if (multiline_limit_reached(limit)) {
return true; return true;
} }
if (!append_line(next_line_buffer_, size)) { if (!append_next_line_to_buffer(next_line_buffer_, size)) {
return false; return false;
} }
if constexpr (escaped_multiline_enabled) {
while (escaped_eol(size)) {
if (multiline_limit_reached(limit)) {
return true;
}
if (!append_next_line_to_buffer(next_line_buffer_,
size)) {
return false;
}
}
}
next_line_converter_.resplit(next_line_buffer_, size); next_line_converter_.resplit(next_line_buffer_, size);
} }
} }
@ -450,7 +464,7 @@ private:
void undo_remove_eol(char* buffer, size_t& string_end) { void undo_remove_eol(char* buffer, size_t& string_end) {
if (next_line_converter_.unterminated_quote()) { if (next_line_converter_.unterminated_quote()) {
string_end -= next_line_converter_.splitter_.escaped_; string_end -= next_line_converter_.size_shifted();
} }
if (crlf_) { if (crlf_) {
std::copy_n("\r\n\0", 3, buffer + string_end); std::copy_n("\r\n\0", 3, buffer + string_end);
@ -483,16 +497,16 @@ private:
first_size += second_size; first_size += second_size;
} }
bool append_line(char*& dst_buffer, size_t& dst_size) { bool append_next_line_to_buffer(char*& buffer, size_t& size) {
undo_remove_eol(dst_buffer, dst_size); undo_remove_eol(buffer, size);
ssize_t ssize = getline(&helper_buffer_, &helper_size_, file_); ssize_t next_ssize = getline(&helper_buffer_, &helper_size_, file_);
if (ssize == -1) { if (next_ssize == -1) {
return false; return false;
} }
size_t size = remove_eol(helper_buffer_, ssize); size_t next_size = remove_eol(helper_buffer_, next_ssize);
realloc_concat(dst_buffer, dst_size, helper_buffer_, size); realloc_concat(buffer, size, helper_buffer_, next_size);
return true; return true;
} }

View File

@ -9,9 +9,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
// TODO remove
#include <iostream>
namespace ss { namespace ss {
template <typename... Ts> template <typename... Ts>
@ -21,6 +18,7 @@ private:
using trim_left = typename setup<Ts...>::trim_left; using trim_left = typename setup<Ts...>::trim_left;
using trim_right = typename setup<Ts...>::trim_right; using trim_right = typename setup<Ts...>::trim_right;
using escape = typename setup<Ts...>::escape; using escape = typename setup<Ts...>::escape;
using multiline = typename setup<Ts...>::multiline;
constexpr static auto string_error = setup<Ts...>::string_error; constexpr static auto string_error = setup<Ts...>::string_error;
constexpr static auto is_const_line = !quote::enabled && !escape::enabled; constexpr static auto is_const_line = !quote::enabled && !escape::enabled;
@ -50,7 +48,9 @@ public:
const split_data& split(line_ptr_type new_line, const split_data& split(line_ptr_type new_line,
const std::string& delimiter = default_delimiter) { const std::string& delimiter = default_delimiter) {
split_data_.clear(); split_data_.clear();
return resplit(new_line, -1, delimiter); line_ = new_line;
begin_ = line_;
return split_impl_select_delim(delimiter);
} }
private: private:
@ -58,6 +58,11 @@ private:
// resplit // resplit
//////////////// ////////////////
// number of characters the end of line is shifted backwards
size_t size_shifted() const {
return escaped_;
}
void adjust_ranges(const char* old_line) { void adjust_ranges(const char* old_line) {
for (auto& [begin, end] : split_data_) { for (auto& [begin, end] : split_data_) {
begin = begin - old_line + line_; begin = begin - old_line + line_;
@ -68,16 +73,16 @@ private:
const split_data& resplit( const split_data& resplit(
line_ptr_type new_line, ssize_t new_size, line_ptr_type new_line, ssize_t new_size,
const std::string& delimiter = default_delimiter) { const std::string& delimiter = default_delimiter) {
line_ = new_line;
// resplitting, continue from last slice // resplitting, continue from last slice
if constexpr (quote::enabled) { if (!quote::enabled || !multiline::enabled || split_data_.empty() ||
if (!split_data_.empty() && unterminated_quote()) { !unterminated_quote()) {
const auto& last = std::prev(split_data_.end()); set_error_invalid_resplit();
const auto [old_line, old_begin] = *last; return split_data_;
}
const auto [old_line, old_begin] = *std::prev(split_data_.end());
size_t begin = old_begin - old_line - 1; size_t begin = old_begin - old_line - 1;
split_data_.pop_back();
adjust_ranges(old_line);
// safety measure // safety measure
if (new_size != -1 && static_cast<size_t>(new_size) < begin) { if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
@ -85,15 +90,17 @@ private:
return split_data_; return split_data_;
} }
std::cout << "======================" << std::endl; // if unterminated quote, the last element is junk
std::cout << "resplitting" << std::endl; split_data_.pop_back();
resplitting_ = true;
line_ = new_line;
adjust_ranges(old_line);
begin_ = line_ + begin; begin_ = line_ + begin;
size_t end = end_ - old_line - escaped_; end_ = line_ - old_line + end_ - escaped_;
end_ = line_ + end;
curr_ = end_; curr_ = end_;
}
} resplitting_ = true;
return split_impl_select_delim(delimiter); return split_impl_select_delim(delimiter);
} }
@ -129,6 +136,15 @@ private:
} }
} }
void set_error_unterminated_escape() {
if constexpr (string_error) {
error_.clear();
error_.append("unterminated escape at the end of the line");
} else {
error_ = true;
}
}
void set_error_unterminated_quote() { void set_error_unterminated_quote() {
unterminated_quote_ = true; unterminated_quote_ = true;
if constexpr (string_error) { if constexpr (string_error) {
@ -215,25 +231,14 @@ private:
// shifting // shifting
//////////////// ////////////////
void shift_and_set_current() {
if constexpr (!is_const_line) {
if (escaped_ > 0) {
std::copy_n(curr_ + escaped_, end_ - curr_ - escaped_, curr_);
curr_ = end_ - escaped_;
return;
}
}
curr_ = end_;
}
void shift_and_push() {
shift_and_set_current();
split_data_.emplace_back(begin_, curr_);
}
void shift_if_escaped(line_ptr_type& curr) { void shift_if_escaped(line_ptr_type& curr) {
if constexpr (escape::enabled) { if constexpr (escape::enabled) {
if (escape::match(*curr)) { if (escape::match(*curr)) {
if (curr[1] == '\0') {
set_error_unterminated_escape();
done_ = true;
return;
}
shift_and_jump_escape(); shift_and_jump_escape();
} }
} }
@ -252,6 +257,22 @@ private:
begin_ = end_ + n; begin_ = end_ + n;
} }
void shift_and_push() {
shift_and_set_current();
split_data_.emplace_back(begin_, curr_);
}
void shift_and_set_current() {
if constexpr (!is_const_line) {
if (escaped_ > 0) {
std::copy_n(curr_ + escaped_, end_ - curr_ - escaped_, curr_);
curr_ = end_ - escaped_;
return;
}
}
curr_ = end_;
}
//////////////// ////////////////
// split impl // split impl
//////////////// ////////////////
@ -273,10 +294,6 @@ private:
template <typename Delim> template <typename Delim>
const split_data& split_impl(const Delim& delim) { const split_data& split_impl(const Delim& delim) {
if (split_data_.empty()) {
begin_ = line_;
}
trim_left_if_enabled(begin_); trim_left_if_enabled(begin_);
for (done_ = false; !done_; read(delim)) for (done_ = false; !done_; read(delim))
@ -293,12 +310,14 @@ private:
void read(const Delim& delim) { void read(const Delim& delim) {
escaped_ = 0; escaped_ = 0;
if constexpr (quote::enabled) { if constexpr (quote::enabled) {
if constexpr (multiline::enabled) {
if (resplitting_) { if (resplitting_) {
resplitting_ = false; resplitting_ = false;
++begin_; ++begin_;
read_quoted(delim); read_quoted(delim);
return; return;
} }
}
if (quote::match(*begin_)) { if (quote::match(*begin_)) {
curr_ = end_ = ++begin_; curr_ = end_ = ++begin_;
read_quoted(delim); read_quoted(delim);
@ -336,19 +355,27 @@ private:
template <typename Delim> template <typename Delim>
void read_quoted(const Delim& delim) { void read_quoted(const Delim& delim) {
if constexpr (quote::enabled) { if constexpr (quote::enabled) {
std::cout << "start loop: " << std::endl;
while (true) { while (true) {
std::cout << "- " << *end_ << std::endl;
if (!quote::match(*end_)) { if (!quote::match(*end_)) {
if constexpr (escape::enabled) { if constexpr (escape::enabled) {
if (escape::match(*end_)) { if (escape::match(*end_)) {
if (end_[1] == '\0') {
// eol, unterminated escape
// eg: ... "hel\\0
set_error_unterminated_escape();
done_ = true;
break;
}
// not eol
shift_and_jump_escape(); shift_and_jump_escape();
++end_; ++end_;
continue; continue;
} }
} }
// not escaped
// unterminated quote error // eol, unterminated quote error
// eg: ..."hell\0 -> quote not terminated // eg: ..."hell\0 -> quote not terminated
if (*end_ == '\0') { if (*end_ == '\0') {
shift_and_set_current(); shift_and_set_current();
@ -357,9 +384,13 @@ private:
done_ = true; done_ = true;
break; break;
} }
// not eol
++end_; ++end_;
continue; continue;
} }
// quote found
// ...
auto [width, valid] = match_delimiter(end_ + 1, delim); auto [width, valid] = match_delimiter(end_ + 1, delim);
@ -368,6 +399,7 @@ private:
shift_push_and_start_next(width + 1); shift_push_and_start_next(width + 1);
break; break;
} }
// not delimiter
// double quote // double quote
// eg: ...,"hel""lo",... -> hel"lo // eg: ...,"hel""lo",... -> hel"lo
@ -376,8 +408,8 @@ private:
++end_; ++end_;
continue; continue;
} }
// not double quote
// not a delimiter
if (width == 0) { if (width == 0) {
// eol // eol
// eg: ...,"hello" \0 -> hello // eg: ...,"hello" \0 -> hello

View File

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

View File

@ -14,10 +14,10 @@ TEST_CASE("converter test split") {
{"x", {"x"}, ","}} // clang-format on {"x", {"x"}, ","}} // clang-format on
) { ) {
auto split = c.split(s, delim); auto split = c.split(s, delim);
CHECK(split.size() == expected.size()); CHECK_EQ(split.size(), expected.size());
for (size_t i = 0; i < split.size(); ++i) { for (size_t i = 0; i < split.size(); ++i) {
auto s = std::string(split[i].first, split[i].second); auto s = std::string(split[i].first, split[i].second);
CHECK(s == expected[i]); CHECK_EQ(s, expected[i]);
} }
} }
} }
@ -28,68 +28,68 @@ TEST_CASE("converter test valid conversions") {
{ {
auto tup = c.convert<int>("5"); auto tup = c.convert<int>("5");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<int, void>("5,junk"); auto tup = c.convert<int, void>("5,junk");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<void, int>("junk,5"); auto tup = c.convert<void, int>("junk,5");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<int, void, void>("5\njunk\njunk", "\n"); auto tup = c.convert<int, void, void>("5\njunk\njunk", "\n");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<void, int, void>("junk 5 junk", " "); auto tup = c.convert<void, int, void>("junk 5 junk", " ");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<void, void, int>("junk\tjunk\t5", "\t"); auto tup = c.convert<void, void, int>("junk\tjunk\t5", "\t");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = auto tup =
c.convert<void, void, std::optional<int>>("junk\tjunk\t5", "\t"); c.convert<void, void, std::optional<int>>("junk\tjunk\t5", "\t");
REQUIRE(c.valid()); REQUIRE(c.valid());
REQUIRE(tup.has_value()); REQUIRE(tup.has_value());
CHECK(tup == 5); CHECK_EQ(tup, 5);
} }
{ {
auto tup = c.convert<int, double, void>("5,6.6,junk"); auto tup = c.convert<int, double, void>("5,6.6,junk");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(5, 6.6)); CHECK_EQ(tup, std::make_tuple(5, 6.6));
} }
{ {
auto tup = c.convert<int, void, double>("5,junk,6.6"); auto tup = c.convert<int, void, double>("5,junk,6.6");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(5, 6.6)); CHECK_EQ(tup, std::make_tuple(5, 6.6));
} }
{ {
auto tup = c.convert<void, int, double>("junk;5;6.6", ";"); auto tup = c.convert<void, int, double>("junk;5;6.6", ";");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(5, 6.6)); CHECK_EQ(tup, std::make_tuple(5, 6.6));
} }
{ {
auto tup = auto tup =
c.convert<void, std::optional<int>, double>("junk;5;6.6", ";"); c.convert<void, std::optional<int>, double>("junk;5;6.6", ";");
REQUIRE(c.valid()); REQUIRE(c.valid());
REQUIRE(std::get<0>(tup).has_value()); REQUIRE(std::get<0>(tup).has_value());
CHECK(tup == std::make_tuple(5, 6.6)); CHECK_EQ(tup, std::make_tuple(5, 6.6));
} }
{ {
auto tup = auto tup =
c.convert<void, std::optional<int>, double>("junk;5.4;6.6", ";"); c.convert<void, std::optional<int>, double>("junk;5.4;6.6", ";");
REQUIRE(c.valid()); REQUIRE(c.valid());
REQUIRE(!std::get<0>(tup).has_value()); REQUIRE_FALSE(std::get<0>(tup).has_value());
CHECK(tup == std::make_tuple(std::optional<int>{}, 6.6)); CHECK_EQ(tup, std::make_tuple(std::optional<int>{}, 6.6));
} }
{ {
auto tup = auto tup =
@ -97,7 +97,7 @@ TEST_CASE("converter test valid conversions") {
";"); ";");
REQUIRE(c.valid()); REQUIRE(c.valid());
REQUIRE(std::holds_alternative<int>(std::get<0>(tup))); REQUIRE(std::holds_alternative<int>(std::get<0>(tup)));
CHECK(tup == std::make_tuple(std::variant<int, double>{5}, 6.6)); CHECK_EQ(tup, std::make_tuple(std::variant<int, double>{5}, 6.6));
} }
{ {
auto tup = auto tup =
@ -105,7 +105,7 @@ TEST_CASE("converter test valid conversions") {
";"); ";");
REQUIRE(c.valid()); REQUIRE(c.valid());
REQUIRE(std::holds_alternative<double>(std::get<0>(tup))); REQUIRE(std::holds_alternative<double>(std::get<0>(tup)));
CHECK(tup == std::make_tuple(std::variant<int, double>{5.5}, 6.6)); CHECK_EQ(tup, std::make_tuple(std::variant<int, double>{5.5}, 6.6));
} }
} }
@ -113,64 +113,64 @@ TEST_CASE("converter test invalid conversions") {
ss::converter c; ss::converter c;
c.convert<int>(""); c.convert<int>("");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int>("10", ""); c.convert<int>("10", "");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int, void>(""); c.convert<int, void>("");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int, void>(",junk"); c.convert<int, void>(",junk");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<void, int>("junk,"); c.convert<void, int>("junk,");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int>("x"); c.convert<int>("x");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int, void>("x"); c.convert<int, void>("x");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int, void>("x,junk"); c.convert<int, void>("x,junk");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<void, int>("junk,x"); c.convert<void, int>("junk,x");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<void, std::variant<int, double>, double>("junk;.5.5;6", ";"); c.convert<void, std::variant<int, double>, double>("junk;.5.5;6", ";");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
} }
TEST_CASE("converter test ss:ax restriction (all except)") { TEST_CASE("converter test ss:ax restriction (all except)") {
ss::converter c; ss::converter c;
c.convert<ss::ax<int, 0>>("0"); c.convert<ss::ax<int, 0>>("0");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::ax<int, 0, 1, 2>>("1"); c.convert<ss::ax<int, 0, 1, 2>>("1");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<void, char, ss::ax<int, 0, 1, 2>>("junk,c,1"); c.convert<void, char, ss::ax<int, 0, 1, 2>>("junk,c,1");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::ax<int, 1>, char>("1,c"); c.convert<ss::ax<int, 1>, char>("1,c");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
int tup = c.convert<ss::ax<int, 1>>("3"); int tup = c.convert<ss::ax<int, 1>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
std::tuple<char, int> tup = c.convert<char, ss::ax<int, 1>>("c,3"); std::tuple<char, int> tup = c.convert<char, ss::ax<int, 1>>("c,3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple('c', 3)); CHECK_EQ(tup, std::make_tuple('c', 3));
} }
{ {
std::tuple<int, char> tup = c.convert<ss::ax<int, 1>, char>("3,c"); std::tuple<int, char> tup = c.convert<ss::ax<int, 1>, char>("3,c");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(3, 'c')); CHECK_EQ(tup, std::make_tuple(3, 'c'));
} }
} }
@ -178,33 +178,33 @@ TEST_CASE("converter test ss:nx restriction (none except)") {
ss::converter c; ss::converter c;
c.convert<ss::nx<int, 1>>("3"); c.convert<ss::nx<int, 1>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<char, ss::nx<int, 1, 2, 69>>("c,3"); c.convert<char, ss::nx<int, 1, 2, 69>>("c,3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::nx<int, 1>, char>("3,c"); c.convert<ss::nx<int, 1>, char>("3,c");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
auto tup = c.convert<ss::nx<int, 3>>("3"); auto tup = c.convert<ss::nx<int, 3>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::nx<int, 0, 1, 2>>("2"); auto tup = c.convert<ss::nx<int, 0, 1, 2>>("2");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 2); CHECK_EQ(tup, 2);
} }
{ {
auto tup = c.convert<char, void, ss::nx<int, 0, 1, 2>>("c,junk,1"); auto tup = c.convert<char, void, ss::nx<int, 0, 1, 2>>("c,junk,1");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple('c', 1)); CHECK_EQ(tup, std::make_tuple('c', 1));
} }
{ {
auto tup = c.convert<ss::nx<int, 1>, char>("1,c"); auto tup = c.convert<ss::nx<int, 1>, char>("1,c");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(1, 'c')); CHECK_EQ(tup, std::make_tuple(1, 'c'));
} }
} }
@ -212,33 +212,33 @@ TEST_CASE("converter test ss:ir restriction (in range)") {
ss::converter c; ss::converter c;
c.convert<ss::ir<int, 0, 2>>("3"); c.convert<ss::ir<int, 0, 2>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<char, ss::ir<int, 4, 69>>("c,3"); c.convert<char, ss::ir<int, 4, 69>>("c,3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::ir<int, 1, 2>, char>("3,c"); c.convert<ss::ir<int, 1, 2>, char>("3,c");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
auto tup = c.convert<ss::ir<int, 1, 5>>("3"); auto tup = c.convert<ss::ir<int, 1, 5>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::ir<int, 0, 2>>("2"); auto tup = c.convert<ss::ir<int, 0, 2>>("2");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 2); CHECK_EQ(tup, 2);
} }
{ {
auto tup = c.convert<char, void, ss::ir<int, 0, 1>>("c,junk,1"); auto tup = c.convert<char, void, ss::ir<int, 0, 1>>("c,junk,1");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple('c', 1)); CHECK_EQ(tup, std::make_tuple('c', 1));
} }
{ {
auto tup = c.convert<ss::ir<int, 1, 20>, char>("1,c"); auto tup = c.convert<ss::ir<int, 1, 20>, char>("1,c");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(1, 'c')); CHECK_EQ(tup, std::make_tuple(1, 'c'));
} }
} }
@ -246,33 +246,33 @@ TEST_CASE("converter test ss:oor restriction (out of range)") {
ss::converter c; ss::converter c;
c.convert<ss::oor<int, 1, 5>>("3"); c.convert<ss::oor<int, 1, 5>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::oor<int, 0, 2>>("2"); c.convert<ss::oor<int, 0, 2>>("2");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<char, ss::oor<int, 0, 1>, void>("c,1,junk"); c.convert<char, ss::oor<int, 0, 1>, void>("c,1,junk");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::oor<int, 1, 20>, char>("1,c"); c.convert<ss::oor<int, 1, 20>, char>("1,c");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
auto tup = c.convert<ss::oor<int, 0, 2>>("3"); auto tup = c.convert<ss::oor<int, 0, 2>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<char, void, ss::oor<int, 4, 69>>("c,junk,3"); auto tup = c.convert<char, void, ss::oor<int, 4, 69>>("c,junk,3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple('c', 3)); CHECK_EQ(tup, std::make_tuple('c', 3));
} }
{ {
auto tup = c.convert<ss::oor<int, 1, 2>, char>("3,c"); auto tup = c.convert<ss::oor<int, 1, 2>, char>("3,c");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(3, 'c')); CHECK_EQ(tup, std::make_tuple(3, 'c'));
} }
} }
@ -293,34 +293,34 @@ TEST_CASE("converter test ss:ne restriction (not empty)") {
ss::converter c; ss::converter c;
c.convert<ss::ne<std::string>>(""); c.convert<ss::ne<std::string>>("");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<int, ss::ne<std::string>>("3,"); c.convert<int, ss::ne<std::string>>("3,");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::ne<std::string>, int>(",3"); c.convert<ss::ne<std::string>, int>(",3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<void, ss::ne<std::string>, int>("junk,,3"); c.convert<void, ss::ne<std::string>, int>("junk,,3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::ne<std::vector<int>>>(""); c.convert<ss::ne<std::vector<int>>>("");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
auto tup = c.convert<ss::ne<std::string>>("s"); auto tup = c.convert<ss::ne<std::string>>("s");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == "s"); CHECK_EQ(tup, "s");
} }
{ {
auto tup = c.convert<std::optional<int>, ss::ne<std::string>>("1,s"); auto tup = c.convert<std::optional<int>, ss::ne<std::string>>("1,s");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple(1, "s")); CHECK_EQ(tup, std::make_tuple(1, "s"));
} }
{ {
auto tup = c.convert<ss::ne<std::vector<int>>>("{1 2 3}"); auto tup = c.convert<ss::ne<std::vector<int>>>("{1 2 3}");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == extracted_vector); CHECK_EQ(tup, extracted_vector);
} }
} }
@ -329,65 +329,65 @@ TEST_CASE(
ss::converter c; ss::converter c;
c.convert<ss::lt<int, 3>>("3"); c.convert<ss::lt<int, 3>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::lt<int, 2>>("3"); c.convert<ss::lt<int, 2>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::gt<int, 3>>("3"); c.convert<ss::gt<int, 3>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::gt<int, 4>>("3"); c.convert<ss::gt<int, 4>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::lte<int, 2>>("3"); c.convert<ss::lte<int, 2>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
c.convert<ss::gte<int, 4>>("3"); c.convert<ss::gte<int, 4>>("3");
REQUIRE(!c.valid()); REQUIRE_FALSE(c.valid());
{ {
auto tup = c.convert<ss::lt<int, 4>>("3"); auto tup = c.convert<ss::lt<int, 4>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::gt<int, 2>>("3"); auto tup = c.convert<ss::gt<int, 2>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::lte<int, 4>>("3"); auto tup = c.convert<ss::lte<int, 4>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::lte<int, 3>>("3"); auto tup = c.convert<ss::lte<int, 3>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::gte<int, 2>>("3"); auto tup = c.convert<ss::gte<int, 2>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
{ {
auto tup = c.convert<ss::gte<int, 3>>("3"); auto tup = c.convert<ss::gte<int, 3>>("3");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == 3); CHECK_EQ(tup, 3);
} }
} }
TEST_CASE("converter test error mode") { TEST_CASE("converter test error mode") {
ss::converter<ss::string_error> c; ss::converter<ss::string_error> c;
c.convert<int>("junk"); c.convert<int>("junk");
CHECK(!c.valid()); CHECK_FALSE(c.valid());
CHECK(!c.error_msg().empty()); CHECK_FALSE(c.error_msg().empty());
} }
TEST_CASE("converter test converter with quotes spacing and escaping") { TEST_CASE("converter test converter with quotes spacing and escaping") {
@ -397,7 +397,7 @@ TEST_CASE("converter test converter with quotes spacing and escaping") {
auto tup = c.convert<std::string, std::string, std::string>( auto tup = c.convert<std::string, std::string, std::string>(
R"("just","some","strings")"); R"("just","some","strings")");
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple("\"just\"", "\"some\"", "\"strings\"")); CHECK_EQ(tup, std::make_tuple("\"just\"", "\"some\"", "\"strings\""));
} }
{ {
@ -406,7 +406,7 @@ TEST_CASE("converter test converter with quotes spacing and escaping") {
auto tup = c.convert<std::string, std::string, double, char>( auto tup = c.convert<std::string, std::string, double, char>(
buff(R"("just",some,"12.3","a")")); buff(R"("just",some,"12.3","a")"));
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple("just", "some", 12.3, 'a')); CHECK_EQ(tup, std::make_tuple("just", "some", 12.3, 'a'));
} }
{ {
@ -415,7 +415,7 @@ TEST_CASE("converter test converter with quotes spacing and escaping") {
auto tup = c.convert<std::string, std::string, double, char>( auto tup = c.convert<std::string, std::string, double, char>(
buff(R"( just , some , 12.3 ,a )")); buff(R"( just , some , 12.3 ,a )"));
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple("just", "some", 12.3, 'a')); CHECK_EQ(tup, std::make_tuple("just", "some", 12.3, 'a'));
} }
{ {
@ -424,7 +424,7 @@ TEST_CASE("converter test converter with quotes spacing and escaping") {
auto tup = auto tup =
c.convert<std::string, std::string>(buff(R"(ju\,st,strings)")); c.convert<std::string, std::string>(buff(R"(ju\,st,strings)"));
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple("ju,st", "strings")); CHECK_EQ(tup, std::make_tuple("ju,st", "strings"));
} }
{ {
@ -433,7 +433,7 @@ TEST_CASE("converter test converter with quotes spacing and escaping") {
auto tup = c.convert<std::string, std::string, double, std::string>( auto tup = c.convert<std::string, std::string, double, std::string>(
buff(R"( ju\,st , "so,me" , 12.34 , "str""ings")")); buff(R"( ju\,st , "so,me" , 12.34 , "str""ings")"));
REQUIRE(c.valid()); REQUIRE(c.valid());
CHECK(tup == std::make_tuple("ju,st", "so,me", 12.34, "str\"ings")); CHECK_EQ(tup, std::make_tuple("ju,st", "so,me", 12.34, "str\"ings"));
} }
} }
@ -446,17 +446,44 @@ TEST_CASE("converter test invalid split conversions") {
// mismatched quote // mismatched quote
auto tup = c.convert<std::string, std::string, double, char>( auto tup = c.convert<std::string, std::string, double, char>(
buff(R"( "just , some , "12.3","a" )")); buff(R"( "just , some , "12.3","a" )"));
CHECK(!c.valid()); CHECK_FALSE(c.valid());
CHECK(!c.unterminated_quote()); CHECK_FALSE(c.unterminated_quote());
CHECK(!c.error_msg().empty()); CHECK_FALSE(c.error_msg().empty());
} }
{ {
// unterminated quote // unterminated quote
auto tup = c.convert<std::string, std::string, double, std::string>( auto tup = c.convert<std::string, std::string, double, std::string>(
buff(R"( ju\,st , "so,me" , 12.34 , "str""ings)")); buff(R"( ju\,st , "so,me" , 12.34 , "str""ings)"));
CHECK(!c.valid()); CHECK_FALSE(c.valid());
CHECK(c.unterminated_quote()); CHECK(c.unterminated_quote());
CHECK(!c.error_msg().empty()); CHECK_FALSE(c.error_msg().empty());
}
{
// unterminated escape
auto tup = c.convert<std::string, std::string, double, std::string>(
buff(R"(just,some,2,strings\)"));
CHECK_FALSE(c.valid());
CHECK_FALSE(c.unterminated_quote());
CHECK_FALSE(c.error_msg().empty());
}
{
// unterminated escape while quoting
auto tup = c.convert<std::string, std::string, double, std::string>(
buff(R"(just,some,2,"strings\)"));
CHECK_FALSE(c.valid());
CHECK_FALSE(c.unterminated_quote());
CHECK_FALSE(c.error_msg().empty());
}
{
// unterminated escaped quote
auto tup = c.convert<std::string, std::string, double, std::string>(
buff(R"(just,some,2,"strings\")"));
CHECK_FALSE(c.valid());
CHECK(c.unterminated_quote());
CHECK_FALSE(c.error_msg().empty());
} }
} }

View File

@ -8,7 +8,7 @@
std::string s = #input; \ std::string s = #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
CHECK(std::abs(t.value() - type(input)) < eps); \ CHECK_LT(std::abs(t.value() - type(input)), eps); \
} \ } \
{ \ { \
/* check negative too */ \ /* check negative too */ \
@ -16,7 +16,7 @@
auto s = std::string("-") + #input; \ auto s = std::string("-") + #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
CHECK(std::abs(t.value() - type(-input)) < eps); \ CHECK_LT(std::abs(t.value() - type(-input)), eps); \
} }
TEST_CASE("testing extract functions for floating point values") { TEST_CASE("testing extract functions for floating point values") {
@ -41,7 +41,7 @@ TEST_CASE("testing extract functions for floating point values") {
std::string s = #input; \ std::string s = #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
CHECK(t.value() == type(input)); \ CHECK_EQ(t.value(), type(input)); \
} \ } \
{ \ { \
/* check negative too */ \ /* check negative too */ \
@ -49,7 +49,7 @@ TEST_CASE("testing extract functions for floating point values") {
auto s = std::string("-") + #input; \ auto s = std::string("-") + #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
CHECK(t.value() == type(-input)); \ CHECK_EQ(t.value(), type(-input)); \
} \ } \
} }
@ -74,7 +74,7 @@ TEST_CASE("extract test functions for decimal values") {
{ \ { \
std::string s = input; \ std::string s = input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
CHECK(!t.has_value()); \ CHECK_FALSE(t.has_value()); \
} }
TEST_CASE("extract test functions for numbers with invalid inputs") { TEST_CASE("extract test functions for numbers with invalid inputs") {
@ -106,7 +106,7 @@ TEST_CASE("extract test functions for numbers with invalid inputs") {
} \ } \
} \ } \
t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
CHECK(!t.has_value()); \ CHECK_FALSE(t.has_value()); \
} \ } \
{ \ { \
std::string s = std::to_string(std::numeric_limits<type>::min()); \ std::string s = std::to_string(std::numeric_limits<type>::min()); \
@ -122,7 +122,7 @@ TEST_CASE("extract test functions for numbers with invalid inputs") {
} \ } \
} \ } \
t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
CHECK(!t.has_value()); \ CHECK_FALSE(t.has_value()); \
} }
TEST_CASE("extract test functions for numbers with out of range inputs") { TEST_CASE("extract test functions for numbers with out of range inputs") {
@ -143,12 +143,12 @@ TEST_CASE("extract test functions for boolean values") {
{false, "false"}}) { {false, "false"}}) {
bool v; bool v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
CHECK(v == b); CHECK_EQ(v, b);
} }
for (const std::string& s : {"2", "tru", "truee", "xxx", ""}) { for (const std::string& s : {"2", "tru", "truee", "xxx", ""}) {
bool v; bool v;
REQUIRE(!ss::extract(s.c_str(), s.c_str() + s.size(), v)); CHECK_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
} }
} }
@ -157,12 +157,12 @@ TEST_CASE("extract test functions for char values") {
{std::pair<char, std::string>{'a', "a"}, {'x', "x"}, {' ', " "}}) { {std::pair<char, std::string>{'a', "a"}, {'x', "x"}, {' ', " "}}) {
char v; char v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
CHECK(v == c); CHECK_EQ(v, c);
} }
for (const std::string& s : {"aa", "xxx", ""}) { for (const std::string& s : {"aa", "xxx", ""}) {
char v; char v;
REQUIRE(!ss::extract(s.c_str(), s.c_str() + s.size(), v)); CHECK_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
} }
} }
@ -174,7 +174,7 @@ TEST_CASE("extract test functions for std::optional") {
std::optional<int> v; std::optional<int> v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
REQUIRE(v.has_value()); REQUIRE(v.has_value());
CHECK(*v == i); CHECK_EQ(*v, i);
} }
for (const auto& [c, s] : for (const auto& [c, s] :
@ -184,19 +184,19 @@ TEST_CASE("extract test functions for std::optional") {
std::optional<char> v; std::optional<char> v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
REQUIRE(v.has_value()); REQUIRE(v.has_value());
CHECK(*v == c); CHECK_EQ(*v, c);
} }
for (const std::string& s : {"aa", "xxx", ""}) { for (const std::string& s : {"aa", "xxx", ""}) {
std::optional<int> v; std::optional<int> v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
REQUIRE(!v.has_value()); CHECK_FALSE(v.has_value());
} }
for (const std::string& s : {"aa", "xxx", ""}) { for (const std::string& s : {"aa", "xxx", ""}) {
std::optional<char> v; std::optional<char> v;
REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v)); REQUIRE(ss::extract(s.c_str(), s.c_str() + s.size(), v));
REQUIRE(!v.has_value()); CHECK_FALSE(v.has_value());
} }
} }
@ -204,7 +204,7 @@ TEST_CASE("extract test functions for std::optional") {
{ \ { \
auto ptr = std::get_if<type>(&var); \ auto ptr = std::get_if<type>(&var); \
REQUIRE(ptr); \ REQUIRE(ptr); \
REQUIRE(el == *ptr); \ REQUIRE_EQ(el, *ptr); \
} }
#define CHECK_NOT_VARIANT(var, type) CHECK(!std::holds_alternative<type>(var)); #define CHECK_NOT_VARIANT(var, type) CHECK(!std::holds_alternative<type>(var));
@ -288,21 +288,21 @@ TEST_CASE("extract test functions for std::variant") {
} }
{ {
std::variant<int, double> var; std::variant<int, double> var;
REQUIRE(!ss::extract(s.c_str(), s.c_str() + s.size(), var)); REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
REQUIRE_VARIANT(var, int{}, int); REQUIRE_VARIANT(var, int{}, int);
CHECK_NOT_VARIANT(var, double); CHECK_NOT_VARIANT(var, double);
} }
{ {
std::variant<double, int> var; std::variant<double, int> var;
REQUIRE(!ss::extract(s.c_str(), s.c_str() + s.size(), var)); REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
REQUIRE_VARIANT(var, double{}, double); REQUIRE_VARIANT(var, double{}, double);
CHECK_NOT_VARIANT(var, int); CHECK_NOT_VARIANT(var, int);
} }
{ {
std::variant<int> var; std::variant<int> var;
REQUIRE(!ss::extract(s.c_str(), s.c_str() + s.size(), var)); REQUIRE_FALSE(ss::extract(s.c_str(), s.c_str() + s.size(), var));
REQUIRE_VARIANT(var, int{}, int); REQUIRE_VARIANT(var, int{}, int);
} }

View File

@ -33,6 +33,11 @@ struct buffer {
} }
} }
char* append_overwrite_last(const char* data, size_t size) {
data_[strlen(data_) - size] = '\0';
return append(data);
}
~buffer() { ~buffer() {
if (data_) { if (data_) {
delete[] data_; delete[] data_;

View File

@ -72,6 +72,7 @@ TEST_CASE("parser test various cases") {
{ {
ss::parser p{f.name, ","}; ss::parser p{f.name, ","};
std::vector<X> i; std::vector<X> i;
std::vector<X> expected = {std::begin(data) + 1, std::end(data)};
p.ignore_next(); p.ignore_next();
while (!p.eof()) { while (!p.eof()) {
@ -80,7 +81,7 @@ TEST_CASE("parser test various cases") {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
CHECK_EQ(i, data); CHECK_EQ(i, expected);
} }
{ {
@ -129,10 +130,17 @@ TEST_CASE("parser test various cases") {
i.push_back(a); i.push_back(a);
} }
} }
std::vector<X> expected = data;
std::remove_if(expected.begin(), expected.end(), std::vector<X> expected;
[](const X& x) { return x.i == excluded; }); for (auto& x : data) {
CHECK_EQ(i, data); if (x.i != excluded) {
expected.push_back(x);
}
}
std::copy_if(data.begin(), data.end(), expected.begin(),
[](const X& x) { return x.i != excluded; });
CHECK_EQ(i, expected);
} }
{ {
@ -146,7 +154,7 @@ TEST_CASE("parser test various cases") {
} }
} }
std::vector<X> expected = {{3, 4, "y"}}; std::vector<X> expected = {{3, 4, "y"}};
CHECK_EQ(i, data); CHECK_EQ(i, expected);
} }
{ {
@ -203,7 +211,7 @@ TEST_CASE("parser test composite conversion") {
p.try_next<int, int, double>(fail) p.try_next<int, int, double>(fail)
.or_else<test_struct>(fail) .or_else<test_struct>(fail)
.or_else<int, char, double>( .or_else<int, char, double>(
[](auto&& data) { CHECK(data == expectedData); }) [](auto&& data) { CHECK_EQ(data, expectedData); })
.on_error(fail) .on_error(fail)
.or_else<test_tuple>(fail) .or_else<test_tuple>(fail)
.values(); .values();
@ -222,7 +230,7 @@ TEST_CASE("parser test composite conversion") {
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] =
p.try_next<int, int, double>([](auto& i1, auto i2, double d) { p.try_next<int, int, double>([](auto& i1, auto i2, double d) {
CHECK(std::tie(i1, i2, d) == expectedData); CHECK_EQ(std::tie(i1, i2, d), expectedData);
}) })
.on_error(fail) .on_error(fail)
.or_object<test_struct, int, double, char>(fail) .or_object<test_struct, int, double, char>(fail)
@ -265,7 +273,7 @@ TEST_CASE("parser test composite conversion") {
auto [d1, d2] = auto [d1, d2] =
p.try_next<int, double>([](auto& i, auto& d) { p.try_next<int, double>([](auto& i, auto& d) {
REQUIRE(std::tie(i, d) == std::tuple{10, 11.1}); REQUIRE_EQ(std::tie(i, d), std::tuple{10, 11.1});
}) })
.or_else<int, double>([](auto&, auto&) { FAIL(""); }) .or_else<int, double>([](auto&, auto&) { FAIL(""); })
.values(); .values();
@ -551,7 +559,7 @@ std::string no_escape(std::string& s) {
return s; return s;
} }
TEST_CASE("parser test csv on multiple lines with escapes xxx") { TEST_CASE("parser test csv on multiple lines with escapes") {
unique_file_name f; unique_file_name f;
std::vector<X> data = {{1, 2, "x\\\nx\\\nx"}, {5, 6, "z\\\nz\\\nz"}, std::vector<X> data = {{1, 2, "x\\\nx\\\nx"}, {5, 6, "z\\\nz\\\nz"},
{7, 8, "u"}, {3, 4, "y\\\ny\\\ny"}, {7, 8, "u"}, {3, 4, "y\\\ny\\\ny"},
@ -571,7 +579,6 @@ TEST_CASE("parser test csv on multiple lines with escapes xxx") {
while (!p.eof()) { while (!p.eof()) {
auto a = p.get_next<int, double, std::string>(); auto a = p.get_next<int, double, std::string>();
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
// std::cout << i.back().s << std::endl;
} }
CHECK_EQ(i, data); CHECK_EQ(i, data);
@ -583,15 +590,15 @@ TEST_CASE("parser test csv on multiple lines with escapes xxx") {
} }
} }
TEST_CASE("parser test csv on multiple lines with quotes and escapes yyy") { TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
unique_file_name f; unique_file_name f;
{ {
std::ofstream out{f.name}; std::ofstream out{f.name};
// out << "1,2,\"just\\\n\nstrings\"" << std::endl; out << "1,2,\"just\\\n\nstrings\"" << std::endl;
out << "3,4,\"j\\\ns\n\\\nx\\\ny\ng\"" << std::endl; out << "3,4,\"just\nsome\\\n\n\\\nstrings\"" << std::endl;
// out << "5,6,\"just\\\n\\\n\n\nstrings" << std::endl; out << "5,6,\"just\\\n\\\n\n\nstrings" << std::endl;
// out << "7,8,\"just strings\"" << std::endl; out << "7,8,\"just strings\"" << std::endl;
// out << "9,10,just strings" << std::endl; out << "9,10,just strings" << std::endl;
} }
ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>> p{f.name}; ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>> p{f.name};
@ -611,28 +618,26 @@ TEST_CASE("parser test csv on multiple lines with quotes and escapes yyy") {
CHECK_EQ(i, data); CHECK_EQ(i, data);
} }
/*
TEST_CASE("parser test multiline restricted") { TEST_CASE("parser test multiline restricted") {
unique_file_name f; unique_file_name f;
{ {
std::ofstream out{f.name}; std::ofstream out{f.name};
//out << "1,2,\"just\n\nstrings\"" << std::endl; out << "1,2,\"just\n\nstrings\"" << std::endl;
//out << "3,4,\"ju\n\n\nnk\"" << std::endl; out << "3,4,\"ju\n\n\nnk\"" << std::endl;
//out << "5,6,just\\\n\\\nstrings" << std::endl; out << "5,6,just\\\n\\\nstrings" << std::endl;
//out << "7,8,ju\\\n\\\n\\\nnk" << std::endl; out << "7,8,ju\\\n\\\n\\\nnk" << std::endl;
//out << "9,10,\"just\\\n\nstrings\"" << std::endl; out << "9,10,\"just\\\n\nstrings\"" << std::endl;
out << "11,12,\"ju\\\n|\n\n\n\n\nk\"" << 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 << "13,14,\"ju\\\n\\\n15,16\"\\\n\\\\\n\nnk\"" << std::endl;
// out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl; out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
out << "19,20,just strings" << std::endl; out << "19,20,just strings" << std::endl;
} }
ss::parser<ss::multiline_restricted<120>, ss::quote<'"'>, ss::escape<'\\'>> ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>>
p{f.name, ","}; p{f.name, ","};
std::vector<X> i; std::vector<X> i;
while (!p.eof()) { while (!p.eof()) {
std::cout << "==========================" << std::endl;
auto a = p.get_next<int, double, std::string>(); auto a = p.get_next<int, double, std::string>();
if (p.valid()) { if (p.valid()) {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
@ -643,6 +648,5 @@ TEST_CASE("parser test multiline restricted") {
{5, 6, "just\n\nstrings"}, {5, 6, "just\n\nstrings"},
{9, 10, "just\n\nstrings"}, {9, 10, "just\n\nstrings"},
{19, 20, "just strings"}}; {19, 20, "just strings"}};
CHECK(std::equal(i.begin(), i.end(), data.begin())); CHECK_EQ(i, data);
} }
*/

View File

@ -193,7 +193,7 @@ void test_combinations(matches_type& matches, std::vector<std::string> delims) {
for (size_t i = 0; i < lines.size(); ++i) { for (size_t i = 0; i < lines.size(); ++i) {
auto vec = s.split(buff(lines[i].c_str()), delim); auto vec = s.split(buff(lines[i].c_str()), delim);
CHECK(s.valid()); CHECK(s.valid());
CHECK(words(vec) == expectations[i]); CHECK_EQ(words(vec), expectations[i]);
} }
} }
} }
@ -506,25 +506,25 @@ TEST_CASE("splitter test error mode") {
// empty delimiter // empty delimiter
ss::splitter<ss::string_error> s; ss::splitter<ss::string_error> s;
s.split(buff("just,some,strings"), ""); s.split(buff("just,some,strings"), "");
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
} }
{ {
// unterminated quote // unterminated quote
ss::splitter<ss::string_error, ss::quote<'"'>> s; ss::splitter<ss::string_error, ss::quote<'"'>> s;
s.split(buff("\"just")); s.split(buff("\"just"));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(s.unterminated_quote()); CHECK(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
} }
} }
template <typename Splitter> template <typename Splitter>
auto expect_unterminated_quote(Splitter& s, const std::string& line) { auto expect_unterminated_quote(Splitter& s, const std::string& line) {
auto vec = s.split(buff(line.c_str())); auto vec = s.split(buff(line.c_str()));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(s.unterminated_quote()); CHECK(s.unterminated_quote());
return vec; return vec;
} }
@ -538,100 +538,135 @@ public:
auto resplit(char* new_line, size_t new_line_size) { auto resplit(char* new_line, size_t new_line_size) {
return splitter.resplit(new_line, new_line_size); return splitter.resplit(new_line, new_line_size);
} }
size_t size_shifted() {
return splitter.size_shifted();
}
}; };
} /* ss */ } /* ss */
TEST_CASE("splitter test resplit unterminated quote") { TEST_CASE("splitter test resplit unterminated quote") {
{ {
ss::converter<ss::quote<'"'>> c; ss::converter<ss::quote<'"'>, ss::multiline, ss::escape<'\\'>> c;
auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("x)");
CHECK_EQ(vec.size(), 1);
REQUIRE(s.unterminated_quote());
{
auto new_line =
buff.append_overwrite_last(R"(a\x)", c.size_shifted());
vec = c.resplit(new_line, strlen(new_line));
CHECK(s.unterminated_quote());
CHECK_EQ(vec.size(), 1);
}
{
auto new_line =
buff.append_overwrite_last(R"(")", c.size_shifted());
vec = c.resplit(new_line, strlen(new_line));
REQUIRE(s.valid());
CHECK_FALSE(s.unterminated_quote());
REQUIRE_EQ(vec.size(), 1);
CHECK_EQ(words(vec)[0], "xax");
}
}
{
ss::converter<ss::quote<'"'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, "\"just"); auto vec = expect_unterminated_quote(s, "\"just");
CHECK(vec.size() == 1); CHECK_EQ(vec.size(), 1);
auto new_line = buff.append(R"(",strings)"); auto new_line = buff.append(R"(",strings)");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
std::vector<std::string> expected{"just", "strings"}; std::vector<std::string> expected{"just", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
{ {
ss::converter<ss::quote<'"'>> c; ss::converter<ss::quote<'"'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, "just,some,\"random"); auto vec = expect_unterminated_quote(s, "just,some,\"random");
std::vector<std::string> expected{"just", "some", "just,some,\""}; std::vector<std::string> expected{"just", "some", "just,some,\""};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
auto new_line = buff.append(R"(",strings)"); auto new_line = buff.append(R"(",strings)");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just", "some", "random", "strings"}; expected = {"just", "some", "random", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
{ {
ss::converter<ss::quote<'"'>> c; ss::converter<ss::quote<'"'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just","some","ran"")"); auto vec = expect_unterminated_quote(s, R"("just","some","ran"")");
std::vector<std::string> expected{"just", "some", R"("just","some",")"}; std::vector<std::string> expected{"just", "some", R"("just","some",")"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0'; auto new_line =
auto new_line = buff.append(R"(,dom","strings")"); buff.append_overwrite_last(R"(,dom","strings")", c.size_shifted());
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just", "some", "ran\",dom", "strings"}; expected = {"just", "some", "ran\",dom", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
{ {
ss::converter<ss::quote<'"'>> c; ss::converter<ss::quote<'"'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just","some","ran)"); auto vec = expect_unterminated_quote(s, R"("just","some","ran)");
std::vector<std::string> expected{"just", "some", R"("just","some",")"}; std::vector<std::string> expected{"just", "some", R"("just","some",")"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
REQUIRE(s.unterminated_quote());
{ {
auto new_line = buff.append(R"(,dom)"); auto new_line = buff.append(R"(,dom)");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(s.unterminated_quote()); CHECK(s.unterminated_quote());
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
{ {
auto new_line = buff.append(R"(",strings)"); auto new_line = buff.append(R"(",strings)");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just", "some", "ran,dom", "strings"}; expected = {"just", "some", "ran,dom", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c; ss::converter<ss::quote<'"'>, ss::escape<'\\'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just\"some","ra)"); auto vec = expect_unterminated_quote(s, R"("just\"some","ra)");
std::vector<std::string> expected{"just\"some"}; std::vector<std::string> expected{"just\"some"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
auto new_line = buff.append(R"(n,dom",str\"ings)"); auto new_line = buff.append(R"(n,dom",str\"ings)");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just\"some", "ran,dom", "str\"ings"}; expected = {"just\"some", "ran,dom", "str\"ings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c; ss::converter<ss::quote<'"'>, ss::escape<'\\'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = auto vec =
expect_unterminated_quote(s, "3,4," expect_unterminated_quote(s, "3,4,"
@ -640,89 +675,97 @@ TEST_CASE("splitter test resplit unterminated quote") {
std::vector<std::string> expected{"3", "4"}; std::vector<std::string> expected{"3", "4"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0'; auto new_line =
auto new_line = buff.append("\nx5strings\""); buff.append_overwrite_last("\nx5strings\"", c.size_shifted());
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"3", "4", "just0\n1\n22\n33333x\n4\nx5strings"}; expected = {"3", "4", "just0\n1\n22\n33333x\n4\nx5strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c; ss::converter<ss::quote<'"'>, ss::escape<'\\'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just\"some","ra"")"); auto vec = expect_unterminated_quote(s, R"("just\"some","ra"")");
std::vector<std::string> expected{"just\"some"}; std::vector<std::string> expected{"just\"some"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0'; auto new_line = buff.append_overwrite_last(R"(n,dom",str\"ings)",
auto new_line = buff.append(R"(n,dom",str\"ings)"); c.size_shifted());
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just\"some", "ra\"n,dom", "str\"ings"}; expected = {"just\"some", "ra\"n,dom", "str\"ings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::escape<'\\'>> c; ss::converter<ss::quote<'"'>, ss::escape<'\\'>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"("just\"some","r\a\a\\\a\")"); auto vec = expect_unterminated_quote(s, R"("just\"some","r\a\a\\\a\")");
std::vector<std::string> expected{"just\"some"}; std::vector<std::string> expected{"just\"some"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0'; auto new_line = buff.append_overwrite_last(R"(n,dom",str\"ings)",
auto new_line = buff.append(R"(n,dom",str\"ings)"); c.size_shifted());
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just\"some", "raa\\a\"n,dom", "str\"ings"}; expected = {"just\"some", "raa\\a\"n,dom", "str\"ings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::trim<' '>> c; ss::converter<ss::quote<'"'>, ss::trim<' '>, ss::multiline> c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"( "just" ,some, "ra )"); auto vec = expect_unterminated_quote(s, R"( "just" ,some, "ra )");
std::vector<std::string> expected{"just", "some"}; std::vector<std::string> expected{"just", "some"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
auto new_line = buff.append(R"( n,dom" , strings )"); auto new_line = buff.append(R"( n,dom" , strings )");
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"just", "some", "ra n,dom", "strings"}; expected = {"just", "some", "ra n,dom", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
{ {
ss::converter<ss::quote<'"'>, ss::trim<' '>, ss::escape<'\\'>> c; ss::converter<ss::quote<'"'>, ss::trim<' '>, ss::escape<'\\'>,
ss::multiline>
c;
auto& s = c.splitter; auto& s = c.splitter;
auto vec = expect_unterminated_quote(s, R"( "ju\"st" ,some, "ra \")"); auto vec = expect_unterminated_quote(s, R"( "ju\"st" ,some, "ra \")");
std::vector<std::string> expected{"ju\"st", "some"}; std::vector<std::string> expected{"ju\"st", "some"};
auto w = words(vec); auto w = words(vec);
w.pop_back(); w.pop_back();
CHECK(w == expected); CHECK_EQ(w, expected);
REQUIRE(s.unterminated_quote());
{ {
buff.data_[strlen(buff.data_) - c.splitter.escaped_] = '\0'; auto new_line =
auto new_line = buff.append(R"( n,dom" , strings )"); buff.append_overwrite_last(R"( n,dom" , strings )",
c.size_shifted());
vec = c.resplit(new_line, strlen(new_line)); vec = c.resplit(new_line, strlen(new_line));
CHECK(s.valid()); CHECK(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
expected = {"ju\"st", "some", "ra \" n,dom", "strings"}; expected = {"ju\"st", "some", "ra \" n,dom", "strings"};
CHECK(words(vec) == expected); CHECK_EQ(words(vec), expected);
} }
} }
} }
@ -735,28 +778,40 @@ TEST_CASE("splitter test invalid splits") {
// empty delimiter // empty delimiter
s.split(buff("some,random,strings"), ""); s.split(buff("some,random,strings"), "");
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
// mismatched delimiter // mismatched delimiter
s.split(buff(R"(some,"random,"strings")")); s.split(buff(R"(some,"random,"strings")"));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
// unterminated escape
s.split(buff(R"(some,random,strings\)"));
CHECK_FALSE(s.valid());
CHECK_FALSE(s.unterminated_quote());
CHECK_FALSE(s.error_msg().empty());
// unterminated escape
s.split(buff(R"(some,random,"strings\)"));
CHECK_FALSE(s.valid());
CHECK_FALSE(s.unterminated_quote());
CHECK_FALSE(s.error_msg().empty());
// unterminated quote // unterminated quote
s.split(buff("some,random,\"strings")); s.split(buff("some,random,\"strings"));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(s.unterminated_quote()); CHECK(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
// invalid resplit // invalid resplit
char new_line[] = "some"; char new_line[] = "some";
auto a = c.resplit(new_line, strlen(new_line)); auto a = c.resplit(new_line, strlen(new_line));
CHECK(!s.valid()); CHECK_FALSE(s.valid());
CHECK(!s.unterminated_quote()); CHECK_FALSE(s.unterminated_quote());
CHECK(!s.error_msg().empty()); CHECK_FALSE(s.error_msg().empty());
} }
TEST_CASE("splitter test with trim_left") { TEST_CASE("splitter test with trim_left") {