add splitter tests

This commit is contained in:
ado 2021-01-23 21:39:18 +01:00
parent 15f0c63643
commit 24fe96dc44
6 changed files with 403 additions and 77 deletions

View File

@ -2,7 +2,7 @@ project('ssp', 'cpp',
default_options : default_options :
['warning_level=3', ['warning_level=3',
'cpp_std=c++17', 'cpp_std=c++17',
'buildtype=debug']) 'buildtype=debugoptimized'])
includes = include_directories('include') includes = include_directories('include')
subdir('test') subdir('test')

View File

@ -1,26 +1,7 @@
#include "test_helpers.hpp"
#include <algorithm> #include <algorithm>
#include <ss/converter.hpp> #include <ss/converter.hpp>
#ifdef CMAKE_GITHUB_CI
#include <doctest/doctest.h>
#else
#include <doctest.h>
#endif
class buffer {
constexpr static auto buff_size = 1024;
char data_[buff_size];
public:
char* operator()(const char* data) {
memset(data_, '\0', buff_size);
strcpy(data_, data);
return data_;
}
};
static buffer buff;
TEST_CASE("testing split") { TEST_CASE("testing split") {
ss::converter c; ss::converter c;
for (const auto& [s, expected, delim] : for (const auto& [s, expected, delim] :

View File

@ -1,11 +1,6 @@
#include <ss/extract.hpp> #include "test_helpers.hpp"
#include <algorithm> #include <algorithm>
#include <ss/extract.hpp>
#ifdef CMAKE_GITHUB_CI
#include <doctest/doctest.h>
#else
#include <doctest.h>
#endif
constexpr auto eps = 0.000001; constexpr auto eps = 0.000001;
using ld = long double; using ld = long double;

22
test/test_helpers.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <cstring>
#ifdef CMAKE_GITHUB_CI
#include <doctest/doctest.h>
#else
#include <doctest.h>
#endif
class buffer {
constexpr static auto buff_size = 1024;
char data_[buff_size];
public:
char* operator()(const char* data) {
memset(data_, '\0', buff_size);
strcpy(data_, data);
return data_;
}
};
[[maybe_unused]] inline buffer buff;

View File

@ -1,20 +1,18 @@
#include "test_helpers.hpp"
#include <algorithm> #include <algorithm>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <ss/parser.hpp> #include <ss/parser.hpp>
#ifdef CMAKE_GITHUB_CI
#include <doctest/doctest.h>
#else
#include <doctest.h>
#endif
struct unique_file_name { struct unique_file_name {
const std::string name; const std::string name;
unique_file_name() : name{std::tmpnam(nullptr)} {} unique_file_name() : name{std::tmpnam(nullptr)} {
}
~unique_file_name() { std::filesystem::remove(name); } ~unique_file_name() {
std::filesystem::remove(name);
}
}; };
struct X { struct X {
@ -30,7 +28,9 @@ struct X {
.append(delim) .append(delim)
.append(s); .append(s);
} }
auto tied() const { return std::tie(i, d, s); } auto tied() const {
return std::tie(i, d, s);
}
}; };
template <typename T> template <typename T>
@ -167,10 +167,13 @@ struct test_struct {
int i; int i;
double d; double d;
char c; char c;
auto tied() { return std::tie(i, d, c); } auto tied() {
return std::tie(i, d, c);
}
}; };
void expect_test_struct(const test_struct&) {} void expect_test_struct(const test_struct&) {
}
// various scenarios // various scenarios
TEST_CASE("testing composite conversion") { TEST_CASE("testing composite conversion") {
@ -392,7 +395,9 @@ struct my_string {
my_string() = default; my_string() = default;
~my_string() { delete[] data; } ~my_string() {
delete[] data;
}
// make sure no object is copied // make sure no object is copied
my_string(const my_string&) = delete; my_string(const my_string&) = delete;
@ -423,7 +428,9 @@ struct xyz {
my_string x; my_string x;
my_string y; my_string y;
my_string z; my_string z;
auto tied() { return std::tie(x, y, z); } auto tied() {
return std::tie(x, y, z);
}
}; };
TEST_CASE("testing the moving of parsed values") { TEST_CASE("testing the moving of parsed values") {

View File

@ -1,48 +1,369 @@
#include "test_helpers.hpp"
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <ss/splitter.hpp> #include <ss/splitter.hpp>
#ifdef CMAKE_GITHUB_CI // TODO make ss::quote accept only one argument
#include <doctest/doctest.h>
#else
#include <doctest.h>
#endif
TEST_CASE("testing splitter with escaping") { namespace {
std::vector<std::string> values{"10", "he\\\"llo", constexpr static auto combinations_size_default = 4;
"\\\"", "\\\"a\\,a\\\"", size_t combinations_size = combinations_size_default;
"3.33", "a\\\""};
char buff[128]; struct set_combinations_size {
// with quote set_combinations_size(size_t size) {
ss::splitter<ss::quote<'"'>, ss::escape<'\\'>> s; combinations_size = size;
std::string delim = ","; }
for (size_t i = 0; i < values.size() * values.size(); ++i) { ~set_combinations_size() {
std::string input1; combinations_size = combinations_size_default;
std::string input2; }
for (size_t j = 0; j < values.size(); ++j) { };
if (i & (1 << j) && j != 2 && j != 3) {
input1.append(values[j]); std::vector<std::string> words(const ss::split_input& input) {
input2.append(values.at(values.size() - 1 - j)); std::vector<std::string> ret;
} else { for (const auto& [begin, end] : input) {
input1.append("\"" + values[j] + "\""); ret.emplace_back(begin, end);
input2.append("\"" + values.at(values.size() - 1 - j) + "\""); }
} return ret;
input1.append(delim); }
input2.append(delim);
[[maybe_unused]] std::string concat(const std::vector<std::string>& v) {
std::string ret = "{";
for (const auto& i : v) {
ret.append(i).append(" ");
}
ret.back() = ('}');
return ret;
}
std::vector<std::string> combinations(const std::vector<std::string>& v,
const std::string& delim, size_t n) {
if (n <= 1) {
return v;
}
std::vector<std::string> ret;
auto inner_combinations = combinations(v, delim, n - 1);
for (auto& i : v) {
for (auto& j : inner_combinations) {
ret.push_back(i + delim + j);
} }
input1.pop_back(); }
input2.pop_back(); return ret;
input1.append("\0\""); }
input2.append("\0\"");
memcpy(buff, input1.c_str(), input1.size() + 1); std::vector<std::vector<std::string>> vector_combinations(
auto tup1 = s.split(buff, delim); const std::vector<std::string>& v, size_t n) {
CHECK(tup1.size() == 6); std::vector<std::vector<std::string>> ret;
if (n <= 1) {
for (auto& i : v) {
ret.push_back({i});
}
return ret;
}
memcpy(buff, input2.c_str(), input2.size() + 1); auto inner_combinations = vector_combinations(v, n - 1);
auto tup2 = s.split(buff, delim); for (auto& i : v) {
CHECK(tup2.size() == 6); for (auto j : inner_combinations) {
j.insert(j.begin(), i);
ret.push_back(std::move(j));
}
}
return ret;
}
using case_type = std::vector<std::string>;
std::pair<std::vector<std::string>, std::vector<std::vector<std::string>>>
make_combinations(const std::vector<std::string>& input,
const std::vector<std::string>& output,
const std::string& delim) {
std::vector<std::string> lines;
std::vector<std::vector<std::string>> expectations;
for (size_t i = 0; i < combinations_size; ++i) {
auto l = combinations(input, delim, i);
lines.reserve(lines.size() + l.size());
lines.insert(lines.end(), l.begin(), l.end());
auto e = vector_combinations(output, i);
expectations.reserve(expectations.size() + e.size());
expectations.insert(expectations.end(), e.begin(), e.end());
}
return {std::move(lines), std::move(expectations)};
}
auto spaced(const case_type& input, std::string s) {
case_type ret = input;
for (auto& i : input) {
ret.push_back(s + i + s);
ret.push_back(i + s);
ret.push_back(s + i);
ret.push_back(s + s + i);
ret.push_back(s + s + i + s);
ret.push_back(s + s + i + s + s);
ret.push_back(s + i + s + s);
ret.push_back(i + s + s);
}
return ret;
}
auto spaced(const case_type& input, std::string s1, std::string s2) {
case_type ret = input;
for (auto& i : input) {
ret.push_back(s1 + i + s2);
ret.push_back(s2 + i + s1);
ret.push_back(s2 + s2 + s1 + s1 + i);
ret.push_back(i + s1 + s2 + s1 + s2);
ret.push_back(s1 + s1 + s1 + i + s2 + s2 + s2);
ret.push_back(s2 + s2 + s2 + i + s1 + s1 + s1);
}
return ret;
}
} /* namespace */
/* ********************************** */
/* ********************************** */
using matches_type = std::vector<std::pair<case_type, std::string>>;
template <typename... Matchers>
void test_combinations(matches_type& matches, std::vector<std::string> delims) {
ss::splitter<Matchers...> s;
std::vector<std::string> inputs;
std::vector<std::string> outputs;
for (const auto& [cases, e] : matches) {
for (const auto& c : cases) {
inputs.emplace_back(c);
outputs.emplace_back(e);
}
}
for (const auto& delim : delims) {
auto [lines, expectations] = make_combinations(inputs, outputs, delim);
REQUIRE(lines.size() == expectations.size());
for (size_t i = 0; i < lines.size(); ++i) {
auto vec = s.split(buff(lines[i].c_str()), delim);
CHECK(s.valid());
CHECK(words(vec) == expectations[i]);
}
}
}
TEST_CASE("testing splitter no setup") {
{
matches_type p{{{"x"}, "x"}, {{"\""}, "\""},
{{""}, ""}, {{"\n"}, "\n"},
{{"\"\""}, "\"\""}, {{"\" \\ \""}, "\" \\ \""},
{{" "}, " "}};
test_combinations(p, {",", ";", "\t", "::"});
}
}
TEST_CASE("testing splitter quote") {
case_type case1 = {R"("""")"};
case_type case2 = {R"("x""x")", R"(x"x)"};
case_type case3 = {R"("")", R"()"};
case_type case4 = {R"("x")", R"(x)"};
case_type case5 = {R"("""""")"};
case_type case6 = {R"("\")", R"(\)"};
case_type case7 = {R"("xxxxxxxxxx")", R"(xxxxxxxxxx)"};
std::vector<std::string> delims = {",", "::", " ", "\t", "\n"};
{
matches_type p{{case1, "\""}, {case2, "x\"x"}, {case3, ""},
{case4, "x"}, {case5, "\"\""}, {case6, "\\"},
{case7, "xxxxxxxxxx"}};
test_combinations<ss::quote<'"'>>(p, delims);
}
case_type case8 = {R"(",")"};
case_type case9 = {R"("x,")"};
case_type case10 = {R"(",x")"};
case_type case11 = {R"("x,x")"};
case_type case12 = {R"(",,")"};
{
matches_type p{{case1, "\""}, {case3, ""}, {case8, ","},
{case9, "x,"}, {case10, ",x"}, {case11, "x,x"},
{case12, ",,"}};
test_combinations<ss::quote<'"'>>(p, {","});
}
case_type case13 = {R"("::")"};
case_type case14 = {R"("x::")"};
case_type case15 = {R"("::x")"};
case_type case16 = {R"("x::x")"};
case_type case17 = {R"("::::")"};
{
matches_type p{{case1, "\""}, {case3, ""}, {case13, "::"},
{case14, "x::"}, {case15, "::x"}, {case16, "x::x"},
{case17, "::::"}};
test_combinations<ss::quote<'"'>>(p, {"::"});
}
}
TEST_CASE("testing splitter trim") {
auto guard = set_combinations_size(3);
case_type case1 = spaced({R"(x)"}, " ");
case_type case2 = spaced({R"(yy)"}, " ");
case_type case3 = spaced({R"(y y)"}, " ");
case_type case4 = spaced({R"()"}, " ");
std::vector<std::string> delims = {",", "::", "\t", "\n"};
{
matches_type p{{case1, "x"},
{case2, "yy"},
{case3, "y y"},
{case4, ""}};
test_combinations<ss::trim<' '>>(p, delims);
}
case_type case5 = spaced({"z"}, "\t");
case_type case6 = spaced({"ab"}, " ", "\t");
case_type case7 = spaced({"a\tb"}, " ", "\t");
case_type case8 = spaced({"a \t b"}, " ", "\t");
{
matches_type p{{case1, "x"}, {case2, "yy"}, {case3, "y y"},
{case4, ""}, {case5, "z"}, {case6, "ab"},
{case7, "a\tb"}, {case8, "a \t b"}};
test_combinations<ss::trim<' ', '\t'>>(p, {",", "::", "\n"});
}
}
TEST_CASE("testing splitter escape") {
case_type case1 = {R"(x)", R"(\x)"};
case_type case2 = {R"(xx)", R"(\xx)", R"(x\x)", R"(\x\x)"};
case_type case3 = {R"(\\)"};
std::vector<std::string> delims = {",", "::", " ", "\t", "\n"};
{
matches_type p{{case1, "x"}, {case2, "xx"}, {case3, "\\"}};
test_combinations<ss::escape<'\\'>>(p, delims);
}
case_type case4 = {R"(\,)"};
case_type case5 = {R"(x#,)"};
case_type case6 = {R"(#,x)"};
case_type case7 = {R"(x\,x)"};
{
matches_type p{{case1, "x"}, {case2, "xx"}, {case3, "\\"},
{case4, ","}, {case5, "x,"}, {case6, ",x"},
{case7, "x,x"}};
test_combinations<ss::escape<'\\', '#'>>(p, {","});
}
case_type case8 = {R"(\:\:)"};
case_type case9 = {R"(x\::x)"};
{
matches_type p{{case1, "x"},
{case2, "xx"},
{case3, "\\"},
{case8, "::"},
{case9, "x::x"}};
test_combinations<ss::escape<'\\'>>(p, {"::"});
}
}
TEST_CASE("testing splitter quote and trim") {
auto guard = set_combinations_size(3);
case_type case1 = spaced({R"("""")"}, " ");
case_type case2 = spaced({R"("x""x")", R"(x"x)"}, " ");
case_type case3 = spaced({R"("")", R"()"}, " ");
case_type case4 = spaced({R"("x")", R"(x)"}, " ");
case_type case5 = spaced({R"("""""")"}, " ");
case_type case6 = spaced({R"("\")", R"(\)"}, " ");
case_type case7 = spaced({R"("xxxxxxxxxx")", R"(xxxxxxxxxx)"}, " ");
std::vector<std::string> delims = {",", "::", "\t", "\n"};
{
matches_type p{{case1, "\""}, {case2, "x\"x"}, {case3, ""},
{case4, "x"}, {case5, "\"\""}, {case6, "\\"},
{case7, "xxxxxxxxxx"}};
test_combinations<ss::quote<'"'>, ss::trim<' '>>(p, delims);
}
return;
case_type case8 = {R"(",")"};
case_type case9 = {R"("x,")"};
case_type case10 = {R"(",x")"};
case_type case11 = {R"("x,x")"};
case_type case12 = {R"(",,")"};
{
matches_type p{{case1, "\""}, {case3, ""}, {case8, ","},
{case9, "x,"}, {case10, ",x"}, {case11, "x,x"},
{case12, ",,"}};
test_combinations<ss::quote<'"'>>(p, {","});
}
case_type case13 = {R"("::")"};
case_type case14 = {R"("x::")"};
case_type case15 = {R"("::x")"};
case_type case16 = {R"("x::x")"};
case_type case17 = {R"("::::")"};
{
matches_type p{{case1, "\""}, {case3, ""}, {case13, "::"},
{case14, "x::"}, {case15, "::x"}, {case16, "x::x"},
{case17, "::::"}};
test_combinations<ss::quote<'"'>>(p, {"::"});
}
}
TEST_CASE("testing splitter quote and escape") {
case_type case1 = {R"("\"")", R"(\")", R"("""")"};
case_type case2 = {R"("x\"x")", R"(x\"x)", R"(x"x)", R"("x""x")"};
case_type case3 = {R"("")", R"()"};
case_type case4 = {R"("x")", R"(x)"};
case_type case5 = {R"("\"\"")", R"("""""")", R"("\"""")", R"("""\"")"};
case_type case6 = {R"("\\")", R"(\\)"};
case_type case7 = {R"("xxxxxxxxxx")", R"(xxxxxxxxxx)"};
std::vector<std::string> delims = {",", "::", " ", "\t", "\n"};
ss::splitter<ss::quote<'"'>, ss::escape<'\\'>> s;
{
matches_type p{{case1, "\""}, {case2, "x\"x"}, {case3, ""},
{case4, "x"}, {case5, "\"\""}, {case6, "\\"},
{case7, "xxxxxxxxxx"}};
test_combinations<ss::quote<'"'>, ss::escape<'\\'>>(p, delims);
}
case_type case8 = {R"('xxxxxxxxxx')", R"(xxxxxxxxxx)"};
case_type case9 = {R"('')", R"()"};
case_type case10 = {R"('#\')", R"(#\)"};
case_type case11 = {R"('#'')", R"(#')", R"('''')"};
case_type case12 = {R"('##')", R"(##)"};
{
matches_type p{{case8, "xxxxxxxxxx"},
{case9, ""},
{case10, "\\"},
{case11, "'"},
{case12, "#"}};
test_combinations<ss::quote<'\''>, ss::escape<'#'>>(p, delims);
}
case_type case13 = {R"("x,x")", R"(x\,x)", R"(x#,x)",
R"("x\,x")", R"("x#,x")", R"("x#,x")"};
case_type case14 = {R"("#\\#")", R"(#\\#)", R"(\\##)", R"("\\##")"};
{
matches_type p{{case1, "\""},
{case2, "x\"x"},
{case3, ""},
{case13, "x,x"},
{case14, "\\#"}};
test_combinations<ss::quote<'"'>, ss::escape<'\\', '#'>>(p, {","});
} }
} }