This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/functions/tests/FN_multi_function_test.cc
Jacques Lucke a2ea32a600 Cleanup: inline signatures into multi-function constructors
This reduces the amount of code. Also the signature should be thought
of as being setup in the constructor, so it's good if the code is there as well.
2023-01-07 18:00:37 +01:00

245 lines
6.3 KiB
C++

/* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "FN_multi_function.hh"
#include "FN_multi_function_builder.hh"
#include "FN_multi_function_test_common.hh"
namespace blender::fn::multi_function::tests {
namespace {
class AddFunction : public MultiFunction {
public:
AddFunction()
{
static Signature signature = []() {
Signature signature;
SignatureBuilder builder("Add", signature);
builder.single_input<int>("A");
builder.single_input<int>("B");
builder.single_output<int>("Result");
return signature;
}();
this->set_signature(&signature);
}
void call(IndexMask mask, MFParams params, Context /*context*/) const override
{
const VArray<int> &a = params.readonly_single_input<int>(0, "A");
const VArray<int> &b = params.readonly_single_input<int>(1, "B");
MutableSpan<int> result = params.uninitialized_single_output<int>(2, "Result");
for (int64_t i : mask) {
result[i] = a[i] + b[i];
}
}
};
TEST(multi_function, AddFunction)
{
AddFunction fn;
Array<int> input1 = {4, 5, 6};
Array<int> input2 = {10, 20, 30};
Array<int> output(3, -1);
ParamsBuilder params(fn, 3);
params.add_readonly_single_input(input1.as_span());
params.add_readonly_single_input(input2.as_span());
params.add_uninitialized_single_output(output.as_mutable_span());
ContextBuilder context;
fn.call({0, 2}, params, context);
EXPECT_EQ(output[0], 14);
EXPECT_EQ(output[1], -1);
EXPECT_EQ(output[2], 36);
}
TEST(multi_function, AddPrefixFunction)
{
AddPrefixFunction fn;
Array<std::string> strings = {
"Hello",
"World",
"This is a test",
"Another much longer string to trigger an allocation",
};
std::string prefix = "AB";
ParamsBuilder params(fn, strings.size());
params.add_readonly_single_input(&prefix);
params.add_single_mutable(strings.as_mutable_span());
ContextBuilder context;
fn.call({0, 2, 3}, params, context);
EXPECT_EQ(strings[0], "ABHello");
EXPECT_EQ(strings[1], "World");
EXPECT_EQ(strings[2], "ABThis is a test");
EXPECT_EQ(strings[3], "ABAnother much longer string to trigger an allocation");
}
TEST(multi_function, CreateRangeFunction)
{
CreateRangeFunction fn;
GVectorArray ranges(CPPType::get<int>(), 5);
GVectorArray_TypedMutableRef<int> ranges_ref{ranges};
Array<int> sizes = {3, 0, 6, 1, 4};
ParamsBuilder params(fn, ranges.size());
params.add_readonly_single_input(sizes.as_span());
params.add_vector_output(ranges);
ContextBuilder context;
fn.call({0, 1, 2, 3}, params, context);
EXPECT_EQ(ranges[0].size(), 3);
EXPECT_EQ(ranges[1].size(), 0);
EXPECT_EQ(ranges[2].size(), 6);
EXPECT_EQ(ranges[3].size(), 1);
EXPECT_EQ(ranges[4].size(), 0);
EXPECT_EQ(ranges_ref[0][0], 0);
EXPECT_EQ(ranges_ref[0][1], 1);
EXPECT_EQ(ranges_ref[0][2], 2);
EXPECT_EQ(ranges_ref[2][0], 0);
EXPECT_EQ(ranges_ref[2][1], 1);
}
TEST(multi_function, GenericAppendFunction)
{
GenericAppendFunction fn(CPPType::get<int32_t>());
GVectorArray vectors(CPPType::get<int32_t>(), 4);
GVectorArray_TypedMutableRef<int> vectors_ref{vectors};
vectors_ref.append(0, 1);
vectors_ref.append(0, 2);
vectors_ref.append(2, 6);
Array<int> values = {5, 7, 3, 1};
ParamsBuilder params(fn, vectors.size());
params.add_vector_mutable(vectors);
params.add_readonly_single_input(values.as_span());
ContextBuilder context;
fn.call(IndexRange(vectors.size()), params, context);
EXPECT_EQ(vectors[0].size(), 3);
EXPECT_EQ(vectors[1].size(), 1);
EXPECT_EQ(vectors[2].size(), 2);
EXPECT_EQ(vectors[3].size(), 1);
EXPECT_EQ(vectors_ref[0][0], 1);
EXPECT_EQ(vectors_ref[0][1], 2);
EXPECT_EQ(vectors_ref[0][2], 5);
EXPECT_EQ(vectors_ref[1][0], 7);
EXPECT_EQ(vectors_ref[2][0], 6);
EXPECT_EQ(vectors_ref[2][1], 3);
EXPECT_EQ(vectors_ref[3][0], 1);
}
TEST(multi_function, CustomMF_Constant)
{
CustomMF_Constant<int> fn{42};
Array<int> outputs(4, 0);
ParamsBuilder params(fn, outputs.size());
params.add_uninitialized_single_output(outputs.as_mutable_span());
ContextBuilder context;
fn.call({0, 2, 3}, params, context);
EXPECT_EQ(outputs[0], 42);
EXPECT_EQ(outputs[1], 0);
EXPECT_EQ(outputs[2], 42);
EXPECT_EQ(outputs[3], 42);
}
TEST(multi_function, CustomMF_GenericConstant)
{
int value = 42;
CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false};
Array<int> outputs(4, 0);
ParamsBuilder params(fn, outputs.size());
params.add_uninitialized_single_output(outputs.as_mutable_span());
ContextBuilder context;
fn.call({0, 1, 2}, params, context);
EXPECT_EQ(outputs[0], 42);
EXPECT_EQ(outputs[1], 42);
EXPECT_EQ(outputs[2], 42);
EXPECT_EQ(outputs[3], 0);
}
TEST(multi_function, CustomMF_GenericConstantArray)
{
std::array<int, 4> values = {3, 4, 5, 6};
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
GVectorArray vector_array{CPPType::get<int32_t>(), 4};
GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array};
ParamsBuilder params(fn, vector_array.size());
params.add_vector_output(vector_array);
ContextBuilder context;
fn.call({1, 2, 3}, params, context);
EXPECT_EQ(vector_array[0].size(), 0);
EXPECT_EQ(vector_array[1].size(), 4);
EXPECT_EQ(vector_array[2].size(), 4);
EXPECT_EQ(vector_array[3].size(), 4);
for (int i = 1; i < 4; i++) {
EXPECT_EQ(vector_array_ref[i][0], 3);
EXPECT_EQ(vector_array_ref[i][1], 4);
EXPECT_EQ(vector_array_ref[i][2], 5);
EXPECT_EQ(vector_array_ref[i][3], 6);
}
}
TEST(multi_function, IgnoredOutputs)
{
OptionalOutputsFunction fn;
{
ParamsBuilder params(fn, 10);
params.add_ignored_single_output("Out 1");
params.add_ignored_single_output("Out 2");
ContextBuilder context;
fn.call(IndexRange(10), params, context);
}
{
Array<int> results_1(10);
Array<std::string> results_2(10, NoInitialization());
ParamsBuilder params(fn, 10);
params.add_uninitialized_single_output(results_1.as_mutable_span(), "Out 1");
params.add_uninitialized_single_output(results_2.as_mutable_span(), "Out 2");
ContextBuilder context;
fn.call(IndexRange(10), params, context);
EXPECT_EQ(results_1[0], 5);
EXPECT_EQ(results_1[3], 5);
EXPECT_EQ(results_1[9], 5);
EXPECT_EQ(results_2[0], "hello, this is a long string");
}
}
} // namespace
} // namespace blender::fn::multi_function::tests