From 7b013986b76d461fd5be22b392d4e83c9a84b9db Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Mon, 19 Feb 2024 17:18:12 +0100 Subject: [PATCH 1/7] [doc] Enable TYPEDEF_HIDES_STRUCT for doxygen --- Doxyfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Doxyfile b/Doxyfile index 45c67eafd..f6f966ddc 100644 --- a/Doxyfile +++ b/Doxyfile @@ -18,3 +18,4 @@ GENERATE_LATEX = NO MACRO_EXPANSION = YES DIRECTORY_GRAPH = NO PREDEFINED = __aarch64__= +TYPEDEF_HIDES_STRUCT = YES -- GitLab From d64f87da80dd480e6316e4c9f1e937e52b23f572 Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Mon, 19 Feb 2024 17:19:02 +0100 Subject: [PATCH 2/7] Check multiplication overflow in morphology workspace --- intrinsiccv/include/intrinsiccv/morphology/workspace.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/intrinsiccv/include/intrinsiccv/morphology/workspace.h b/intrinsiccv/include/intrinsiccv/morphology/workspace.h index 32623301f..3132c9054 100644 --- a/intrinsiccv/include/intrinsiccv/morphology/workspace.h +++ b/intrinsiccv/include/intrinsiccv/morphology/workspace.h @@ -92,7 +92,11 @@ class MorphologyWorkspace final { size_t buffer_rows_stride = buffer_rows_width * channels; buffer_rows_stride = __builtin_align_up(buffer_rows_stride, kAlignment); size_t buffer_rows_height = 2 * rows_per_iteration; - size_t buffer_rows_size = buffer_rows_stride * buffer_rows_height; + size_t buffer_rows_size = 0UL; + if (__builtin_mul_overflow(buffer_rows_stride, buffer_rows_height, + &buffer_rows_size)) { + return INTRINSICCV_ERROR_RANGE; + } buffer_rows_size += kAlignment - 1; // Storage for indirect row access. -- GitLab From f34b8ab3531df50398ce3904065561ab16ec2091 Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Mon, 19 Feb 2024 17:20:06 +0100 Subject: [PATCH 3/7] Enable 'allocator_may_return_null' for AddressSanitizer To be able to test too big allocations --- scripts/ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/ci.sh b/scripts/ci.sh index f6592562f..4e47e6402 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -57,6 +57,8 @@ scripts/prefix_testsuite_names.py build/test-results/sme/intrinsiccv-api-test.xm LLVM_COV=llvm-cov scripts/generate_coverage_report.py # Clang address & undefined behaviour sanitizers +# Allow malloc to return NULL +export ASAN_OPTIONS="allocator_may_return_null=1" cmake -S . -B build/sanitize -G Ninja \ -DINTRINSICCV_ENABLE_SME2=OFF \ -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -Wno-pass-failed" -- GitLab From 62f345cf29958a10c0a2c5b863916b80634eb058 Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Tue, 20 Feb 2024 13:52:05 +0100 Subject: [PATCH 4/7] [test] Add border_values and constant border handling to test framework --- test/api/test_scale.cpp | 2 +- test/api/test_sobel.cpp | 15 ++++- test/api/test_transpose.cpp | 2 +- test/framework/array.h | 5 +- test/framework/border.cpp | 51 ++++++++++++++++ test/framework/border.h | 1 + test/framework/kernel.h | 105 +++++++++++++++++++------------- test/framework/test_array2d.cpp | 2 +- test/framework/test_border.cpp | 8 +-- test/framework/test_kernel.cpp | 63 +++++++++++-------- 10 files changed, 174 insertions(+), 80 deletions(-) diff --git a/test/api/test_scale.cpp b/test/api/test_scale.cpp index 89e48c6cc..9a4b85634 100644 --- a/test/api/test_scale.cpp +++ b/test/api/test_scale.cpp @@ -90,7 +90,7 @@ class ScaleTestLinearBase { GenerateLinearSeries generator(min()); - source.fill(&generator); + source.fill(generator); calculate_expected(source, expected); diff --git a/test/api/test_sobel.cpp b/test/api/test_sobel.cpp index 34cd6b73c..b22c58c30 100644 --- a/test/api/test_sobel.cpp +++ b/test/api/test_sobel.cpp @@ -40,6 +40,12 @@ static constexpr std::array kSupportedBorders = { INTRINSICCV_BORDER_TYPE_REPLICATE, }; +// Dummy border values because BORDER_TYPE_CONSTANT is not used +static constexpr std::array + kSupportedBorderValues = {{ + {0, 0, 0, 0}, // default + }}; + // Test for Sobel 3x3 operator. template class Sobel3x3Test : public test::KernelTest { @@ -49,7 +55,8 @@ class Sobel3x3Test : public test::KernelTest { intrinsiccv_error_t call_api(const test::Array2D *input, test::Array2D *output, - intrinsiccv_border_type_t) override { + intrinsiccv_border_type_t, + intrinsiccv_border_values_t) override { auto api = KernelTestParams::kIsHorizontal ? sobel_3x3_horizontal() : sobel_3x3_vertical(); @@ -65,11 +72,13 @@ class Sobel3x3Test : public test::KernelTest { auto array_layouts = test::default_array_layouts(mask.width(), mask.height()); // Create generators and execute test. - test::SequenceGenerator tested_borders{kSupportedBorders}; test::SequenceGenerator tested_array_layouts{array_layouts}; + test::SequenceGenerator tested_borders{kSupportedBorders}; + test::SequenceGenerator tested_border_values{kSupportedBorderValues}; test::PseudoRandomNumberGenerator element_generator; this->test::KernelTest::test( - kernel, &tested_array_layouts, &tested_borders, &element_generator); + kernel, tested_array_layouts, tested_borders, tested_border_values, + element_generator); } }; // end of class Sobel3x3Test diff --git a/test/api/test_transpose.cpp b/test/api/test_transpose.cpp index 7c5c1c1c0..b1ed4e953 100644 --- a/test/api/test_transpose.cpp +++ b/test/api/test_transpose.cpp @@ -50,7 +50,7 @@ class TestTranspose final { // No specific values to test test::PseudoRandomNumberGenerator generator; - source.fill(&generator); + source.fill(generator); calculate_expected(source, expected); diff --git a/test/framework/array.h b/test/framework/array.h index e702cfad0..83be903e2 100644 --- a/test/framework/array.h +++ b/test/framework/array.h @@ -107,14 +107,13 @@ class Array2D : public TwoDimensional { // Fills the underlying memory range with a given generator skipping padding // bytes. - void fill(Generator *generator) { - ASSERT_NE(generator, nullptr); + void fill(Generator &generator) { ASSERT_EQ(valid(), true); ElementType *ptr = data(); for (size_t row = 0; row < height(); ++row) { for (size_t column = 0; column < width(); ++column) { - std::optional optional_value = generator->next(); + std::optional optional_value = generator.next(); ASSERT_NE(optional_value, std::nullopt); if (optional_value.has_value()) { ptr[column] = optional_value.value(); diff --git a/test/framework/border.cpp b/test/framework/border.cpp index ed49fa07b..6b8263cd6 100644 --- a/test/framework/border.cpp +++ b/test/framework/border.cpp @@ -60,8 +60,55 @@ static void replicate(const Bordered *bordered, } } +// Creates constant border elements. +// +// Constant borders use the given values for top, left, right and bottom border. +// For example: +// | left border | elements | right border | +// | X X | A B C D E | Y Y | +template +static void constant(const Bordered *bordered, + intrinsiccv_border_values_t border_values, + TwoDimensional *elements) { + ASSERT_LE((bordered->left() + bordered->right()) * elements->channels(), + elements->width()); + ASSERT_LE(bordered->top() + bordered->bottom(), elements->height()); + + // Left and right border columns. + for (size_t row = 0; row < elements->height(); ++row) { + for (size_t channel = 0; channel < elements->channels(); ++channel) { + for (size_t column = 0; column < bordered->left(); ++column) { + size_t dst_column = column * elements->channels() + channel; + elements->at(row, dst_column)[0] = border_values.left; + } + + for (size_t column = 0; column < bordered->right(); ++column) { + size_t dst_column = + elements->width() + + (column - bordered->right()) * elements->channels() + channel; + elements->at(row, dst_column)[0] = border_values.right; + } + } + } + + // Top and bottom border rows. + for (size_t row = 0; row < bordered->top(); ++row) { + for (size_t column = 0; column < elements->width(); ++column) { + elements->at(row, column)[0] = border_values.top; + } + } + + for (size_t row = elements->height() - bordered->bottom(); + row < elements->height(); ++row) { + for (size_t column = 0; column < elements->width(); ++column) { + elements->at(row, column)[0] = border_values.bottom; + } + } +} + template void prepare_borders(intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values, const Bordered *bordered, TwoDimensional *elements) { ASSERT_NE(bordered, nullptr); @@ -73,10 +120,14 @@ void prepare_borders(intrinsiccv_border_type_t border_type, case INTRINSICCV_BORDER_TYPE_REPLICATE: return replicate(bordered, elements); + + case INTRINSICCV_BORDER_TYPE_CONSTANT: + return constant(bordered, border_values, elements); } } template void prepare_borders(intrinsiccv_border_type_t, + intrinsiccv_border_values_t, const Bordered *, TwoDimensional *); diff --git a/test/framework/border.h b/test/framework/border.h index cef6c2f4a..f8f1e71f7 100644 --- a/test/framework/border.h +++ b/test/framework/border.h @@ -13,6 +13,7 @@ namespace test { // Prepares bordering elements given a border type and bordering requirements. template void prepare_borders(intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values, const Bordered *bordered, TwoDimensional *elements); diff --git a/test/framework/kernel.h b/test/framework/kernel.h index c503951b4..7df7dc0ed 100644 --- a/test/framework/kernel.h +++ b/test/framework/kernel.h @@ -30,8 +30,10 @@ class Kernel : protected Array2D, public Bordered { using Array2D::width; explicit Kernel(Array2D mask) - : Array2D(mask), - anchor_{mask.width() / 2, mask.height() / 2} {} + : Kernel(mask, {mask.width() / 2, mask.height() / 2}) {} + + explicit Kernel(Array2D mask, Point anchor) + : Array2D(mask), anchor_{anchor} {} // Returns the anchor point of the kernel. Point anchor() const { return anchor_; } @@ -74,65 +76,82 @@ class KernelTest { KernelTest() : debug_{false} {} // Enables debug mode. - KernelTest &with_debug() { + KernelTest& with_debug() { debug_ = true; return *this; } - void test(Generator> *kernel_generator, - Generator *array_layout_generator, - Generator *border_type_generator, - Generator *element_generator) { - ASSERT_NE(kernel_generator, nullptr); - kernel_generator->reset(); + void test(Generator>& kernel_generator, + Generator& array_layout_generator, + Generator& border_type_generator, + Generator& border_values_generator, + Generator& element_generator) { + kernel_generator.reset(); std::optional> maybe_kernel; - while ((maybe_kernel = kernel_generator->next()) != std::nullopt) { + while ((maybe_kernel = kernel_generator.next()) != std::nullopt) { test(*maybe_kernel, array_layout_generator, border_type_generator, - element_generator); + border_values_generator, element_generator); ASSERT_NO_FAILURES(); } } void test(Kernel kernel, - Generator *array_layout_generator, - Generator *border_type_generator, - Generator *element_generator) { - ASSERT_NE(array_layout_generator, nullptr); - array_layout_generator->reset(); + Generator& array_layout_generator, + Generator& border_type_generator, + Generator& border_values_generator, + Generator& element_generator) { + array_layout_generator.reset(); std::optional maybe_array_layout; - while ((maybe_array_layout = array_layout_generator->next()) != + while ((maybe_array_layout = array_layout_generator.next()) != std::nullopt) { ArrayLayout array_layout = *maybe_array_layout; create_arrays(kernel, array_layout); ASSERT_NO_FAILURES(); - test(kernel, array_layout, border_type_generator, element_generator); + test(kernel, array_layout, border_type_generator, border_values_generator, + element_generator); ASSERT_NO_FAILURES(); } } void test(Kernel kernel, ArrayLayout array_layout, - Generator *border_type_generator, - Generator *element_generator) { - ASSERT_NE(border_type_generator, nullptr); - border_type_generator->reset(); + Generator& border_type_generator, + Generator& border_values_generator, + Generator& element_generator) { + border_type_generator.reset(); std::optional maybe_border_type; - while ((maybe_border_type = border_type_generator->next()) != + while ((maybe_border_type = border_type_generator.next()) != std::nullopt) { + test(kernel, array_layout, *maybe_border_type, border_values_generator, + element_generator); + ASSERT_NO_FAILURES(); + } + } + + void test(Kernel kernel, ArrayLayout array_layout, + intrinsiccv_border_type_t border_type, + Generator& border_values_generator, + Generator& element_generator) { + border_values_generator.reset(); + std::optional maybe_border_values; + while ((maybe_border_values = border_values_generator.next()) != std::nullopt) { - test(kernel, array_layout, *maybe_border_type, element_generator); + test(kernel, array_layout, border_type, *maybe_border_values, + element_generator); ASSERT_NO_FAILURES(); } } void test(Kernel kernel, ArrayLayout array_layout, intrinsiccv_border_type_t border_type, - Generator *element_generator) { + intrinsiccv_border_values_t border_values, + Generator& element_generator) { prepare_source(element_generator); - prepare_expected(kernel, array_layout, border_type); + prepare_expected(kernel, array_layout, border_type, border_values); prepare_actual(); - check_results(this->call_api(&input_, &actual_, border_type)); + check_results( + this->call_api(&input_, &actual_, border_type, border_values)); } protected: @@ -140,12 +159,13 @@ class KernelTest { // // The arguments are never nullptr. virtual intrinsiccv_error_t call_api( - const Array2D *input, Array2D *output, - intrinsiccv_border_type_t border_type) = 0; + const Array2D* input, Array2D* output, + intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values) = 0; // Calculates the expected output. - virtual void calculate_expected(const Kernel &kernel, - const TwoDimensional &source) { + virtual void calculate_expected(const Kernel& kernel, + const TwoDimensional& source) { for (size_t row = 0; row < expected_.height(); ++row) { for (size_t column = 0; column < expected_.width(); ++column) { IntermediateType result; @@ -157,8 +177,8 @@ class KernelTest { // Calculates the expected element at a given position. virtual IntermediateType calculate_expected_at( - const Kernel &kernel, - const TwoDimensional &source, size_t row, size_t column) { + const Kernel& kernel, + const TwoDimensional& source, size_t row, size_t column) { IntermediateType result{0}; for (size_t height = 0; height < kernel.height(); ++height) { for (size_t width = 0; width < kernel.width(); ++width) { @@ -173,8 +193,8 @@ class KernelTest { } // Creates arrays for a given layout. - void create_arrays(const Kernel &kernel, - const ArrayLayout &array_layout) { + void create_arrays(const Kernel& kernel, + const ArrayLayout& array_layout) { input_ = Array2D{array_layout}; ASSERT_TRUE(input_.valid()); @@ -193,9 +213,8 @@ class KernelTest { } // Prepares input to the kernel-based operation. - void prepare_source(Generator *element_generator) { - ASSERT_NE(element_generator, nullptr); - element_generator->reset(); + void prepare_source(Generator& element_generator) { + element_generator.reset(); input_.fill(element_generator); if (debug_) { @@ -205,9 +224,10 @@ class KernelTest { } // Computes expected output of the kernel-based operation. - void prepare_expected(const Kernel &kernel, - const ArrayLayout &array_layout, - intrinsiccv_border_type_t border_type) { + virtual void prepare_expected(const Kernel& kernel, + const ArrayLayout& array_layout, + intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values) { input_with_borders_.set(kernel.anchor().x, kernel.anchor().y * array_layout.channels, &input_); @@ -216,7 +236,8 @@ class KernelTest { dump(&input_with_borders_); } - prepare_borders(border_type, &kernel, &input_with_borders_); + prepare_borders(border_type, border_values, &kernel, + &input_with_borders_); if (debug_) { std::cout << "[input_with_borders with borders]" << std::endl; diff --git a/test/framework/test_array2d.cpp b/test/framework/test_array2d.cpp index 8c143ebc9..2a780baec 100644 --- a/test/framework/test_array2d.cpp +++ b/test/framework/test_array2d.cpp @@ -214,7 +214,7 @@ TEST(Array2D, FillWithGenerator) { const size_t num_elements = width * height; std::array elements = {11, 12, 13, 14, 15, 16}; test::SequenceGenerator generator{elements}; - array.fill(&generator); + array.fill(generator); EXPECT_EQ(array.at(0, 0)[0], 11); EXPECT_EQ(array.at(0, 1)[0], 12); EXPECT_EQ(array.at(0, 2)[0], 13); diff --git a/test/framework/test_border.cpp b/test/framework/test_border.cpp index ebdf2231e..3a627d99d 100644 --- a/test/framework/test_border.cpp +++ b/test/framework/test_border.cpp @@ -49,7 +49,7 @@ TEST(Border, Replicate_1Ch_1Element) { ImplementsBorder bordered{1, 1, 1, 1}; test::prepare_borders(INTRINSICCV_BORDER_TYPE_REPLICATE, - &bordered, &actual); + {0, 0, 0, 0}, &bordered, &actual); EXPECT_EQ_ARRAY2D(expected, actual); } @@ -78,7 +78,7 @@ TEST(Border, Replicate_1Ch_2Elements) { ImplementsBorder bordered{2, 2, 2, 2}; test::prepare_borders(INTRINSICCV_BORDER_TYPE_REPLICATE, - &bordered, &actual); + {0, 0, 0, 0}, &bordered, &actual); EXPECT_EQ_ARRAY2D(expected, actual); } @@ -105,7 +105,7 @@ TEST(Border, Replicate_2Ch_1Element) { ImplementsBorder bordered{1, 1, 1, 1}; test::prepare_borders(INTRINSICCV_BORDER_TYPE_REPLICATE, - &bordered, &actual); + {0, 0, 0, 0}, &bordered, &actual); EXPECT_EQ_ARRAY2D(expected, actual); } @@ -134,6 +134,6 @@ TEST(Border, Replicate_2Ch_2Elements) { ImplementsBorder bordered{2, 2, 2, 2}; test::prepare_borders(INTRINSICCV_BORDER_TYPE_REPLICATE, - &bordered, &actual); + {0, 0, 0, 0}, &bordered, &actual); EXPECT_EQ_ARRAY2D(expected, actual); } diff --git a/test/framework/test_kernel.cpp b/test/framework/test_kernel.cpp index e23b70f96..81b96a8ef 100644 --- a/test/framework/test_kernel.cpp +++ b/test/framework/test_kernel.cpp @@ -92,17 +92,19 @@ class ExampleKernelTest : public test::KernelTest { using IntermediateType = typename KernelTestParams::IntermediateType; using OutputType = typename KernelTestParams::OutputType; - intrinsiccv_error_t call_api(const test::Array2D *input, - test::Array2D *output, - intrinsiccv_border_type_t border_type) override { - ++api_calls_; - + intrinsiccv_error_t call_api( + const test::Array2D *input, test::Array2D *output, + intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values) override { // Check the expected border type. EXPECT_EQ(border_type, kBorders[border_count_ % kBorders.size()]); - ++border_count_; - if (border_count_ == kBorders.size()) { - border_count_ = 0; - } + // Check the expected border value. + auto act = border_values; + auto exp = kBorderValues[border_value_count_ % kBorderValues.size()]; + EXPECT_EQ(act.top, exp.top); + EXPECT_EQ(act.right, exp.right); + EXPECT_EQ(act.bottom, exp.bottom); + EXPECT_EQ(act.left, exp.left); // Check the expected layout. const test::ArrayLayout &expected_array_layout = @@ -120,8 +122,15 @@ class ExampleKernelTest : public test::KernelTest { // EXPECT_EQ(input->stride(), output->stride()); EXPECT_EQ(input->channels(), output->channels()); - if (border_count_ == 0) { - ++array_layouts_; + ++api_calls_; + ++border_value_count_; + if (border_value_count_ == kBorderValues.size()) { + border_value_count_ = 0; + ++border_count_; + if (border_count_ == kBorders.size()) { + border_count_ = 0; + ++array_layouts_; + } } // Fake some result. @@ -131,7 +140,7 @@ class ExampleKernelTest : public test::KernelTest { } public: - static const std::array, 2> kKernels; + static const std::array, 3> kKernels; static constexpr std::array kArrayLayouts = {{ {3, 2, 10, 1}, @@ -139,29 +148,30 @@ class ExampleKernelTest : public test::KernelTest { {9, 7, 11, 3}, }}; - static constexpr std::array kBorders = { - // NOTE: At the time of writing this test only replicate was implemented. - INTRINSICCV_BORDER_TYPE_REPLICATE, - INTRINSICCV_BORDER_TYPE_REPLICATE, - INTRINSICCV_BORDER_TYPE_REPLICATE, - INTRINSICCV_BORDER_TYPE_REPLICATE, - }; + static constexpr std::array kBorders = { + INTRINSICCV_BORDER_TYPE_REPLICATE, INTRINSICCV_BORDER_TYPE_CONSTANT}; + + static constexpr std::array kBorderValues = { + {{0, 0, 0, 0}, {1, 2, 3, 4}}}; size_t api_calls_{0}; size_t array_layouts_{0}; size_t border_count_{0}; + size_t border_value_count_{0}; }; // end of class class ExampleKernelTest // Disable check for possible exceptions thrown outside main. // The check isn't important in a test program. // NOLINTBEGIN(cert-err58-cpp) template -const std::array, 2> +const std::array, 3> ExampleKernelTest::kKernels = { test::Kernel{ test::Array2D{3, 3}}, test::Kernel{ test::Array2D{4, 4}}, + test::Kernel{ + test::Array2D{8, 4}}, }; // NOLINTEND(cert-err58-cpp) @@ -169,21 +179,24 @@ const std::array, 2> TEST(KernelTest, Test) { test::SequenceGenerator tested_kernels{ ExampleKernelTest::kKernels}; - test::SequenceGenerator tested_borders{ - ExampleKernelTest::kBorders}; test::SequenceGenerator tested_array_layouts{ ExampleKernelTest::kArrayLayouts}; + test::SequenceGenerator tested_borders{ + ExampleKernelTest::kBorders}; + test::SequenceGenerator tested_border_values{ + ExampleKernelTest::kBorderValues}; test::PseudoRandomNumberGenerator element_generator; ExampleKernelTest kernel_test; - kernel_test.test(&tested_kernels, &tested_array_layouts, &tested_borders, - &element_generator); + kernel_test.test(tested_kernels, tested_array_layouts, tested_borders, + tested_border_values, element_generator); EXPECT_EQ(kernel_test.api_calls_, ExampleKernelTest::kKernels.size() * ExampleKernelTest::kArrayLayouts.size() * - ExampleKernelTest::kBorders.size()); + ExampleKernelTest::kBorders.size() * + ExampleKernelTest::kBorderValues.size()); EXPECT_EQ(kernel_test.array_layouts_, ExampleKernelTest::kKernels.size() * ExampleKernelTest::kArrayLayouts.size()); -- GitLab From 5602cab25af4e987fcdfdbcd57b59076dec57c9f Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Tue, 20 Feb 2024 13:52:41 +0100 Subject: [PATCH 5/7] Fix anchor coordinates in kernel test framework --- test/framework/kernel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/framework/kernel.h b/test/framework/kernel.h index 7df7dc0ed..cd5bac357 100644 --- a/test/framework/kernel.h +++ b/test/framework/kernel.h @@ -228,8 +228,8 @@ class KernelTest { const ArrayLayout& array_layout, intrinsiccv_border_type_t border_type, intrinsiccv_border_values_t border_values) { - input_with_borders_.set(kernel.anchor().x, - kernel.anchor().y * array_layout.channels, &input_); + input_with_borders_.set(kernel.anchor().y, + kernel.anchor().x * array_layout.channels, &input_); if (debug_) { std::cout << "[input_with_borders without borders]" << std::endl; -- GitLab From 9b43ab877e4e6b8b938242cc1881a566427e4531 Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Tue, 20 Feb 2024 13:52:53 +0100 Subject: [PATCH 6/7] Add more kernel test array layouts --- test/framework/utils.cpp | 10 +++++++++- test/framework/utils.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/framework/utils.cpp b/test/framework/utils.cpp index 0640bb2e0..63c987a88 100644 --- a/test/framework/utils.cpp +++ b/test/framework/utils.cpp @@ -48,7 +48,7 @@ template void dump(const TwoDimensional *); template void dump(const TwoDimensional *); template void dump(const TwoDimensional *); -std::array default_array_layouts(size_t min_width, +std::array default_array_layouts(size_t min_width, size_t min_height) { size_t vl = test::Options::vector_length(); size_t width = std::max(min_width, vl); @@ -59,15 +59,23 @@ std::array default_array_layouts(size_t min_width, { min_width, min_height, 0, 1}, { min_width * 2, min_height, 0, 2}, { min_width * 3, min_height, 0, 3}, + { min_width * 4, min_height, 0, 4}, + { min_width * 8, min_height * 3, 0, 8}, { min_width, min_height, vl, 1}, { min_width * 2, min_height, vl, 2}, { min_width * 3, min_height, vl, 3}, + { min_width * 4, min_height, vl, 4}, + { min_width * 8, min_height * 3, vl, 8}, { width - 1, min_height, 0, 1}, {2 * (width - 1), min_height + 1, 0, 2}, {3 * (width - 1), min_height + 2, 0, 3}, + {4 * (width + 1), min_height + 3, 0, 4}, + { width * 8, min_height * 3, 0, 8}, { width - 1, min_height, vl, 1}, {2 * (width - 1), min_height + 1, vl, 2}, {3 * (width - 1), min_height + 2, vl, 3}, + {4 * (width + 1), min_height + 3, vl, 4}, + { width * 8, min_height * 3, vl, 8}, // clang-format on }}; } diff --git a/test/framework/utils.h b/test/framework/utils.h index ccdcaad97..ad76a3695 100644 --- a/test/framework/utils.h +++ b/test/framework/utils.h @@ -83,7 +83,7 @@ template void dump(const TwoDimensional *elements); // Returns an array of default tested layouts. -std::array default_array_layouts(size_t min_width, +std::array default_array_layouts(size_t min_width, size_t min_height); namespace internal { -- GitLab From 700b8accd2bef0bbbd74ff569b92ce9f1b095d76 Mon Sep 17 00:00:00 2001 From: Denes Tarjan Date: Tue, 20 Feb 2024 13:53:12 +0100 Subject: [PATCH 7/7] [test] Implement morphology tests --- intrinsiccv/include/intrinsiccv/intrinsiccv.h | 2 +- test/api/test_morphology.cpp | 454 ++++++++++++++---- 2 files changed, 362 insertions(+), 94 deletions(-) diff --git a/intrinsiccv/include/intrinsiccv/intrinsiccv.h b/intrinsiccv/include/intrinsiccv/intrinsiccv.h index d75cb6469..19dc8573b 100644 --- a/intrinsiccv/include/intrinsiccv/intrinsiccv.h +++ b/intrinsiccv/include/intrinsiccv/intrinsiccv.h @@ -744,7 +744,7 @@ intrinsiccv_error_t intrinsiccv_morphology_release( /// Example for dilate: /// ``` /// [ 2, 8, 9, 3, 6 ] kernel: (3, 3) [ 8, 9, 9, 9, 6 ] -/// [ 7, 2, 4, 1, 5 ] anchor: (1, 1) -> [ 7, 9, 9, 9, 8 ] +/// [ 7, 2, 4, 1, 5 ] anchor: (1, 1) -> [ 8, 9, 9, 9, 8 ] /// [ 4, 3, 6, 8, 1 ] border: replicate [ 7, 7, 8, 8, 8 ] /// [ 1, 2, 5, 3, 7 ] [ 4, 6, 8, 8, 8 ] /// ``` diff --git a/test/api/test_morphology.cpp b/test/api/test_morphology.cpp index 065b75f3f..21e0a5a41 100644 --- a/test/api/test_morphology.cpp +++ b/test/api/test_morphology.cpp @@ -4,33 +4,254 @@ #include +#include +#include + +#include "framework/array.h" +#include "framework/generator.h" +#include "framework/kernel.h" #include "framework/operation.h" #include "intrinsiccv/intrinsiccv.h" -#define INTRINSICCV_DILATE(type, suffix) \ - INTRINSICCV_API(dilate, intrinsiccv_dilate_##suffix, type) - -#define INTRINSICCV_ERODE(type, suffix) \ - INTRINSICCV_API(erode, intrinsiccv_erode_##suffix, type) +#define INTRINSICCV_PARAMS(name, impl, type, op) \ + template , bool> = true> \ + class name { \ + public: \ + static decltype(auto) api() { return &impl; } \ + static decltype(auto) operation() { \ + return [](type a, type b) { return op(a, b); }; \ + } \ + }; -INTRINSICCV_DILATE(uint8_t, u8); -INTRINSICCV_ERODE(uint8_t, u8); +INTRINSICCV_PARAMS(DilateParams, intrinsiccv_dilate_u8, uint8_t, std::max); +INTRINSICCV_PARAMS(ErodeParams, intrinsiccv_erode_u8, uint8_t, std::min); template -class MorphologyTest : public testing::Test {}; +struct MorphologyKernelTestParams { + using InputType = ElementType; + using IntermediateType = ElementType; + using OutputType = ElementType; +}; // end of struct MorphologyKernelTestParams + +static constexpr std::array kSupportedBorders = { + INTRINSICCV_BORDER_TYPE_REPLICATE, + INTRINSICCV_BORDER_TYPE_CONSTANT, +}; + +template class OperationParams, + size_t kernelWidth, size_t kernelHeight> +class MorphologyTest + : public test::KernelTest> { + using Base = test::KernelTest>; + using typename Base::InputType; + using typename Base::IntermediateType; + using typename Base::OutputType; + + public: + MorphologyTest() + : mask_{kernelWidth, kernelHeight}, kernel_{mask_}, iterations_{1} {} + + MorphologyTest &with_anchor(test::Point anchor) { + kernel_ = test::Kernel(mask_, anchor); + return *this; + } -template -class DilateTest : public testing::Test {}; + MorphologyTest &with_iterations(size_t iter) { + iterations_ = iter; + return *this; + } -template -class ErodeTest : public testing::Test {}; + void test() { + auto array_layouts = test::default_array_layouts(kernelWidth, kernelHeight); + test::SequenceGenerator tested_array_layouts{array_layouts}; + test::SequenceGenerator tested_borders{kSupportedBorders}; + test::SequenceGenerator tested_border_values{test_border_values()}; + test::PseudoRandomNumberGenerator element_generator; + Base::test(kernel_, tested_array_layouts, tested_borders, + tested_border_values, element_generator); + } + + protected: + test::Array2D mask_; + test::Kernel kernel_; + size_t iterations_; + + intrinsiccv_error_t call_api( + const test::Array2D *input, test::Array2D *output, + intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values) override { + intrinsiccv_morphology_context_t *context = nullptr; + auto kernelRect = intrinsiccv_rectangle_t{kernelWidth, kernelHeight}; + intrinsiccv_point_t anchor{kernel_.anchor().x, kernel_.anchor().y}; + auto ret = intrinsiccv_morphology_create( + &context, kernelRect, anchor, border_type, border_values, + input->channels(), iterations_, sizeof(InputType), + intrinsiccv_rectangle_t{input->width() / input->channels(), + input->height()}); + if (ret != INTRINSICCV_OK) { + return ret; + } + + ret = OperationParams::api()( + input->data(), input->stride(), output->data(), output->stride(), + input->width() / input->channels(), input->height(), context); + auto releaseRet = intrinsiccv_morphology_release(context); + if (releaseRet != INTRINSICCV_OK) { + return releaseRet; + } + + return ret; + } + + void prepare_expected(const test::Kernel &kernel, + const test::ArrayLayout &array_layout, + intrinsiccv_border_type_t border_type, + intrinsiccv_border_values_t border_values) override { + Base::prepare_expected(kernel, array_layout, border_type, border_values); + if (iterations_ > 1) { + test::Array2D saved_input = this->input_; + for (size_t i = 1; i < iterations_; ++i) { + this->input_ = this->expected_; + Base::prepare_expected(kernel, array_layout, border_type, + border_values); + } + this->input_ = saved_input; + } + } + + IntermediateType calculate_expected_at( + const test::Kernel &kernel, + const test::TwoDimensional &source, size_t row, + size_t column) override { + IntermediateType result = source.at(row, column)[0]; + for (size_t height = 0; height < kernel.height(); ++height) { + for (size_t width = 0; width < kernel.width(); ++width) { + result = OperationParams::operation()( + result, + source.at(row + height, column + width * source.channels())[0]); + } + } + return result; + } + + static constexpr double min_border() { + return static_cast(std::numeric_limits::min()); + } + + static constexpr double max_border() { + return static_cast(std::numeric_limits::max()); + } + + const std::array &test_border_values() const { + static const std::array values = { + {{0, 0, 0, 0}, // default + {7, 42, 99, 9}, + {min_border(), max_border(), min_border(), max_border()}, + {0, min_border(), max_border(), 0}}}; + return values; + } +}; // end of class class MorphologyTest + +template +class Morphology : public testing::Test {}; using ElementTypes = ::testing::Types; -TYPED_TEST_SUITE(MorphologyTest, ElementTypes); -TYPED_TEST_SUITE(DilateTest, ElementTypes); -TYPED_TEST_SUITE(ErodeTest, ElementTypes); -TYPED_TEST(MorphologyTest, UnsupportedBorderType) { +TYPED_TEST_SUITE(Morphology, ElementTypes); + +TYPED_TEST(Morphology, Dilate1x1) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode1x1) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate1x2) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode1x2) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate3x1) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode3x1) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate3x3) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode3x3) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate5x5) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode5x5) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate11x11) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode11x11) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate4x4) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode7x5) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate8x4) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Dilate6x10) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Erode12x4) { + MorphologyTest{}.test(); +} + +TYPED_TEST(Morphology, Iterations) { + MorphologyTest{}.with_iterations(2).test(); + MorphologyTest{}.with_iterations(3).test(); + MorphologyTest{}.with_iterations(4).test(); +} + +TYPED_TEST(Morphology, Anchors) { + MorphologyTest{}.with_anchor({0, 0}).test(); + MorphologyTest{}.with_anchor({2, 0}).test(); + MorphologyTest{}.with_anchor({0, 4}).test(); + MorphologyTest{}.with_anchor({2, 4}).test(); +} + +static intrinsiccv_error_t make_minimal_context( + intrinsiccv_morphology_context_t **context, size_t type_size, + intrinsiccv_border_type_t border = INTRINSICCV_BORDER_TYPE_REPLICATE) { + return intrinsiccv_morphology_create( + context, intrinsiccv_rectangle_t{1, 1}, intrinsiccv_point_t{0, 0}, border, + intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, type_size, + intrinsiccv_rectangle_t{1, 1}); +} + +TYPED_TEST(Morphology, UnsupportedBorderType) { for (intrinsiccv_border_type_t border : { INTRINSICCV_BORDER_TYPE_REFLECT, INTRINSICCV_BORDER_TYPE_WRAP, @@ -39,55 +260,82 @@ TYPED_TEST(MorphologyTest, UnsupportedBorderType) { INTRINSICCV_BORDER_TYPE_NONE, }) { intrinsiccv_morphology_context_t *context = nullptr; - EXPECT_EQ( - INTRINSICCV_ERROR_NOT_IMPLEMENTED, - intrinsiccv_morphology_create( - &context, intrinsiccv_rectangle_t{1, 1}, intrinsiccv_point_t{0, 0}, - border, intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, - sizeof(TypeParam), intrinsiccv_rectangle_t{1, 1})); + EXPECT_EQ(INTRINSICCV_ERROR_NOT_IMPLEMENTED, + make_minimal_context(&context, sizeof(TypeParam), border)); ASSERT_EQ(nullptr, context); } } -TYPED_TEST(MorphologyTest, UnsupportedSize) { +TYPED_TEST(Morphology, UnsupportedSize) { intrinsiccv_morphology_context_t *context = nullptr; + intrinsiccv_rectangle_t small_rect{1, 1}; + intrinsiccv_point_t anchor{0, 0}; + intrinsiccv_border_type_t border = INTRINSICCV_BORDER_TYPE_REPLICATE; + intrinsiccv_border_values_t border_values{0, 0, 1, 1}; - for (intrinsiccv_rectangle_t rect : { + for (intrinsiccv_rectangle_t bad_rect : { intrinsiccv_rectangle_t{INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1}, intrinsiccv_rectangle_t{INTRINSICCV_MAX_IMAGE_PIXELS, INTRINSICCV_MAX_IMAGE_PIXELS}, }) { EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - intrinsiccv_morphology_create( - &context, rect, intrinsiccv_point_t{0, 0}, - INTRINSICCV_BORDER_TYPE_REPLICATE, - intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, - sizeof(TypeParam), intrinsiccv_rectangle_t{1, 1})); + intrinsiccv_morphology_create(&context, bad_rect, anchor, border, + border_values, 1, 1, + sizeof(TypeParam), small_rect)); ASSERT_EQ(nullptr, context); EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - intrinsiccv_morphology_create( - &context, intrinsiccv_rectangle_t{1, 1}, - intrinsiccv_point_t{0, 0}, INTRINSICCV_BORDER_TYPE_REPLICATE, - intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, - sizeof(TypeParam), rect)); + intrinsiccv_morphology_create(&context, small_rect, anchor, + border, border_values, 1, 1, + sizeof(TypeParam), bad_rect)); ASSERT_EQ(nullptr, context); } } -TYPED_TEST(MorphologyTest, InvalidAnchor) { +TYPED_TEST(Morphology, TooBigImage) { intrinsiccv_morphology_context_t *context = nullptr; + intrinsiccv_rectangle_t kernel{3, 10000}, image{1UL << 34, 10000}; + intrinsiccv_border_type_t border = INTRINSICCV_BORDER_TYPE_REPLICATE; + intrinsiccv_border_values_t border_values{0, 0, 1, 1}; + intrinsiccv_point_t anchor{1, 1}; + EXPECT_EQ(INTRINSICCV_ERROR_ALLOCATION, + intrinsiccv_morphology_create(&context, kernel, anchor, border, + border_values, 1, 1, + sizeof(TypeParam), image)); + + intrinsiccv_rectangle_t kernel2{3, 1UL << 33}, image2{1UL << 33, 100}; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - intrinsiccv_morphology_create( - &context, intrinsiccv_rectangle_t{1, 1}, - intrinsiccv_point_t{1, 0}, INTRINSICCV_BORDER_TYPE_REPLICATE, - intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, - sizeof(TypeParam), intrinsiccv_rectangle_t{1, 1})); + intrinsiccv_morphology_create(&context, kernel2, anchor, border, + border_values, 1, 1, + sizeof(TypeParam), image2)); +} + +TYPED_TEST(Morphology, InvalidAnchors) { + intrinsiccv_morphology_context_t *context = nullptr; + intrinsiccv_rectangle_t kernel1{1, 1}, kernel2{6, 4}, image{20, 20}; + intrinsiccv_border_type_t border = INTRINSICCV_BORDER_TYPE_REPLICATE; + intrinsiccv_border_values_t border_values{0, 0, 1, 1}; + intrinsiccv_point_t anchor1{1, 0}, anchor2{6, 3}, anchor3{5, 4}; + + EXPECT_EQ(INTRINSICCV_ERROR_RANGE, + intrinsiccv_morphology_create(&context, kernel1, anchor1, border, + border_values, 1, 1, + sizeof(TypeParam), image)); + ASSERT_EQ(nullptr, context); + EXPECT_EQ(INTRINSICCV_ERROR_RANGE, + intrinsiccv_morphology_create(&context, kernel2, anchor2, border, + border_values, 1, 1, + sizeof(TypeParam), image)); + ASSERT_EQ(nullptr, context); + EXPECT_EQ(INTRINSICCV_ERROR_RANGE, + intrinsiccv_morphology_create(&context, kernel2, anchor3, border, + border_values, 1, 1, + sizeof(TypeParam), image)); ASSERT_EQ(nullptr, context); } -TYPED_TEST(MorphologyTest, InvalidTypeSize) { +TYPED_TEST(Morphology, InvalidTypeSize) { intrinsiccv_morphology_context_t *context = nullptr; EXPECT_EQ( @@ -100,7 +348,7 @@ TYPED_TEST(MorphologyTest, InvalidTypeSize) { ASSERT_EQ(nullptr, context); } -TYPED_TEST(MorphologyTest, InvalidChannelNumber) { +TYPED_TEST(Morphology, InvalidChannelNumber) { intrinsiccv_morphology_context_t *context = nullptr; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, @@ -113,36 +361,50 @@ TYPED_TEST(MorphologyTest, InvalidChannelNumber) { ASSERT_EQ(nullptr, context); } -static intrinsiccv_error_t make_minimal_context( - intrinsiccv_morphology_context_t **context, size_t type_size) { - return intrinsiccv_morphology_create( - context, intrinsiccv_rectangle_t{1, 1}, intrinsiccv_point_t{0, 0}, - INTRINSICCV_BORDER_TYPE_REPLICATE, - intrinsiccv_border_values_t{0, 0, 1, 1}, 1, 1, type_size, - intrinsiccv_rectangle_t{1, 1}); +TYPED_TEST(Morphology, ImageBiggerThanContext) { + intrinsiccv_morphology_context_t *context = nullptr; + intrinsiccv_rectangle_t kernel{3, 3}, image{5, 5}; + intrinsiccv_border_type_t border = INTRINSICCV_BORDER_TYPE_REPLICATE; + intrinsiccv_border_values_t border_values{0, 0, 1, 1}; + intrinsiccv_point_t anchor{1, 1}; + + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_create( + &context, kernel, anchor, border, border_values, + 1, 1, sizeof(TypeParam), image)); + const size_t w = 7, h = 7; + TypeParam src[w * h], dst[w * h]; + EXPECT_EQ( + INTRINSICCV_ERROR_CONTEXT_MISMATCH, + ErodeParams::api()(src, sizeof(TypeParam) * w, dst, + sizeof(TypeParam) * w, w, h, context)); + EXPECT_EQ( + INTRINSICCV_ERROR_CONTEXT_MISMATCH, + DilateParams::api()(src, sizeof(TypeParam) * w, dst, + sizeof(TypeParam) * w, w, h, context)); + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(DilateTest, NullPointer) { +TYPED_TEST(Morphology, DilateNullPointer) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1] = {}, dst[1]; - test::test_null_args(dilate(), src, sizeof(TypeParam), dst, - sizeof(TypeParam), 1, 1, context); + test::test_null_args(DilateParams::api(), src, sizeof(TypeParam), + dst, sizeof(TypeParam), 1, 1, context); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(ErodeTest, NullPointer) { +TYPED_TEST(Morphology, ErodeNullPointer) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1] = {}, dst[1]; - test::test_null_args(erode(), src, sizeof(TypeParam), dst, - sizeof(TypeParam), 1, 1, context); + test::test_null_args(ErodeParams::api(), src, sizeof(TypeParam), + dst, sizeof(TypeParam), 1, 1, context); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(DilateTest, Misalignment) { +TYPED_TEST(Morphology, DilateMisalignment) { if (sizeof(TypeParam) == 1) { // misalignment impossible return; @@ -151,15 +413,16 @@ TYPED_TEST(DilateTest, Misalignment) { ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, - dilate()(src, sizeof(TypeParam) + 1, dst, - sizeof(TypeParam), 1, 1, context)); - EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, - dilate()(src, sizeof(TypeParam), dst, - sizeof(TypeParam) + 1, 1, 1, context)); + DilateParams::api()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, context)); + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + DilateParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(ErodeTest, Misalignment) { +TYPED_TEST(Morphology, ErodeMisalignment) { if (sizeof(TypeParam) == 1) { // misalignment impossible return; @@ -168,80 +431,85 @@ TYPED_TEST(ErodeTest, Misalignment) { ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, - erode()(src, sizeof(TypeParam) + 1, dst, - sizeof(TypeParam), 1, 1, context)); - EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, - erode()(src, sizeof(TypeParam), dst, - sizeof(TypeParam) + 1, 1, 1, context)); + ErodeParams::api()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, context)); + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + ErodeParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(DilateTest, ImageSize) { +TYPED_TEST(Morphology, DilateImageSize) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - dilate()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, context)); - EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - dilate()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - INTRINSICCV_MAX_IMAGE_PIXELS, - INTRINSICCV_MAX_IMAGE_PIXELS, context)); + DilateParams::api()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), + INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, context)); + EXPECT_EQ( + INTRINSICCV_ERROR_RANGE, + DilateParams::api()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), + INTRINSICCV_MAX_IMAGE_PIXELS, INTRINSICCV_MAX_IMAGE_PIXELS, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(ErodeTest, ImageSize) { +TYPED_TEST(Morphology, ErodeImageSize) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, context)); - EXPECT_EQ(INTRINSICCV_ERROR_RANGE, - erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - INTRINSICCV_MAX_IMAGE_PIXELS, - INTRINSICCV_MAX_IMAGE_PIXELS, context)); + ErodeParams::api()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), + INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, context)); + EXPECT_EQ( + INTRINSICCV_ERROR_RANGE, + ErodeParams::api()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), + INTRINSICCV_MAX_IMAGE_PIXELS, INTRINSICCV_MAX_IMAGE_PIXELS, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(DilateTest, InvalidContextSizeType) { +TYPED_TEST(Morphology, DilateInvalidContextSizeType) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam) + 1)); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_CONTEXT_MISMATCH, - dilate()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - 1, 1, context)); + DilateParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(ErodeTest, InvalidContextSizeType) { +TYPED_TEST(Morphology, ErodeInvalidContextSizeType) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam) + 1)); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_CONTEXT_MISMATCH, - erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - 1, 1, context)); + ErodeParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(DilateTest, InvalidContextImageSize) { +TYPED_TEST(Morphology, DilateInvalidContextImageSize) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_CONTEXT_MISMATCH, - dilate()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - 2, 1, context)); + DilateParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 2, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -TYPED_TEST(ErodeTest, InvalidContextImageSize) { +TYPED_TEST(Morphology, ErodeInvalidContextImageSize) { intrinsiccv_morphology_context_t *context = nullptr; ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); TypeParam src[1], dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_CONTEXT_MISMATCH, - erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), - 2, 1, context)); + ErodeParams::api()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 2, 1, context)); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } -- GitLab