diff --git a/include/ss/converter.hpp b/include/ss/converter.hpp index c3614a4..fff5fbd 100644 --- a/include/ss/converter.hpp +++ b/include/ss/converter.hpp @@ -127,11 +127,6 @@ public: no_void_validator_tup_t convert( line_ptr_type line, const std::string& delim = default_delimiter) { input_ = split(line, delim); - if (!splitter_.valid()) { - set_error_line_not_split(); - no_void_validator_tup_t ret{}; - return ret; - } return convert(input_); } @@ -191,6 +186,7 @@ public: } void set_error_mode(error_mode mode) { + splitter_.set_error_mode(mode); error_mode_ = mode; } @@ -234,10 +230,10 @@ private: return error; } - void set_error_line_not_split() { + void set_error_unterminated_quote() { if (error_mode_ == error_mode::error_string) { string_error_.clear(); - string_error_.append("line not split correctly"); + string_error_.append(splitter_.error_msg()); } else { bool_error_ = true; } @@ -283,11 +279,19 @@ private: template no_void_validator_tup_t convert_impl(const split_input& elems) { clear_error(); + + if (!splitter_.valid()) { + set_error_unterminated_quote(); + no_void_validator_tup_t ret{}; + return ret; + } + if (sizeof...(Ts) != elems.size()) { set_error_number_of_colums(sizeof...(Ts), elems.size()); no_void_validator_tup_t ret{}; return ret; } + return extract_tuple(elems); } diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index a94c71c..4806b06 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -9,6 +9,8 @@ #include #include +// TODO rule of 5-3-1 +// TODO threads namespace ss { template diff --git a/include/ss/splitter.hpp b/include/ss/splitter.hpp index ae77ff2..8180590 100644 --- a/include/ss/splitter.hpp +++ b/include/ss/splitter.hpp @@ -119,7 +119,7 @@ public: } const split_input& split(line_ptr_type new_line, - const std::string& delimiter = default_delimiter) { + const std::string& delimiter = default_delimiter) { output_.clear(); return resplit(new_line, -1, delimiter); } @@ -131,8 +131,9 @@ public: } } - const split_input& resplit(line_ptr_type new_line, ssize_t new_size, - const std::string& delimiter = default_delimiter) { + const split_input& resplit( + line_ptr_type new_line, ssize_t new_size, + const std::string& delimiter = default_delimiter) { line_ = new_line; // resplitting, continue from last slice @@ -175,6 +176,16 @@ private: } } + void set_error_mismatched_quote(size_t n) { + if (error_mode_ == error_mode::error_string) { + string_error_.clear(); + string_error_.append("mismatched quote at position: " + + std::to_string(n)); + } else { + bool_error_ = true; + } + } + void set_error_unterminated_quote() { unterminated_quote_ = true; if (error_mode_ == error_mode::error_string) { @@ -186,9 +197,11 @@ private: } void set_error_invalid_resplit() { + unterminated_quote_ = false; if (error_mode_ == error_mode::error_string) { string_error_.clear(); - string_error_.append("invalid_resplit"); + string_error_.append("invalid resplit, new line must be longer" + "than the end of the last slice"); } else { bool_error_ = true; } @@ -388,9 +401,10 @@ private: // eg no trim: ...,"hello"\0 -> hello output_.emplace_back(begin_, curr_); } else { - // missmatched quote + // mismatched quote // eg: ...,"hel"lo,... -> error - // or not + set_error_mismatched_quote(end_ - line_); + output_.emplace_back(line_, begin_); } state_ = state::finished; break; diff --git a/test/test_converter.cpp b/test/test_converter.cpp index 14c28ea..e8eec52 100644 --- a/test/test_converter.cpp +++ b/test/test_converter.cpp @@ -115,6 +115,9 @@ TEST_CASE("testing invalid conversions") { c.convert(""); REQUIRE(!c.valid()); + c.convert("10", ""); + REQUIRE(!c.valid()); + c.convert(""); REQUIRE(!c.valid()); @@ -438,3 +441,24 @@ TEST_CASE("testing converter with quotes spacing and escaping") { CHECK(tup == std::make_tuple("ju,st", "so,me", 12.34, "str\"ings")); } } + +TEST_CASE("testing invalid split conversions") { + ss::converter, ss::trim<' '>, ss::quote<'"'>> c; + c.set_error_mode(ss::error_mode::error_string); + + { + // mismatched quote + auto tup = c.convert( + buff(R"( "just , some , "12.3","a" )")); + CHECK(!c.valid()); + CHECK(!c.unterminated_quote()); + } + + { + // unterminated quote + auto tup = c.convert( + buff(R"( ju\,st , "so,me" , 12.34 , "str""ings)")); + CHECK(!c.valid()); + CHECK(c.unterminated_quote()); + } +} diff --git a/test/test_helpers.hpp b/test/test_helpers.hpp index 903cde8..f9317cc 100644 --- a/test/test_helpers.hpp +++ b/test/test_helpers.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #ifdef CMAKE_GITHUB_CI @@ -8,19 +9,35 @@ #endif class buffer { - constexpr static auto buff_size = 1024; - char data_[buff_size]; + char* data_{nullptr}; public: char* operator()(const char* data) { - memset(data_, '\0', buff_size); + if (data_) { + delete[] data_; + } + data_ = new char[strlen(data) + 1]; strcpy(data_, data); return data_; } char* append(const char* data) { - strcat(data_, data); - return data_; + if (data_) { + char* new_data_ = new char[strlen(data_) + strlen(data) + 1]; + strcpy(new_data_, data_); + strcat(new_data_, data); + delete[] data_; + data_ = new_data_; + return data_; + } else { + return operator()(data); + } + } + + ~buffer() { + if (data_) { + delete[] data_; + } } }; diff --git a/test/test_splitter.cpp b/test/test_splitter.cpp index de1ff6f..82b2b10 100644 --- a/test/test_splitter.cpp +++ b/test/test_splitter.cpp @@ -668,3 +668,28 @@ TEST_CASE("testing unterminated quote") { } } } + +TEST_CASE("testing invalid splits") { + ss::splitter, ss::trim<' '>, ss::escape<'\\'>> s; + + // empty delimiter + s.split(buff("some,random,strings"), ""); + CHECK(!s.valid()); + CHECK(!s.unterminated_quote()); + + // mismatched delimiter + s.split(buff(R"(some,"random,"strings")")); + CHECK(!s.valid()); + CHECK(!s.unterminated_quote()); + + // unterminated quote + s.split(buff("some,random,\"strings")); + CHECK(!s.valid()); + CHECK(s.unterminated_quote()); + + // invalid resplit + char new_line[] = "some"; + auto a = s.resplit(new_line, strlen(new_line)); + CHECK(!s.valid()); + CHECK(!s.unterminated_quote()); +}