mirror of
				https://github.com/red0124/ssp.git
				synced 2025-10-31 05:06:46 +01:00 
			
		
		
		
	add splitter, update converter and parser, update unit tests
This commit is contained in:
		
							parent
							
								
									cd264faa70
								
							
						
					
					
						commit
						69d6df12be
					
				| @ -1,17 +1,4 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| // TODO remove
 | ||||
| #include <iostream> | ||||
| #ifndef DBG | ||||
| void log(const std::string& log) { | ||||
|     std::cout << log << std::endl; | ||||
| } | ||||
| #else | ||||
| void log(const std::string&) { | ||||
| } | ||||
| #endif | ||||
| //
 | ||||
| //
 | ||||
| #include "extract.hpp" | ||||
| #include "function_traits.hpp" | ||||
| #include "restrictions.hpp" | ||||
| @ -20,10 +7,6 @@ void log(const std::string&) { | ||||
| #include <type_traits> | ||||
| #include <vector> | ||||
| 
 | ||||
| constexpr auto space = '_'; | ||||
| constexpr auto escaping = true; | ||||
| constexpr auto quote = '"'; | ||||
| 
 | ||||
| namespace ss { | ||||
| INIT_HAS_METHOD(tied); | ||||
| INIT_HAS_METHOD(ss_valid); | ||||
| @ -122,29 +105,368 @@ constexpr bool tied_class_v = tied_class<Ts...>::value; | ||||
| // the error can be set inside a string, or a bool
 | ||||
| enum class error_mode { error_string, error_bool }; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////////////////
 | ||||
| template <char... Cs> | ||||
| struct matcher { | ||||
| private: | ||||
|     template <char X, char... Xs> | ||||
|     static bool match_impl(char c) { | ||||
|         if constexpr (sizeof...(Xs) != 0) { | ||||
|             return (c == X) || match_impl<Xs...>(c); | ||||
|         } | ||||
|         return (c == X); | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     static bool match(char c) { | ||||
|         return match_impl<Cs...>(c); | ||||
|     } | ||||
|     constexpr static bool enabled = true; | ||||
| }; | ||||
| 
 | ||||
| template <> | ||||
| class matcher<'\0'> { | ||||
| public: | ||||
|     constexpr static bool enabled = false; | ||||
|     static bool match(char c) = delete; | ||||
| }; | ||||
| 
 | ||||
| ////////////////
 | ||||
| // is instance of
 | ||||
| ////////////////
 | ||||
| 
 | ||||
| template <typename T, template <char...> class Template> | ||||
| struct is_instance_of_char { | ||||
|     constexpr static bool value = false; | ||||
| }; | ||||
| 
 | ||||
| template <char... Ts, template <char...> class Template> | ||||
| struct is_instance_of_char<Template<Ts...>, Template> { | ||||
|     constexpr static bool value = true; | ||||
| }; | ||||
| 
 | ||||
| ///////////////////////////////////////////////////
 | ||||
| 
 | ||||
| template <char... Cs> | ||||
| struct quote : matcher<Cs...> {}; | ||||
| 
 | ||||
| template <char... Cs> | ||||
| struct trim : matcher<Cs...> {}; | ||||
| 
 | ||||
| template <char... Cs> | ||||
| struct escape : matcher<Cs...> {}; | ||||
| 
 | ||||
| /////////////////////////////////////////////////
 | ||||
| // -> type traits
 | ||||
| template <bool B, typename T, typename U> | ||||
| struct if_then_else; | ||||
| 
 | ||||
| template <typename T, typename U> | ||||
| struct if_then_else<true, T, U> { | ||||
|     using type = T; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename U> | ||||
| struct if_then_else<false, T, U> { | ||||
|     using type = U; | ||||
| }; | ||||
| 
 | ||||
| //////////////////////////////////////////////
 | ||||
| template <template <char...> class Matcher, typename... Ts> | ||||
| struct get_matcher; | ||||
| 
 | ||||
| template <template <char...> class Matcher, typename T, typename... Ts> | ||||
| struct get_matcher<Matcher, T, Ts...> { | ||||
|     using type = | ||||
|         typename if_then_else<is_instance_of_char<T, Matcher>::value, T, | ||||
|                               typename get_matcher<Matcher, Ts...>::type>::type; | ||||
| }; | ||||
| 
 | ||||
| template <template <char...> class Matcher> | ||||
| struct get_matcher<Matcher> { | ||||
|     using type = Matcher<'\0'>; | ||||
| }; | ||||
| 
 | ||||
| ///////////////////////////////////////////////
 | ||||
| // TODO add restriction
 | ||||
| template <typename... Ts> | ||||
| struct setup { | ||||
|     using quote = typename get_matcher<quote, Ts...>::type; | ||||
|     using trim = typename get_matcher<trim, Ts...>::type; | ||||
|     using escape = typename get_matcher<escape, Ts...>::type; | ||||
| }; | ||||
| 
 | ||||
| template <typename... Ts> | ||||
| struct setup<setup<Ts...>> : setup<Ts...> {}; | ||||
| 
 | ||||
| /////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| enum class State { finished, begin, reading, quoting }; | ||||
| using range = std::pair<const char*, const char*>; | ||||
| 
 | ||||
| using string_range = std::pair<const char*, const char*>; | ||||
| using split_input = std::vector<string_range>; | ||||
| 
 | ||||
| template <typename... Ts> | ||||
| class splitter { | ||||
|     using Setup = setup<Ts...>; | ||||
|     using quote = typename Setup::quote; | ||||
|     using trim = typename Setup::trim; | ||||
|     using escape = typename Setup::escape; | ||||
| 
 | ||||
|     bool match(const char* end_i, char delim) { | ||||
|         return *end_i == delim; | ||||
|     }; | ||||
| 
 | ||||
|     bool match(const char* end_i, const std::string& delim) { | ||||
|         return strncmp(end_i, delim.c_str(), delim.size()) == 0; | ||||
|     }; | ||||
| 
 | ||||
|     size_t delimiter_size(char) { | ||||
|         return 1; | ||||
|     } | ||||
|     size_t delimiter_size(const std::string& delim) { | ||||
|         return delim.size(); | ||||
|     } | ||||
| 
 | ||||
|     void trim_if_enabled(char*& curr) { | ||||
|         if constexpr (trim::enabled) { | ||||
|             while (trim::match(*curr)) { | ||||
|                 ++curr; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void shift_if_escaped(char*& curr_i) { | ||||
|         if constexpr (escape::enabled) { | ||||
|             if (escape::match(*curr_i)) { | ||||
|                 *curr = end[1]; | ||||
|                 ++end; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void shift() { | ||||
|         *curr = *end; | ||||
|         ++end; | ||||
|         ++curr; | ||||
|     } | ||||
| 
 | ||||
|     void shift(size_t n) { | ||||
|         memcpy(curr, end, n); | ||||
|         end += n; | ||||
|         curr += n; | ||||
|     } | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     std::tuple<size_t, bool> match_delimiter(char* begin, const Delim& delim) { | ||||
|         char* end_i = begin; | ||||
| 
 | ||||
|         trim_if_enabled(end_i); | ||||
| 
 | ||||
|         // just spacing
 | ||||
|         if (*end_i == '\0') { | ||||
|             return {0, false}; | ||||
|         } | ||||
| 
 | ||||
|         // not a delimiter
 | ||||
|         if (!match(end_i, delim)) { | ||||
|             shift_if_escaped(end_i); | ||||
|             return {1 + end_i - begin, false}; | ||||
|         } | ||||
| 
 | ||||
|         end_i += delimiter_size(delim); | ||||
|         trim_if_enabled(end_i); | ||||
| 
 | ||||
|         // delimiter
 | ||||
|         return {end_i - begin, true}; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     bool valid() { | ||||
|         return error_.empty(); | ||||
|     } | ||||
| 
 | ||||
|     split_input& split(char* new_line, const std::string& d = ",") { | ||||
|         line = new_line; | ||||
|         output_.clear(); | ||||
|         switch (d.size()) { | ||||
|         case 0: | ||||
|             // set error
 | ||||
|             return output_; | ||||
|         case 1: | ||||
|             return split_impl(d[0]); | ||||
|         default: | ||||
|             return split_impl(d); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     std::vector<range>& split_impl(const Delim& delim) { | ||||
|         state = State::begin; | ||||
|         begin = line; | ||||
| 
 | ||||
|         trim_if_enabled(begin); | ||||
| 
 | ||||
|         while (state != State::finished) { | ||||
|             curr = end = begin; | ||||
|             switch (state) { | ||||
|             case (State::begin): | ||||
|                 state_begin(); | ||||
|                 break; | ||||
|             case (State::reading): | ||||
|                 state_reading(delim); | ||||
|                 break; | ||||
|             case (State::quoting): | ||||
|                 state_quoting(delim); | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         return output_; | ||||
|     } | ||||
| 
 | ||||
|     void state_begin() { | ||||
|         if constexpr (quote::enabled) { | ||||
|             if (quote::match(*begin)) { | ||||
|                 ++begin; | ||||
|                 state = State::quoting; | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         state = State::reading; | ||||
|     } | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     void state_reading(const Delim& delim) { | ||||
|         while (true) { | ||||
|             auto [width, valid] = match_delimiter(end, delim); | ||||
| 
 | ||||
|             // not a delimiter
 | ||||
|             if (!valid) { | ||||
|                 if (width == 0) { | ||||
|                     // eol
 | ||||
|                     output_.emplace_back(begin, curr); | ||||
|                     state = State::finished; | ||||
|                     break; | ||||
|                 } else { | ||||
|                     shift(width); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // found delimiter
 | ||||
|             push_and_start_next(width); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     void state_quoting(const Delim& delim) { | ||||
|         if constexpr (quote::enabled) { | ||||
|             while (true) { | ||||
|                 if (quote::match(*end)) { | ||||
|                     // double quote
 | ||||
|                     // eg: ...,"hel""lo,... -> hel"lo
 | ||||
|                     if (quote::match(end[1])) { | ||||
|                         ++end; | ||||
|                         shift(); | ||||
|                         continue; | ||||
|                     } | ||||
| 
 | ||||
|                     auto [width, valid] = match_delimiter(end + 1, delim); | ||||
| 
 | ||||
|                     // not a delimiter
 | ||||
|                     if (!valid) { | ||||
|                         if (width == 0) { | ||||
|                             // eol
 | ||||
|                             // eg: ...,"hello"   \0 -> hello
 | ||||
|                             // eg no trim: ...,"hello"\0 -> hello
 | ||||
|                             output_.emplace_back(begin, curr); | ||||
|                         } else { | ||||
|                             // missmatched quote
 | ||||
|                             // eg: ...,"hel"lo,... -> error
 | ||||
|                         } | ||||
|                         state = State::finished; | ||||
|                         break; | ||||
|                     } | ||||
| 
 | ||||
|                     // delimiter
 | ||||
|                     push_and_start_next(width + 1); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 if constexpr (escape::enabled) { | ||||
|                     if (escape::match(*end)) { | ||||
|                         ++end; | ||||
|                         shift(); | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // unterminated error
 | ||||
|                 // eg: ..."hell\0 -> quote not terminated
 | ||||
|                 if (*end == '\0') { | ||||
|                     *curr = '\0'; | ||||
|                     state = State::finished; | ||||
|                     break; | ||||
|                 } | ||||
|                 shift(); | ||||
|             } | ||||
|         } else { | ||||
|             // set error impossible scenario
 | ||||
|             state = State::finished; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void push_and_start_next(size_t n) { | ||||
|         output_.emplace_back(begin, curr); | ||||
|         begin = end + n; | ||||
|         state = State::begin; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::vector<range> output_; | ||||
|     std::string error_ = ""; | ||||
|     State state; | ||||
|     char* curr; | ||||
|     char* end; | ||||
|     char* begin; | ||||
|     char* line; | ||||
| }; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| ////////////////
 | ||||
| // converter
 | ||||
| ////////////////
 | ||||
| 
 | ||||
| template <typename... Matchers> | ||||
| class converter { | ||||
|     using string_range = std::pair<const char*, const char*>; | ||||
|     constexpr static auto default_delimiter = ','; | ||||
|     constexpr static auto default_delimiter = ","; | ||||
| 
 | ||||
| public: | ||||
|     using split_input = std::vector<string_range>; | ||||
| 
 | ||||
|     // parses line with given delimiter, returns a 'T' object created with
 | ||||
|     // extracted values of type 'Ts'
 | ||||
|     template <typename T, typename... Ts> | ||||
|     T convert_object(const char* const line, const std::string& delim = "") { | ||||
|     T convert_object(char* line, const std::string& delim = default_delimiter) { | ||||
|         return to_object<T>(convert<Ts...>(line, delim)); | ||||
|     } | ||||
| 
 | ||||
|     // parses line with given delimiter, returns tuple of objects with
 | ||||
|     // extracted values of type 'Ts'
 | ||||
|     template <typename... Ts> | ||||
|     no_void_validator_tup_t<Ts...> convert(const char* const line, | ||||
|                                            const std::string& delim = "") { | ||||
|     no_void_validator_tup_t<Ts...> convert( | ||||
|         char* line, const std::string& delim = default_delimiter) { | ||||
|         input_ = split(line, delim); | ||||
|         return convert<Ts...>(input_); | ||||
|     } | ||||
| @ -205,21 +527,15 @@ public: | ||||
| 
 | ||||
|     // 'splits' string by given delimiter, returns vector of pairs which
 | ||||
|     // contain the beginnings and the ends of each column of the string
 | ||||
|     const split_input& split(const char* const line, | ||||
|                              const std::string& delim = "") { | ||||
|     const split_input& split(char* line, | ||||
|                              const std::string& delim = default_delimiter) { | ||||
|         input_.clear(); | ||||
|         if (line[0] == '\0') { | ||||
|             return input_; | ||||
|         } | ||||
| 
 | ||||
|         switch (delim.size()) { | ||||
|         case 0: | ||||
|             return split_impl(line, ','); | ||||
|         case 1: | ||||
|             return split_impl(line, delim[0]); | ||||
|         default: | ||||
|             return split_impl(line, delim, delim.size()); | ||||
|         }; | ||||
|         input_ = splitter_.split(line, delim); | ||||
|         return input_; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
| @ -316,116 +632,6 @@ private: | ||||
|         return convert_impl<Ts...>(elems); | ||||
|     } | ||||
| 
 | ||||
|     ////////////////
 | ||||
|     // substring
 | ||||
|     ////////////////
 | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     const split_input& split_impl(const char* const line, Delim delim, | ||||
|                                   size_t delim_size = 1) { | ||||
|         auto [range, begin] = substring(line, delim); | ||||
|         input_.push_back(range); | ||||
|         while (range.second[0] != '\0') { | ||||
|             if constexpr (quote != '\0') { | ||||
|                 if (*begin == quote) { | ||||
|                     ++begin; | ||||
|                 } | ||||
|                 if (*begin == '\0') { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             std::tie(range, begin) = substring(begin + delim_size, delim); | ||||
|             log("-> " + std::string{range.first, range.second}); | ||||
|             input_.push_back(range); | ||||
|         } | ||||
|         return input_; | ||||
|     } | ||||
| 
 | ||||
|     size_t match(const char* begin, char delim) const { | ||||
|         const char* p = begin; | ||||
|         if constexpr (space == '\0') { | ||||
|             if (*p == delim) { | ||||
|                 return 1; | ||||
|             } | ||||
|         } else { | ||||
|             while (*p == space) { | ||||
|                 ++p; | ||||
|             } | ||||
|             if (*p == '\0') { | ||||
|                 return p - begin; | ||||
|             } | ||||
|             if (*p != delim) { | ||||
|                 return 0; | ||||
|             } | ||||
|             do | ||||
|                 ++p; | ||||
|             while (*p == space); | ||||
|             return p - begin; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     size_t match(const char* end, const std::string& delim) const { | ||||
|         // TODO
 | ||||
|         log("ahamm"); | ||||
|         return strncmp(end, delim.c_str(), delim.size()) != 0; | ||||
|     } | ||||
| 
 | ||||
|     template <typename Delim> | ||||
|     std::tuple<string_range, const char*> substring(const char* begin, | ||||
|                                                     Delim delim) { | ||||
|         const char* end; | ||||
|         const char* i; | ||||
|         for (i = begin; *i != '\0'; ++i) | ||||
|             ; | ||||
|         log(">> " + std::string{begin, i}); | ||||
|         if constexpr (quote != '\0') { | ||||
|             if (*begin == quote) { | ||||
|                 ++begin; | ||||
| 
 | ||||
|                 for (end = begin; true; ++end) { | ||||
| 
 | ||||
|                     if (*end == '\0') { | ||||
|                         log("error"); | ||||
|                         set_error_unterminated_quote(); | ||||
|                         return {string_range{begin, end}, end}; | ||||
|                     } | ||||
| 
 | ||||
|                     if constexpr (escaping) { | ||||
|                         if (end[-1] == '\\') { | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (*end == quote) { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // end is not \0
 | ||||
|                 size_t to_ignore = match(end + 1, delim); | ||||
|                 log(std::to_string(to_ignore)); | ||||
|                 if (to_ignore != 0) { | ||||
|                     return {string_range{begin, end}, end + to_ignore}; | ||||
|                 } | ||||
| 
 | ||||
|                 log("error"); | ||||
|                 set_error_invalid_quotation(); | ||||
|                 return {string_range{begin, end}, end}; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (end = begin; *end != '\0'; ++end) { | ||||
|             size_t to_ignore = match(end, delim); | ||||
|             log(std::to_string(to_ignore)); | ||||
|             if (to_ignore != 0) { | ||||
|                 return {string_range{begin, end}, end + to_ignore}; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return {string_range{begin, end}, end}; | ||||
|     } | ||||
| 
 | ||||
|     ////////////////
 | ||||
|     // conversion
 | ||||
|     ////////////////
 | ||||
| @ -437,6 +643,11 @@ private: | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if constexpr (std::is_same_v<T, std::string>) { | ||||
|             extract(msg.first, msg.second, dst); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!extract(msg.first, msg.second, dst)) { | ||||
|             set_error_invalid_conversion(msg, pos); | ||||
|             return; | ||||
| @ -494,17 +705,7 @@ private: | ||||
|     std::string string_error_; | ||||
|     bool bool_error_; | ||||
|     enum error_mode error_mode_ { error_mode::error_bool }; | ||||
|     splitter<Matchers...> splitter_; | ||||
| }; | ||||
| 
 | ||||
| template <> | ||||
| inline void converter::extract_one<std::string>(std::string& dst, | ||||
|                                                 const string_range msg, | ||||
|                                                 size_t) { | ||||
|     if (!valid()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     extract(msg.first, msg.second, dst); | ||||
| } | ||||
| 
 | ||||
| } /* ss */ | ||||
|  | ||||
| @ -250,8 +250,8 @@ private: | ||||
|         char* buffer_{nullptr}; | ||||
|         char* next_line_buffer_{nullptr}; | ||||
| 
 | ||||
|         converter converter_; | ||||
|         converter next_line_converter_; | ||||
|         converter<> converter_; | ||||
|         converter<> next_line_converter_; | ||||
| 
 | ||||
|         size_t size_{0}; | ||||
|         const std::string& delim_; | ||||
| @ -288,7 +288,7 @@ private: | ||||
|             next_line_converter_.set_error_mode(mode); | ||||
|         } | ||||
| 
 | ||||
|         converter& get_converter() { | ||||
|         converter<>& get_converter() { | ||||
|             return converter_; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| CXX=clang++-9 | ||||
| CXXFLAGS=-Wall -Wextra -std=c++17 -O0 -lstdc++fs | ||||
| TESTS=test_converter | ||||
| CXX=clang++ | ||||
| CXXFLAGS=-Wall -Wextra -std=c++17 -lstdc++fs | ||||
| TESTS=test_parser test_converter test_extractions | ||||
| 
 | ||||
| all: $(TESTS) | ||||
| 
 | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -4,13 +4,29 @@ | ||||
| #include "doctest.h" | ||||
| #include <algorithm> | ||||
| 
 | ||||
| /* TODO
 | ||||
| TEST_CASE("testing quoting with escaping") { | ||||
|     std::vector<std::string> values{"10",          "he\\\"llo", "\\\"", | ||||
|                                     "\\\"a,a\\\"", "3.33",      "a\\\""}; | ||||
| class buffer { | ||||
|     constexpr static auto buff_size = 1024; | ||||
|     char data_[buff_size]; | ||||
| 
 | ||||
| public: | ||||
|     char* operator()(const char* data) { | ||||
|         memset(data_, '\0', buff_size); | ||||
|         strcpy(data_, data); | ||||
|         return data_; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| buffer buff; | ||||
| 
 | ||||
| TEST_CASE("testing splitter with escaping") { | ||||
|     std::vector<std::string> values{"10",   "he\\\"llo", | ||||
|                                     "\\\"", "\\\"a\\,a\\\"", | ||||
|                                     "3.33", "a\\\""}; | ||||
| 
 | ||||
|     char buff[128]; | ||||
|     // with quote
 | ||||
|     ss::converter c; | ||||
|     ss::splitter<ss::quote<'"'>, ss::escape<'\\'>> s; | ||||
|     std::string delim = ","; | ||||
|     for (size_t i = 0; i < values.size() * values.size(); ++i) { | ||||
|         std::string input1; | ||||
|         std::string input2; | ||||
| @ -22,44 +38,25 @@ TEST_CASE("testing quoting with escaping") { | ||||
|                 input1.append("\"" + values[j] + "\""); | ||||
|                 input2.append("\"" + values.at(values.size() - 1 - j) + "\""); | ||||
|             } | ||||
|             input1.push_back(','); | ||||
|             input2.push_back(','); | ||||
|             input1.append(delim); | ||||
|             input2.append(delim); | ||||
|         } | ||||
|         input1.pop_back(); | ||||
|         input2.pop_back(); | ||||
|         input1.append("\0\""); | ||||
|         input2.append("\0\""); | ||||
| 
 | ||||
|         auto tup1 = c.convert<int, std::string, std::string, std::string, | ||||
|                               double, std::string>(input1.c_str(), ","); | ||||
|         if (!c.valid()) { | ||||
|             FAIL("invalid: " + input1); | ||||
|         } else { | ||||
|             auto [a, b, c, d, e, f] = tup1; | ||||
|             CHECK(a == 10); | ||||
|             CHECK(b == "he\"llo"); | ||||
|             CHECK(c == "\""); | ||||
|             CHECK(d == "\"a,a\""); | ||||
|             CHECK(e == 3.33); | ||||
|             CHECK(f == "a\""); | ||||
|             std::cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' << e | ||||
|                       << ' ' << f << std::endl; | ||||
|             CHECK(tup1 == | ||||
|                   std::make_tuple(10, "he\"llo", "\"", "\"a,a\"", 3.33, "a\"")); | ||||
|         } | ||||
|         memcpy(buff, input1.c_str(), input1.size() + 1); | ||||
|         auto tup1 = s.split(buff, delim); | ||||
|         CHECK(tup1.size() == 6); | ||||
| 
 | ||||
|         auto tup2 = c.convert<std::string, double, std::string, std::string, | ||||
|                               std::string, int>(input2.c_str(), ","); | ||||
|         if (!c.valid()) { | ||||
|             FAIL("invalid: " + input2); | ||||
|         } else { | ||||
|             CHECK(tup2 == | ||||
|                   std::make_tuple("a\"", 3.33, "\"a,a\"", "\"", "he\"llo", 10)); | ||||
|         } | ||||
|         memcpy(buff, input2.c_str(), input2.size() + 1); | ||||
|         auto tup2 = s.split(buff, delim); | ||||
|         CHECK(tup2.size() == 6); | ||||
|     } | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
| TEST_CASE("testing quoting without escaping") { | ||||
|     std::vector<std::string> values{"10", "hello", ",", "a,a", "3.33", "a"}; | ||||
| 
 | ||||
| @ -117,6 +114,7 @@ TEST_CASE("testing quoting without escaping") { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| TEST_CASE("testing split") { | ||||
|     ss::converter c; | ||||
| @ -124,13 +122,12 @@ TEST_CASE("testing split") { | ||||
|          // clang-format off
 | ||||
|                 {std::tuple{"a,b,c,d", std::vector{"a", "b", "c", "d"}, ","}, | ||||
|                 {"", {}, " "}, | ||||
|                 {"a,b,c", {"a", "b", "c"}, ""}, | ||||
|                 {" 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); | ||||
|         auto split = c.split(buff(s), delim); | ||||
|         CHECK(split.size() == expected.size()); | ||||
|         for (size_t i = 0; i < split.size(); ++i) { | ||||
|             auto s = std::string(split[i].first, split[i].second); | ||||
| @ -143,84 +140,85 @@ TEST_CASE("testing valid conversions") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<int>("5"); | ||||
|         auto tup = c.convert<int>(buff("5")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<int, void>("5,junk"); | ||||
|         auto tup = c.convert<int, void>(buff("5,junk")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<void, int>("junk,5"); | ||||
|         auto tup = c.convert<void, int>(buff("junk,5")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<int, void, void>("5\njunk\njunk", "\n"); | ||||
|         auto tup = c.convert<int, void, void>(buff("5\njunk\njunk"), "\n"); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         // TODO make \t -> ' '
 | ||||
|         auto tup = c.convert<void, int, void>("junk\t5\tjunk", "\t"); | ||||
|         auto tup = c.convert<void, int, void>(buff("junk\t5\tjunk"), "\t"); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<void, void, int>("junk\tjunk\t5", "\t"); | ||||
|         auto tup = c.convert<void, void, int>(buff("junk\tjunk\t5"), "\t"); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = | ||||
|             c.convert<void, void, std::optional<int>>("junk\tjunk\t5", "\t"); | ||||
|             c.convert<void, void, std::optional<int>>(buff("junk\tjunk\t5"), | ||||
|                                                       "\t"); | ||||
|         REQUIRE(c.valid()); | ||||
|         REQUIRE(tup.has_value()); | ||||
|         CHECK(tup == 5); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<int, double, void>("5,6.6,junk"); | ||||
|         auto tup = c.convert<int, double, void>(buff("5,6.6,junk")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{5, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<int, void, double>("5,junk,6.6"); | ||||
|         auto tup = c.convert<int, void, double>(buff("5,junk,6.6")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{5, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<void, int, double>("junk;5;6.6", ";"); | ||||
|         auto tup = c.convert<void, int, double>(buff("junk;5;6.6"), ";"); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{5, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = | ||||
|             c.convert<void, std::optional<int>, double>("junk;5;6.6", ";"); | ||||
|             c.convert<void, std::optional<int>, double>(buff("junk;5;6.6"), | ||||
|                                                         ";"); | ||||
|         REQUIRE(c.valid()); | ||||
|         REQUIRE(std::get<0>(tup).has_value()); | ||||
|         CHECK(tup == std::tuple{5, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = | ||||
|             c.convert<void, std::optional<int>, double>("junk;5.4;6.6", ";"); | ||||
|             c.convert<void, std::optional<int>, double>(buff("junk;5.4;6.6"), | ||||
|                                                         ";"); | ||||
|         REQUIRE(c.valid()); | ||||
|         REQUIRE(!std::get<0>(tup).has_value()); | ||||
|         CHECK(tup == std::tuple{std::nullopt, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = | ||||
|             c.convert<void, std::variant<int, double>, double>("junk;5;6.6", | ||||
|                                                                ";"); | ||||
|         auto tup = c.convert<void, std::variant<int, double>, | ||||
|                              double>(buff("junk;5;6.6"), ";"); | ||||
|         REQUIRE(c.valid()); | ||||
|         REQUIRE(std::holds_alternative<int>(std::get<0>(tup))); | ||||
|         CHECK(tup == std::tuple{std::variant<int, double>{5}, 6.6}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = | ||||
|             c.convert<void, std::variant<int, double>, double>("junk;5.5;6.6", | ||||
|                                                                ";"); | ||||
|         auto tup = c.convert<void, std::variant<int, double>, | ||||
|                              double>(buff("junk;5.5;6.6"), ";"); | ||||
|         REQUIRE(c.valid()); | ||||
|         REQUIRE(std::holds_alternative<double>(std::get<0>(tup))); | ||||
|         CHECK(tup == std::tuple{std::variant<int, double>{5.5}, 6.6}); | ||||
| @ -230,60 +228,63 @@ TEST_CASE("testing valid conversions") { | ||||
| TEST_CASE("testing invalid conversions") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<int>(""); | ||||
|     c.convert<int>(buff("")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int, void>(""); | ||||
|     c.convert<int, void>(buff("")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int, void>(",junk"); | ||||
|     c.convert<int, void>(buff(",junk")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<void, int>("junk,"); | ||||
|     c.convert<void, int>(buff("junk,")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int>("x"); | ||||
|     c.convert<int>(buff("x")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int, void>("x"); | ||||
|     c.convert<int, void>(buff("x")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int, void>("x,junk"); | ||||
|     c.convert<int, void>(buff("x,junk")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<void, int>("junk,x"); | ||||
|     c.convert<void, int>(buff("junk,x")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<void, std::variant<int, double>, double>("junk;.5.5;6", ";"); | ||||
|     c.convert<void, std::variant<int, double>, double>(buff("junk;.5.5;6"), | ||||
|                                                        ";"); | ||||
|     REQUIRE(!c.valid()); | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("testing ss:ax restriction (all except)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::ax<int, 0>>("0"); | ||||
|     c.convert<ss::ax<int, 0>>(buff("0")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::ax<int, 0, 1, 2>>("1"); | ||||
|     c.convert<ss::ax<int, 0, 1, 2>>(buff("1")); | ||||
|     REQUIRE(!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>>(buff("junk,c,1")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::ax<int, 1>, char>("1,c"); | ||||
|     c.convert<ss::ax<int, 1>, char>(buff("1,c")); | ||||
|     REQUIRE(!c.valid()); | ||||
|     { | ||||
|         int tup = c.convert<ss::ax<int, 1>>("3"); | ||||
|         int tup = c.convert<ss::ax<int, 1>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(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>>(buff("c,3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::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>(buff("3,c")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{3, 'c'}); | ||||
|     } | ||||
| @ -292,32 +293,33 @@ TEST_CASE("testing ss:ax restriction (all except)") { | ||||
| TEST_CASE("testing ss:nx restriction (none except)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::nx<int, 1>>("3"); | ||||
|     c.convert<ss::nx<int, 1>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<char, ss::nx<int, 1, 2, 69>>("c,3"); | ||||
|     c.convert<char, ss::nx<int, 1, 2, 69>>(buff("c,3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::nx<int, 1>, char>("3,c"); | ||||
|     c.convert<ss::nx<int, 1>, char>(buff("3,c")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::nx<int, 3>>("3"); | ||||
|         auto tup = c.convert<ss::nx<int, 3>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<ss::nx<int, 0, 1, 2>>("2"); | ||||
|         auto tup = c.convert<ss::nx<int, 0, 1, 2>>(buff("2")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(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>>(buff("c,junk,1")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{'c', 1}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<ss::nx<int, 1>, char>("1,c"); | ||||
|         auto tup = c.convert<ss::nx<int, 1>, char>(buff("1,c")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{1, 'c'}); | ||||
|     } | ||||
| @ -326,32 +328,32 @@ TEST_CASE("testing ss:nx restriction (none except)") { | ||||
| TEST_CASE("testing ss:ir restriction (in range)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::ir<int, 0, 2>>("3"); | ||||
|     c.convert<ss::ir<int, 0, 2>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<char, ss::ir<int, 4, 69>>("c,3"); | ||||
|     c.convert<char, ss::ir<int, 4, 69>>(buff("c,3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::ir<int, 1, 2>, char>("3,c"); | ||||
|     c.convert<ss::ir<int, 1, 2>, char>(buff("3,c")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::ir<int, 1, 5>>("3"); | ||||
|         auto tup = c.convert<ss::ir<int, 1, 5>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<ss::ir<int, 0, 2>>("2"); | ||||
|         auto tup = c.convert<ss::ir<int, 0, 2>>(buff("2")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(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>>(buff("c,junk,1")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::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>(buff("1,c")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{1, 'c'}); | ||||
|     } | ||||
| @ -360,32 +362,32 @@ TEST_CASE("testing ss:ir restriction (in range)") { | ||||
| TEST_CASE("testing ss:oor restriction (out of range)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::oor<int, 1, 5>>("3"); | ||||
|     c.convert<ss::oor<int, 1, 5>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::oor<int, 0, 2>>("2"); | ||||
|     c.convert<ss::oor<int, 0, 2>>(buff("2")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<char, ss::oor<int, 0, 1>, void>("c,1,junk"); | ||||
|     c.convert<char, ss::oor<int, 0, 1>, void>(buff("c,1,junk")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::oor<int, 1, 20>, char>("1,c"); | ||||
|     c.convert<ss::oor<int, 1, 20>, char>(buff("1,c")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::oor<int, 0, 2>>("3"); | ||||
|         auto tup = c.convert<ss::oor<int, 0, 2>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(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>>(buff("c,junk,3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::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>(buff("3,c")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{3, 'c'}); | ||||
|     } | ||||
| @ -407,33 +409,34 @@ inline bool ss::extract(const char* begin, const char* end, | ||||
| TEST_CASE("testing ss:ne restriction (not empty)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::ne<std::string>>(""); | ||||
|     c.convert<ss::ne<std::string>>(buff("")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<int, ss::ne<std::string>>("3,"); | ||||
|     c.convert<int, ss::ne<std::string>>(buff("3,")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::ne<std::string>, int>(",3"); | ||||
|     c.convert<ss::ne<std::string>, int>(buff(",3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<void, ss::ne<std::string>, int>("junk,,3"); | ||||
|     c.convert<void, ss::ne<std::string>, int>(buff("junk,,3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::ne<std::vector<int>>>(""); | ||||
|     c.convert<ss::ne<std::vector<int>>>(buff("")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::ne<std::string>>("s"); | ||||
|         auto tup = c.convert<ss::ne<std::string>>(buff("s")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(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>>(buff("1,s")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == std::tuple{1, "s"}); | ||||
|     } | ||||
|     { | ||||
|         auto tup = c.convert<ss::ne<std::vector<int>>>("{1 2 3}"); | ||||
|         auto tup = c.convert<ss::ne<std::vector<int>>>(buff("{1 2 3}")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == extracted_vector); | ||||
|     } | ||||
| @ -442,56 +445,56 @@ TEST_CASE("testing ss:ne restriction (not empty)") { | ||||
| TEST_CASE("testing ss:lt ss::lte ss::gt ss::gte restriction (in range)") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<ss::lt<int, 3>>("3"); | ||||
|     c.convert<ss::lt<int, 3>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::lt<int, 2>>("3"); | ||||
|     c.convert<ss::lt<int, 2>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::gt<int, 3>>("3"); | ||||
|     c.convert<ss::gt<int, 3>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::gt<int, 4>>("3"); | ||||
|     c.convert<ss::gt<int, 4>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::lte<int, 2>>("3"); | ||||
|     c.convert<ss::lte<int, 2>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     c.convert<ss::gte<int, 4>>("3"); | ||||
|     c.convert<ss::gte<int, 4>>(buff("3")); | ||||
|     REQUIRE(!c.valid()); | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::lt<int, 4>>("3"); | ||||
|         auto tup = c.convert<ss::lt<int, 4>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::gt<int, 2>>("3"); | ||||
|         auto tup = c.convert<ss::gt<int, 2>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::lte<int, 4>>("3"); | ||||
|         auto tup = c.convert<ss::lte<int, 4>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::lte<int, 3>>("3"); | ||||
|         auto tup = c.convert<ss::lte<int, 3>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::gte<int, 2>>("3"); | ||||
|         auto tup = c.convert<ss::gte<int, 2>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         auto tup = c.convert<ss::gte<int, 3>>("3"); | ||||
|         auto tup = c.convert<ss::gte<int, 3>>(buff("3")); | ||||
|         REQUIRE(c.valid()); | ||||
|         CHECK(tup == 3); | ||||
|     } | ||||
| @ -500,12 +503,12 @@ TEST_CASE("testing ss:lt ss::lte ss::gt ss::gte restriction (in range)") { | ||||
| TEST_CASE("testing error mode") { | ||||
|     ss::converter c; | ||||
| 
 | ||||
|     c.convert<int>("junk"); | ||||
|     c.convert<int>(buff("junk")); | ||||
|     CHECK(!c.valid()); | ||||
|     CHECK(c.error_msg().empty()); | ||||
| 
 | ||||
|     c.set_error_mode(ss::error_mode::error_string); | ||||
|     c.convert<int>("junk"); | ||||
|     c.convert<int>(buff("junk")); | ||||
|     CHECK(!c.valid()); | ||||
|     CHECK(!c.error_msg().empty()); | ||||
| } | ||||
|  | ||||
| @ -56,6 +56,7 @@ TEST_CASE("testing parser") { | ||||
|     make_and_write(f.name, data); | ||||
|     { | ||||
|         ss::parser p{f.name, ","}; | ||||
|         p.set_error_mode(ss::error_mode::error_string); | ||||
|         std::vector<X> i; | ||||
| 
 | ||||
|         while (!p.eof()) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user