mirror of
https://github.com/red0124/ssp.git
synced 2025-01-23 13:05:20 +01:00
Update ssp.hpp, add more parser unit tests
This commit is contained in:
parent
a152a8cb4a
commit
2c7bc763a5
51
ssp.hpp
51
ssp.hpp
@ -2399,9 +2399,9 @@ public:
|
|||||||
if constexpr (throw_on_error) {
|
if constexpr (throw_on_error) {
|
||||||
try {
|
try {
|
||||||
reader_.parse();
|
reader_.parse();
|
||||||
} catch (...) {
|
} catch (const ss::exception& e) {
|
||||||
read_line();
|
read_line();
|
||||||
throw;
|
decorate_rethrow(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reader_.parse();
|
reader_.parse();
|
||||||
@ -2427,9 +2427,9 @@ public:
|
|||||||
auto value = reader_.converter_.template convert<T, Ts...>();
|
auto value = reader_.converter_.template convert<T, Ts...>();
|
||||||
read_line();
|
read_line();
|
||||||
return value;
|
return value;
|
||||||
} catch (...) {
|
} catch (const ss::exception& e) {
|
||||||
read_line();
|
read_line();
|
||||||
throw;
|
decorate_rethrow(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2510,12 +2510,15 @@ public:
|
|||||||
using value = std::conditional_t<get_object, T,
|
using value = std::conditional_t<get_object, T,
|
||||||
no_void_validator_tup_t<T, Ts...>>;
|
no_void_validator_tup_t<T, Ts...>>;
|
||||||
|
|
||||||
iterator() : parser_{nullptr} {
|
iterator() : parser_{nullptr}, value_{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator(parser<Options...>* parser) : parser_{parser} {
|
iterator(parser<Options...>* parser) : parser_{parser}, value_{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator(const iterator& other) = default;
|
||||||
|
iterator(iterator&& other) = default;
|
||||||
|
|
||||||
value& operator*() {
|
value& operator*() {
|
||||||
return value_;
|
return value_;
|
||||||
}
|
}
|
||||||
@ -2525,7 +2528,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
iterator& operator++() {
|
iterator& operator++() {
|
||||||
if (parser_->eof()) {
|
if (!parser_ || parser_->eof()) {
|
||||||
parser_ = nullptr;
|
parser_ = nullptr;
|
||||||
} else {
|
} else {
|
||||||
if constexpr (get_object) {
|
if constexpr (get_object) {
|
||||||
@ -2554,8 +2557,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value value_;
|
|
||||||
parser<Options...>* parser_;
|
parser<Options...>* parser_;
|
||||||
|
value value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
iterable(parser<Options...>* parser) : parser_{parser} {
|
iterable(parser<Options...>* parser) : parser_{parser} {
|
||||||
@ -2766,7 +2769,14 @@ private:
|
|||||||
std::string raw_header_copy = raw_header_;
|
std::string raw_header_copy = raw_header_;
|
||||||
splitter.split(raw_header_copy.data(), reader_.delim_);
|
splitter.split(raw_header_copy.data(), reader_.delim_);
|
||||||
for (const auto& [begin, end] : splitter.split_data_) {
|
for (const auto& [begin, end] : splitter.split_data_) {
|
||||||
header_.emplace_back(begin, end);
|
std::string field{begin, end};
|
||||||
|
if (std::find(header_.begin(), header_.end(), field) !=
|
||||||
|
header_.end()) {
|
||||||
|
handle_error_invalid_header(field);
|
||||||
|
header_.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
header_.push_back(std::move(field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2898,6 +2908,29 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_error_invalid_header(const std::string& field) {
|
||||||
|
constexpr static auto error_msg = "header contains duplicates: ";
|
||||||
|
|
||||||
|
if constexpr (string_error) {
|
||||||
|
error_.clear();
|
||||||
|
error_.append(error_msg).append(error_msg);
|
||||||
|
} else if constexpr (throw_on_error) {
|
||||||
|
throw ss::exception{error_msg + field};
|
||||||
|
} else {
|
||||||
|
error_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void decorate_rethrow(const ss::exception& e) const {
|
||||||
|
static_assert(throw_on_error,
|
||||||
|
"throw_on_error needs to be enabled to use this method");
|
||||||
|
throw ss::exception{std::string{file_name_}
|
||||||
|
.append(" ")
|
||||||
|
.append(std::to_string(reader_.line_number_))
|
||||||
|
.append(": ")
|
||||||
|
.append(e.what())};
|
||||||
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// line reading
|
// line reading
|
||||||
////////////////
|
////////////////
|
||||||
|
@ -1259,21 +1259,47 @@ void test_invalid_fields_impl(const std::vector<std::string>& lines,
|
|||||||
{
|
{
|
||||||
// Field used multiple times
|
// Field used multiple times
|
||||||
ss::parser<Ts...> p{f.name, ","};
|
ss::parser<Ts...> p{f.name, ","};
|
||||||
auto command = [&] { p.use_fields(fields[0], fields[0]); };
|
auto command = [&] { p.use_fields(fields.at(0), fields.at(0)); };
|
||||||
|
if (!fields.empty()) {
|
||||||
expect_error_on_command(p, command);
|
expect_error_on_command(p, command);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Mapping out of range
|
// Mapping out of range
|
||||||
ss::parser<Ts...> p{f.name, ","};
|
ss::parser<Ts...> p{f.name, ","};
|
||||||
auto command = [&] {
|
auto command = [&] {
|
||||||
p.use_fields(fields[0]);
|
p.use_fields(fields.at(0));
|
||||||
p.template get_next<std::string, std::string>();
|
p.template get_next<std::string, std::string>();
|
||||||
};
|
};
|
||||||
|
if (!fields.empty()) {
|
||||||
expect_error_on_command(p, command);
|
expect_error_on_command(p, command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Invalid header
|
||||||
|
ss::parser<Ts...> p{f.name, ","};
|
||||||
|
auto command = [&] { p.use_fields(fields); };
|
||||||
|
|
||||||
|
if (!fields.empty()) {
|
||||||
|
// Pass if there are no duplicates, fail otherwise
|
||||||
|
if (std::unordered_set<std::string>{fields.begin(), fields.end()}
|
||||||
|
.size() != fields.size()) {
|
||||||
|
expect_error_on_command(p, command);
|
||||||
|
} else {
|
||||||
|
command();
|
||||||
|
CHECK(p.valid());
|
||||||
|
if (!p.valid()) {
|
||||||
|
if constexpr (ss::setup<Ts...>::string_error) {
|
||||||
|
std::cout << p.error_msg() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
void test_invalid_fields(const std::vector<std::string>& lines,
|
void test_invalid_fields(const std::vector<std::string>& lines,
|
||||||
const std::vector<std::string>& fields) {
|
const std::vector<std::string>& fields) {
|
||||||
@ -1282,13 +1308,28 @@ void test_invalid_fields(const std::vector<std::string>& lines,
|
|||||||
test_invalid_fields_impl<ss::throw_on_error>(lines, fields);
|
test_invalid_fields_impl<ss::throw_on_error>(lines, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add more test cases
|
|
||||||
TEST_CASE("parser test invalid header fields usage") {
|
TEST_CASE("parser test invalid header fields usage") {
|
||||||
|
test_invalid_fields({}, {});
|
||||||
|
|
||||||
|
test_invalid_fields({"Int"}, {"Int"});
|
||||||
|
test_invalid_fields({"Int", "1"}, {"Int"});
|
||||||
|
test_invalid_fields({"Int", "1", "2"}, {"Int"});
|
||||||
|
|
||||||
|
test_invalid_fields({"Int,String"}, {"Int", "String"});
|
||||||
|
test_invalid_fields({"Int,String", "1,hi"}, {"Int", "String"});
|
||||||
|
test_invalid_fields({"Int,String", "2,hello"}, {"Int", "String"});
|
||||||
|
|
||||||
|
test_invalid_fields({"Int,String,Double"}, {"Int", "String", "Double"});
|
||||||
test_invalid_fields({"Int,String,Double", "1,hi,2.34"},
|
test_invalid_fields({"Int,String,Double", "1,hi,2.34"},
|
||||||
{"Int", "String", "Double"});
|
{"Int", "String", "Double"});
|
||||||
|
test_invalid_fields({"Int,String,Double", "1,hi,2.34", "2,hello,3.45"},
|
||||||
|
{"Int", "String", "Double"});
|
||||||
|
|
||||||
test_invalid_fields({"Int,Int,Int", "1,2,3"},
|
test_invalid_fields({"Int,Int,Int"}, {"Int", "Int", "Int"});
|
||||||
{"Int", "Int", "Int"});
|
test_invalid_fields({"Int,Int,Int", "1,2,3"}, {"Int", "Int", "Int"});
|
||||||
|
|
||||||
|
test_invalid_fields({"Int,String,Int"}, {"Int", "String", "Int"});
|
||||||
|
test_invalid_fields({"Int,String,Int", "1,hi,3"}, {"Int", "String", "Int"});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
|
Loading…
Reference in New Issue
Block a user