diff --git a/Modules/Core/Common/include/itkImage.h b/Modules/Core/Common/include/itkImage.h index 7ff14cea465..b8b2edc5c7e 100644 --- a/Modules/Core/Common/include/itkImage.h +++ b/Modules/Core/Common/include/itkImage.h @@ -318,6 +318,51 @@ class ITK_TEMPLATE_EXPORT Image : public ImageBase unsigned int GetNumberOfComponentsPerPixel() const override; + /** Returns (image1 == image2). */ + friend bool + operator==(const Image & lhs, const Image & rhs) + { + if ((lhs.GetBufferedRegion() != rhs.GetBufferedRegion()) || (lhs.m_Spacing != rhs.m_Spacing) || + (lhs.m_Origin != rhs.m_Origin) || (lhs.m_Direction != rhs.m_Direction) || + (lhs.m_InverseDirection != rhs.m_InverseDirection)) + { + return false; + } + + if (lhs.m_Buffer == rhs.m_Buffer) + { + return true; + } + + if ((lhs.m_Buffer == nullptr) || (rhs.m_Buffer == nullptr)) + { + return false; + } + + auto & lhsBuffer = *(lhs.m_Buffer); + auto & rhsBuffer = *(rhs.m_Buffer); + + const auto bufferSize = lhsBuffer.Size(); + + if (bufferSize != rhsBuffer.Size()) + { + return false; + } + + const TPixel * const lhsBufferPointer = lhsBuffer.GetBufferPointer(); + const TPixel * const rhsBufferPointer = rhsBuffer.GetBufferPointer(); + + return ((lhsBufferPointer == rhsBufferPointer) || + std::equal(lhsBufferPointer, lhsBufferPointer + bufferSize, rhsBufferPointer)); + } + + /** Returns (image1 != image2). */ + friend bool + operator!=(const Image & lhs, const Image & rhs) + { + return !(lhs == rhs); + } + protected: Image(); void diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index 734002dbed0..864e0cbbc45 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -608,6 +608,7 @@ set(ITKCommonGTests itkConstantBoundaryImageNeighborhoodPixelAccessPolicyGTest.cxx itkFixedArrayGTest.cxx itkImageNeighborhoodOffsetsGTest.cxx + itkImageGTest.cxx itkImageBaseGTest.cxx itkImageBufferRangeGTest.cxx itkImageRegionRangeGTest.cxx diff --git a/Modules/Core/Common/test/itkImageGTest.cxx b/Modules/Core/Common/test/itkImageGTest.cxx new file mode 100644 index 00000000000..ed2f1e46ce8 --- /dev/null +++ b/Modules/Core/Common/test/itkImageGTest.cxx @@ -0,0 +1,177 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +// First include the header file to be tested: +#include "itkImage.h" +#include + +namespace +{ +template +void +Expect_equal(const T & object1, const T & object2) +{ + // Test that equal objects can be used as arguments to GoogleTest EXPECT_EQ. + EXPECT_EQ(object1, object2); + EXPECT_EQ(object2, object1); + + // Test symmetry, as well as consistency between equal and unequal. + EXPECT_TRUE(object1 == object2); + EXPECT_TRUE(object2 == object1); + EXPECT_FALSE(object1 != object2); + EXPECT_FALSE(object2 != object1); +} + + +template +void +Expect_unequal(const T & object1, const T & object2) +{ + // Test that unequal objects can be used as arguments to GoogleTest EXPECT_NE. + EXPECT_NE(object1, object2); + EXPECT_NE(object2, object1); + + // Test symmetry, as well as consistency between equal and unequal. + EXPECT_TRUE(object1 != object2); + EXPECT_TRUE(object2 != object1); + EXPECT_FALSE(object1 == object2); + EXPECT_FALSE(object2 == object1); +} + + +template +void +Expect_equal_to_itself(const T & object) +{ + Expect_equal(object, object); +} + + +template +void +Expect_new_objects_equal() +{ + Expect_equal(*T::New(), *T::New()); +} + + +template +void +Expect_new_object_equal_to_itself() +{ + Expect_equal_to_itself(*T::New()); +} + + +template +void +Expect_allocated_initialized_image_equal_to_itself() +{ + using SizeType = typename TImage::SizeType; + + const auto image = TImage::New(); + image->SetRegions(SizeType::Filled(2)); + + // Allocate and initialize the image: + image->Allocate(true); + + Expect_equal_to_itself(*image); +} + + +template +void +Expect_unequal_when_sizes_differ() +{ + using SizeType = typename TImage::SizeType; + + const auto image1 = TImage::New(); + image1->SetRegions(SizeType::Filled(2)); + image1->Allocate(true); + + const auto image2 = TImage::New(); + image2->SetRegions(SizeType::Filled(3)); + image2->Allocate(true); + + Expect_unequal(*image1, *image2); +} + + +template +void +Expect_unequal_when_pixel_values_differ() +{ + using SizeType = typename TImage::SizeType; + + const auto imageSize = SizeType::Filled(2); + + const auto image1 = TImage::New(); + image1->SetRegions(imageSize); + image1->Allocate(); + image1->FillBuffer(1); + + const auto image2 = TImage::New(); + image2->SetRegions(imageSize); + image2->Allocate(); + image2->FillBuffer(2); + + Expect_unequal(*image1, *image2); +} + +} // namespace + + +// Tests that for any ImageType, objects constructed by ImageType::New() +// compare equal, using operator==(const Image &, const Image &). +TEST(Image, NewObjectsEqual) +{ + Expect_new_objects_equal>(); + Expect_new_objects_equal>(); +} + + +// Tests that an image compares equal to itself, +// using operator==(const Image &, const Image &). +TEST(Image, EqualToItself) +{ + // Tests an object when it is newly created: + Expect_new_object_equal_to_itself>(); + Expect_new_object_equal_to_itself>(); + + // Tests an object that is allocated and intialized. + Expect_allocated_initialized_image_equal_to_itself>(); + Expect_allocated_initialized_image_equal_to_itself>(); +} + + +// Tests that two image compare unequal when their sizes differ, +// using operator!=(const Image &, const Image &). +TEST(Image, UnequalWhenSizesDiffer) +{ + Expect_unequal_when_sizes_differ>(); + Expect_unequal_when_sizes_differ>(); +} + + +// Tests that two image compare unequal when their pixel values differ, +// using operator!=(const Image &, const Image &). +TEST(Image, UnequalWhenPixelValuesDiffer) +{ + Expect_unequal_when_pixel_values_differ>(); + Expect_unequal_when_pixel_values_differ>(); +}