diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index 7702883a24b..debf5a0fb09 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -6,7 +6,6 @@ set( itkCommandObserverObjectTest.cxx itkAdaptorComparisonTest.cxx itkCovariantVectorGeometryTest.cxx - itkDataTypeTest.cxx itkDecoratorTest.cxx itkExtractImage3Dto2DTest.cxx itkExtractImageTest.cxx @@ -31,9 +30,6 @@ set( itkImageSliceIteratorTest.cxx itkRGBPixelTest.cxx itkLightObjectTest.cxx - itkBoundingBoxTest.cxx - itkBoundaryConditionTest.cxx - itkByteSwapTest.cxx itkSparseImageTest.cxx itkSimpleFilterWatcherTest.cxx itkSymmetricEllipsoidInteriorExteriorSpatialFunctionTest.cxx @@ -64,8 +60,6 @@ set( itkRealTimeClockTest.cxx itkRealTimeIntervalTest.cxx itkRealTimeStampTest.cxx - itkTimeStampTest.cxx - itkIntTypesTest.cxx itkBSplineKernelFunctionTest.cxx itkArrayTest.cxx itkImageIteratorTest.cxx @@ -76,12 +70,6 @@ set( itkDirectoryTest.cxx itkObjectStoreTest.cxx itkObjectFactoryTest.cxx - itkEventObjectTest.cxx - itkMathCastWithRangeCheckTest.cxx - itkMathRoundProfileTest1.cxx - itkMathRoundTest.cxx - itkMathRoundTest2.cxx - itkModifiedTimeTest.cxx itkMultipleLogOutputTest.cxx itkVectorTest.cxx itkImageTest.cxx @@ -103,7 +91,6 @@ set( itkTimeProbeTest2.cxx itkSpatialOrientationTest.cxx itkStdStreamStateSaveTest.cxx - itkVersionTest.cxx VNLSparseLUSolverTraitsTest.cxx itkSobelOperatorImageConvolutionTest.cxx itkSobelOperatorImageFilterTest.cxx @@ -225,13 +212,6 @@ target_link_libraries( ) itk_add_test(NAME SystemInformation COMMAND itkSystemInformation) -itk_add_test( - NAME itkVersionTest - COMMAND - ITKCommon1TestDriver - itkVersionTest -) - if(ITK_BUILD_SHARED_LIBS) ## Create a library to test ITK loadable factories set(FactoryTest_Source itkFactoryTestLib.cxx) @@ -321,12 +301,6 @@ itk_add_test( ITKCommon1TestDriver itkCovariantVectorGeometryTest ) -itk_add_test( - NAME itkDataTypeTest - COMMAND - ITKCommon1TestDriver - itkDataTypeTest -) itk_add_test( NAME itkDecoratorTest COMMAND @@ -469,30 +443,6 @@ itk_add_test( ITKCommon2TestDriver itkAutoPointerTest ) -itk_add_test( - NAME itkTimeStampTest - COMMAND - ITKCommon1TestDriver - itkTimeStampTest -) -itk_add_test( - NAME itkBoundingBoxTest - COMMAND - ITKCommon1TestDriver - itkBoundingBoxTest -) -itk_add_test( - NAME itkBoundaryConditionTest - COMMAND - ITKCommon1TestDriver - itkBoundaryConditionTest -) -itk_add_test( - NAME itkByteSwapTest - COMMAND - ITKCommon1TestDriver - itkByteSwapTest -) itk_add_test( NAME itkBSplineInterpolationWeightFunctionTest COMMAND @@ -629,42 +579,6 @@ itk_add_test( ITKCommon2TestDriver itkConstShapedNeighborhoodIteratorTest2 ) -itk_add_test( - NAME itkEventObjectTest - COMMAND - ITKCommon1TestDriver - itkEventObjectTest -) -itk_add_test( - NAME itkMathCastWithRangeCheckTest - COMMAND - ITKCommon1TestDriver - itkMathCastWithRangeCheckTest -) -itk_add_test( - NAME itkMathRoundProfileTest1 - COMMAND - ITKCommon1TestDriver - itkMathRoundProfileTest1 -) -itk_add_test( - NAME itkMathRoundTest - COMMAND - ITKCommon1TestDriver - itkMathRoundTest -) -itk_add_test( - NAME itkMathRoundTest2 - COMMAND - ITKCommon1TestDriver - itkMathRoundTest2 -) -itk_add_test( - NAME itkModifiedTimeTest - COMMAND - ITKCommon1TestDriver - itkModifiedTimeTest -) itk_add_test( NAME itkExceptionObjectTest COMMAND @@ -1245,12 +1159,6 @@ itk_add_test( --full-output itkNumericTraitsTest ) -itk_add_test( - NAME itkIntTypesTest - COMMAND - ITKCommon1TestDriver - itkIntTypesTest -) itk_add_test( NAME itkOctreeTest COMMAND @@ -1884,6 +1792,17 @@ set( itkWeakPointerGTest.cxx itkCommonTypeTraitsGTest.cxx itkMathGTest.cxx + itkDataTypeGTest.cxx + itkBoundaryConditionGTest.cxx + itkBoundingBoxGTest.cxx + itkTimeStampGTest.cxx + itkEventObjectGTest.cxx + itkByteSwapGTest.cxx + itkIntTypesGTest.cxx + itkMathCastWithRangeCheckGTest.cxx + itkMathRoundGTest.cxx + itkModifiedTimeGTest.cxx + itkVersionGTest.cxx itkMetaDataDictionaryGTest.cxx itkSpatialOrientationAdaptorGTest.cxx itkAnatomicalOrientationGTest.cxx diff --git a/Modules/Core/Common/test/itkBoundaryConditionTest.cxx b/Modules/Core/Common/test/itkBoundaryConditionGTest.cxx similarity index 62% rename from Modules/Core/Common/test/itkBoundaryConditionTest.cxx rename to Modules/Core/Common/test/itkBoundaryConditionGTest.cxx index b27cf287a40..bb4f6dfd8f9 100644 --- a/Modules/Core/Common/test/itkBoundaryConditionTest.cxx +++ b/Modules/Core/Common/test/itkBoundaryConditionGTest.cxx @@ -19,6 +19,8 @@ #include "itkImageRegionIterator.h" #include "itkConstantBoundaryCondition.h" #include "itkNeighborhoodIterator.h" +#include "itkGTest.h" + namespace { void @@ -26,7 +28,6 @@ println(const char * c) { std::cout << std::endl << c << std::endl; } -} // namespace template void @@ -63,94 +64,36 @@ filln(itk::Image * img) } } } +} // namespace -int -itkBoundaryConditionTest(int, char *[]) +TEST(BoundaryCondition, ConstantBoundaryAtImageEdge) { - using ImageType2D = itk::Image; - using ImageType3D = itk::Image; - using ImageTypeND = itk::Image; println("Creating some images"); - // Create some images itk::ImageRegion<2> Region2D; - itk::ImageRegion<3> Region3D; - itk::ImageRegion<4> RegionND; - - itk::Size<2> size2D; + itk::Size<2> size2D; size2D[0] = 30; size2D[1] = 15; - - itk::Size<3> size3D; - size3D[0] = 100; - size3D[1] = 100; - size3D[2] = 10; - - itk::Size<4> sizeND; - sizeND[0] = 10; - sizeND[1] = 10; - sizeND[2] = 4; - sizeND[3] = 2; - itk::Index<2> orig2D; orig2D[0] = 0; orig2D[1] = 0; - - itk::Index<3> orig3D; - orig3D[0] = 0; - orig3D[1] = 0; - orig3D[2] = 0; - - itk::Index<4> origND; - origND[0] = 0; - origND[1] = 0; - origND[2] = 0; - origND[3] = 0; - Region2D.SetSize(size2D); - Region3D.SetSize(size3D); - RegionND.SetSize(sizeND); - Region2D.SetIndex(orig2D); - Region3D.SetIndex(orig3D); - RegionND.SetIndex(origND); auto image2D = ImageType2D::New(); - auto image3D = ImageType3D::New(); - auto imageND = ImageTypeND::New(); - image2D->SetRegions(Region2D); - image3D->SetRegions(Region3D); - imageND->SetRegions(RegionND); - image2D->Allocate(); - image3D->Allocate(); - imageND->Allocate(); println("Initializing some images"); - filln(image2D); - image3D->FillBuffer(1.0f); - imageND->FillBuffer(1.0f); println("Initializing smart neighborhood iterators"); itk::Size<2> sz2; sz2[0] = 2; sz2[1] = 1; - itk::Size<3> sz3; - sz3[0] = 2; - sz3[1] = 3; - sz3[2] = 1; - - itk::Size<4> szN; - szN[0] = 1; - szN[1] = 3; - szN[2] = 1; - szN[3] = 1; - using SmartIteratorType = itk::NeighborhoodIterator>; SmartIteratorType it2d(sz2, image2D, image2D->GetRequestedRegion()); @@ -167,11 +110,67 @@ itkBoundaryConditionTest(int, char *[]) --it2d; tempN = it2d.GetNeighborhood(); - printn(tempN.GetBufferReference(), tempN.GetSize()); + // The 2D image is 30x15, filled with 100*j + i. + // The last pixel is at (29, 14): value = 100*14 + 29 = 1429. + // With radius {2,1} and ConstantBoundaryCondition(0): + // Row 0 (j=13): pixels at x=27,28,29,30(OOB),31(OOB) -> 1327, 1328, 1329, 0, 0 + // Row 1 (j=14): pixels at x=27,28,29,30(OOB),31(OOB) -> 1427, 1428, 1429, 0, 0 + // Row 2 (j=15, OOB): all 0 -> 0, 0, 0, 0, 0 + const auto & buf = tempN.GetBufferReference(); + EXPECT_EQ(buf[0], 1327.0f); + EXPECT_EQ(buf[1], 1328.0f); + EXPECT_EQ(buf[2], 1329.0f); + EXPECT_EQ(buf[3], 0.0f); + EXPECT_EQ(buf[4], 0.0f); + EXPECT_EQ(buf[5], 1427.0f); + EXPECT_EQ(buf[6], 1428.0f); + EXPECT_EQ(buf[7], 1429.0f); + EXPECT_EQ(buf[8], 0.0f); + EXPECT_EQ(buf[9], 0.0f); + EXPECT_EQ(buf[10], 0.0f); + EXPECT_EQ(buf[11], 0.0f); + EXPECT_EQ(buf[12], 0.0f); + EXPECT_EQ(buf[13], 0.0f); + EXPECT_EQ(buf[14], 0.0f); std::cout << " ________________________________________ " << std::endl; +} + +TEST(BoundaryCondition, ZeroFluxNeumannBoundaryTraversal) +{ + using ImageType2D = itk::Image; + + itk::ImageRegion<2> Region2D; + itk::Size<2> size2D; + size2D[0] = 30; + size2D[1] = 15; + itk::Index<2> orig2D; + orig2D[0] = 0; + orig2D[1] = 0; + Region2D.SetSize(size2D); + Region2D.SetIndex(orig2D); + + auto image2D = ImageType2D::New(); + image2D->SetRegions(Region2D); + image2D->Allocate(); + filln(image2D); + + itk::Size<2> sz2; + sz2[0] = 2; + sz2[1] = 1; + + using SmartIteratorType = itk::NeighborhoodIterator>; + + SmartIteratorType it2d(sz2, image2D, image2D->GetRequestedRegion()); + + itk::ConstantBoundaryCondition cbc; + cbc.SetConstant(0.0f); + it2d.OverrideBoundaryCondition(&cbc); + + SmartIteratorType::NeighborhoodType temp2N; + temp2N = it2d.GetNeighborhood(); // initialize itk::ZeroFluxNeumannBoundaryCondition neumann; for (int yak = 0; yak < 2; ++yak) @@ -186,6 +185,6 @@ itkBoundaryConditionTest(int, char *[]) it2d.OverrideBoundaryCondition(&neumann); } - - return EXIT_SUCCESS; + // If we reach here without crashing, the test passes + EXPECT_TRUE(it2d.IsAtEnd()); } diff --git a/Modules/Core/Common/test/itkBoundingBoxGTest.cxx b/Modules/Core/Common/test/itkBoundingBoxGTest.cxx new file mode 100644 index 00000000000..31b50fc19f0 --- /dev/null +++ b/Modules/Core/Common/test/itkBoundingBoxGTest.cxx @@ -0,0 +1,200 @@ +/*========================================================================= + * + * 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 + * + * https://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. + * + *=========================================================================*/ + +#ifndef ITK_LEGACY_REMOVE +# define ITK_LEGACY_TEST +#endif +#include "itkBoundingBox.h" +#include "itkMath.h" +#include "itkGTest.h" + +#include +#include + +TEST(BoundingBox, EmptyBoxDefaults) +{ + using BB = itk::BoundingBox; + auto myBox = BB::New(); + + std::cout << "Testing Bounding Box" << std::endl; + + // Empty box: all bounds should be zero-initialized + const BB::BoundsArrayType & bounds = myBox->GetBounds(); + for (unsigned int i = 0; i < bounds.Size(); ++i) + { + EXPECT_TRUE(itk::Math::ExactlyEquals(bounds[i], BB::CoordinateType{})); + } + std::cout << "Null GetBoundingBox test passed" << std::endl; + + // Empty box: center should be zero + BB::PointType center = myBox->GetCenter(); + for (unsigned int i = 0; i < 1; ++i) + { + EXPECT_TRUE(itk::Math::ExactlyEquals(center[i], BB::CoordinateType{})); + } + std::cout << "Null GetCenter test passed" << std::endl; + + EXPECT_TRUE(itk::Math::ExactlyEquals(myBox->GetDiagonalLength2(), 0.0)); + std::cout << "Null GetDiagonalLength2 test passed" << std::endl; + + EXPECT_EQ(myBox->GetPoints(), nullptr); + std::cout << "Null GetPoints test passed" << std::endl; +} + +TEST(BoundingBox, OneDimensionalBox) +{ + using BB = itk::BoundingBox; + auto myBox = BB::New(); + + const BB::PointsContainerPointer Points = BB::PointsContainer::New(); + itk::Point P; + + for (unsigned int i = 0; i < 10; ++i) + { + P[0] = static_cast(i); + Points->InsertElement(i, P); + } + std::cout << "Insert points passed" << std::endl; + + myBox->SetPoints(Points); + EXPECT_TRUE(myBox->ComputeBoundingBox()); + std::cout << "Compute Bounding Box passed" << std::endl; + + const BB::BoundsArrayType & bounds = myBox->GetBounds(); + EXPECT_EQ(bounds[0], 0.0); + EXPECT_EQ(bounds[1], 9.0); + std::cout << "GetBoundingBox passed" << std::endl; + + BB::PointType center = myBox->GetCenter(); + EXPECT_EQ(center[0], 4.5); + std::cout << "GetCenter test passed" << std::endl; + + const itk::NumericTraits::AccumulateType diagonal = myBox->GetDiagonalLength2(); + EXPECT_EQ(diagonal, 81.0); + std::cout << "GetDiagonalLength2 passed" << std::endl; + + // End with a Print. + myBox->Print(std::cout); +} + +TEST(BoundingBox, ThreeDimensionalIsInside) +{ + using CC = itk::BoundingBox; + auto my3DBox = CC::New(); + + const CC::PointsContainerPointer Points3D = CC::PointsContainer::New(); + + std::cout << " Some Testing in 3D " << std::endl; + + constexpr CC::PointType::ValueType qval1[3]{ -1.0f, -1.0f, -1.0f }; + CC::PointType Q = qval1; + Points3D->InsertElement(0, Q); + + CC::PointType::ValueType qval2[3] = { 1.0f, 1.0f, 1.0f }; + Q = qval2; + Points3D->InsertElement(1, Q); + std::cout << "Insert points passed" << std::endl; + + my3DBox->SetPoints(Points3D); + EXPECT_TRUE(my3DBox->ComputeBoundingBox()); + std::cout << "Compute Bounding Box passed" << std::endl; + + CC::PointType::ValueType qval3[3] = { 0.0f, 0.0f, 0.0f }; + Q = qval3; + EXPECT_TRUE(my3DBox->IsInside(Q)) << "Point " << Q << " should be inside"; + + CC::PointType::ValueType qval4[3] = { 2.0f, 0.0f, 0.0f }; + Q = qval4; + EXPECT_FALSE(my3DBox->IsInside(Q)) << "Point " << Q << " should be outside"; +} + +TEST(BoundingBox, ComputeCorners) +{ + using CC = itk::BoundingBox; + auto my3DBox = CC::New(); + + const CC::PointsContainerPointer Points3D = CC::PointsContainer::New(); + + constexpr CC::PointType::ValueType qval1[3]{ -1.0f, -1.0f, -1.0f }; + CC::PointType Q = qval1; + Points3D->InsertElement(0, Q); + + CC::PointType::ValueType qval2[3] = { 1.0f, 1.0f, 1.0f }; + Q = qval2; + Points3D->InsertElement(1, Q); + + my3DBox->SetPoints(Points3D); + my3DBox->ComputeBoundingBox(); + + std::cout << "Testing ComputeCorners() : "; + const auto corners = my3DBox->ComputeCorners(); + auto it = corners.begin(); + unsigned int j = 0; + while (it != corners.end()) + { + for (unsigned int i = 0; i < 3; ++i) + { + EXPECT_EQ((*it)[i], + std::pow(-1.0, static_cast(j / (static_cast(std::pow(2.0, static_cast(i))))))); + } + j++; + ++it; + } + std::cout << "[PASSED]" << std::endl; +} + +TEST(BoundingBox, DeepCopy) +{ + using CC = itk::BoundingBox; + auto my3DBox = CC::New(); + + const CC::PointsContainerPointer Points3D = CC::PointsContainer::New(); + + constexpr CC::PointType::ValueType qval1[3]{ -1.0f, -1.0f, -1.0f }; + CC::PointType Q = qval1; + Points3D->InsertElement(0, Q); + + CC::PointType::ValueType qval2[3] = { 1.0f, 1.0f, 1.0f }; + Q = qval2; + Points3D->InsertElement(1, Q); + + my3DBox->SetPoints(Points3D); + my3DBox->ComputeBoundingBox(); + + constexpr double tolerance{ 1e-10 }; + const CC::Pointer clone = my3DBox->DeepCopy(); + const CC::BoundsArrayType & originalBounds = my3DBox->GetBounds(); + const CC::BoundsArrayType & clonedbounds = clone->GetBounds(); + for (unsigned int i = 0; i < originalBounds.Size(); ++i) + { + EXPECT_NEAR(originalBounds[i], clonedbounds[i], tolerance); + } +} + +#ifndef ITK_LEGACY_REMOVE +TEST(BoundingBox, LegacyGetCorners) +{ + // Expect four corners for a two-dimensional box: + const auto boundingBox_2D = itk::BoundingBox::New(); + EXPECT_EQ(boundingBox_2D->GetCorners()->size(), 4u); + + // Expect eight corners for a three-dimensional box: + const auto boundingBox_3D = itk::BoundingBox::New(); + EXPECT_EQ(boundingBox_3D->GetCorners()->size(), 8u); +} +#endif diff --git a/Modules/Core/Common/test/itkBoundingBoxTest.cxx b/Modules/Core/Common/test/itkBoundingBoxTest.cxx deleted file mode 100644 index 51e470b2f18..00000000000 --- a/Modules/Core/Common/test/itkBoundingBoxTest.cxx +++ /dev/null @@ -1,231 +0,0 @@ -/*========================================================================= - * - * 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 - * - * https://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. - * - *=========================================================================*/ - -#ifndef ITK_LEGACY_REMOVE -# define ITK_LEGACY_TEST -#endif -#include -#include "itkBoundingBox.h" -#include "itkMath.h" - -int -itkBoundingBoxTest(int, char *[]) -{ - // Test out the bounding box code - - using BB = itk::BoundingBox; - auto myBox = BB::New(); - - const BB::PointsContainerPointer Points = BB::PointsContainer::New(); - - itk::Point P; - - std::cout << "Testing Bounding Box" << std::endl; - { - const BB::BoundsArrayType & bounds = myBox->GetBounds(); - for (unsigned int i = 0; i < bounds.Size(); ++i) - { - if (itk::Math::NotExactlyEquals(bounds[i], BB::CoordinateType{})) - { - std::cerr << "Bounding Box initialization test failed" << std::endl; - std::cerr << bounds << std::endl; - return EXIT_FAILURE; - } - } - } - std::cout << "Null GetBoundingBox test passed" << std::endl; - - { - BB::PointType center = myBox->GetCenter(); - for (unsigned int i = 0; i < 1; ++i) - { - if (itk::Math::NotExactlyEquals(center[i], BB::CoordinateType{})) - { - std::cerr << "Empty Box GetCenter initialization test failed" << std::endl; - return EXIT_FAILURE; - } - } - std::cout << "Null GetCenter test passed" << std::endl; - } - - - if (itk::Math::NotExactlyEquals(myBox->GetDiagonalLength2(), 0.0)) - { - return EXIT_FAILURE; - } - std::cout << "Null GetDiagonalLength2 test passed" << std::endl; - - if (myBox->GetPoints()) - { - return EXIT_FAILURE; - } - std::cout << "Null GetPoints test passed" << std::endl; - - - for (unsigned int i = 0; i < 10; ++i) - { - P[0] = static_cast(i); - Points->InsertElement(i, P); - } - std::cout << "Insert points passed" << std::endl; - - myBox->SetPoints(Points); - if (!myBox->ComputeBoundingBox()) - { - return EXIT_FAILURE; - } - std::cout << "Compute Bounding Box passed" << std::endl; - - // Now we should have something - { - const BB::BoundsArrayType & bounds = myBox->GetBounds(); - if ((bounds[0] != 0.0) || (bounds[1] != 9.0)) - { - std::cerr << "Bounding Box initialization test failed" << std::endl; - std::cerr << bounds << std::endl; - return EXIT_FAILURE; - } - std::cout << "GetBoundingBox passed" << std::endl; - } - - - { - BB::PointType center = myBox->GetCenter(); - for (unsigned int i = 0; i < 1; ++i) - { - if (center[i] != 4.5) - { - std::cerr << "Empty Box GetCenter initialization test failed" << std::endl; - return EXIT_FAILURE; - } - } - std::cout << "Null GetCenter test passed" << std::endl; - } - - const itk::NumericTraits::AccumulateType diagonal = myBox->GetDiagonalLength2(); - if (diagonal != 81.0) - { - return EXIT_FAILURE; - } - std::cout << "GetDiagonalLength2 passed" << std::endl; - - const BB::PointsContainerConstPointer NewPoints = myBox->GetPoints(); - - // End with a Print. - myBox->Print(std::cout); - - - // Test the IsInside method in 3D - std::cout << " Some Testing in 3D " << std::endl; - - using CC = itk::BoundingBox; - auto my3DBox = CC::New(); - - const CC::PointsContainerPointer Points3D = CC::PointsContainer::New(); - - constexpr CC::PointType::ValueType qval1[3]{ -1.0f, -1.0f, -1.0f }; - CC::PointType Q = qval1; - Points3D->InsertElement(0, Q); - - CC::PointType::ValueType qval2[3] = { 1.0f, 1.0f, 1.0f }; - Q = qval2; - Points3D->InsertElement(1, Q); - std::cout << "Insert points passed" << std::endl; - - my3DBox->SetPoints(Points3D); - if (!my3DBox->ComputeBoundingBox()) - { - return EXIT_FAILURE; - } - std::cout << "Compute Bounding Box passed" << std::endl; - - CC::PointType::ValueType qval3[3] = { 0.0f, 0.0f, 0.0f }; - Q = qval3; - if (!my3DBox->IsInside(Q)) - { - std::cerr << "Point " << Q << " Should be reported inside " << std::endl; - return EXIT_FAILURE; - } - - CC::PointType::ValueType qval4[3] = { 2.0f, 0.0f, 0.0f }; - Q = qval4; - if (my3DBox->IsInside(Q)) - { - std::cerr << "Point " << Q << " Should be reported outside " << std::endl; - return EXIT_FAILURE; - } - - // Testing the corners - std::cout << "Testing ComputeCorners() : "; - const auto corners = my3DBox->ComputeCorners(); - auto it = corners.begin(); - unsigned int j = 0; - while (it != corners.end()) - { - for (unsigned int i = 0; i < 3; ++i) - { - if ((*it)[i] != - std::pow(-1.0, static_cast(j / (static_cast(std::pow(2.0, static_cast(i))))))) - { - std::cout << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - } - j++; - ++it; - } - std::cout << "[PASSED]" << std::endl; - - // Testing the DeepCopy method - { - constexpr double tolerance{ 1e-10 }; - const CC::Pointer clone = my3DBox->DeepCopy(); - const CC::BoundsArrayType & originalBounds = my3DBox->GetBounds(); - const CC::BoundsArrayType & clonedbounds = clone->GetBounds(); - for (unsigned int i = 0; i < originalBounds.Size(); ++i) - { - if (itk::Math::Absolute(originalBounds[i] - clonedbounds[i]) > tolerance) - { - std::cerr << "Cloning test failed" << std::endl; - std::cerr << originalBounds << std::endl; - std::cerr << clonedbounds << std::endl; - return EXIT_FAILURE; - } - } - } - -#ifndef ITK_LEGACY_REMOVE - // Expect four corners for a two-dimensional box: - const auto boundingBox_2D = itk::BoundingBox::New(); - if (boundingBox_2D->GetCorners()->size() != 4) - { - std::cerr << "Wrong number of corners for 2D box (expects 4):" << boundingBox_2D->GetCorners()->size() << std::endl; - return EXIT_FAILURE; - } - - // Expect eight corners for a three-dimensional box: - const auto boundingBox_3D = itk::BoundingBox::New(); - if (boundingBox_3D->GetCorners()->size() != 8) - { - std::cerr << "Wrong number of corners for 3D box (expects 8):" << boundingBox_3D->GetCorners()->size() << std::endl; - return EXIT_FAILURE; - } -#endif - std::cout << "BoundingBox test PASSED ! " << std::endl; - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkByteSwapTest.cxx b/Modules/Core/Common/test/itkByteSwapGTest.cxx similarity index 83% rename from Modules/Core/Common/test/itkByteSwapTest.cxx rename to Modules/Core/Common/test/itkByteSwapGTest.cxx index eb2566cceaa..d62546bd6ca 100644 --- a/Modules/Core/Common/test/itkByteSwapTest.cxx +++ b/Modules/Core/Common/test/itkByteSwapGTest.cxx @@ -16,28 +16,23 @@ * *=========================================================================*/ -#include #include "itkByteSwapper.h" #include "itkMath.h" +#include "itkGTest.h" + +#include -int -itkByteSwapTest(int, char *[]) +TEST(ByteSwap, EndianConsistency) { - // Test out the Byte Swap code + // SystemIsBigEndian and SystemIsLE must be opposites + EXPECT_NE(itk::ByteSwapper::SystemIsBigEndian(), itk::ByteSwapper::SystemIsLE()); + // SystemIsBE and SystemIsLittleEndian must be opposites + EXPECT_NE(itk::ByteSwapper::SystemIsBE(), itk::ByteSwapper::SystemIsLittleEndian()); +} +TEST(ByteSwap, DoubleSwapRestoresUnsignedChar) +{ std::cout << "Starting test" << std::endl; - - // Try to swap a char - - if constexpr (itk::ByteSwapper::SystemIsBigEndian() == itk::ByteSwapper::SystemIsLE()) - { - return EXIT_FAILURE; - } - if constexpr (itk::ByteSwapper::SystemIsBE() == itk::ByteSwapper::SystemIsLittleEndian()) - { - return EXIT_FAILURE; - } - unsigned char uc = 'a'; constexpr unsigned char uc1 = 'a'; if constexpr (itk::ByteSwapper::SystemIsBigEndian()) @@ -50,12 +45,12 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&uc); itk::ByteSwapper::SwapFromSystemToBigEndian(&uc); } - if (uc != uc1) - { - return EXIT_FAILURE; - } + EXPECT_EQ(uc, uc1); std::cout << "Passed unsigned char: " << uc << std::endl; +} +TEST(ByteSwap, DoubleSwapRestoresUnsignedShort) +{ unsigned short us = 1; constexpr unsigned short us1{ 1 }; if constexpr (itk::ByteSwapper::SystemIsBE()) @@ -68,11 +63,12 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&us); itk::ByteSwapper::SwapFromSystemToBigEndian(&us); } - if (us != us1) - { - return EXIT_FAILURE; - } + EXPECT_EQ(us, us1); std::cout << "Passed unsigned short: " << us << std::endl; +} + +TEST(ByteSwap, DoubleSwapRestoresUnsignedInt) +{ unsigned int ui = 1; constexpr unsigned int ui1{ 1 }; if constexpr (itk::ByteSwapper::SystemIsBigEndian()) @@ -85,12 +81,12 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&ui); itk::ByteSwapper::SwapFromSystemToBigEndian(&ui); } - if (ui != ui1) - { - return EXIT_FAILURE; - } + EXPECT_EQ(ui, ui1); std::cout << "Passed unsigned int: " << ui << std::endl; +} +TEST(ByteSwap, DoubleSwapRestoresUnsignedLong) +{ unsigned long ul = 1; constexpr unsigned long ul1{ 1 }; try @@ -105,10 +101,7 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&ul); itk::ByteSwapper::SwapFromSystemToBigEndian(&ul); } - if (ul != ul1) - { - return EXIT_FAILURE; - } + EXPECT_EQ(ul, ul1); std::cout << "Passed unsigned long: " << ul << std::endl; } catch (const itk::ExceptionObject & err) @@ -116,7 +109,10 @@ itkByteSwapTest(int, char *[]) std::cout << "Caught unsigned long exception size is: " << sizeof(unsigned long) << std::endl; err.Print(std::cerr); } +} +TEST(ByteSwap, DoubleSwapRestoresUnsignedLongLong) +{ unsigned long long ull = 1; constexpr unsigned long long ull1 = 1; try @@ -131,10 +127,7 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&ull); itk::ByteSwapper::SwapFromSystemToBigEndian(&ull); } - if (ull != ull1) - { - return EXIT_FAILURE; - } + EXPECT_EQ(ull, ull1); std::cout << "Passed unsigned long long: " << ull << std::endl; } catch (const itk::ExceptionObject & err) @@ -142,7 +135,10 @@ itkByteSwapTest(int, char *[]) std::cout << "Caught unsigned long long exception size is: " << sizeof(unsigned long long) << std::endl; err.Print(std::cerr); } +} +TEST(ByteSwap, DoubleSwapRestoresFloat) +{ float f = 1.0; constexpr float f1{ 1.0 }; try @@ -157,19 +153,19 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&f); itk::ByteSwapper::SwapFromSystemToBigEndian(&f); } - if (itk::Math::NotExactlyEquals(f, f1)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(itk::Math::ExactlyEquals(f, f1)); std::cout << "Passed float: " << f << std::endl; } catch (const itk::ExceptionObject & err) { std::cout << "Caught float exception size is: " << sizeof(float) << std::endl; err.Print(std::cerr); - return EXIT_FAILURE; + FAIL() << "Unexpected exception for float swap"; } +} +TEST(ByteSwap, DoubleSwapRestoresDouble) +{ double d = 1.0; constexpr double d1{ 1.0 }; try @@ -184,18 +180,13 @@ itkByteSwapTest(int, char *[]) itk::ByteSwapper::SwapFromSystemToBigEndian(&d); itk::ByteSwapper::SwapFromSystemToBigEndian(&d); } - if (itk::Math::NotExactlyEquals(d, d1)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(itk::Math::ExactlyEquals(d, d1)); std::cout << "Passed unsigned int d: " << d << std::endl; } catch (const itk::ExceptionObject & err) { std::cout << "Good catch! Caught double exception size is: " << sizeof(double) << std::endl; err.Print(std::cerr); - return EXIT_FAILURE; + FAIL() << "Unexpected exception for double swap"; } - // we failed to throw an exception for the double swap (once it's implemented, this should return 0 - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkDataTypeTest.cxx b/Modules/Core/Common/test/itkDataTypeGTest.cxx similarity index 80% rename from Modules/Core/Common/test/itkDataTypeTest.cxx rename to Modules/Core/Common/test/itkDataTypeGTest.cxx index c1e1843e00a..beb52c7b3ff 100644 --- a/Modules/Core/Common/test/itkDataTypeTest.cxx +++ b/Modules/Core/Common/test/itkDataTypeGTest.cxx @@ -16,27 +16,23 @@ * *=========================================================================*/ -#include #include "itkVector.h" +#include "itkGTest.h" + +#include -int -itkDataTypeTest(int, char *[]) +TEST(DataType, VectorElementAccess) { - int status = 0; itk::Vector v; - v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; + std::cout << "Vector value = "; for (unsigned int i = 0; i < v.GetVectorDimension(); ++i) { - if (v[i] != static_cast(i + 1)) - { - std::cout << std::endl << "ERROR: v[" << i << "] = " << v[i] << " but should = " << i + 1 << std::endl; - status++; - } + EXPECT_EQ(v[i], static_cast(i + 1)); std::cout << v[i]; if (i < v.GetVectorDimension() - 1) { @@ -44,6 +40,4 @@ itkDataTypeTest(int, char *[]) } } std::cout << std::endl; - - return status; } diff --git a/Modules/Core/Common/test/itkEventObjectTest.cxx b/Modules/Core/Common/test/itkEventObjectGTest.cxx similarity index 70% rename from Modules/Core/Common/test/itkEventObjectTest.cxx rename to Modules/Core/Common/test/itkEventObjectGTest.cxx index 1fec0aafcb4..bd8ae5bb71f 100644 --- a/Modules/Core/Common/test/itkEventObjectTest.cxx +++ b/Modules/Core/Common/test/itkEventObjectGTest.cxx @@ -17,6 +17,8 @@ *=========================================================================*/ #include "itkEventObject.h" +#include "itkGTest.h" + #include namespace itk @@ -29,50 +31,36 @@ itkEventMacroDeclaration(TestOtherEvent, AnyEvent); itkEventMacroDefinition(TestOtherEvent, AnyEvent); } // namespace itk - -int -itkEventObjectTest(int, char *[]) +TEST(EventObject, EventDerivationCheck) { - // test constructor - const itk::TestEvent event; - + const itk::TestEvent event; itk::TestDerivedEvent derivedEvent; + // A base event should match a derived event + EXPECT_TRUE(event.CheckEvent(&derivedEvent)); - // test if the event derives - if (!event.CheckEvent(&derivedEvent)) - { - std::cerr << "Derivation test failed " << std::endl; - return EXIT_FAILURE; - } - + // An event should match itself itk::TestEvent event2; - // test if the event matches itself - if (!event.CheckEvent(&event2)) - { - std::cerr << "Same class test failed " << std::endl; - return EXIT_FAILURE; - } - + EXPECT_TRUE(event.CheckEvent(&event2)); + // An event should not match an unrelated event itk::TestOtherEvent otherEvent; - // test that it doesn't match and unrelated event - if (event.CheckEvent(&otherEvent)) - { - std::cerr << "Error: matched unrelated event" << std::endl; - return EXIT_FAILURE; - } + EXPECT_FALSE(event.CheckEvent(&otherEvent)); +} +TEST(EventObject, PrintAndName) +{ + const itk::TestEvent event; // exercise the PrintSelf() method by calling Print() event.Print(std::cout); // exercise the GetEventName() method - std::cout << event.GetEventName() << std::endl; + const char * name = event.GetEventName(); + std::cout << name << std::endl; + EXPECT_STREQ(name, "TestEvent"); // exercise the shift operator std::cout << event << std::endl; - - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkIntTypesTest.cxx b/Modules/Core/Common/test/itkIntTypesGTest.cxx similarity index 55% rename from Modules/Core/Common/test/itkIntTypesTest.cxx rename to Modules/Core/Common/test/itkIntTypesGTest.cxx index 2ac3be551f7..9ec98a4bba0 100644 --- a/Modules/Core/Common/test/itkIntTypesTest.cxx +++ b/Modules/Core/Common/test/itkIntTypesGTest.cxx @@ -18,8 +18,9 @@ #include "itkIntTypes.h" #include "itkNumericTraits.h" +#include "itkGTest.h" -#include // For cout. +#include namespace { @@ -98,61 +99,56 @@ CheckType(size_t size, bool exactSize, bool issigned, const char * name, T * = n #define CHECKTYPE(T, SIZE, EXACT, ISSIGNED) CheckType(SIZE, EXACT, ISSIGNED, #T) -int -itkIntTypesTest(int, char *[]) +TEST(IntTypes, FixedWidthTypes) { - bool pass = true; - // fixed width types - pass &= CHECKTYPE(itk::int8_t, 1, true, true); - pass &= CHECKTYPE(itk::uint8_t, 1, true, false); + EXPECT_TRUE(CHECKTYPE(itk::int8_t, 1, true, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint8_t, 1, true, false)); - pass &= CHECKTYPE(itk::int16_t, 2, true, true); - pass &= CHECKTYPE(itk::uint16_t, 2, true, false); + EXPECT_TRUE(CHECKTYPE(itk::int16_t, 2, true, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint16_t, 2, true, false)); - pass &= CHECKTYPE(itk::int32_t, 4, true, true); - pass &= CHECKTYPE(itk::uint32_t, 4, true, false); + EXPECT_TRUE(CHECKTYPE(itk::int32_t, 4, true, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint32_t, 4, true, false)); + EXPECT_TRUE(CHECKTYPE(itk::int64_t, 8, true, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint64_t, 8, true, false)); +} - // least types - pass &= CHECKTYPE(itk::int_least8_t, 1, false, true); - pass &= CHECKTYPE(itk::uint_least8_t, 1, false, false); - - pass &= CHECKTYPE(itk::int_least16_t, 2, false, true); - pass &= CHECKTYPE(itk::uint_least16_t, 2, false, false); - - pass &= CHECKTYPE(itk::int_least32_t, 4, false, true); - pass &= CHECKTYPE(itk::uint_least32_t, 4, false, false); - - // fast types - pass &= CHECKTYPE(itk::int_fast8_t, 1, false, true); - pass &= CHECKTYPE(itk::uint_fast8_t, 1, false, false); - - pass &= CHECKTYPE(itk::int_fast16_t, 2, false, true); - pass &= CHECKTYPE(itk::uint_fast16_t, 2, false, false); +TEST(IntTypes, LeastTypes) +{ + EXPECT_TRUE(CHECKTYPE(itk::int_least8_t, 1, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_least8_t, 1, false, false)); - pass &= CHECKTYPE(itk::int_fast32_t, 4, false, true); - pass &= CHECKTYPE(itk::uint_fast32_t, 4, false, false); + EXPECT_TRUE(CHECKTYPE(itk::int_least16_t, 2, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_least16_t, 2, false, false)); - pass &= CHECKTYPE(itk::int64_t, 8, true, true); - pass &= CHECKTYPE(itk::uint64_t, 8, true, false); + EXPECT_TRUE(CHECKTYPE(itk::int_least32_t, 4, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_least32_t, 4, false, false)); - pass &= CHECKTYPE(itk::int_least64_t, 8, false, true); - pass &= CHECKTYPE(itk::uint_least64_t, 8, false, false); + EXPECT_TRUE(CHECKTYPE(itk::int_least64_t, 8, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_least64_t, 8, false, false)); +} - pass &= CHECKTYPE(itk::int_fast64_t, 8, false, true); - pass &= CHECKTYPE(itk::uint_fast64_t, 8, false, false); +TEST(IntTypes, FastTypes) +{ + EXPECT_TRUE(CHECKTYPE(itk::int_fast8_t, 1, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_fast8_t, 1, false, false)); - pass &= CHECKTYPE(itk::intmax_t, 4, false, true); - pass &= CHECKTYPE(itk::uintmax_t, 4, false, false); + EXPECT_TRUE(CHECKTYPE(itk::int_fast16_t, 2, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_fast16_t, 2, false, false)); - pass &= CHECKTYPE(itk::intptr_t, sizeof(void *), false, true); - pass &= CHECKTYPE(itk::uintptr_t, sizeof(void *), false, false); + EXPECT_TRUE(CHECKTYPE(itk::int_fast32_t, 4, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_fast32_t, 4, false, false)); + EXPECT_TRUE(CHECKTYPE(itk::int_fast64_t, 8, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uint_fast64_t, 8, false, false)); +} - if (pass) - { - return EXIT_SUCCESS; - } +TEST(IntTypes, MaxAndPtrTypes) +{ + EXPECT_TRUE(CHECKTYPE(itk::intmax_t, 4, false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uintmax_t, 4, false, false)); - return EXIT_FAILURE; + EXPECT_TRUE(CHECKTYPE(itk::intptr_t, sizeof(void *), false, true)); + EXPECT_TRUE(CHECKTYPE(itk::uintptr_t, sizeof(void *), false, false)); } diff --git a/Modules/Core/Common/test/itkMathCastWithRangeCheckTest.cxx b/Modules/Core/Common/test/itkMathCastWithRangeCheckGTest.cxx similarity index 67% rename from Modules/Core/Common/test/itkMathCastWithRangeCheckTest.cxx rename to Modules/Core/Common/test/itkMathCastWithRangeCheckGTest.cxx index 050edf3b05d..e641c486385 100644 --- a/Modules/Core/Common/test/itkMathCastWithRangeCheckTest.cxx +++ b/Modules/Core/Common/test/itkMathCastWithRangeCheckGTest.cxx @@ -17,6 +17,8 @@ *=========================================================================*/ #include "itkMath.h" +#include "itkGTest.h" + #include @@ -115,49 +117,53 @@ DoCastWithRangeCheckTestForTypes(const T1 * = nullptr) } // end namespace -int -itkMathCastWithRangeCheckTest(int, char *[]) +TEST(MathCastWithRangeCheck, OverflowThrowsException) +{ + // Wrap in lambda to avoid comma in template args confusing the macro parser + EXPECT_THROW( + ([&]() { itk::Math::CastWithRangeCheck(static_cast(itk::NumericTraits::max()) + 10); }()), + itk::RangeError); + std::cout << "caught exception as expected" << std::endl; +} + +TEST(MathCastWithRangeCheck, ExhaustiveSmallTypes) { bool pass = true; + pass &= DoCastWithRangeCheckTestExulstive(); + pass &= DoCastWithRangeCheckTestExulstive(); + pass &= DoCastWithRangeCheckTestExulstive(); + pass &= DoCastWithRangeCheckTestExulstive(); + pass &= DoCastWithRangeCheckTestExulstive(); + EXPECT_TRUE(pass); +} - try - { - itk::Math::CastWithRangeCheck(static_cast(itk::NumericTraits::max()) + 10); - pass = false; - std::cout << "failed to through exception with " << static_cast(itk::NumericTraits::max()) + 10 - << " to int "; - } - catch (...) - { - std::cout << "caught exception as expected" << std::endl; - } +TEST(MathCastWithRangeCheck, AllTypesToUnsignedChar) { EXPECT_TRUE(DoCastWithRangeCheckTestForTypes()); } +TEST(MathCastWithRangeCheck, AllTypesToSignedChar) { EXPECT_TRUE(DoCastWithRangeCheckTestForTypes()); } - DoCastWithRangeCheckTestExulstive(); - DoCastWithRangeCheckTestExulstive(); - DoCastWithRangeCheckTestExulstive(); - DoCastWithRangeCheckTestExulstive(); +TEST(MathCastWithRangeCheck, AllTypesToUnsignedShort) +{ + EXPECT_TRUE(DoCastWithRangeCheckTestForTypes()); +} - DoCastWithRangeCheckTestExulstive(); +TEST(MathCastWithRangeCheck, AllTypesToShort) +{ + const bool pass = DoCastWithRangeCheckTestForTypes(); + EXPECT_TRUE(pass); +} +TEST(MathCastWithRangeCheck, AllTypesToUnsignedInt) { EXPECT_TRUE(DoCastWithRangeCheckTestForTypes()); } - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); -#ifdef ITK_USE_LONG_LONG - pass &= DoCastWithRangeCheckTestForTypes(); - pass &= DoCastWithRangeCheckTestForTypes(); -#endif +TEST(MathCastWithRangeCheck, AllTypesToInt) +{ + const bool pass = DoCastWithRangeCheckTestForTypes(); + EXPECT_TRUE(pass); +} - if (pass) - { - return EXIT_SUCCESS; - } +TEST(MathCastWithRangeCheck, AllTypesToUnsignedLong) { EXPECT_TRUE(DoCastWithRangeCheckTestForTypes()); } - return EXIT_FAILURE; +TEST(MathCastWithRangeCheck, AllTypesToLong) +{ + const bool pass = DoCastWithRangeCheckTestForTypes(); + EXPECT_TRUE(pass); } diff --git a/Modules/Core/Common/test/itkMathRoundTest2.cxx b/Modules/Core/Common/test/itkMathRoundGTest.cxx similarity index 55% rename from Modules/Core/Common/test/itkMathRoundTest2.cxx rename to Modules/Core/Common/test/itkMathRoundGTest.cxx index f8faf5be10c..d4a7ea33e78 100644 --- a/Modules/Core/Common/test/itkMathRoundTest2.cxx +++ b/Modules/Core/Common/test/itkMathRoundGTest.cxx @@ -17,7 +17,25 @@ *=========================================================================*/ #include "itkMath.h" +#include "itkIndex.h" +#include "itkGTest.h" + #include +#include + +// Helper from original itkMathRoundTest +namespace +{ +bool +math_test_helper(const std::string_view str, bool test) +{ + if (!test) + { + std::cout << "test (" << str << ") failed" << std::endl; + } + return test; +} +} // namespace #define RoundTestHelperMacro(rndname, input, output) \ if (rndname((input)) != (output)) \ @@ -44,13 +62,10 @@ TemplatedRoundTest() T roundOutput[] = { -8, -8, -9, 8, 9, 9, -9, -9, -10, 9, 10, 10, 0, 0, -1 }; - constexpr T halftoevenOutput[]{ -8, -8, -9, 8, 8, 9, -9, -10, -10, 9, 10, 10, 0, 0, -1 }; - T * halfupOutput = roundOutput; - //////// // input data for floor and ceil methods constexpr float fcinput[]{ 8.0f, 8.9999f, 8.0001f, -8.0f, -8.9999f, -8.0001f, 9.0f, 9.9999f, @@ -58,82 +73,117 @@ TemplatedRoundTest() constexpr T floorOutput[]{ 8, 8, 8, -8, -9, -9, 9, 9, 9, -9, -10, -10, -1, -1, -2 }; - constexpr T ceilOutput[]{ 8, 9, 9, -8, -8, -8, 9, 10, 10, -9, -9, -9, -1, 0, -1 }; - // Round for (unsigned int i = 0; i < numberOfElements; ++i) { - RoundTestHelperMacro(itk::Math::Round, static_cast(input[i]), roundOutput[i]); - RoundTestHelperMacro(itk::Math::Round, static_cast(input[i]), roundOutput[i]); } // RoundHalfIntegerToEven for (unsigned int i = 0; i < numberOfElements; ++i) { - - RoundTestHelperMacro(itk::Math::RoundHalfIntegerToEven, static_cast(input[i]), halftoevenOutput[i]); - RoundTestHelperMacro(itk::Math::RoundHalfIntegerToEven, static_cast(input[i]), halftoevenOutput[i]); } // RoundHalfIntegerUp for (unsigned int i = 0; i < numberOfElements; ++i) { - RoundTestHelperMacro(itk::Math::RoundHalfIntegerUp, static_cast(input[i]), halfupOutput[i]); - RoundTestHelperMacro(itk::Math::RoundHalfIntegerUp, static_cast(input[i]), halfupOutput[i]); } // Floor for (unsigned int i = 0; i < numberOfElements; ++i) { - RoundTestHelperMacro(itk::Math::Floor, static_cast(fcinput[i]), floorOutput[i]); - RoundTestHelperMacro(itk::Math::Floor, static_cast(fcinput[i]), floorOutput[i]); } // Ceil for (unsigned int i = 0; i < numberOfElements; ++i) { - RoundTestHelperMacro(itk::Math::Ceil, static_cast(fcinput[i]), ceilOutput[i]); - RoundTestHelperMacro(itk::Math::Ceil, static_cast(fcinput[i]), ceilOutput[i]); } - return ok; } } // namespace -int -itkMathRoundTest2(int, char *[]) + +TEST(MathRound, IndexValueType) { bool ok = true; + using IndexValueType = itk::Index<3>::IndexValueType; + + ok &= math_test_helper("rnd(-8.4999) == -8", itk::Math::Round(-8.4999) == -8); + ok &= math_test_helper("rnd(-8.4999f) == -8", itk::Math::Round(-8.4999f) == -8); + ok &= math_test_helper("rnd(-8.50 == -8", itk::Math::Round(-8.50) == -8); + ok &= math_test_helper("rnd(-8.50f) == -8", itk::Math::Round(-8.50f) == -8); + ok &= math_test_helper("rnd(-8.5001) == -9", itk::Math::Round(-8.5001) == -9); + ok &= math_test_helper("rnd(-8.5001f) == -9", itk::Math::Round(-8.5001f) == -9); + ok &= math_test_helper("rnd(8.4999) == 8", itk::Math::Round(8.4999) == 8); + ok &= math_test_helper("rnd(8.4999f) == 8", itk::Math::Round(8.4999f) == 8); + ok &= math_test_helper("rnd(8.50) == 9", itk::Math::Round(8.50) == 9); + ok &= math_test_helper("rnd(8.50f) == 9", itk::Math::Round(8.50f) == 9); + ok &= math_test_helper("rnd(8.5001) == 9", itk::Math::Round(8.5001) == 9); + ok &= math_test_helper("rnd(8.5001f) == 9", itk::Math::Round(8.5001f) == 9); + + ok &= + math_test_helper("rnd_halfinttoeven(-8.50) == -8", itk::Math::RoundHalfIntegerToEven(-8.50) == -8); + ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", itk::Math::RoundHalfIntegerToEven(8.50) == 8); + ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", + itk::Math::RoundHalfIntegerToEven(-9.50) == -10); + ok &= + math_test_helper("rnd_halfinttoeven(9.50) == 10", itk::Math::RoundHalfIntegerToEven(9.50) == 10); + + ok &= math_test_helper("rnd_halfintup(-8.50) == -8", itk::Math::RoundHalfIntegerUp(-8.50) == -8); + ok &= math_test_helper("rnd_halfintup(8.50) == 9", itk::Math::RoundHalfIntegerUp(8.50) == 9); + ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50) == -9); + ok &= math_test_helper("rnd_halfintup(9.50) == 10", itk::Math::RoundHalfIntegerUp(9.50) == 10); + + ok &= math_test_helper("floor(8.0) == 8", itk::Math::Floor(8.0) == 8); + ok &= math_test_helper("floor(-8.9999) == -9", itk::Math::Floor(-8.9999) == -9); + ok &= math_test_helper("floor(-9.9999) == -10", itk::Math::Floor(-9.9999) == -10); + + ok &= math_test_helper("ceil(8.9999) == 9", itk::Math::Ceil(8.9999) == 9); + ok &= math_test_helper("ceil(-8.0001) == -8", itk::Math::Ceil(-8.0001) == -8); + ok &= math_test_helper("ceil(9.9999) == 10", itk::Math::Ceil(9.9999) == 10); + + EXPECT_TRUE(ok); +} + +TEST(MathRound, CharType) +{ std::cout << "Testing char type" << std::endl; - ok &= TemplatedRoundTest(); + EXPECT_TRUE(TemplatedRoundTest()); +} + +TEST(MathRound, ShortType) +{ std::cout << "Testing short type" << std::endl; - ok &= TemplatedRoundTest(); + EXPECT_TRUE(TemplatedRoundTest()); +} + +TEST(MathRound, IntType) +{ std::cout << "Testing int type" << std::endl; - ok &= TemplatedRoundTest(); - std::cout << "Testing long type" << std::endl; - ok &= TemplatedRoundTest(); - std::cout << "Testing vxl_int_64 type" << std::endl; - ok &= TemplatedRoundTest(); + EXPECT_TRUE(TemplatedRoundTest()); +} - if (!ok) - { - return EXIT_FAILURE; - } +TEST(MathRound, LongType) +{ + std::cout << "Testing long type" << std::endl; + EXPECT_TRUE(TemplatedRoundTest()); +} - std::cout << "Test passed" << std::endl; - return EXIT_SUCCESS; +TEST(MathRound, VxlInt64Type) +{ + std::cout << "Testing vxl_int_64 type" << std::endl; + EXPECT_TRUE(TemplatedRoundTest()); } diff --git a/Modules/Core/Common/test/itkMathRoundProfileTest1.cxx b/Modules/Core/Common/test/itkMathRoundProfileTest1.cxx deleted file mode 100644 index edeb7388e0d..00000000000 --- a/Modules/Core/Common/test/itkMathRoundProfileTest1.cxx +++ /dev/null @@ -1,231 +0,0 @@ -/*========================================================================= - * - * 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 - * - * https://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. - * - *=========================================================================*/ - -#include "itkTimeProbesCollectorBase.h" -#include "itkMath.h" - -int -itkMathRoundTestHelperFunction(double x) -{ - x += 0.5; - return static_cast(x >= 0. ? x : (itk::Math::ExactlyEquals(x, static_cast(x)) ? x : x - 1.)); -} - -#define itkRoundMacro(x, y) \ - if (x >= 0.5) \ - { \ - y = static_cast(x + 0.5); \ - } \ - else \ - { \ - ITK_GCC_PRAGMA_PUSH \ - ITK_GCC_SUPPRESS_Wfloat_equal \ - if ((x + 0.5) == static_cast(x + 0.5)) \ - { \ - y = static_cast(x + 0.5); \ - } \ - else \ - { \ - y = static_cast(x - 0.5); \ - } \ - ITK_GCC_PRAGMA_POP \ - } \ - ITK_MACROEND_NOOP_STATEMENT - -int -itkMathRoundProfileTest1(int, char *[]) -{ - itk::TimeProbesCollectorBase chronometer; - - using ArrayType = std::vector; - using IntArrayType = std::vector; - - ArrayType input; - IntArrayType output1; - IntArrayType output2; - IntArrayType output3; - IntArrayType output4; - - constexpr unsigned long numberOfValues{ 1000L }; - - constexpr double initialValue{ -10.0 }; - - constexpr double valueIncrement{ (-initialValue - initialValue) / numberOfValues }; - - std::cout << "Initial Value = " << initialValue << std::endl; - std::cout << "Value Increment = " << valueIncrement << std::endl; - - for (unsigned long i = 0; i < numberOfValues; ++i) - { - const double inputValue = initialValue + i * valueIncrement; - input.push_back(inputValue); - } - - - // - // Make sure that entries in the .5 locations are included - // - for (int k = -10; k <= 10; ++k) - { - const double value = k + 0.5; - input.push_back(value); - } - - - output1.resize(input.size()); - output2.resize(input.size()); - output3.resize(input.size()); - output4.resize(input.size()); - - for (unsigned int tours = 0; tours < 100; ++tours) - { - // - // Count the time of simply assigning values in an std::vector - // - // - auto outItr1src = output1.begin(); - auto outItr2dst = output2.begin(); - - const auto outEnd1 = output1.end(); - - chronometer.Start("std::vector"); - - while (outItr1src != outEnd1) - { - *outItr2dst++ = *outItr1src++; - } - - chronometer.Stop("std::vector"); - - auto inpItr = input.begin(); - auto inputEnd = input.end(); - - auto outItr1nc = output1.begin(); - - // - // Count the time of rounding plus storing in container - // - chronometer.Start("if-round"); - - while (inpItr != inputEnd) - { - *outItr1nc++ = itkMathRoundTestHelperFunction(*inpItr++); - } - - chronometer.Stop("if-round"); - - - inpItr = input.begin(); - inputEnd = input.end(); - - auto outItr3nc = output3.begin(); - - // - // Count the time of rounding plus storing in container - // - chronometer.Start("Functor"); - - while (inpItr != inputEnd) - { - const double x = (*inpItr++) + 0.5; - *outItr3nc++ = static_cast(x >= 0. ? x : (itk::Math::ExactlyEquals(x, static_cast(x)) ? x : x - 1.)); - } - - chronometer.Stop("Functor"); - - inpItr = input.begin(); - inputEnd = input.end(); - - auto outItr4nc = output4.begin(); - - // - // Count the time of rounding plus storing in container - // - chronometer.Start("Macro"); - - while (inpItr != inputEnd) - { - itkRoundMacro(*inpItr, *outItr4nc); - ++inpItr; - ++outItr4nc; - } - - chronometer.Stop("Macro"); - - - inpItr = input.begin(); - inputEnd = input.end(); - - auto outItr = output2.begin(); - - // - // Count the time of rounding plus storing in container - // - chronometer.Start("itk::Math::Round"); - - while (inpItr != inputEnd) - { - *outItr++ = itk::Math::Round(*inpItr++); - } - - chronometer.Stop("itk::Math::Round"); - } - - chronometer.Report(std::cout); - - // - // Now test the correctness of the output - // - auto inpItr = input.begin(); - const auto inputEnd = input.end(); - - auto outItr1 = output1.begin(); - auto outItr2 = output2.begin(); - - bool roundMismatch = false; - - std::cout << std::endl; - std::cout << std::endl; - - while (inpItr != inputEnd) - { - if (*outItr1 != *outItr2) - { - std::cout << "Warning*** For input: " << *inpItr << " if-round: " << *outItr1 - << " differs from itk::Math::Round: " << *outItr2 << std::endl; - - roundMismatch = true; - } - ++inpItr; - ++outItr1; - ++outItr2; - } - - std::cout << std::endl; - std::cout << "Tested " << output1.size() << " entries " << std::endl; - std::cout << std::endl; - - if (roundMismatch) - { - std::cout << "******* On this platform, itk::Math::Round() does not round half integers upward ********" - << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkMathRoundTest.cxx b/Modules/Core/Common/test/itkMathRoundTest.cxx deleted file mode 100644 index d7773ab257b..00000000000 --- a/Modules/Core/Common/test/itkMathRoundTest.cxx +++ /dev/null @@ -1,205 +0,0 @@ -/*========================================================================= - * - * 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 - * - * https://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. - * - *=========================================================================*/ - -#include -#include -#include "itkIndex.h" - -bool -math_test_helper(const std::string_view str, bool test) -{ - if (!test) - { - std::cout << "test (" << str << ") failed" << std::endl; - } - return test; -} - -int -itkMathRoundTest(int, char *[]) -{ - bool ok = true; - - using IndexValueType = itk::Index<3>::IndexValueType; - - ok &= math_test_helper("rnd(-8.4999) == -8", itk::Math::Round(-8.4999) == -8); - ok &= math_test_helper("rnd(-8.4999f) == -8", itk::Math::Round(-8.4999f) == -8); - ok &= math_test_helper("rnd(-8.50 == -8", itk::Math::Round(-8.50) == -8); - ok &= math_test_helper("rnd(-8.50f) == -8", itk::Math::Round(-8.50f) == -8); - ok &= math_test_helper("rnd(-8.5001) == -9", itk::Math::Round(-8.5001) == -9); - ok &= math_test_helper("rnd(-8.5001f) == -9", itk::Math::Round(-8.5001f) == -9); - ok &= math_test_helper("rnd(8.4999) == 8", itk::Math::Round(8.4999) == 8); - ok &= math_test_helper("rnd(8.4999f) == 8", itk::Math::Round(8.4999f) == 8); - ok &= math_test_helper("rnd(8.50) == 9", itk::Math::Round(8.50) == 9); - ok &= math_test_helper("rnd(8.50f) == 9", itk::Math::Round(8.50f) == 9); - ok &= math_test_helper("rnd(8.5001) == 9", itk::Math::Round(8.5001) == 9); - ok &= math_test_helper("rnd(8.5001f) == 9", itk::Math::Round(8.5001f) == 9); - - ok &= math_test_helper("rnd(-9.4999) == -9 ", itk::Math::Round(-9.4999) == -9); - ok &= math_test_helper("rnd(-9.4999f) == -9 ", itk::Math::Round(-9.4999f) == -9); - ok &= math_test_helper("rnd(-9.50) == -9 ", itk::Math::Round(-9.50) == -9); - ok &= math_test_helper("rnd(-9.50f) == -9 ", itk::Math::Round(-9.50f) == -9); - ok &= math_test_helper("rnd(-9.5001) == -10", itk::Math::Round(-9.5001) == -10); - ok &= math_test_helper("rnd(-9.5001f) == -10", itk::Math::Round(-9.5001f) == -10); - ok &= math_test_helper("rnd(9.4999) == 9 ", itk::Math::Round(9.4999) == 9); - ok &= math_test_helper("rnd(9.4999f) == 9 ", itk::Math::Round(9.4999f) == 9); - ok &= math_test_helper("rnd(9.50) == 10", itk::Math::Round(9.50) == 10); - ok &= math_test_helper("rnd(9.50f) == 10", itk::Math::Round(9.50f) == 10); - ok &= math_test_helper("rnd(9.5001) == 10", itk::Math::Round(9.5001) == 10); - ok &= math_test_helper("rnd(9.5001f) == 10", itk::Math::Round(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", - itk::Math::RoundHalfIntegerToEven(-8.4999) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.4999f) == -8", - itk::Math::RoundHalfIntegerToEven(-8.4999f) == -8); - ok &= - math_test_helper("rnd_halfinttoeven(-8.50) == -8", itk::Math::RoundHalfIntegerToEven(-8.50) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.50f) == -8", - itk::Math::RoundHalfIntegerToEven(-8.50f) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", - itk::Math::RoundHalfIntegerToEven(-8.5001) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001f) == -9", - itk::Math::RoundHalfIntegerToEven(-8.5001f) == -9); - ok &= - math_test_helper("rnd_halfinttoeven(8.4999) == 8", itk::Math::RoundHalfIntegerToEven(8.4999) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.4999f) == 8", - itk::Math::RoundHalfIntegerToEven(8.4999f) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", itk::Math::RoundHalfIntegerToEven(8.50) == 8); - ok &= - math_test_helper("rnd_halfinttoeven(8.50f) == 8", itk::Math::RoundHalfIntegerToEven(8.50f) == 8); - ok &= - math_test_helper("rnd_halfinttoeven(8.5001) == 9", itk::Math::RoundHalfIntegerToEven(8.5001) == 9); - ok &= math_test_helper("rnd_halfinttoeven(8.5001f) == 9", - itk::Math::RoundHalfIntegerToEven(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", - itk::Math::RoundHalfIntegerToEven(-9.4999) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.4999f) == -9 ", - itk::Math::RoundHalfIntegerToEven(-9.4999f) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", - itk::Math::RoundHalfIntegerToEven(-9.50) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.50f) == -10", - itk::Math::RoundHalfIntegerToEven(-9.50f) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", - itk::Math::RoundHalfIntegerToEven(-9.5001) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001f) == -10", - itk::Math::RoundHalfIntegerToEven(-9.5001f) == -10); - ok &= - math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999) == 9); - ok &= math_test_helper("rnd_halfinttoeven(9.4999f) == 9 ", - itk::Math::RoundHalfIntegerToEven(9.4999f) == 9); - ok &= - math_test_helper("rnd_halfinttoeven(9.50) == 10", itk::Math::RoundHalfIntegerToEven(9.50) == 10); - ok &= - math_test_helper("rnd_halfinttoeven(9.50f) == 10", itk::Math::RoundHalfIntegerToEven(9.50f) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", - itk::Math::RoundHalfIntegerToEven(9.5001) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001f) == 10", - itk::Math::RoundHalfIntegerToEven(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", itk::Math::RoundHalfIntegerUp(-8.4999) == -8); - ok &= - math_test_helper("rnd_halfintup(-8.4999f) == -8", itk::Math::RoundHalfIntegerUp(-8.4999f) == -8); - ok &= math_test_helper("rnd_halfintup(-8.50) == -8", itk::Math::RoundHalfIntegerUp(-8.50) == -8); - ok &= math_test_helper("rnd_halfintup(-8.50f) == -8", itk::Math::RoundHalfIntegerUp(-8.50f) == -8); - ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", itk::Math::RoundHalfIntegerUp(-8.5001) == -9); - ok &= - math_test_helper("rnd_halfintup(-8.5001f) == -9", itk::Math::RoundHalfIntegerUp(-8.5001f) == -9); - ok &= math_test_helper("rnd_halfintup(8.4999) == 8", itk::Math::RoundHalfIntegerUp(8.4999) == 8); - ok &= math_test_helper("rnd_halfintup(8.4999f) == 8", itk::Math::RoundHalfIntegerUp(8.4999f) == 8); - ok &= math_test_helper("rnd_halfintup(8.50) == 9", itk::Math::RoundHalfIntegerUp(8.50) == 9); - ok &= math_test_helper("rnd_halfintup(8.50f) == 9", itk::Math::RoundHalfIntegerUp(8.50f) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001) == 9", itk::Math::RoundHalfIntegerUp(8.5001) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001f) == 9", itk::Math::RoundHalfIntegerUp(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999) == -9); - ok &= - math_test_helper("rnd_halfintup(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999f) == -9); - ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50) == -9); - ok &= math_test_helper("rnd_halfintup(-9.50f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50f) == -9); - ok &= - math_test_helper("rnd_halfintup(-9.5001) == -10", itk::Math::RoundHalfIntegerUp(-9.5001) == -10); - ok &= - math_test_helper("rnd_halfintup(-9.5001f) == -10", itk::Math::RoundHalfIntegerUp(-9.5001f) == -10); - ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999) == 9); - ok &= math_test_helper("rnd_halfintup(9.4999f) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999f) == 9); - ok &= math_test_helper("rnd_halfintup(9.50) == 10", itk::Math::RoundHalfIntegerUp(9.50) == 10); - ok &= math_test_helper("rnd_halfintup(9.50f) == 10", itk::Math::RoundHalfIntegerUp(9.50f) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001) == 10", itk::Math::RoundHalfIntegerUp(9.5001) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001f) == 10", itk::Math::RoundHalfIntegerUp(9.5001f) == 10); - - ok &= math_test_helper("floor(8.0) == 8", itk::Math::Floor(8.0) == 8); - ok &= math_test_helper("floor(8.0f) == 8", itk::Math::Floor(8.0f) == 8); - ok &= math_test_helper("floor(8.9999) == 8", itk::Math::Floor(8.9999) == 8); - ok &= math_test_helper("floor(8.9999f) == 8", itk::Math::Floor(8.9999f) == 8); - ok &= math_test_helper("floor(8.0001) == 8", itk::Math::Floor(8.0001) == 8); - ok &= math_test_helper("floor(8.0001f) == 8", itk::Math::Floor(8.0001f) == 8); - ok &= math_test_helper("floor(-8.0) == -8", itk::Math::Floor(-8.0) == -8); - ok &= math_test_helper("floor(-8.0f) == -8", itk::Math::Floor(-8.0f) == -8); - ok &= math_test_helper("floor(-8.9999) == -9", itk::Math::Floor(-8.9999) == -9); - ok &= math_test_helper("floor(-8.9999f) == -9", itk::Math::Floor(-8.9999f) == -9); - ok &= math_test_helper("floor(-8.0001) == -9", itk::Math::Floor(-8.0001) == -9); - ok &= math_test_helper("floor(-8.0001f) == -9", itk::Math::Floor(-8.0001f) == -9); - - ok &= math_test_helper("floor(9.0) == 9 ", itk::Math::Floor(9.0) == 9); - ok &= math_test_helper("floor(9.0f) == 9 ", itk::Math::Floor(9.0f) == 9); - ok &= math_test_helper("floor(9.9999) == 9 ", itk::Math::Floor(9.9999) == 9); - ok &= math_test_helper("floor(9.9999f) == 9 ", itk::Math::Floor(9.9999f) == 9); - ok &= math_test_helper("floor(9.0001) == 9 ", itk::Math::Floor(9.0001) == 9); - ok &= math_test_helper("floor(9.0001f) == 9 ", itk::Math::Floor(9.0001f) == 9); - ok &= math_test_helper("floor(-9.0) == -9 ", itk::Math::Floor(-9.0) == -9); - ok &= math_test_helper("floor(-9.0f) == -9 ", itk::Math::Floor(-9.0f) == -9); - ok &= math_test_helper("floor(-9.9999) == -10", itk::Math::Floor(-9.9999) == -10); - ok &= math_test_helper("floor(-9.9999f) == -10", itk::Math::Floor(-9.9999f) == -10); - ok &= math_test_helper("floor(-9.0001) == -10", itk::Math::Floor(-9.0001) == -10); - ok &= math_test_helper("floor(-9.0001f) == -10", itk::Math::Floor(-9.0001f) == -10); - - ok &= math_test_helper("ceil(8.0) == 8", itk::Math::Ceil(8.0) == 8); - ok &= math_test_helper("ceil(8.0f) == 8", itk::Math::Ceil(8.0f) == 8); - ok &= math_test_helper("ceil(8.9999) == 9", itk::Math::Ceil(8.9999) == 9); - ok &= math_test_helper("ceil(8.9999f) == 9", itk::Math::Ceil(8.9999f) == 9); - ok &= math_test_helper("ceil(8.0001) == 9", itk::Math::Ceil(8.0001) == 9); - ok &= math_test_helper("ceil(8.0001f) == 9", itk::Math::Ceil(8.0001f) == 9); - ok &= math_test_helper("ceil(-8.0) == -8", itk::Math::Ceil(-8.0) == -8); - ok &= math_test_helper("ceil(-8.0f) == -8", itk::Math::Ceil(-8.0f) == -8); - ok &= math_test_helper("ceil(-8.9999) == -8", itk::Math::Ceil(-8.9999) == -8); - ok &= math_test_helper("ceil(-8.9999f) == -8", itk::Math::Ceil(-8.9999f) == -8); - ok &= math_test_helper("ceil(-8.0001) == -8", itk::Math::Ceil(-8.0001) == -8); - ok &= math_test_helper("ceil(-8.0001f) == -8", itk::Math::Ceil(-8.0001f) == -8); - - ok &= math_test_helper("ceil(9.0) == 9 ", itk::Math::Ceil(9.0) == 9); - ok &= math_test_helper("ceil(9.0f) == 9 ", itk::Math::Ceil(9.0f) == 9); - ok &= math_test_helper("ceil(9.9999) == 10", itk::Math::Ceil(9.9999) == 10); - ok &= math_test_helper("ceil(9.9999f) == 10", itk::Math::Ceil(9.9999f) == 10); - ok &= math_test_helper("ceil(9.0001) == 10", itk::Math::Ceil(9.0001) == 10); - ok &= math_test_helper("ceil(9.0001f) == 10", itk::Math::Ceil(9.0001f) == 10); - ok &= math_test_helper("ceil(-9.0) == -9 ", itk::Math::Ceil(-9.0) == -9); - ok &= math_test_helper("ceil(-9.0f) == -9 ", itk::Math::Ceil(-9.0f) == -9); - ok &= math_test_helper("ceil(-9.9999) == -9 ", itk::Math::Ceil(-9.9999) == -9); - ok &= math_test_helper("ceil(-9.9999f) == -9 ", itk::Math::Ceil(-9.9999f) == -9); - ok &= math_test_helper("ceil(-9.0001) == -9 ", itk::Math::Ceil(-9.0001) == -9); - ok &= math_test_helper("ceil(-9.0001f) == -9 ", itk::Math::Ceil(-9.0001f) == -9); - - if (!ok) - { - return EXIT_FAILURE; - } - - std::cout << "Test passed" << std::endl; - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkModifiedTimeTest.cxx b/Modules/Core/Common/test/itkModifiedTimeGTest.cxx similarity index 72% rename from Modules/Core/Common/test/itkModifiedTimeTest.cxx rename to Modules/Core/Common/test/itkModifiedTimeGTest.cxx index 4cf28431135..a7fad3c09f5 100644 --- a/Modules/Core/Common/test/itkModifiedTimeTest.cxx +++ b/Modules/Core/Common/test/itkModifiedTimeGTest.cxx @@ -18,9 +18,11 @@ #include "itkBoundingBox.h" #include "itkIntTypes.h" +#include "itkGTest.h" -int -itkModifiedTimeTest(int, char *[]) +#include + +TEST(ModifiedTime, ModifiedTimeUpdatesOnChange) { using Point = itk::Point; using PointsContainer = itk::VectorContainer; @@ -52,28 +54,14 @@ itkModifiedTimeTest(int, char *[]) std::cout << "BB time after modification: " << bbAfterTime << std::endl; std::cout << "PC time after modification: " << pcAfterTime << std::endl; - if (pcAfterTime == pcBeforeTime) - { - std::cout << "Points Container Modified Time is not being " << std::endl; - std::cout << "updated by call to Modified()" << std::endl; - return EXIT_FAILURE; - } - - if (bbAfterTime == bbBeforeTime) - { - std::cout << "Bounding Box Modified Time is not being " << std::endl; - std::cout << "updated by changes in the points" << std::endl; - return EXIT_FAILURE; - } - - if (bbAfterTime < pcAfterTime) - { - std::cout << "Bounding Box Modified Time is not as recent " << std::endl; - std::cout << "as the modifiction in the points" << std::endl; - return EXIT_FAILURE; - } + // Points container modified time must increase after Modified() call + EXPECT_NE(pcAfterTime, pcBeforeTime); + EXPECT_GT(pcAfterTime, pcBeforeTime); - std::cout << "Test PASSED !" << std::endl; + // Bounding box modified time must reflect the change in points + EXPECT_NE(bbAfterTime, bbBeforeTime); + EXPECT_GT(bbAfterTime, bbBeforeTime); - return EXIT_SUCCESS; + // Bounding box modified time should be at least as recent as the points container + EXPECT_GE(bbAfterTime, pcAfterTime); } diff --git a/Modules/Core/Common/test/itkTimeStampGTest.cxx b/Modules/Core/Common/test/itkTimeStampGTest.cxx new file mode 100644 index 00000000000..30b66ed31e9 --- /dev/null +++ b/Modules/Core/Common/test/itkTimeStampGTest.cxx @@ -0,0 +1,143 @@ +/*========================================================================= + * + * 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 + * + * https://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. + * + *=========================================================================*/ + +#include "itkTimeStamp.h" +#include "itkMultiThreaderBase.h" +#include "itkGTest.h" + +#include +#include +#include + +static_assert(std::is_nothrow_default_constructible_v, "Check TimeStamp default-constructibility"); +static_assert(std::is_trivially_copy_constructible_v, "Check TimeStamp copy-constructibility"); +static_assert(std::is_trivially_copy_assignable_v, "Check TimeStamp copy-assignability"); +static_assert(std::is_trivially_destructible_v, "Check TimeStamp destructibility"); + +// A helper struct for the test, the idea is to have one timestamp per thread. +// To ease the writing of the test, we use MultiThreaderBase::SingleMethodExecute +// with an array of timestamps in the shared data. +struct TimeStampTestHelper +{ + std::vector timestamps; + std::vector counters; +}; + +ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION +modified_function(void * ptr) +{ + using WorkUnitInfoType = itk::MultiThreaderBase::WorkUnitInfo; + + auto * infoStruct = static_cast(ptr); + + const itk::ThreadIdType workUnitID = infoStruct->WorkUnitID; + + auto * helper = static_cast(infoStruct->UserData); + + helper->timestamps[workUnitID].Modified(); + helper->counters[workUnitID]++; + + return ITK_THREAD_RETURN_DEFAULT_VALUE; +} + +TEST(TimeStamp, TypeTraits) +{ + // static_asserts above verify these at compile time; this test documents them + EXPECT_TRUE(std::is_nothrow_default_constructible_v); + EXPECT_TRUE(std::is_trivially_copy_constructible_v); + EXPECT_TRUE(std::is_trivially_copy_assignable_v); + EXPECT_TRUE(std::is_trivially_destructible_v); +} + +TEST(TimeStamp, ThreadSafeMonotonicity) +{ + TimeStampTestHelper helper; + + // Set up the multithreader + const itk::MultiThreaderBase::Pointer multithreader = itk::MultiThreaderBase::New(); + multithreader->SetNumberOfWorkUnits(itk::ITK_MAX_THREADS + 10); // will be clamped + multithreader->SetSingleMethod(modified_function, &helper); + + // Test that the number of threads has actually been clamped + const itk::ThreadIdType numberOfThreads = multithreader->GetMaximumNumberOfThreads(); + EXPECT_LE(numberOfThreads, itk::ITK_MAX_THREADS); + + const itk::ThreadIdType numberOfWorkUnits = multithreader->GetNumberOfWorkUnits(); + + // Set up the helper class + helper.counters.resize(numberOfWorkUnits); + helper.timestamps.resize(numberOfWorkUnits); + for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) + { + helper.counters[k] = 0; + } + + // Declare an array to test whether all modified times have been used + const auto istimestamped = std::make_unique(numberOfWorkUnits); + + // Call Modified once on any object to make it up-to-date + multithreader->Modified(); + + const itk::ModifiedTimeType init_mtime = multithreader->GetMTime(); + std::cout << "init_mtime: " << init_mtime << std::endl; + + itk::ModifiedTimeType prev_mtime = init_mtime; + + constexpr unsigned int num_exp{ 500 }; + + for (unsigned int i = 0; i < num_exp; ++i) + { + multithreader->SingleMethodExecute(); + + itk::ModifiedTimeType min_mtime = helper.timestamps[0].GetMTime(); + itk::ModifiedTimeType max_mtime = helper.timestamps[0].GetMTime(); + for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) + { + const itk::ModifiedTimeType & mtime = helper.timestamps[k].GetMTime(); + if (mtime > max_mtime) + { + max_mtime = mtime; + } + else if (mtime < min_mtime) + { + min_mtime = mtime; + } + + // initialize the array to false + istimestamped[k] = false; + } + + // Each work unit should have gotten a unique, consecutive modified time + EXPECT_EQ(max_mtime - prev_mtime, numberOfWorkUnits) << "Iteration " << i; + EXPECT_EQ(min_mtime, prev_mtime + 1) << "Iteration " << i; + + for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) + { + // Test whether all modified times have been used exactly once + const itk::ModifiedTimeType index = helper.timestamps[k].GetMTime() - min_mtime; + + EXPECT_FALSE(istimestamped[index]) << helper.timestamps[k].GetMTime() << " was used twice as a timestamp!"; + istimestamped[index] = true; + + // Test the counters: each thread should have been called i+1 times + EXPECT_EQ(helper.counters[k], i + 1) << "counter[" << k << "] at iteration " << i; + } + + prev_mtime = max_mtime; + } +} diff --git a/Modules/Core/Common/test/itkTimeStampTest.cxx b/Modules/Core/Common/test/itkTimeStampTest.cxx deleted file mode 100644 index 1ca0f03404a..00000000000 --- a/Modules/Core/Common/test/itkTimeStampTest.cxx +++ /dev/null @@ -1,194 +0,0 @@ -/*========================================================================= - * - * 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 - * - * https://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. - * - *=========================================================================*/ - -#include "itkTimeStamp.h" -#include "itkMultiThreaderBase.h" - -#include -#include // For make_unique. -#include - -static_assert(std::is_nothrow_default_constructible_v, "Check TimeStamp default-constructibility"); -static_assert(std::is_trivially_copy_constructible_v, "Check TimeStamp copy-constructibility"); -static_assert(std::is_trivially_copy_assignable_v, "Check TimeStamp copy-assignability"); -static_assert(std::is_trivially_destructible_v, "Check TimeStamp destructibility"); - -// A helper struct for the test, the idea is to have one timestamp per thread. -// To ease the writing of the test, we use MultiThreaderBase::SingleMethodExecute -// with an array of timestamps in the shared data -struct TimeStampTestHelper -{ - std::vector timestamps; - std::vector counters; -}; - -ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION -modified_function(void * ptr) -{ - using WorkUnitInfoType = itk::MultiThreaderBase::WorkUnitInfo; - - auto * infoStruct = static_cast(ptr); - - const itk::ThreadIdType workUnitID = infoStruct->WorkUnitID; - - auto * helper = static_cast(infoStruct->UserData); - - helper->timestamps[workUnitID].Modified(); - helper->counters[workUnitID]++; - - return ITK_THREAD_RETURN_DEFAULT_VALUE; -} - -int -itkTimeStampTest(int, char *[]) -{ - bool success = true; - - try - { - TimeStampTestHelper helper; - - // Set up the multithreader - const itk::MultiThreaderBase::Pointer multithreader = itk::MultiThreaderBase::New(); - multithreader->SetNumberOfWorkUnits(itk::ITK_MAX_THREADS + 10); // this will be clamped - multithreader->SetSingleMethod(modified_function, &helper); - - // Test that the number of threads has actually been clamped - const itk::ThreadIdType numberOfThreads = multithreader->GetMaximumNumberOfThreads(); - - if (numberOfThreads > itk::ITK_MAX_THREADS) - { - std::cerr << "[TEST FAILED]" << std::endl; - std::cerr << "numberOfThreads > ITK_MAX_THREADS" << std::endl; - return EXIT_FAILURE; - } - - const itk::ThreadIdType numberOfWorkUnits = multithreader->GetNumberOfWorkUnits(); - - // Set up the helper class - helper.counters.resize(numberOfWorkUnits); - helper.timestamps.resize(numberOfWorkUnits); - for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) - { - helper.counters[k] = 0; - } - - // Declare an array to test whether the all modified times have - // been used - const auto istimestamped = std::make_unique(numberOfWorkUnits); - - // Call Modified once on any object to make it up-to-date - multithreader->Modified(); - - const itk::ModifiedTimeType init_mtime = multithreader->GetMTime(); - std::cout << "init_mtime: " << init_mtime << std::endl; - - itk::ModifiedTimeType prev_mtime = init_mtime; - - constexpr unsigned int num_exp{ 500 }; - - for (unsigned int i = 0; i < num_exp; ++i) - { - multithreader->SingleMethodExecute(); - - itk::ModifiedTimeType min_mtime = helper.timestamps[0].GetMTime(); - itk::ModifiedTimeType max_mtime = helper.timestamps[0].GetMTime(); - for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) - { - const itk::ModifiedTimeType & mtime = helper.timestamps[k].GetMTime(); - if (mtime > max_mtime) - { - max_mtime = mtime; - } - else if (mtime < min_mtime) - { - min_mtime = mtime; - } - - // initialize the array to false - istimestamped[k] = false; - } - - bool iter_success = (((max_mtime - prev_mtime) == numberOfWorkUnits) && (min_mtime == prev_mtime + 1)); - - if (iter_success) - { - for (itk::ThreadIdType k = 0; k < numberOfWorkUnits; ++k) - { - // Test whether the all modified times have - // been used - const itk::ModifiedTimeType index = helper.timestamps[k].GetMTime() - min_mtime; - - if (istimestamped[index]) - { - iter_success = false; - std::cerr << helper.timestamps[k].GetMTime() << " was used twice as a timestamp!" << std::endl; - } - else - { - istimestamped[index] = true; - } - - // Test the counters - if (helper.counters[k] != i + 1) - { - iter_success = false; - std::cerr << "counter[" << k << "] = " << helper.counters[k]; - std::cerr << " at iteration " << i << std::endl; - } - } - } - - if (!iter_success) - { - std::cerr << "[Iteration " << i << " FAILED]" << std::endl; - std::cerr << "max_mtime : " << max_mtime << std::endl; - std::cerr << "min_mtime : " << min_mtime << std::endl; - std::cerr << "prev_mtime : " << prev_mtime << std::endl; - std::cerr << "num_threads : " << numberOfThreads << std::endl; - std::cerr << "num_work_units : " << numberOfWorkUnits << std::endl; - std::cerr << "max - prev mtime: " << max_mtime - prev_mtime << std::endl; - std::cerr << std::endl; - success = false; - - // Note that in a more general setting, (max_mtime-prev_mtime)>numberOfWorkUnits - // might be a normal case since the modified time of a time stamp - // is global. If a new itk object is created this will also increment - // the time. In our specific test, there's no reason for another ITK object to be - // modified though - } - - prev_mtime = max_mtime; - } - } - catch (const itk::ExceptionObject & e) - { - std::cerr << "[TEST FAILED]" << std::endl; - std::cerr << "Exception caught: " << e << std::endl; - return EXIT_FAILURE; - } - - if (!success) - { - std::cerr << "[TEST FAILED]" << std::endl; - return EXIT_FAILURE; - } - - std::cout << "[TEST PASSED]" << std::endl; - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkVersionTest.cxx b/Modules/Core/Common/test/itkVersionGTest.cxx similarity index 74% rename from Modules/Core/Common/test/itkVersionTest.cxx rename to Modules/Core/Common/test/itkVersionGTest.cxx index 48781a2126d..1fbb1b14a2e 100644 --- a/Modules/Core/Common/test/itkVersionTest.cxx +++ b/Modules/Core/Common/test/itkVersionGTest.cxx @@ -17,34 +17,38 @@ *=========================================================================*/ #include "itkVersion.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" #include +#include - -int -itkVersionTest(int, char *[]) +TEST(Version, BasicObjectMethods) { - constexpr int testPassStatus{ EXIT_SUCCESS }; - const itk::Version::Pointer version = itk::Version::New(); + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(version, Version, Object); +} - ITK_EXERCISE_BASIC_OBJECT_METHODS(version, Version, Object); - +TEST(Version, VersionStrings) +{ const char * itkVersion = itk::Version::GetITKVersion(); std::cout << "itk version: " << itkVersion << std::endl; + EXPECT_NE(itkVersion, nullptr); + EXPECT_FALSE(std::string_view(itkVersion).empty()); const int itkMajorVersion = itk::Version::GetITKMajorVersion(); std::cout << "itk Major version: " << itkMajorVersion << std::endl; + EXPECT_EQ(itkMajorVersion, ITK_VERSION_MAJOR); const int itkMinorVersion = itk::Version::GetITKMinorVersion(); std::cout << "itk Minor version: " << itkMinorVersion << std::endl; + EXPECT_EQ(itkMinorVersion, ITK_VERSION_MINOR); const int itkBuildVersion = itk::Version::GetITKBuildVersion(); std::cout << "itk Build version: " << itkBuildVersion << std::endl; + EXPECT_EQ(itkBuildVersion, ITK_VERSION_PATCH); const char * itkSourceVersion = itk::Version::GetITKSourceVersion(); std::cout << "itk Source version: " << itkSourceVersion << std::endl; - - return testPassStatus; + EXPECT_NE(itkSourceVersion, nullptr); + EXPECT_FALSE(std::string_view(itkSourceVersion).empty()); }