Skip to content
Snippets Groups Projects
Commit 0d067c5a authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Add tests for FunctionArgumentConverter

On the way, fixed a few minor issues:
- simplified conversion to string
- fixed missing alternative when converting to tuples
- change a few copies into moves
parent 6bb4fc79
No related branches found
No related tags found
1 merge request!54Feature/language coverage
......@@ -31,9 +31,20 @@ class FunctionArgumentToStringConverter final : public IFunctionArgumentConverte
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
std::visit(
[&](auto&& v) {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_arithmetic_v<T>) {
exec_policy.currentContext()[m_argument_id] = std::to_string(v);
} else if constexpr (std::is_same_v<T, std::string>) {
exec_policy.currentContext()[m_argument_id] = v;
} else {
std::ostringstream sout;
sout << value;
sout << value << std::ends;
exec_policy.currentContext()[m_argument_id] = sout.str();
}
},
value);
return {};
}
......@@ -100,6 +111,7 @@ class FunctionTinyVectorArgumentConverter final : public IFunctionArgumentConver
} else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) {
exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero};
} else {
static_assert(std::is_same_v<ExpectedValueType, TinyVector<1>>);
exec_policy.currentContext()[m_argument_id] =
std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));
}
......@@ -132,19 +144,36 @@ class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.emplace_back(v[i]);
list_value.emplace_back(std::move(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else if constexpr ((std::is_convertible_v<ContentT, ContentType>)and not is_tiny_vector_v<ContentType>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.push_back(static_cast<ContentType>(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
} else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)});
} else {
throw UnexpectedError(demangle<ValueT>() + " unexpected value type");
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
}
},
value);
} else {
throw UnexpectedError(demangle<std::decay_t<decltype(*this)>>() + ": did nothing!");
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ProvidedValueType>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
return {};
}
......@@ -174,31 +203,43 @@ class FunctionListArgumentConverter final : public IFunctionArgumentConverter
std::visit(
[&](auto&& vi) {
using Vi_T = std::decay_t<decltype(vi)>;
if constexpr (is_tiny_vector_v<ContentType>) {
throw NotImplementedError("TinyVector case");
if constexpr (std::is_same_v<Vi_T, ContentType>) {
list_value.emplace_back(vi);
} else if constexpr (is_tiny_vector_v<ContentType>) {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<Vi_T>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
} else if constexpr (std::is_convertible_v<Vi_T, ContentType>) {
list_value.emplace_back(vi);
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected types");
// LCOV_EXCL_STOP
}
},
(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else if constexpr (std::is_same_v<ValueT, ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(v);
} else if constexpr (is_std_vector_v<ValueT>) {
using ContentT = typename ValueT::value_type;
if constexpr (std::is_same_v<ContentT, ContentType>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.emplace_back(v[i]);
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
exec_policy.currentContext()[m_argument_id] = v;
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<ContentT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
} else if constexpr (std::is_same_v<ValueT, ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{v});
} else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ValueT> and
not is_tiny_vector_v<ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)});
} else {
// LCOV_EXCL_START
throw UnexpectedError(demangle<ValueT>() + " unexpected value type");
// LCOV_EXCL_STOP
}
},
value);
......
......@@ -58,6 +58,7 @@ add_executable (unit_tests
test_ExecutionPolicy.cpp
test_FakeProcessor.cpp
test_ForProcessor.cpp
test_FunctionArgumentConverter.cpp
test_FunctionProcessor.cpp
test_FunctionSymbolId.cpp
test_FunctionTable.cpp
......
#include <catch2/catch.hpp>
#include <language/node_processor/FunctionArgumentConverter.hpp>
#include <language/utils/SymbolTable.hpp>
// clazy:excludeall=non-pod-global-static
TEST_CASE("FunctionArgumentConverter", "[language]")
{
ExecutionPolicy::Context context(0, std::make_shared<ExecutionPolicy::Context::Values>(3));
ExecutionPolicy execution_policy(ExecutionPolicy{}, context);
SECTION("FunctionArgumentToStringConverter")
{
const std::string s{"foo"};
FunctionArgumentToStringConverter converter0{0};
converter0.convert(execution_policy, s);
const TinyVector<3> X{1, 3.2, 4};
FunctionArgumentToStringConverter converter1{1};
converter1.convert(execution_policy, X);
std::ostringstream os_X;
os_X << X << std::ends;
const double x = 3.2;
FunctionArgumentToStringConverter converter2{2};
converter2.convert(execution_policy, x);
REQUIRE(std::get<std::string>(execution_policy.currentContext()[0]) == s);
REQUIRE(std::get<std::string>(execution_policy.currentContext()[1]) == os_X.str());
REQUIRE(std::get<std::string>(execution_policy.currentContext()[2]) == std::to_string(x));
}
SECTION("FunctionArgumentConverter")
{
const double double_value = 1.7;
FunctionArgumentConverter<double, double> converter0{0};
converter0.convert(execution_policy, double{double_value});
const uint64_t uint64_value = 3;
FunctionArgumentConverter<double, uint64_t> converter1{1};
converter1.convert(execution_policy, uint64_value);
const bool bool_value = false;
FunctionArgumentConverter<uint64_t, bool> converter2{2};
converter2.convert(execution_policy, bool_value);
REQUIRE(std::get<double>(execution_policy.currentContext()[0]) == double_value);
REQUIRE(std::get<double>(execution_policy.currentContext()[1]) == static_cast<double>(uint64_value));
REQUIRE(std::get<uint64_t>(execution_policy.currentContext()[2]) == static_cast<uint64_t>(bool_value));
}
SECTION("FunctionTinyVectorArgumentConverter")
{
const TinyVector<3> x3{1.7, 2.9, -3};
FunctionTinyVectorArgumentConverter<TinyVector<3>, TinyVector<3>> converter0{0};
converter0.convert(execution_policy, TinyVector{x3});
const double x1 = 6.3;
FunctionTinyVectorArgumentConverter<TinyVector<1>, double> converter1{1};
converter1.convert(execution_policy, double{x1});
AggregateDataVariant values{std::vector<DataVariant>{6.3, 3.2, 4ul}};
FunctionTinyVectorArgumentConverter<TinyVector<3>, TinyVector<3>> converter2{2};
converter2.convert(execution_policy, values);
REQUIRE(std::get<TinyVector<3>>(execution_policy.currentContext()[0]) == x3);
REQUIRE(std::get<TinyVector<1>>(execution_policy.currentContext()[1]) == TinyVector<1>{x1});
REQUIRE(std::get<TinyVector<3>>(execution_policy.currentContext()[2]) == TinyVector<3>{6.3, 3.2, 4ul});
AggregateDataVariant bad_values{std::vector<DataVariant>{6.3, 3.2, std::string{"bar"}}};
REQUIRE_THROWS_WITH(converter2.convert(execution_policy, bad_values), std::string{"unexpected error: "} +
demangle<std::string>() +
" unexpected aggregate value type");
}
SECTION("FunctionTupleArgumentConverter")
{
const TinyVector<3> x3{1.7, 2.9, -3};
FunctionTupleArgumentConverter<TinyVector<3>, TinyVector<3>> converter0{0};
converter0.convert(execution_policy, TinyVector{x3});
const double a = 1.2;
const double b = -3.5;
const double c = 2.6;
FunctionTupleArgumentConverter<double, double> converter1{1};
converter1.convert(execution_policy, std::vector{a, b, c});
const uint64_t i = 1;
const uint64_t j = 3;
const uint64_t k = 6;
FunctionTupleArgumentConverter<double, uint64_t> converter2{2};
converter2.convert(execution_policy, std::vector<uint64_t>{i, j, k});
REQUIRE(std::get<std::vector<TinyVector<3>>>(execution_policy.currentContext()[0]) ==
std::vector<TinyVector<3>>{x3});
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a, b, c});
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[2]) == std::vector<double>{i, j, k});
converter1.convert(execution_policy, a);
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a});
converter1.convert(execution_policy, j);
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{j});
// Errors
REQUIRE_THROWS_WITH(converter0.convert(execution_policy, j),
"unexpected error: cannot convert 'unsigned long' to 'TinyVector<3ul, double>'");
}
SECTION("FunctionListArgumentConverter")
{
const uint64_t i = 3;
FunctionListArgumentConverter<double, double> converter0{0};
converter0.convert(execution_policy, i);
const double a = 6.3;
const double b = -1.3;
const double c = 3.6;
FunctionListArgumentConverter<double, double> converter1{1};
converter1.convert(execution_policy, std::vector<double>{a, b, c});
AggregateDataVariant v{std::vector<DataVariant>{1ul, 2.3, -3l}};
FunctionListArgumentConverter<double, double> converter2{2};
converter2.convert(execution_policy, v);
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[0]) == std::vector<double>{i});
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a, b, c});
REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[2]) == std::vector<double>{1ul, 2.3, -3l});
FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_0{0};
converterR2_0.convert(execution_policy, TinyVector<2>{1, 3.2});
FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_1{1};
converterR2_1.convert(execution_policy, std::vector{TinyVector<2>{1, 3.2}, TinyVector<2>{-1, 0.2}});
AggregateDataVariant v_R2{std::vector<DataVariant>{TinyVector<2>{-3, 12.2}, TinyVector<2>{2, 1.2}}};
FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_2{2};
converterR2_2.convert(execution_policy, v_R2);
REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[0]) ==
std::vector<TinyVector<2>>{TinyVector<2>{1, 3.2}});
REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[1]) ==
std::vector<TinyVector<2>>{TinyVector<2>{1, 3.2}, TinyVector<2>{-1, 0.2}});
REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[2]) ==
std::vector<TinyVector<2>>{TinyVector<2>{-3, 12.2}, TinyVector<2>{2, 1.2}});
}
SECTION("FunctionArgumentToFunctionSymbolIdConverter")
{
std::shared_ptr symbol_table = std::make_shared<SymbolTable>();
const uint64_t f_id = 3;
FunctionArgumentToFunctionSymbolIdConverter converter0{0, symbol_table};
converter0.convert(execution_policy, f_id);
REQUIRE(std::get<FunctionSymbolId>(execution_policy.currentContext()[0]).id() == f_id);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment