mirror of
https://github.com/red0124/ssp.git
synced 2025-02-02 16:51:12 +01:00
Merge pull request #11 from red0124/improvement/update_setup_and_trim
Improvement/update setup and trim
This commit is contained in:
commit
2f9e00b8a8
19
include/ss/common.hpp
Normal file
19
include/ss/common.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ss {
|
||||||
|
|
||||||
|
struct none {};
|
||||||
|
|
||||||
|
using string_range = std::pair<const char*, const char*>;
|
||||||
|
using split_data = std::vector<string_range>;
|
||||||
|
|
||||||
|
constexpr inline auto default_delimiter = ",";
|
||||||
|
|
||||||
|
template <bool StringError>
|
||||||
|
inline void assert_string_error_defined() {
|
||||||
|
static_assert(StringError,
|
||||||
|
"'string_error' needs to be enabled to use 'error_msg'");
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* ss */
|
@ -40,19 +40,13 @@ template <typename T>
|
|||||||
using no_validator_t = typename no_validator<T>::type;
|
using no_validator_t = typename no_validator<T>::type;
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct no_validator_tup {
|
struct no_validator_tup : apply_trait<no_validator, std::tuple<Ts...>> {};
|
||||||
using type = typename apply_trait<no_validator, std::tuple<Ts...>>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct no_validator_tup<std::tuple<Ts...>> {
|
struct no_validator_tup<std::tuple<Ts...>> : no_validator_tup<Ts...> {};
|
||||||
using type = typename no_validator_tup<Ts...>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct no_validator_tup<std::tuple<T>> {
|
struct no_validator_tup<std::tuple<T>> : no_validator<T> {};
|
||||||
using type = no_validator_t<T>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
|
using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
|
||||||
@ -62,10 +56,7 @@ using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
|
|||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct no_void_tup {
|
struct no_void_tup : filter_not<std::is_void, no_validator_tup_t<Ts...>> {};
|
||||||
using type =
|
|
||||||
typename filter_not<std::is_void, no_validator_tup_t<Ts...>>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
|
using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
|
||||||
@ -76,14 +67,11 @@ using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
|
|||||||
|
|
||||||
// replace 'validators' and remove void from tuple
|
// replace 'validators' and remove void from tuple
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct no_void_validator_tup {
|
struct no_void_validator_tup : no_validator_tup<no_void_tup_t<Ts...>> {};
|
||||||
using type = no_validator_tup_t<no_void_tup_t<Ts...>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct no_void_validator_tup<std::tuple<Ts...>> {
|
struct no_void_validator_tup<std::tuple<Ts...>>
|
||||||
using type = no_validator_tup_t<no_void_tup_t<Ts...>>;
|
: no_validator_tup<no_void_tup_t<Ts...>> {};
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::type;
|
using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::type;
|
||||||
@ -131,12 +119,12 @@ public:
|
|||||||
no_void_validator_tup_t<Ts...> convert(
|
no_void_validator_tup_t<Ts...> convert(
|
||||||
line_ptr_type line, const std::string& delim = default_delimiter) {
|
line_ptr_type line, const std::string& delim = default_delimiter) {
|
||||||
split(line, delim);
|
split(line, delim);
|
||||||
return convert<Ts...>(splitter_.split_input_);
|
return convert<Ts...>(splitter_.split_data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// parses already split line, returns 'T' object with extracted values
|
// parses already split line, returns 'T' object with extracted values
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
T convert_object(const split_input& elems) {
|
T convert_object(const split_data& elems) {
|
||||||
return to_object<T>(convert<Ts...>(elems));
|
return to_object<T>(convert<Ts...>(elems));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,17 +139,12 @@ public:
|
|||||||
// one argument is given which is a class which has a tied
|
// one argument is given which is a class which has a tied
|
||||||
// method which returns a tuple, returns that type
|
// method which returns a tuple, returns that type
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
no_void_validator_tup_t<T, Ts...> convert(const split_input& elems) {
|
no_void_validator_tup_t<T, Ts...> convert(const split_data& elems) {
|
||||||
if constexpr (sizeof...(Ts) == 0 &&
|
if constexpr (sizeof...(Ts) == 0 && is_instance_of_v<std::tuple, T>) {
|
||||||
is_instance_of<T, std::tuple>::value) {
|
|
||||||
return convert_impl(elems, static_cast<T*>(nullptr));
|
return convert_impl(elems, static_cast<T*>(nullptr));
|
||||||
|
|
||||||
} else if constexpr (tied_class_v<T, Ts...>) {
|
} else if constexpr (tied_class_v<T, Ts...>) {
|
||||||
using arg_ref_tuple =
|
using arg_ref_tuple = std::result_of_t<decltype (&T::tied)(T)>;
|
||||||
typename std::result_of_t<decltype (&T::tied)(T)>;
|
using arg_tuple = apply_trait_t<std::decay, arg_ref_tuple>;
|
||||||
|
|
||||||
using arg_tuple =
|
|
||||||
typename apply_trait<std::decay, arg_ref_tuple>::type;
|
|
||||||
|
|
||||||
return to_object<T>(
|
return to_object<T>(
|
||||||
convert_impl(elems, static_cast<arg_tuple*>(nullptr)));
|
convert_impl(elems, static_cast<arg_tuple*>(nullptr)));
|
||||||
@ -173,7 +156,7 @@ public:
|
|||||||
// same as above, but uses cached split line
|
// same as above, but uses cached split line
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
no_void_validator_tup_t<T, Ts...> convert() {
|
no_void_validator_tup_t<T, Ts...> convert() {
|
||||||
return convert<T, Ts...>(splitter_.split_input_);
|
return convert<T, Ts...>(splitter_.split_data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid() const {
|
bool valid() const {
|
||||||
@ -185,8 +168,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string& error_msg() const {
|
const std::string& error_msg() const {
|
||||||
static_assert(string_error,
|
assert_string_error_defined<string_error>();
|
||||||
"'string_error' needs to be enabled to use 'error_msg'");
|
|
||||||
return error_;
|
return error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,11 +178,11 @@ public:
|
|||||||
|
|
||||||
// 'splits' string by given delimiter, returns vector of pairs which
|
// 'splits' string by given delimiter, returns vector of pairs which
|
||||||
// contain the beginnings and the ends of each column of the string
|
// contain the beginnings and the ends of each column of the string
|
||||||
const split_input& split(line_ptr_type line,
|
const split_data& split(line_ptr_type line,
|
||||||
const std::string& delim = default_delimiter) {
|
const std::string& delim = default_delimiter) {
|
||||||
splitter_.split_input_.clear();
|
splitter_.split_data_.clear();
|
||||||
if (line[0] == '\0') {
|
if (line[0] == '\0') {
|
||||||
return splitter_.split_input_;
|
return splitter_.split_data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
return splitter_.split(line, delim);
|
return splitter_.split(line, delim);
|
||||||
@ -211,11 +193,15 @@ private:
|
|||||||
// resplit
|
// resplit
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
const split_input& resplit(line_ptr_type new_line, ssize_t new_size,
|
const split_data& resplit(line_ptr_type new_line, ssize_t new_size,
|
||||||
const std::string& delim = default_delimiter) {
|
const std::string& delim = default_delimiter) {
|
||||||
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
|
||||||
////////////////
|
////////////////
|
||||||
@ -248,6 +234,15 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_error_multiline_limit_reached() {
|
||||||
|
if constexpr (string_error) {
|
||||||
|
error_.clear();
|
||||||
|
error_.append("multiline limit reached.");
|
||||||
|
} else {
|
||||||
|
error_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_error_invalid_conversion(const string_range msg, size_t pos) {
|
void set_error_invalid_conversion(const string_range msg, size_t pos) {
|
||||||
if constexpr (string_error) {
|
if constexpr (string_error) {
|
||||||
error_.clear();
|
error_.clear();
|
||||||
@ -285,7 +280,7 @@ private:
|
|||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
no_void_validator_tup_t<Ts...> convert_impl(const split_input& elems) {
|
no_void_validator_tup_t<Ts...> convert_impl(const split_data& elems) {
|
||||||
clear_error();
|
clear_error();
|
||||||
|
|
||||||
if (!splitter_.valid()) {
|
if (!splitter_.valid()) {
|
||||||
@ -306,7 +301,7 @@ private:
|
|||||||
// do not know how to specialize by return type :(
|
// do not know how to specialize by return type :(
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
no_void_validator_tup_t<std::tuple<Ts...>> convert_impl(
|
no_void_validator_tup_t<std::tuple<Ts...>> convert_impl(
|
||||||
const split_input& elems, const std::tuple<Ts...>*) {
|
const split_data& elems, const std::tuple<Ts...>*) {
|
||||||
return convert_impl<Ts...>(elems);
|
return convert_impl<Ts...>(elems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,11 +340,11 @@ private:
|
|||||||
|
|
||||||
template <size_t ArgN, size_t TupN, typename... Ts>
|
template <size_t ArgN, size_t TupN, typename... Ts>
|
||||||
void extract_multiple(no_void_validator_tup_t<Ts...>& tup,
|
void extract_multiple(no_void_validator_tup_t<Ts...>& tup,
|
||||||
const split_input& elems) {
|
const split_data& elems) {
|
||||||
using elem_t = std::tuple_element_t<ArgN, std::tuple<Ts...>>;
|
using elem_t = std::tuple_element_t<ArgN, std::tuple<Ts...>>;
|
||||||
|
|
||||||
constexpr bool not_void = !std::is_void_v<elem_t>;
|
constexpr bool not_void = !std::is_void_v<elem_t>;
|
||||||
constexpr bool one_element = count_not<std::is_void, Ts...>::size == 1;
|
constexpr bool one_element = count_not_v<std::is_void, Ts...> == 1;
|
||||||
|
|
||||||
if constexpr (not_void) {
|
if constexpr (not_void) {
|
||||||
if constexpr (one_element) {
|
if constexpr (one_element) {
|
||||||
@ -367,8 +362,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
no_void_validator_tup_t<Ts...> extract_tuple(const split_input& elems) {
|
no_void_validator_tup_t<Ts...> extract_tuple(const split_data& elems) {
|
||||||
static_assert(!all_of<std::is_void, Ts...>::value,
|
static_assert(!all_of_v<std::is_void, Ts...>,
|
||||||
"at least one parameter must be non void");
|
"at least one parameter must be non void");
|
||||||
no_void_validator_tup_t<Ts...> ret{};
|
no_void_validator_tup_t<Ts...> ret{};
|
||||||
extract_multiple<0, 0, Ts...>(ret, elems);
|
extract_multiple<0, 0, Ts...>(ret, elems);
|
||||||
@ -379,7 +374,7 @@ private:
|
|||||||
// members
|
// members
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
error_type error_;
|
error_type error_{};
|
||||||
splitter<Matchers...> splitter_;
|
splitter<Matchers...> splitter_;
|
||||||
|
|
||||||
template <typename...>
|
template <typename...>
|
||||||
|
@ -225,8 +225,8 @@ struct unsupported_type {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> &&
|
std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> &&
|
||||||
!is_instance_of<T, std::optional>::value &&
|
!is_instance_of_v<std::optional, T> &&
|
||||||
!is_instance_of<T, std::variant>::value,
|
!is_instance_of_v<std::variant, T>,
|
||||||
bool>
|
bool>
|
||||||
extract(const char*, const char*, T&) {
|
extract(const char*, const char*, T&) {
|
||||||
static_assert(error::unsupported_type<T>::value,
|
static_assert(error::unsupported_type<T>::value,
|
||||||
@ -246,7 +246,7 @@ extract(const char* begin, const char* end, T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<is_instance_of<T, std::optional>::value, bool> extract(
|
std::enable_if_t<is_instance_of_v<std::optional, T>, bool> extract(
|
||||||
const char* begin, const char* end, T& value) {
|
const char* begin, const char* end, T& value) {
|
||||||
typename T::value_type raw_value;
|
typename T::value_type raw_value;
|
||||||
if (extract(begin, end, raw_value)) {
|
if (extract(begin, end, raw_value)) {
|
||||||
@ -271,7 +271,7 @@ bool extract_variant(const char* begin, const char* end, T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<is_instance_of<T, std::variant>::value, bool> extract(
|
std::enable_if_t<is_instance_of_v<std::variant, T>, bool> extract(
|
||||||
const char* begin, const char* end, T& value) {
|
const char* begin, const char* end, T& value) {
|
||||||
return extract_variant<T, 0>(begin, end, value);
|
return extract_variant<T, 0>(begin, end, value);
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,17 @@ namespace ss {
|
|||||||
|
|
||||||
template <typename... Matchers>
|
template <typename... Matchers>
|
||||||
class parser {
|
class parser {
|
||||||
struct none {};
|
|
||||||
|
|
||||||
constexpr static auto string_error = setup<Matchers...>::string_error;
|
constexpr static auto string_error = setup<Matchers...>::string_error;
|
||||||
constexpr static auto multiline = 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)
|
||||||
@ -48,8 +52,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string& error_msg() const {
|
const std::string& error_msg() const {
|
||||||
static_assert(string_error,
|
assert_string_error_defined<string_error>();
|
||||||
"'string_error' needs to be enabled to use 'error_msg'");
|
|
||||||
return error_;
|
return error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,11 +160,13 @@ public:
|
|||||||
if (!parser_.valid()) {
|
if (!parser_.valid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (!std::is_same_v<U, decltype(tuple_output)>) {
|
if constexpr (!std::is_same_v<U, decltype(tuple_output)>) {
|
||||||
value = to_object<U>(std::move(tuple_output));
|
value = to_object<U>(std::move(tuple_output));
|
||||||
} else {
|
} else {
|
||||||
value = std::move(tuple_output);
|
value = std::move(tuple_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_.try_invoke(*value, std::forward<Fun>(fun));
|
parser_.try_invoke(*value, std::forward<Fun>(fun));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,6 +182,10 @@ public:
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// members
|
||||||
|
////////////////
|
||||||
|
|
||||||
std::tuple<Ts...> values_;
|
std::tuple<Ts...> values_;
|
||||||
parser& parser_;
|
parser& parser_;
|
||||||
};
|
};
|
||||||
@ -321,7 +330,7 @@ private:
|
|||||||
helper_buffer_{other.helper_buffer_}, converter_{std::move(
|
helper_buffer_{other.helper_buffer_}, converter_{std::move(
|
||||||
other.converter_)},
|
other.converter_)},
|
||||||
next_line_converter_{std::move(other.next_line_converter_)},
|
next_line_converter_{std::move(other.next_line_converter_)},
|
||||||
size_{other.size_},
|
size_{other.size_}, next_line_size_{other.size_},
|
||||||
helper_size_{other.helper_size_}, delim_{std::move(other.delim_)},
|
helper_size_{other.helper_size_}, delim_{std::move(other.delim_)},
|
||||||
file_{other.file_}, crlf_{other.crlf_} {
|
file_{other.file_}, crlf_{other.crlf_} {
|
||||||
other.buffer_ = nullptr;
|
other.buffer_ = nullptr;
|
||||||
@ -338,6 +347,7 @@ private:
|
|||||||
converter_ = std::move(other.converter_);
|
converter_ = std::move(other.converter_);
|
||||||
next_line_converter_ = std::move(other.next_line_converter_);
|
next_line_converter_ = std::move(other.next_line_converter_);
|
||||||
size_ = other.size_;
|
size_ = other.size_;
|
||||||
|
next_line_size_ = other.next_line_size_;
|
||||||
helper_size_ = other.helper_size_;
|
helper_size_ = other.helper_size_;
|
||||||
delim_ = std::move(other.delim_);
|
delim_ = std::move(other.delim_);
|
||||||
file_ = other.file_;
|
file_ = other.file_;
|
||||||
@ -367,17 +377,23 @@ private:
|
|||||||
reader& operator=(const reader& other) = delete;
|
reader& operator=(const reader& other) = delete;
|
||||||
|
|
||||||
bool read_next() {
|
bool read_next() {
|
||||||
ssize_t ssize = getline(&next_line_buffer_, &size_, file_);
|
memset(next_line_buffer_, '\0', next_line_size_);
|
||||||
|
ssize_t ssize =
|
||||||
|
getline(&next_line_buffer_, &next_line_size_, file_);
|
||||||
|
|
||||||
if (ssize == -1) {
|
if (ssize == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = remove_eol(next_line_buffer_, ssize);
|
size_t size = remove_eol(next_line_buffer_, ssize);
|
||||||
|
size_t limit = 0;
|
||||||
|
|
||||||
if constexpr (multiline && setup<Matchers...>::escape::enabled) {
|
if constexpr (escaped_multiline_enabled) {
|
||||||
while (escaped_eol(size)) {
|
while (escaped_eol(size)) {
|
||||||
if (!append_line(next_line_buffer_, size)) {
|
if (multiline_limit_reached(limit)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!append_next_line_to_buffer(next_line_buffer_, size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,11 +401,27 @@ private:
|
|||||||
|
|
||||||
next_line_converter_.split(next_line_buffer_, delim_);
|
next_line_converter_.split(next_line_buffer_, delim_);
|
||||||
|
|
||||||
if constexpr (multiline && setup<Matchers...>::quote::enabled) {
|
if constexpr (quoted_multiline_enabled) {
|
||||||
while (unterminated_quote()) {
|
while (unterminated_quote()) {
|
||||||
if (!append_line(next_line_buffer_, size)) {
|
if (multiline_limit_reached(limit)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,9 +431,20 @@ private:
|
|||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
std::swap(buffer_, next_line_buffer_);
|
std::swap(buffer_, next_line_buffer_);
|
||||||
|
std::swap(size_, next_line_size_);
|
||||||
std::swap(converter_, next_line_converter_);
|
std::swap(converter_, next_line_converter_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool multiline_limit_reached(size_t& limit) {
|
||||||
|
if constexpr (multiline::size > 0) {
|
||||||
|
if (limit++ >= multiline::size) {
|
||||||
|
next_line_converter_.set_error_multiline_limit_reached();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool escaped_eol(size_t size) {
|
bool escaped_eol(size_t size) {
|
||||||
const char* curr;
|
const char* curr;
|
||||||
for (curr = next_line_buffer_ + size - 1;
|
for (curr = next_line_buffer_ + size - 1;
|
||||||
@ -419,12 +462,15 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void undo_remove_eol(size_t& string_end) {
|
void undo_remove_eol(char* buffer, size_t& string_end) {
|
||||||
|
if (next_line_converter_.unterminated_quote()) {
|
||||||
|
string_end -= next_line_converter_.size_shifted();
|
||||||
|
}
|
||||||
if (crlf_) {
|
if (crlf_) {
|
||||||
std::copy_n("\r\n\0", 3, next_line_buffer_ + string_end);
|
std::copy_n("\r\n\0", 3, buffer + string_end);
|
||||||
string_end += 2;
|
string_end += 2;
|
||||||
} else {
|
} else {
|
||||||
std::copy_n("\n\0", 2, next_line_buffer_ + string_end);
|
std::copy_n("\n\0", 2, buffer + string_end);
|
||||||
string_end += 1;
|
string_end += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,23 +490,23 @@ private:
|
|||||||
|
|
||||||
void realloc_concat(char*& first, size_t& first_size,
|
void realloc_concat(char*& first, size_t& first_size,
|
||||||
const char* const second, size_t second_size) {
|
const char* const second, size_t second_size) {
|
||||||
first = static_cast<char*>(realloc(static_cast<void*>(first),
|
next_line_size_ = first_size + second_size + 2;
|
||||||
first_size + second_size + 2));
|
first = static_cast<char*>(
|
||||||
|
realloc(static_cast<void*>(first), next_line_size_));
|
||||||
std::copy_n(second, second_size + 1, first + first_size);
|
std::copy_n(second, second_size + 1, first + first_size);
|
||||||
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_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,6 +521,7 @@ private:
|
|||||||
converter<Matchers...> next_line_converter_;
|
converter<Matchers...> next_line_converter_;
|
||||||
|
|
||||||
size_t size_{0};
|
size_t size_{0};
|
||||||
|
size_t next_line_size_{0};
|
||||||
size_t helper_size_{0};
|
size_t helper_size_{0};
|
||||||
|
|
||||||
std::string delim_;
|
std::string delim_;
|
||||||
@ -488,7 +535,7 @@ private:
|
|||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
std::string file_name_;
|
std::string file_name_;
|
||||||
error_type error_;
|
error_type error_{};
|
||||||
reader reader_;
|
reader reader_;
|
||||||
size_t line_number_{0};
|
size_t line_number_{0};
|
||||||
bool eof_{false};
|
bool eof_{false};
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// matcher
|
||||||
|
////////////////
|
||||||
|
|
||||||
template <char... Cs>
|
template <char... Cs>
|
||||||
struct matcher {
|
struct matcher {
|
||||||
private:
|
private:
|
||||||
@ -36,7 +40,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename FirstMatcher, typename SecondMatcher>
|
template <typename FirstMatcher, typename SecondMatcher>
|
||||||
constexpr bool matches_intersect() {
|
inline constexpr bool matches_intersect() {
|
||||||
for (const auto& first_match : FirstMatcher::matches) {
|
for (const auto& first_match : FirstMatcher::matches) {
|
||||||
for (const auto& second_match : SecondMatcher::matches) {
|
for (const auto& second_match : SecondMatcher::matches) {
|
||||||
if (first_match != '\0' && first_match == second_match) {
|
if (first_match != '\0' && first_match == second_match) {
|
||||||
@ -47,6 +51,13 @@ constexpr bool matches_intersect() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FirstMatcher, typename SecondMatcher1,
|
||||||
|
typename SecondMatcher2>
|
||||||
|
inline constexpr bool matches_intersect_union() {
|
||||||
|
return matches_intersect<FirstMatcher, SecondMatcher1>() ||
|
||||||
|
matches_intersect<FirstMatcher, SecondMatcher2>();
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class matcher<'\0'> {
|
class matcher<'\0'> {
|
||||||
public:
|
public:
|
||||||
@ -55,31 +66,52 @@ public:
|
|||||||
static bool match(char c) = delete;
|
static bool match(char c) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// setup
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// matcher
|
||||||
|
////////////////
|
||||||
|
|
||||||
template <char C>
|
template <char C>
|
||||||
struct quote : matcher<C> {};
|
struct quote : matcher<C> {};
|
||||||
|
|
||||||
template <char... Cs>
|
template <char... Cs>
|
||||||
struct trim : matcher<Cs...> {};
|
struct trim : matcher<Cs...> {};
|
||||||
|
|
||||||
|
template <char... Cs>
|
||||||
|
struct trim_left : matcher<Cs...> {};
|
||||||
|
|
||||||
|
template <char... Cs>
|
||||||
|
struct trim_right : matcher<Cs...> {};
|
||||||
|
|
||||||
template <char... Cs>
|
template <char... Cs>
|
||||||
struct escape : matcher<Cs...> {};
|
struct escape : matcher<Cs...> {};
|
||||||
|
|
||||||
template <typename T, template <char...> class Template>
|
template <typename T, template <char...> class Template>
|
||||||
struct is_instance_of_matcher {
|
struct is_instance_of_matcher : std::false_type {};
|
||||||
constexpr static bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <char... Ts, template <char...> class Template>
|
template <char... Ts, template <char...> class Template>
|
||||||
struct is_instance_of_matcher<Template<Ts...>, Template> {
|
struct is_instance_of_matcher<Template<Ts...>, Template> : std::true_type {};
|
||||||
constexpr static bool value = true;
|
|
||||||
};
|
template <typename T, template <char...> class Template>
|
||||||
|
using is_instance_of_matcher_t =
|
||||||
|
typename is_instance_of_matcher<T, Template>::type;
|
||||||
|
|
||||||
template <template <char...> class Matcher, typename... Ts>
|
template <template <char...> class Matcher, typename... Ts>
|
||||||
struct get_matcher;
|
struct get_matcher;
|
||||||
|
|
||||||
template <template <char...> class Matcher, typename T, typename... Ts>
|
template <template <char...> class Matcher, typename T, typename... Ts>
|
||||||
struct get_matcher<Matcher, T, Ts...> {
|
struct get_matcher<Matcher, T, Ts...> {
|
||||||
using type = ternary_t<is_instance_of_matcher<T, Matcher>::value, T,
|
|
||||||
|
template <typename U>
|
||||||
|
struct is_matcher : is_instance_of_matcher<U, Matcher> {};
|
||||||
|
|
||||||
|
static_assert(count_v<is_matcher, T, Ts...> <= 1,
|
||||||
|
"the same matcher is cannot"
|
||||||
|
"be defined multiple times");
|
||||||
|
using type = ternary_t<is_matcher<T>::value, T,
|
||||||
typename get_matcher<Matcher, Ts...>::type>;
|
typename get_matcher<Matcher, Ts...>::type>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,39 +123,119 @@ struct get_matcher<Matcher> {
|
|||||||
template <template <char...> class Matcher, typename... Ts>
|
template <template <char...> class Matcher, typename... Ts>
|
||||||
using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
|
using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
|
||||||
|
|
||||||
class multiline;
|
////////////////
|
||||||
|
// multiline
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
template <size_t S, bool B = true>
|
||||||
|
struct multiline_restricted {
|
||||||
|
constexpr static auto size = S;
|
||||||
|
constexpr static auto enabled = B;
|
||||||
|
};
|
||||||
|
|
||||||
|
using multiline = multiline_restricted<0>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_instance_of_multiline : std::false_type {};
|
||||||
|
|
||||||
|
template <size_t S, bool B>
|
||||||
|
struct is_instance_of_multiline<multiline_restricted<S, B>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using is_instance_of_multiline_t = typename is_instance_of_multiline<T>::type;
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct get_multiline;
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
struct get_multiline<T, Ts...> {
|
||||||
|
using type = ternary_t<is_instance_of_multiline<T>::value, T,
|
||||||
|
typename get_multiline<Ts...>::type>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct get_multiline<> {
|
||||||
|
using type = multiline_restricted<0, false>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
using get_multiline_t = typename get_multiline<Ts...>::type;
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// string_error
|
||||||
|
////////////////
|
||||||
|
|
||||||
class string_error;
|
class string_error;
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// setup implementation
|
||||||
|
////////////////
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct setup {
|
struct setup {
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_multiline : std::is_same<T, multiline> {};
|
struct is_matcher
|
||||||
|
: std::disjunction<is_instance_of_matcher_t<T, quote>,
|
||||||
constexpr static auto count_multiline = count<is_multiline, Ts...>::size;
|
is_instance_of_matcher_t<T, escape>,
|
||||||
|
is_instance_of_matcher_t<T, trim>,
|
||||||
|
is_instance_of_matcher_t<T, trim_left>,
|
||||||
|
is_instance_of_matcher_t<T, trim_right>> {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_string_error : std::is_same<T, string_error> {};
|
struct is_string_error : std::is_same<T, string_error> {};
|
||||||
|
|
||||||
constexpr static auto count_string_error =
|
constexpr static auto count_matcher = count_v<is_matcher, Ts...>;
|
||||||
count<is_string_error, Ts...>::size;
|
constexpr static auto count_multiline =
|
||||||
|
count_v<is_instance_of_multiline, Ts...>;
|
||||||
|
constexpr static auto count_string_error = count_v<is_string_error, Ts...>;
|
||||||
|
|
||||||
|
constexpr static auto number_of_valid_setup_types =
|
||||||
|
count_matcher + count_multiline + count_string_error;
|
||||||
|
|
||||||
|
using trim_left_only = get_matcher_t<trim_left, Ts...>;
|
||||||
|
using trim_right_only = get_matcher_t<trim_right, Ts...>;
|
||||||
|
using trim_all = get_matcher_t<trim, Ts...>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using quote = get_matcher_t<quote, Ts...>;
|
using quote = get_matcher_t<quote, Ts...>;
|
||||||
using trim = get_matcher_t<trim, Ts...>;
|
|
||||||
using escape = get_matcher_t<escape, Ts...>;
|
using escape = get_matcher_t<escape, Ts...>;
|
||||||
constexpr static bool multiline = (count_multiline == 1);
|
|
||||||
|
using trim_left = ternary_t<trim_all::enabled, trim_all, trim_left_only>;
|
||||||
|
using trim_right = ternary_t<trim_all::enabled, trim_all, trim_right_only>;
|
||||||
|
|
||||||
|
using multiline = get_multiline_t<Ts...>;
|
||||||
constexpr static bool string_error = (count_string_error == 1);
|
constexpr static bool string_error = (count_string_error == 1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#define ASSERT_MSG "cannot have the same match character in multiple matchers"
|
||||||
|
static_assert(!matches_intersect<escape, quote>(), ASSERT_MSG);
|
||||||
|
|
||||||
|
constexpr static auto quote_trim_intersect =
|
||||||
|
matches_intersect_union<quote, trim_left, trim_right>();
|
||||||
|
static_assert(!quote_trim_intersect, ASSERT_MSG);
|
||||||
|
|
||||||
|
constexpr static auto escape_trim_intersect =
|
||||||
|
matches_intersect_union<escape, trim_left, trim_right>();
|
||||||
|
static_assert(!escape_trim_intersect, ASSERT_MSG);
|
||||||
|
|
||||||
|
#undef ASSERT_MSG
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
!multiline || (multiline && (quote::enabled || escape::enabled)),
|
!multiline::enabled ||
|
||||||
|
(multiline::enabled && (quote::enabled || escape::enabled)),
|
||||||
"to enable multiline either quote or escape need to be enabled");
|
"to enable multiline either quote or escape need to be enabled");
|
||||||
|
|
||||||
#define ASSERT_MSG "cannot have the same match character in multiple matchers"
|
static_assert(!(trim_all::enabled && trim_left_only::enabled) &&
|
||||||
static_assert(!matches_intersect<quote, trim>(), ASSERT_MSG);
|
!(trim_all::enabled && trim_right_only::enabled),
|
||||||
static_assert(!matches_intersect<trim, escape>(), ASSERT_MSG);
|
"ambiguous trim setup");
|
||||||
static_assert(!matches_intersect<escape, quote>(), ASSERT_MSG);
|
|
||||||
#undef ASSERT_MSG
|
static_assert(count_multiline <= 1, "mutliline defined multiple times");
|
||||||
|
static_assert(count_string_error <= 1,
|
||||||
|
"string_error defined multiple times");
|
||||||
|
|
||||||
|
static_assert(number_of_valid_setup_types == sizeof...(Ts),
|
||||||
|
"one or multiple invalid setup parameters defined");
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "common.hpp"
|
||||||
#include "setup.hpp"
|
#include "setup.hpp"
|
||||||
#include "type_traits.hpp"
|
#include "type_traits.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -10,17 +11,14 @@
|
|||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
// TODO move to common or something
|
|
||||||
using string_range = std::pair<const char*, const char*>;
|
|
||||||
using split_input = std::vector<string_range>;
|
|
||||||
constexpr static auto default_delimiter = ",";
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
class splitter {
|
class splitter {
|
||||||
private:
|
private:
|
||||||
using quote = typename setup<Ts...>::quote;
|
using quote = typename setup<Ts...>::quote;
|
||||||
using trim = typename setup<Ts...>::trim;
|
using trim_left = typename setup<Ts...>::trim_left;
|
||||||
|
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;
|
||||||
@ -39,8 +37,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string& error_msg() const {
|
const std::string& error_msg() const {
|
||||||
static_assert(string_error,
|
assert_string_error_defined<string_error>();
|
||||||
"'string_error' needs to be enabled to use 'error_msg'");
|
|
||||||
return error_;
|
return error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +45,12 @@ public:
|
|||||||
return unterminated_quote_;
|
return unterminated_quote_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const split_input& 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_input_.clear();
|
split_data_.clear();
|
||||||
return resplit(new_line, -1, delimiter);
|
line_ = new_line;
|
||||||
|
begin_ = line_;
|
||||||
|
return split_impl_select_delim(delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -59,35 +58,50 @@ 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_input_) {
|
for (auto& [begin, end] : split_data_) {
|
||||||
begin = begin - old_line + line_;
|
begin = begin - old_line + line_;
|
||||||
end = end - old_line + line_;
|
end = end - old_line + line_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const split_input& 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 (!split_input_.empty() && unterminated_quote()) {
|
if (!quote::enabled || !multiline::enabled || split_data_.empty() ||
|
||||||
const auto& last = std::prev(split_input_.end());
|
!unterminated_quote()) {
|
||||||
const auto [old_line, old_begin] = *last;
|
set_error_invalid_resplit();
|
||||||
size_t begin = old_begin - old_line - 1;
|
return split_data_;
|
||||||
split_input_.pop_back();
|
|
||||||
adjust_ranges(old_line);
|
|
||||||
|
|
||||||
// safety measure
|
|
||||||
if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
|
|
||||||
set_error_invalid_resplit();
|
|
||||||
return split_input_;
|
|
||||||
}
|
|
||||||
|
|
||||||
begin_ = line_ + begin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto [old_line, old_begin] = *std::prev(split_data_.end());
|
||||||
|
size_t begin = old_begin - old_line - 1;
|
||||||
|
|
||||||
|
// safety measure
|
||||||
|
if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
|
||||||
|
set_error_invalid_resplit();
|
||||||
|
return split_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if unterminated quote, the last element is junk
|
||||||
|
split_data_.pop_back();
|
||||||
|
|
||||||
|
line_ = new_line;
|
||||||
|
adjust_ranges(old_line);
|
||||||
|
|
||||||
|
begin_ = line_ + begin;
|
||||||
|
end_ = line_ - old_line + end_ - escaped_;
|
||||||
|
curr_ = end_;
|
||||||
|
|
||||||
|
resplitting_ = true;
|
||||||
|
|
||||||
return split_impl_select_delim(delimiter);
|
return split_impl_select_delim(delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,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) {
|
||||||
@ -163,9 +186,17 @@ private:
|
|||||||
return delim.size();
|
return delim.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void trim_if_enabled(line_ptr_type& curr) {
|
void trim_left_if_enabled(line_ptr_type& curr) {
|
||||||
if constexpr (trim::enabled) {
|
if constexpr (trim_left::enabled) {
|
||||||
while (trim::match(*curr)) {
|
while (trim_left::match(*curr)) {
|
||||||
|
++curr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void trim_right_if_enabled(line_ptr_type& curr) {
|
||||||
|
if constexpr (trim_right::enabled) {
|
||||||
|
while (trim_right::match(*curr)) {
|
||||||
++curr;
|
++curr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +207,7 @@ private:
|
|||||||
const Delim& delim) {
|
const Delim& delim) {
|
||||||
line_ptr_type end = begin;
|
line_ptr_type end = begin;
|
||||||
|
|
||||||
trim_if_enabled(end);
|
trim_right_if_enabled(end);
|
||||||
|
|
||||||
// just spacing
|
// just spacing
|
||||||
if (*end == '\0') {
|
if (*end == '\0') {
|
||||||
@ -190,7 +221,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
end += delimiter_size(delim);
|
end += delimiter_size(delim);
|
||||||
trim_if_enabled(end);
|
trim_left_if_enabled(end);
|
||||||
|
|
||||||
// delimiter
|
// delimiter
|
||||||
return {end - begin, true};
|
return {end - begin, true};
|
||||||
@ -200,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_input_.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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,17 +257,33 @@ 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
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
const split_input& split_impl_select_delim(
|
const split_data& split_impl_select_delim(
|
||||||
const std::string& delimiter = default_delimiter) {
|
const std::string& delimiter = default_delimiter) {
|
||||||
clear_error();
|
clear_error();
|
||||||
switch (delimiter.size()) {
|
switch (delimiter.size()) {
|
||||||
case 0:
|
case 0:
|
||||||
set_error_empty_delimiter();
|
set_error_empty_delimiter();
|
||||||
return split_input_;
|
return split_data_;
|
||||||
case 1:
|
case 1:
|
||||||
return split_impl(delimiter[0]);
|
return split_impl(delimiter[0]);
|
||||||
default:
|
default:
|
||||||
@ -256,18 +292,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Delim>
|
template <typename Delim>
|
||||||
const split_input& split_impl(const Delim& delim) {
|
const split_data& split_impl(const Delim& delim) {
|
||||||
|
|
||||||
if (split_input_.empty()) {
|
trim_left_if_enabled(begin_);
|
||||||
begin_ = line_;
|
|
||||||
}
|
|
||||||
|
|
||||||
trim_if_enabled(begin_);
|
|
||||||
|
|
||||||
for (done_ = false; !done_; read(delim))
|
for (done_ = false; !done_; read(delim))
|
||||||
;
|
;
|
||||||
|
|
||||||
return split_input_;
|
return split_data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@ -278,6 +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_) {
|
||||||
|
resplitting_ = false;
|
||||||
|
++begin_;
|
||||||
|
read_quoted(delim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (quote::match(*begin_)) {
|
if (quote::match(*begin_)) {
|
||||||
curr_ = end_ = ++begin_;
|
curr_ = end_ = ++begin_;
|
||||||
read_quoted(delim);
|
read_quoted(delim);
|
||||||
@ -319,23 +359,38 @@ private:
|
|||||||
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();
|
||||||
set_error_unterminated_quote();
|
set_error_unterminated_quote();
|
||||||
split_input_.emplace_back(line_, begin_);
|
split_data_.emplace_back(line_, begin_);
|
||||||
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);
|
||||||
|
|
||||||
@ -344,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
|
||||||
@ -352,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
|
||||||
@ -363,7 +419,7 @@ private:
|
|||||||
// mismatched quote
|
// mismatched quote
|
||||||
// eg: ...,"hel"lo,... -> error
|
// eg: ...,"hel"lo,... -> error
|
||||||
set_error_mismatched_quote(end_ - line_);
|
set_error_mismatched_quote(end_ - line_);
|
||||||
split_input_.emplace_back(line_, begin_);
|
split_data_.emplace_back(line_, begin_);
|
||||||
}
|
}
|
||||||
done_ = true;
|
done_ = true;
|
||||||
break;
|
break;
|
||||||
@ -375,17 +431,18 @@ private:
|
|||||||
// members
|
// members
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
static_assert(std::is_same_v<error_type, bool> ||
|
public:
|
||||||
std::is_same_v<error_type, std::string>);
|
error_type error_{};
|
||||||
error_type error_;
|
|
||||||
bool unterminated_quote_{false};
|
bool unterminated_quote_{false};
|
||||||
|
bool done_{true};
|
||||||
|
bool resplitting_{false};
|
||||||
|
size_t escaped_{0};
|
||||||
|
split_data split_data_;
|
||||||
|
|
||||||
line_ptr_type begin_;
|
line_ptr_type begin_;
|
||||||
line_ptr_type curr_;
|
line_ptr_type curr_;
|
||||||
line_ptr_type end_;
|
line_ptr_type end_;
|
||||||
line_ptr_type line_;
|
line_ptr_type line_;
|
||||||
bool done_;
|
|
||||||
size_t escaped_{0};
|
|
||||||
split_input split_input_;
|
|
||||||
|
|
||||||
template <typename...>
|
template <typename...>
|
||||||
friend class converter;
|
friend class converter;
|
||||||
|
@ -103,6 +103,9 @@ struct apply_trait<Trait, std::tuple<T>> {
|
|||||||
using type = std::tuple<typename Trait<T>::type>;
|
using type = std::tuple<typename Trait<T>::type>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
using apply_trait_t = typename apply_trait<Trait, Ts...>::type;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// apply optional trait
|
// apply optional trait
|
||||||
////////////////
|
////////////////
|
||||||
@ -143,6 +146,9 @@ struct apply_optional_trait<Trait, std::tuple<T>> {
|
|||||||
std::tuple<typename optional_trait<typename Trait<T>::type, T>::type>;
|
std::tuple<typename optional_trait<typename Trait<T>::type, T>::type>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
using apply_trait_optional_t = apply_optional_trait<Trait, Ts...>;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// filter false_type
|
// filter false_type
|
||||||
////////////////
|
////////////////
|
||||||
@ -192,6 +198,9 @@ struct negate_impl {
|
|||||||
using type = std::integral_constant<bool, !Trait<Ts...>::value>;
|
using type = std::integral_constant<bool, !Trait<Ts...>::value>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait>
|
||||||
|
using negate_impl_t = typename negate_impl<Trait>::type;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// filter by trait
|
// filter by trait
|
||||||
////////////////
|
////////////////
|
||||||
@ -235,20 +244,23 @@ struct count;
|
|||||||
|
|
||||||
template <template <typename...> class Trait, typename T, typename... Ts>
|
template <template <typename...> class Trait, typename T, typename... Ts>
|
||||||
struct count<Trait, T, Ts...> {
|
struct count<Trait, T, Ts...> {
|
||||||
static constexpr size_t size =
|
static constexpr size_t value =
|
||||||
std::tuple_size<filter_if_t<Trait, T, Ts...>>::value;
|
std::tuple_size<filter_if_t<Trait, T, Ts...>>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename T>
|
template <template <typename...> class Trait, typename T>
|
||||||
struct count<Trait, T> {
|
struct count<Trait, T> {
|
||||||
static constexpr size_t size = Trait<T>::value;
|
static constexpr size_t value = Trait<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait>
|
template <template <typename...> class Trait>
|
||||||
struct count<Trait> {
|
struct count<Trait> {
|
||||||
static constexpr size_t size = 0;
|
static constexpr size_t value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
constexpr size_t count_v = count<Trait, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// count not
|
// count not
|
||||||
////////////////
|
////////////////
|
||||||
@ -258,34 +270,40 @@ struct count_not;
|
|||||||
|
|
||||||
template <template <typename...> class Trait, typename T, typename... Ts>
|
template <template <typename...> class Trait, typename T, typename... Ts>
|
||||||
struct count_not<Trait, T, Ts...> {
|
struct count_not<Trait, T, Ts...> {
|
||||||
static constexpr size_t size =
|
static constexpr size_t value =
|
||||||
std::tuple_size<filter_not_t<Trait, T, Ts...>>::value;
|
std::tuple_size<filter_not_t<Trait, T, Ts...>>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename T>
|
template <template <typename...> class Trait, typename T>
|
||||||
struct count_not<Trait, T> {
|
struct count_not<Trait, T> {
|
||||||
static constexpr size_t size = !Trait<T>::value;
|
static constexpr size_t value = !Trait<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait>
|
template <template <typename...> class Trait>
|
||||||
struct count_not<Trait> {
|
struct count_not<Trait> {
|
||||||
static constexpr size_t size = 0;
|
static constexpr size_t value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
constexpr size_t count_not_v = count_not<Trait, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// all of
|
// all of
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct all_of {
|
struct all_of {
|
||||||
static constexpr bool value = count<Trait, Ts...>::size == sizeof...(Ts);
|
static constexpr bool value = count_v<Trait, Ts...> == sizeof...(Ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct all_of<Trait, std::tuple<Ts...>> {
|
struct all_of<Trait, std::tuple<Ts...>> {
|
||||||
static constexpr bool value = count<Trait, Ts...>::size == sizeof...(Ts);
|
static constexpr bool value = count_v<Trait, Ts...> == sizeof...(Ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
constexpr bool all_of_v = all_of<Trait, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// any of
|
// any of
|
||||||
////////////////
|
////////////////
|
||||||
@ -293,43 +311,52 @@ struct all_of<Trait, std::tuple<Ts...>> {
|
|||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct any_of {
|
struct any_of {
|
||||||
static_assert(sizeof...(Ts) > 0);
|
static_assert(sizeof...(Ts) > 0);
|
||||||
static constexpr bool value = count<Trait, Ts...>::size > 0;
|
static constexpr bool value = count_v<Trait, Ts...> > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct any_of<Trait, std::tuple<Ts...>> {
|
struct any_of<Trait, std::tuple<Ts...>> {
|
||||||
static_assert(sizeof...(Ts) > 0);
|
static_assert(sizeof...(Ts) > 0);
|
||||||
static constexpr bool value = count<Trait, Ts...>::size > 0;
|
static constexpr bool value = count_v<Trait, Ts...> > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
constexpr bool any_of_v = any_of<Trait, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// none of
|
// none of
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct none_of {
|
struct none_of {
|
||||||
static constexpr bool value = count<Trait, Ts...>::size == 0;
|
static constexpr bool value = count_v<Trait, Ts...> == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename...> class Trait, typename... Ts>
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
struct none_of<Trait, std::tuple<Ts...>> {
|
struct none_of<Trait, std::tuple<Ts...>> {
|
||||||
static constexpr bool value = count<Trait, Ts...>::size == 0;
|
static constexpr bool value = count_v<Trait, Ts...> == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Trait, typename... Ts>
|
||||||
|
constexpr bool none_of_v = none_of<Trait, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// is instance of
|
// is instance of
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <typename T, template <typename...> class Template>
|
template <template <typename...> class Template, typename T>
|
||||||
struct is_instance_of {
|
struct is_instance_of {
|
||||||
constexpr static bool value = false;
|
constexpr static bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts, template <typename...> class Template>
|
template <template <typename...> class Template, typename... Ts>
|
||||||
struct is_instance_of<Template<Ts...>, Template> {
|
struct is_instance_of<Template, Template<Ts...>> {
|
||||||
constexpr static bool value = true;
|
constexpr static bool value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Template, typename... Ts>
|
||||||
|
constexpr bool is_instance_of_v = is_instance_of<Template, Ts...>::value;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// ternary
|
// ternary
|
||||||
////////////////
|
////////////////
|
||||||
@ -354,17 +381,21 @@ using ternary_t = typename ternary<B, T, U>::type;
|
|||||||
// tuple to struct
|
// tuple to struct
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
template <class S, std::size_t... Is, class Tup>
|
template <class T, std::size_t... Is, class U>
|
||||||
S to_object(std::index_sequence<Is...>, Tup&& tup) {
|
T to_object_impl(std::index_sequence<Is...>, U&& data) {
|
||||||
return {std::get<Is>(std::forward<Tup>(tup))...};
|
return {std::get<Is>(std::forward<U>(data))...};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Tup may not be a tuple ...
|
template <class T, class U>
|
||||||
template <class S, class Tup>
|
T to_object(U&& data) {
|
||||||
S to_object(Tup&& tup) {
|
using NoRefU = std::remove_reference_t<U>;
|
||||||
using T = std::remove_reference_t<Tup>;
|
if constexpr (is_instance_of_v<std::tuple, NoRefU>) {
|
||||||
return to_object<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
|
return to_object_impl<
|
||||||
std::forward<Tup>(tup));
|
T>(std::make_index_sequence<std::tuple_size<NoRefU>{}>{},
|
||||||
|
std::forward<U>(data));
|
||||||
|
} else {
|
||||||
|
return T{std::forward<U>(data)};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* trait */
|
} /* trait */
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,9 @@
|
|||||||
#include <doctest.h>
|
#include <doctest.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class buffer {
|
struct buffer {
|
||||||
char* data_{nullptr};
|
char* data_{nullptr};
|
||||||
|
|
||||||
public:
|
|
||||||
char* operator()(const char* data) {
|
char* operator()(const char* data) {
|
||||||
if (data_) {
|
if (data_) {
|
||||||
delete[] data_;
|
delete[] data_;
|
||||||
@ -34,6 +33,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_;
|
||||||
|
@ -66,12 +66,13 @@ TEST_CASE("parser test various cases") {
|
|||||||
i.emplace_back(ss::to_object<X>(a));
|
i.emplace_back(ss::to_object<X>(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
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(std::equal(i.begin(), i.end(), data.begin() + 1));
|
CHECK_EQ(i, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -91,7 +92,7 @@ TEST_CASE("parser test various cases") {
|
|||||||
i.push_back(p.get_object<X, int, double, std::string>());
|
i.push_back(p.get_object<X, int, double, std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -103,7 +104,7 @@ TEST_CASE("parser test various cases") {
|
|||||||
i.push_back(p.get_object<X, tup>());
|
i.push_back(p.get_object<X, tup>());
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -114,7 +115,7 @@ TEST_CASE("parser test various cases") {
|
|||||||
i.push_back(p.get_next<X>());
|
i.push_back(p.get_next<X>());
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -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(std::equal(i.begin(), i.end(), expected.begin()));
|
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(std::equal(i.begin(), i.end(), expected.begin()));
|
CHECK_EQ(i, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -194,7 +202,7 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
auto expect_error = [](auto error) { CHECK(!error.empty()); };
|
auto expect_error = [](auto error) { CHECK(!error.empty()); };
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(!p.eof());
|
REQUIRE_FALSE(p.eof());
|
||||||
|
|
||||||
{
|
{
|
||||||
constexpr static auto expectedData = std::tuple{10, 'a', 11.1};
|
constexpr static auto expectedData = std::tuple{10, 'a', 11.1};
|
||||||
@ -203,17 +211,17 @@ 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();
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(d3);
|
REQUIRE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
CHECK(*d3 == expectedData);
|
CHECK_EQ(*d3, expectedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -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)
|
||||||
@ -234,10 +242,10 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(d1);
|
REQUIRE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(!d3);
|
REQUIRE_FALSE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
CHECK(*d1 == expectedData);
|
CHECK_EQ(*d1, expectedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -252,12 +260,12 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.or_else<int, char, double>(fail)
|
.or_else<int, char, double>(fail)
|
||||||
.values();
|
.values();
|
||||||
|
|
||||||
REQUIRE(!p.valid());
|
REQUIRE_FALSE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(!d3);
|
REQUIRE_FALSE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
REQUIRE(!d5);
|
REQUIRE_FALSE(d5);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -265,14 +273,14 @@ 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();
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(d1);
|
REQUIRE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -283,9 +291,9 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.values();
|
.values();
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(d2);
|
REQUIRE(d2);
|
||||||
CHECK(d2->tied() == std::tuple{1, 11.1, 'a'});
|
CHECK_EQ(d2->tied(), std::tuple{1, 11.1, 'a'});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -300,12 +308,12 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.on_error(expect_error)
|
.on_error(expect_error)
|
||||||
.values();
|
.values();
|
||||||
|
|
||||||
REQUIRE(!p.valid());
|
REQUIRE_FALSE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(!d3);
|
REQUIRE_FALSE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
REQUIRE(!d5);
|
REQUIRE_FALSE(d5);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -319,12 +327,12 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(d1);
|
REQUIRE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
CHECK(*d1 == std::tuple{10, std::nullopt});
|
CHECK_EQ(*d1, std::tuple{10, std::nullopt});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
REQUIRE(!p.eof());
|
REQUIRE_FALSE(p.eof());
|
||||||
|
|
||||||
auto [d1, d2] = p.try_next<int, std::variant<int, std::string>>()
|
auto [d1, d2] = p.try_next<int, std::variant<int, std::string>>()
|
||||||
.on_error(fail)
|
.on_error(fail)
|
||||||
@ -334,8 +342,8 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(d1);
|
REQUIRE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
CHECK(*d1 == std::tuple{11, std::variant<int, std::string>{"junk"}});
|
CHECK_EQ(*d1, std::tuple{11, std::variant<int, std::string>{"junk"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -346,12 +354,12 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.values();
|
.values();
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(d1);
|
REQUIRE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
CHECK(d1->tied() == std::tuple{10, 11.1, 'c'});
|
CHECK_EQ(d1->tied(), std::tuple{10, 11.1, 'c'});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
REQUIRE(!p.eof());
|
REQUIRE_FALSE(p.eof());
|
||||||
|
|
||||||
auto [d1, d2, d3, d4] =
|
auto [d1, d2, d3, d4] =
|
||||||
p.try_next<int, int>([] { return false; })
|
p.try_next<int, int>([] { return false; })
|
||||||
@ -361,11 +369,11 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.values();
|
.values();
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(d3);
|
REQUIRE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
CHECK(d3.value() == std::tuple{10, 20});
|
CHECK_EQ(d3.value(), std::tuple{10, 20});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -379,11 +387,11 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
.values();
|
.values();
|
||||||
|
|
||||||
REQUIRE(p.valid());
|
REQUIRE(p.valid());
|
||||||
REQUIRE(!d1);
|
REQUIRE_FALSE(d1);
|
||||||
REQUIRE(!d2);
|
REQUIRE_FALSE(d2);
|
||||||
REQUIRE(d3);
|
REQUIRE(d3);
|
||||||
REQUIRE(!d4);
|
REQUIRE_FALSE(d4);
|
||||||
CHECK(d3->tied() == std::tuple{10, 22.2, 'f'});
|
CHECK_EQ(d3->tied(), std::tuple{10, 22.2, 'f'});
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(p.eof());
|
CHECK(p.eof());
|
||||||
@ -446,7 +454,7 @@ TEST_CASE("parser test the moving of parsed values") {
|
|||||||
|
|
||||||
ss::parser p{f.name, ","};
|
ss::parser p{f.name, ","};
|
||||||
auto x = p.get_next<my_string>();
|
auto x = p.get_next<my_string>();
|
||||||
CHECK(move_called < 3);
|
CHECK_LT(move_called, 3);
|
||||||
move_called_one_col = move_called;
|
move_called_one_col = move_called;
|
||||||
move_called = 0;
|
move_called = 0;
|
||||||
}
|
}
|
||||||
@ -461,21 +469,21 @@ TEST_CASE("parser test the moving of parsed values") {
|
|||||||
|
|
||||||
ss::parser p{f.name, ","};
|
ss::parser p{f.name, ","};
|
||||||
auto x = p.get_next<my_string, my_string, my_string>();
|
auto x = p.get_next<my_string, my_string, my_string>();
|
||||||
CHECK(move_called <= 3 * move_called_one_col);
|
CHECK_LE(move_called, 3 * move_called_one_col);
|
||||||
move_called = 0;
|
move_called = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ss::parser p{f.name, ","};
|
ss::parser p{f.name, ","};
|
||||||
auto x = p.get_object<xyz, my_string, my_string, my_string>();
|
auto x = p.get_object<xyz, my_string, my_string, my_string>();
|
||||||
CHECK(move_called <= 6 * move_called_one_col);
|
CHECK_LE(move_called, 6 * move_called_one_col);
|
||||||
move_called = 0;
|
move_called = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ss::parser p{f.name, ","};
|
ss::parser p{f.name, ","};
|
||||||
auto x = p.get_next<xyz>();
|
auto x = p.get_next<xyz>();
|
||||||
CHECK(move_called <= 6 * move_called_one_col);
|
CHECK_LE(move_called, 6 * move_called_one_col);
|
||||||
move_called = 0;
|
move_called = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,10 +511,10 @@ TEST_CASE("parser test error mode") {
|
|||||||
|
|
||||||
ss::parser<ss::string_error> p(f.name, ",");
|
ss::parser<ss::string_error> p(f.name, ",");
|
||||||
|
|
||||||
REQUIRE(!p.eof());
|
REQUIRE_FALSE(p.eof());
|
||||||
p.get_next<int>();
|
p.get_next<int>();
|
||||||
CHECK(!p.valid());
|
CHECK_FALSE(p.valid());
|
||||||
CHECK(!p.error_msg().empty());
|
CHECK_FALSE(p.error_msg().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string no_quote(const std::string& s) {
|
std::string no_quote(const std::string& s) {
|
||||||
@ -516,7 +524,7 @@ std::string no_quote(const std::string& s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("parser test csv on multiple lines with quotes") {
|
TEST_CASE("parser test csv on multiple lines with quotes zzz") {
|
||||||
unique_file_name f;
|
unique_file_name f;
|
||||||
std::vector<X> data = {{1, 2, "\"x\nx\nx\""}, {3, 4, "\"y\ny\ny\""},
|
std::vector<X> data = {{1, 2, "\"x\nx\nx\""}, {3, 4, "\"y\ny\ny\""},
|
||||||
{5, 6, "\"z\nz\""}, {7, 8, "\"u\"\"\""},
|
{5, 6, "\"z\nz\""}, {7, 8, "\"u\"\"\""},
|
||||||
@ -537,7 +545,7 @@ TEST_CASE("parser test csv on multiple lines with quotes") {
|
|||||||
i.emplace_back(ss::to_object<X>(a));
|
i.emplace_back(ss::to_object<X>(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
|
|
||||||
ss::parser<ss::quote<'"'>> p_no_multiline{f.name, ","};
|
ss::parser<ss::quote<'"'>> p_no_multiline{f.name, ","};
|
||||||
while (!p.eof()) {
|
while (!p.eof()) {
|
||||||
@ -553,8 +561,8 @@ std::string no_escape(std::string& s) {
|
|||||||
|
|
||||||
TEST_CASE("parser test csv on multiple lines with escapes") {
|
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"}, {3, 4, "y\\\ny\\\ny"},
|
std::vector<X> data = {{1, 2, "x\\\nx\\\nx"}, {5, 6, "z\\\nz\\\nz"},
|
||||||
{5, 6, "z\\\nz"}, {7, 8, "u"},
|
{7, 8, "u"}, {3, 4, "y\\\ny\\\ny"},
|
||||||
{9, 10, "v\\\\"}, {11, 12, "w\\\n"}};
|
{9, 10, "v\\\\"}, {11, 12, "w\\\n"}};
|
||||||
|
|
||||||
make_and_write(f.name, data);
|
make_and_write(f.name, data);
|
||||||
@ -573,11 +581,72 @@ TEST_CASE("parser test csv on multiple lines with escapes") {
|
|||||||
i.emplace_back(ss::to_object<X>(a));
|
i.emplace_back(ss::to_object<X>(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(std::equal(i.begin(), i.end(), data.begin()));
|
CHECK_EQ(i, data);
|
||||||
|
|
||||||
ss::parser<ss::escape<'\\'>> p_no_multiline{f.name, ","};
|
ss::parser<ss::escape<'\\'>> p_no_multiline{f.name, ","};
|
||||||
while (!p.eof()) {
|
while (!p.eof()) {
|
||||||
auto a = p_no_multiline.get_next<int, double, std::string>();
|
auto a = p_no_multiline.get_next<int, double, std::string>();
|
||||||
CHECK(!p.valid());
|
CHECK_FALSE(p.valid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
|
||||||
|
unique_file_name f;
|
||||||
|
{
|
||||||
|
std::ofstream out{f.name};
|
||||||
|
out << "1,2,\"just\\\n\nstrings\"" << std::endl;
|
||||||
|
out << "3,4,\"just\nsome\\\n\n\\\nstrings\"" << std::endl;
|
||||||
|
out << "5,6,\"just\\\n\\\n\n\nstrings" << std::endl;
|
||||||
|
out << "7,8,\"just strings\"" << std::endl;
|
||||||
|
out << "9,10,just strings" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>> p{f.name};
|
||||||
|
std::vector<X> i;
|
||||||
|
|
||||||
|
while (!p.eof()) {
|
||||||
|
auto a = p.get_next<int, double, std::string>();
|
||||||
|
if (p.valid()) {
|
||||||
|
i.emplace_back(ss::to_object<X>(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<X> data = {{1, 2, "just\n\nstrings"},
|
||||||
|
{3, 4, "just\nsome\n\n\nstrings"},
|
||||||
|
{9, 10, "just strings"}};
|
||||||
|
|
||||||
|
CHECK_EQ(i, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parser test multiline restricted") {
|
||||||
|
unique_file_name f;
|
||||||
|
{
|
||||||
|
std::ofstream out{f.name};
|
||||||
|
out << "1,2,\"just\n\nstrings\"" << std::endl;
|
||||||
|
out << "3,4,\"ju\n\n\nnk\"" << std::endl;
|
||||||
|
out << "5,6,just\\\n\\\nstrings" << std::endl;
|
||||||
|
out << "7,8,ju\\\n\\\n\\\nnk" << std::endl;
|
||||||
|
out << "9,10,\"just\\\n\nstrings\"" << std::endl;
|
||||||
|
out << "11,12,\"ju\\\n|\n\n\n\n\nk\"" << std::endl;
|
||||||
|
out << "13,14,\"ju\\\n\\\n15,16\"\\\n\\\\\n\nnk\"" << std::endl;
|
||||||
|
out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
|
||||||
|
out << "19,20,just strings" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>>
|
||||||
|
p{f.name, ","};
|
||||||
|
std::vector<X> i;
|
||||||
|
|
||||||
|
while (!p.eof()) {
|
||||||
|
auto a = p.get_next<int, double, std::string>();
|
||||||
|
if (p.valid()) {
|
||||||
|
i.emplace_back(ss::to_object<X>(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<X> data = {{1, 2, "just\n\nstrings"},
|
||||||
|
{5, 6, "just\n\nstrings"},
|
||||||
|
{9, 10, "just\n\nstrings"},
|
||||||
|
{19, 20, "just strings"}};
|
||||||
|
CHECK_EQ(i, data);
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ struct set_combinations_size {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::string> words(const ss::split_input& input) {
|
std::vector<std::string> words(const ss::split_data& input) {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
for (const auto& [begin, end] : input) {
|
for (const auto& [begin, end] : input) {
|
||||||
ret.emplace_back(begin, end);
|
ret.emplace_back(begin, end);
|
||||||
@ -88,6 +88,30 @@ auto spaced(const case_type& input, const std::string& s1,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto spaced_left(const case_type& input, const std::string& s) {
|
||||||
|
case_type ret = input;
|
||||||
|
for (const auto& i : input) {
|
||||||
|
ret.push_back(concat(i));
|
||||||
|
ret.push_back(concat(s, i));
|
||||||
|
ret.push_back(concat(s, s, i));
|
||||||
|
ret.push_back(concat(s, s, s, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto spaced_right(const case_type& input, const std::string& s) {
|
||||||
|
case_type ret = input;
|
||||||
|
for (const auto& i : input) {
|
||||||
|
ret.push_back(concat(i));
|
||||||
|
ret.push_back(concat(i, s));
|
||||||
|
ret.push_back(concat(i, s, s));
|
||||||
|
ret.push_back(concat(i, s, s, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> combinations(const std::vector<std::string>& v,
|
std::vector<std::string> combinations(const std::vector<std::string>& v,
|
||||||
const std::string& delim, size_t n) {
|
const std::string& delim, size_t n) {
|
||||||
if (n <= 1) {
|
if (n <= 1) {
|
||||||
@ -169,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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,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;
|
||||||
}
|
}
|
||||||
@ -514,166 +538,234 @@ 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 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);
|
||||||
|
|
||||||
auto new_line = buff.append(R"(,dom","strings")");
|
auto new_line =
|
||||||
|
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 vec =
|
||||||
|
expect_unterminated_quote(s, "3,4,"
|
||||||
|
"\"just0\\\n1\\\n22\\\n33333x\\\n4");
|
||||||
|
|
||||||
|
std::vector<std::string> expected{"3", "4"};
|
||||||
|
auto w = words(vec);
|
||||||
|
w.pop_back();
|
||||||
|
CHECK_EQ(w, expected);
|
||||||
|
REQUIRE(s.unterminated_quote());
|
||||||
|
{
|
||||||
|
auto new_line =
|
||||||
|
buff.append_overwrite_last("\nx5strings\"", c.size_shifted());
|
||||||
|
vec = c.resplit(new_line, strlen(new_line));
|
||||||
|
CHECK(s.valid());
|
||||||
|
CHECK_FALSE(s.unterminated_quote());
|
||||||
|
expected = {"3", "4", "just0\n1\n22\n33333x\n4\nx5strings"};
|
||||||
|
CHECK_EQ(words(vec), expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
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_overwrite_last(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","ra\")");
|
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());
|
||||||
{
|
{
|
||||||
auto new_line = buff.append(R"(n,dom",str\"ings)");
|
auto new_line = buff.append_overwrite_last(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", "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());
|
||||||
{
|
{
|
||||||
auto new_line = buff.append(R"( n,dom" , strings )");
|
auto new_line =
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -686,26 +778,139 @@ 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") {
|
||||||
|
auto guard = set_combinations_size(3);
|
||||||
|
case_type case1 = spaced_left({R"(x )"}, " ");
|
||||||
|
case_type case2 = spaced_left({R"(yy )"}, " ");
|
||||||
|
case_type case3 = spaced_left({R"(y y )"}, " ");
|
||||||
|
case_type case4 = spaced_left({R"()"}, " ");
|
||||||
|
|
||||||
|
std::vector<std::string> delims = {",", "::", "\t", "\n"};
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, "x "},
|
||||||
|
{case2, "yy "},
|
||||||
|
{case3, "y y "},
|
||||||
|
{case4, ""}};
|
||||||
|
test_combinations<ss::trim_left<' '>>(p, delims);
|
||||||
|
}
|
||||||
|
|
||||||
|
case_type case5 = spaced_left({"z "}, "\t");
|
||||||
|
case_type case6 = spaced_left({"ab\t "}, " \t");
|
||||||
|
case_type case7 = spaced_left({"a\tb "}, " \t");
|
||||||
|
case_type case8 = spaced_left({"a \t b "}, " \t");
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, "x "}, {case2, "yy "}, {case3, "y y "},
|
||||||
|
{case4, ""}, {case5, "z "}, {case6, "ab\t "},
|
||||||
|
{case7, "a\tb "}, {case8, "a \t b "}};
|
||||||
|
test_combinations<ss::trim_left<' ', '\t'>>(p, {",", "::", "\n"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("splitter test with trim_right") {
|
||||||
|
auto guard = set_combinations_size(3);
|
||||||
|
case_type case1 = spaced_right({R"( x)"}, " ");
|
||||||
|
case_type case2 = spaced_right({R"( yy)"}, " ");
|
||||||
|
case_type case3 = spaced_right({R"( y y)"}, " ");
|
||||||
|
case_type case4 = spaced_right({R"()"}, " ");
|
||||||
|
|
||||||
|
std::vector<std::string> delims = {",", "::", "\t", "\n"};
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, " x"},
|
||||||
|
{case2, " yy"},
|
||||||
|
{case3, " y y"},
|
||||||
|
{case4, ""}};
|
||||||
|
test_combinations<ss::trim_right<' '>>(p, delims);
|
||||||
|
}
|
||||||
|
|
||||||
|
case_type case5 = spaced_right({" z"}, "\t");
|
||||||
|
case_type case6 = spaced_right({"\t ab"}, " \t");
|
||||||
|
case_type case7 = spaced_right({"\ta\tb"}, " \t");
|
||||||
|
case_type case8 = spaced_right({" \t a \t b"}, " \t");
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, " x"}, {case2, " yy"},
|
||||||
|
{case3, " y y"}, {case4, ""},
|
||||||
|
{case5, " z"}, {case6, "\t ab"},
|
||||||
|
{case7, "\ta\tb"}, {case8, " \t a \t b"}};
|
||||||
|
test_combinations<ss::trim_right<' ', '\t'>>(p, {",", "::", "\n"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("splitter test with trim_right and trim_left") {
|
||||||
|
auto guard = set_combinations_size(3);
|
||||||
|
case_type case1 = spaced_right({R"(-x)"}, "-");
|
||||||
|
case_type case2 = spaced_left({R"(yy_)"}, "_");
|
||||||
|
case_type case3 = spaced_right({R"(-y y)"}, "-");
|
||||||
|
case_type case4 = spaced_left({R"()"}, "-");
|
||||||
|
case_type case5 = spaced_left({R"()"}, "_");
|
||||||
|
case_type case6 = {"___---", "_-", "______-"};
|
||||||
|
|
||||||
|
std::vector<std::string> delims = {",", "::", "\t", "\n"};
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, "-x"}, {case2, "yy_"}, {case3, "-y y"},
|
||||||
|
{case4, ""}, {case5, ""}, {case6, ""}};
|
||||||
|
test_combinations<ss::trim_left<'_'>, ss::trim_right<'-'>>(p, delims);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("splitter test with quote and escape, trim_left and trim_right") {
|
||||||
|
auto guard = set_combinations_size(3);
|
||||||
|
case_type case1 = spaced_left({R"("\"")", R"(\")", R"("""")"}, "_");
|
||||||
|
case_type case2 =
|
||||||
|
spaced_left({R"("x\"x")", R"(x\"x)", R"(x"x)", R"("x""x")"}, "_");
|
||||||
|
case_type case3 = spaced_left({R"("")", R"()"}, "_");
|
||||||
|
case_type case4 = spaced_left({R"("x")", R"(x)"}, "_");
|
||||||
|
case_type case5 =
|
||||||
|
spaced_right({R"("\"\"")", R"("""""")", R"("\"""")", R"("""\"")"}, "-");
|
||||||
|
case_type case6 = spaced_right({R"("\\")", R"(\\)"}, "-");
|
||||||
|
case_type case7 = spaced_right({R"("xxxxxxxxxx")", R"(xxxxxxxxxx)"}, "-");
|
||||||
|
|
||||||
|
std::vector<std::string> delims = {"::", "\n"};
|
||||||
|
|
||||||
|
{
|
||||||
|
matches_type p{{case1, "\""}, {case2, "x\"x"}, {case3, ""},
|
||||||
|
{case5, "\"\""}, {case6, "\\"}, {case7, "xxxxxxxxxx"}};
|
||||||
|
test_combinations<ss::quote<'"'>, ss::escape<'\\'>, ss::trim_left<'_'>,
|
||||||
|
ss::trim_right<'-'>>(p, delims);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user