From 41b89d1d3db427745c0cc5feb24a9d7a9462bf03 Mon Sep 17 00:00:00 2001 From: ado Date: Sun, 9 Jul 2023 17:11:52 +0200 Subject: [PATCH] Add converter tests with throw_on_error --- include/ss/converter.hpp | 12 +- include/ss/setup.hpp | 1 + include/ss/splitter.hpp | 1 + test/test_converter.cpp | 504 ++++++++++++++++++++++++++++++++++++++- test/test_helpers.hpp | 10 + test/test_splitter.cpp | 26 +- 6 files changed, 527 insertions(+), 27 deletions(-) diff --git a/include/ss/converter.hpp b/include/ss/converter.hpp index a9e3156..ea911fd 100644 --- a/include/ss/converter.hpp +++ b/include/ss/converter.hpp @@ -121,7 +121,12 @@ public: no_void_validator_tup_t convert( line_ptr_type line, const std::string& delim = default_delimiter) { split(line, delim); - return convert(splitter_.split_data_); + if (splitter_.valid()) { + return convert(splitter_.split_data_); + } else { + set_error_bad_split(); + return {}; + } } // parses already split line, returns 'T' object with extracted values @@ -227,7 +232,7 @@ private: return error; } - void set_error_unterminated_quote() { + void set_error_bad_split() { if constexpr (string_error) { error_.clear(); error_.append(splitter_.error_msg()); @@ -340,10 +345,11 @@ private: template no_void_validator_tup_t convert_impl(const split_data& elems) { clear_error(); + // TODO check if this is needed using return_type = no_void_validator_tup_t; if (!splitter_.valid()) { - set_error_unterminated_quote(); + set_error_bad_split(); no_void_validator_tup_t ret{}; return ret; } diff --git a/include/ss/setup.hpp b/include/ss/setup.hpp index 7fd8ce4..e80da45 100644 --- a/include/ss/setup.hpp +++ b/include/ss/setup.hpp @@ -250,6 +250,7 @@ public: constexpr static bool ignore_empty = (count_ignore_empty == 1); constexpr static bool throw_on_error = (count_throw_on_error == 1); // TODO set string_error if throw_on_error is defined + // TODO throw_on_error should be unique private: #define ASSERT_MSG "cannot have the same match character in multiple matchers" diff --git a/include/ss/splitter.hpp b/include/ss/splitter.hpp index 027a7ff..af04d9d 100644 --- a/include/ss/splitter.hpp +++ b/include/ss/splitter.hpp @@ -163,6 +163,7 @@ private: } void set_error_invalid_resplit() { + // TODO check this unterminated_quote_ = false; if constexpr (string_error) { error_.clear(); diff --git a/test/test_converter.cpp b/test/test_converter.cpp index 24a9987..2dbdbca 100644 --- a/test/test_converter.cpp +++ b/test/test_converter.cpp @@ -22,6 +22,30 @@ TEST_CASE("converter test split") { } } +TEST_CASE("converter test split with exceptions") { + ss::converter c; + try { + for (const auto& [s, expected, delim] : + // clang-format off + {std::make_tuple("a,b,c,d", std::vector{"a", "b", "c", "d"}, ","), + {"", {}, " "}, + {" x x x x | x ", {" x x x x ", " x "}, "|"}, + {"a::b::c::d", {"a", "b", "c", "d"}, "::"}, + {"x\t-\ty", {"x", "y"}, "\t-\t"}, + {"x", {"x"}, ","}} // clang-format on + ) { + auto split = c.split(s, delim); + CHECK_EQ(split.size(), expected.size()); + for (size_t i = 0; i < split.size(); ++i) { + auto s = std::string(split[i].first, split[i].second); + CHECK_EQ(s, expected[i]); + } + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test valid conversions") { ss::converter c; @@ -116,12 +140,153 @@ TEST_CASE("converter test valid conversions") { } } +TEST_CASE("converter test valid conversions with exceptions") { + ss::converter c; + + try { + auto tup = c.convert("5"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("5,junk"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("junk,5"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("5\njunk\njunk", "\n"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("junk 5 junk", " "); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("junk\tjunk\t5", "\t"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = + c.convert>("junk\tjunk\t5", "\t"); + REQUIRE(c.valid()); + REQUIRE(tup.has_value()); + CHECK_EQ(tup, 5); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("5,6.6,junk"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(5, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("5,junk,6.6"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(5, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("junk;5;6.6", ";"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(5, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = + c.convert, double>("junk;5;6.6", ";"); + REQUIRE(c.valid()); + REQUIRE(std::get<0>(tup).has_value()); + CHECK_EQ(tup, std::make_tuple(5, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = + c.convert, double>("junk;5.4;6.6", ";"); + REQUIRE(c.valid()); + REQUIRE_FALSE(std::get<0>(tup).has_value()); + CHECK_EQ(tup, std::make_tuple(std::optional{}, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = + c.convert, double>("junk;5;6.6", + ";"); + REQUIRE(c.valid()); + REQUIRE(std::holds_alternative(std::get<0>(tup))); + CHECK_EQ(tup, std::make_tuple(std::variant{5}, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = + c.convert, double>("junk;5.5;6.6", + ";"); + REQUIRE(c.valid()); + REQUIRE(std::holds_alternative(std::get<0>(tup))); + CHECK_EQ(tup, std::make_tuple(std::variant{5.5}, 6.6)); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + auto tup = c.convert("junk;s1;6.6;s2", ";"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(std::string_view{"s1"}, 6.6, + std::string_view{"s2"})); + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test invalid conversions") { ss::converter c; c.convert(""); REQUIRE_FALSE(c.valid()); + c.convert("1", ""); + REQUIRE_FALSE(c.valid()); + c.convert("10", ""); REQUIRE_FALSE(c.valid()); @@ -150,6 +315,24 @@ TEST_CASE("converter test invalid conversions") { REQUIRE_FALSE(c.valid()); } +TEST_CASE("converter test invalid conversions with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert("")); + REQUIRE_EXCEPTION(c.convert("1", "")); + REQUIRE_EXCEPTION(c.convert("10", "")); + REQUIRE_EXCEPTION(c.convert("")); + REQUIRE_EXCEPTION(c.convert(",junk")); + REQUIRE_EXCEPTION(c.convert("junk,")); + REQUIRE_EXCEPTION(c.convert("x")); + REQUIRE_EXCEPTION(c.convert("x")); + REQUIRE_EXCEPTION(c.convert("x,junk")); + REQUIRE_EXCEPTION(c.convert("junk,x")); + REQUIRE_EXCEPTION( + c.convert, double>("junk;.5.5;6", ";")); +} + TEST_CASE("converter test ss:ax restriction (all except)") { ss::converter c; @@ -181,6 +364,33 @@ TEST_CASE("converter test ss:ax restriction (all except)") { } } +TEST_CASE("converter test ss:ax restriction (all except) with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("0")); + REQUIRE_EXCEPTION(c.convert>("1")); + REQUIRE_EXCEPTION(c.convert>("junk,c,1")); + REQUIRE_EXCEPTION(c.convert, char>("1,c")); + + try { + { + int tup = c.convert>("3"); + CHECK_EQ(tup, 3); + } + { + std::tuple tup = c.convert>("c,3"); + CHECK_EQ(tup, std::make_tuple('c', 3)); + } + { + std::tuple tup = c.convert, char>("3,c"); + CHECK_EQ(tup, std::make_tuple(3, 'c')); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test ss:nx restriction (none except)") { ss::converter c; @@ -215,6 +425,40 @@ TEST_CASE("converter test ss:nx restriction (none except)") { } } +TEST_CASE("converter test ss:nx restriction (none except) with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("c,3")); + REQUIRE_EXCEPTION(c.convert, char>("3,c")); + + try { + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + { + auto tup = c.convert>("2"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 2); + } + { + auto tup = c.convert>("c,junk,1"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple('c', 1)); + } + { + auto tup = c.convert, char>("1,c"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(1, 'c')); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test ss:ir restriction (in range)") { ss::converter c; @@ -249,6 +493,40 @@ TEST_CASE("converter test ss:ir restriction (in range)") { } } +TEST_CASE("converter test ss:ir restriction (in range) with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("c,3")); + REQUIRE_EXCEPTION(c.convert, char>("3,c")); + + try { + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + { + auto tup = c.convert>("2"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 2); + } + { + auto tup = c.convert>("c,junk,1"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple('c', 1)); + } + { + auto tup = c.convert, char>("1,c"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(1, 'c')); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test ss:oor restriction (out of range)") { ss::converter c; @@ -283,6 +561,38 @@ TEST_CASE("converter test ss:oor restriction (out of range)") { } } +TEST_CASE("converter test ss:oor restriction (out of range) with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("2")); + REQUIRE_EXCEPTION(c.convert, void>("c,1,junk")); + REQUIRE_EXCEPTION(c.convert, char>("1,c")); + + try { + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("c,junk,3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple('c', 3)); + } + + { + auto tup = c.convert, char>("3,c"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(3, 'c')); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + const std::vector extracted_vector = {1, 2, 3}; // custom extract @@ -331,6 +641,38 @@ TEST_CASE("converter test ss:ne restriction (not empty)") { } } +TEST_CASE("converter test ss:ne restriction (not empty) with exceptions") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("")); + REQUIRE_EXCEPTION(c.convert>("3,")); + REQUIRE_EXCEPTION(c.convert, int>(",3")); + REQUIRE_EXCEPTION(c.convert, int>("junk,,3")); + REQUIRE_EXCEPTION(c.convert>>("")); + + try { + { + auto tup = c.convert>("s"); + REQUIRE(c.valid()); + CHECK_EQ(tup, "s"); + } + { + auto tup = + c.convert, ss::ne>("1,s"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple(1, "s")); + } + { + auto tup = c.convert>>("{1 2 3}"); + REQUIRE(c.valid()); + CHECK_EQ(tup, extracted_vector); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE( "converter test ss:lt ss::lte ss::gt ss::gte restriction (in range)") { ss::converter c; @@ -390,6 +732,59 @@ TEST_CASE( } } +TEST_CASE("converter test ss:lt ss::lte ss::gt ss::gte restriction (in range) " + "with exception") { + // TODO remove ss::string_error + ss::converter c; + + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("3")); + REQUIRE_EXCEPTION(c.convert>("3")); + + try { + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + + { + auto tup = c.convert>("3"); + REQUIRE(c.valid()); + CHECK_EQ(tup, 3); + } + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test error mode") { ss::converter c; c.convert("junk"); @@ -397,6 +792,12 @@ TEST_CASE("converter test error mode") { CHECK_FALSE(c.error_msg().empty()); } +TEST_CASE("converter test throw on error mode") { + // TODO remove ss::string_error + ss::converter c; + REQUIRE_EXCEPTION(c.convert("junk")); +} + TEST_CASE("converter test converter with quotes spacing and escaping") { { ss::converter c; @@ -444,6 +845,67 @@ TEST_CASE("converter test converter with quotes spacing and escaping") { } } +TEST_CASE("converter test converter with quotes spacing and escaping with " + "exceptions") { + // TODO remove ss::string_error on all below + try { + ss::converter c; + + auto tup = c.convert( + R"("just","some","strings")"); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple("\"just\"", "\"some\"", "\"strings\"")); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + ss::converter> c; + + auto tup = c.convert( + buff(R"("just",some,"12.3","a")")); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple("just", "some", 12.3, 'a')); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + ss::converter> c; + + auto tup = c.convert( + buff(R"( just , some , 12.3 ,a )")); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple("just", "some", 12.3, 'a')); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + ss::converter> c; + + auto tup = + c.convert(buff(R"(ju\,st,strings)")); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple("ju,st", "strings")); + } catch (ss::exception& e) { + FAIL(e.what()); + } + + try { + ss::converter, + ss::trim<' '>, ss::quote<'"'>> + c; + + auto tup = c.convert( + buff(R"( ju\,st , "so,me" , 12.34 , "str""ings")")); + REQUIRE(c.valid()); + CHECK_EQ(tup, std::make_tuple("ju,st", "so,me", 12.34, "str\"ings")); + } catch (ss::exception& e) { + FAIL(e.what()); + } +} + TEST_CASE("converter test invalid split conversions") { ss::converter, ss::trim<' '>, ss::quote<'"'>> @@ -451,7 +913,7 @@ TEST_CASE("converter test invalid split conversions") { { // mismatched quote - auto tup = c.convert( + c.convert( buff(R"( "just , some , "12.3","a" )")); CHECK_FALSE(c.valid()); CHECK_FALSE(c.unterminated_quote()); @@ -460,7 +922,7 @@ TEST_CASE("converter test invalid split conversions") { { // unterminated quote - auto tup = c.convert( + c.convert( buff(R"( ju\,st , "so,me" , 12.34 , "str""ings)")); CHECK_FALSE(c.valid()); CHECK(c.unterminated_quote()); @@ -469,7 +931,7 @@ TEST_CASE("converter test invalid split conversions") { { // unterminated escape - auto tup = c.convert( + c.convert( buff(R"(just,some,2,strings\)")); CHECK_FALSE(c.valid()); CHECK_FALSE(c.unterminated_quote()); @@ -478,7 +940,7 @@ TEST_CASE("converter test invalid split conversions") { { // unterminated escape while quoting - auto tup = c.convert( + c.convert( buff(R"(just,some,2,"strings\)")); CHECK_FALSE(c.valid()); CHECK_FALSE(c.unterminated_quote()); @@ -487,10 +949,42 @@ TEST_CASE("converter test invalid split conversions") { { // unterminated escaped quote - auto tup = c.convert( + c.convert( buff(R"(just,some,2,"strings\")")); CHECK_FALSE(c.valid()); CHECK(c.unterminated_quote()); CHECK_FALSE(c.error_msg().empty()); } } + +TEST_CASE("converter test invalid split conversions with exceptions") { + // TODO remove ss::string_error + ss::converter, ss::trim<' '>, + ss::quote<'"'>, ss::throw_on_error> + c; + + // mismatched quote + REQUIRE_EXCEPTION(c.convert( + buff(R"( "just , some , "12.3","a" )"))); + CHECK_FALSE(c.unterminated_quote()); + + // unterminated quote + REQUIRE_EXCEPTION(c.convert( + buff(R"( ju\,st , "so,me" , 12.34 , "str""ings)"))); + CHECK(c.unterminated_quote()); + + // unterminated escape + REQUIRE_EXCEPTION(c.convert( + buff(R"(just,some,2,strings\)"))); + CHECK_FALSE(c.unterminated_quote()); + + // unterminated escape while quoting + REQUIRE_EXCEPTION(c.convert( + buff(R"(just,some,2,"strings\)"))); + CHECK_FALSE(c.unterminated_quote()); + + // unterminated escaped quote + REQUIRE_EXCEPTION(c.convert( + buff(R"(just,some,2,"strings\")"))); + CHECK(c.unterminated_quote()); +} diff --git a/test/test_helpers.hpp b/test/test_helpers.hpp index 06ea703..8cab8bf 100644 --- a/test/test_helpers.hpp +++ b/test/test_helpers.hpp @@ -79,3 +79,13 @@ struct buffer { } #define CHECK_NOT_VARIANT(var, type) CHECK(!std::holds_alternative(var)); +// TODO remove +#include + +#define REQUIRE_EXCEPTION(...) \ + try { \ + __VA_ARGS__; \ + FAIL("Expected exception"); \ + } catch (ss::exception & e) { \ + CHECK_FALSE(std::string{e.what()}.empty()); \ + } diff --git a/test/test_splitter.cpp b/test/test_splitter.cpp index ecf2a22..4a75f6b 100644 --- a/test/test_splitter.cpp +++ b/test/test_splitter.cpp @@ -525,10 +525,8 @@ TEST_CASE("splitter test error mode") { s.split(buff("just,some,strings"), ""); FAIL("expected exception"); } catch (ss::exception& e) { - CHECK_EQ(std::string{e.what()}, s.error_msg()); - CHECK_FALSE(s.valid()); + CHECK_FALSE(std::string{e.what()}.empty()); CHECK_FALSE(s.unterminated_quote()); - CHECK_FALSE(s.error_msg().empty()); } } @@ -1107,15 +1105,6 @@ TEST_CASE("splitter test invalid splits") { CHECK_FALSE(s.error_msg().empty()); } -#define CHECK_EXCEPTION(CLASS, OPERATION) \ - try { \ - OPERATION; \ - } catch (ss::exception & e) { \ - CHECK_FALSE(CLASS.valid()); \ - CHECK_FALSE(CLASS.error_msg().empty()); \ - CHECK_EQ(CLASS.error_msg(), std::string{e.what()}); \ - } - TEST_CASE("splitter test invalid splits with exceptions") { ss::converter, ss::trim<' '>, ss::escape<'\\'>, ss::throw_on_error> @@ -1123,28 +1112,28 @@ TEST_CASE("splitter test invalid splits with exceptions") { auto& s = c.splitter; // empty delimiter - CHECK_EXCEPTION(s, s.split(buff("some,random,strings"), "")); + REQUIRE_EXCEPTION(s.split(buff("some,random,strings"), "")); CHECK_FALSE(s.unterminated_quote()); // mismatched delimiter - CHECK_EXCEPTION(s, s.split(buff(R"(some,"random,"strings")"))); + REQUIRE_EXCEPTION(s.split(buff(R"(some,"random,"strings")"))); CHECK_FALSE(s.unterminated_quote()); // unterminated escape - CHECK_EXCEPTION(s, s.split(buff(R"(some,random,strings\)"))); + REQUIRE_EXCEPTION(s.split(buff(R"(some,random,strings\)"))); CHECK_FALSE(s.unterminated_quote()); // unterminated escape - CHECK_EXCEPTION(s, s.split(buff(R"(some,random,"strings\)"))); + REQUIRE_EXCEPTION(s.split(buff(R"(some,random,"strings\)"))); CHECK_FALSE(s.unterminated_quote()); // unterminated quote - CHECK_EXCEPTION(s, s.split(buff("some,random,\"strings"))); + REQUIRE_EXCEPTION(s.split(buff("some,random,\"strings"))); CHECK(s.unterminated_quote()); // invalid resplit char new_line[] = "some"; - CHECK_EXCEPTION(s, c.resplit(new_line, strlen(new_line))); + REQUIRE_EXCEPTION(c.resplit(new_line, strlen(new_line))); CHECK_FALSE(s.unterminated_quote()); } @@ -1248,4 +1237,3 @@ TEST_CASE("splitter test with quote and escape, trim_left and trim_right") { ss::trim_right<'-'>>(p, delims); } } -