diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index 7702883a24b..f21be887ae4 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -2,18 +2,8 @@ itk_module_test() set( ITKCommon1Tests itkImageRegionExplicitTest.cxx - itkAbortProcessObjectTest.cxx - itkCommandObserverObjectTest.cxx - itkAdaptorComparisonTest.cxx - itkCovariantVectorGeometryTest.cxx - itkDataTypeTest.cxx - itkDecoratorTest.cxx itkExtractImage3Dto2DTest.cxx itkExtractImageTest.cxx - itkFilterDispatchTest.cxx - itkFloodFilledSpatialFunctionTest.cxx - itkFloodFillIteratorTest.cxx - itkGaussianDerivativeOperatorTest.cxx itkMapContainerTest.cxx itkVectorContainerTest.cxx itkIteratorTests.cxx @@ -24,22 +14,16 @@ set( itkImageIteratorsForwardBackwardTest.cxx itkImageLinearIteratorTest.cxx itkImageAdaptorPipeLineTest.cxx - itkImportContainerTest.cxx - itkImportImageTest.cxx itkImageRandomIteratorTest.cxx itkImageRandomIteratorTest2.cxx itkImageSliceIteratorTest.cxx itkRGBPixelTest.cxx itkLightObjectTest.cxx - itkBoundingBoxTest.cxx - itkBoundaryConditionTest.cxx - itkByteSwapTest.cxx itkSparseImageTest.cxx itkSimpleFilterWatcherTest.cxx itkSymmetricEllipsoidInteriorExteriorSpatialFunctionTest.cxx itkSymmetricSecondRankTensorImageReadTest.cxx itkSymmetricSecondRankTensorImageWriteReadTest.cxx - itkArray2DTest.cxx itkFloatingPointExceptionsTest.cxx itkFixedArrayTest2.cxx itkNeighborhoodAlgorithmTest.cxx @@ -51,71 +35,46 @@ set( itkStreamingImageFilterTest2.cxx itkStreamingImageFilterTest3.cxx itkLoggerTest.cxx - itkDerivativeOperatorTest.cxx itkColorTableTest.cxx itkNumericTraitsTest.cxx itkImageRegionTest.cxx itkExceptionObjectTest.cxx itkNeighborhoodOperatorTest.cxx itkNumericsTest.cxx - itkAnnulusOperatorTest.cxx itkLineIteratorTest.cxx itkGaussianSpatialFunctionTest.cxx itkRealTimeClockTest.cxx itkRealTimeIntervalTest.cxx itkRealTimeStampTest.cxx - itkTimeStampTest.cxx - itkIntTypesTest.cxx - itkBSplineKernelFunctionTest.cxx - itkArrayTest.cxx itkImageIteratorTest.cxx itkImageRegionIteratorTest.cxx itkImageScanlineIteratorTest1.cxx - itkCrossHelperTest.cxx itkImageIteratorWithIndexTest.cxx itkDirectoryTest.cxx itkObjectStoreTest.cxx itkObjectFactoryTest.cxx - itkEventObjectTest.cxx - itkMathCastWithRangeCheckTest.cxx - itkMathRoundProfileTest1.cxx - itkMathRoundTest.cxx - itkMathRoundTest2.cxx - itkModifiedTimeTest.cxx itkMultipleLogOutputTest.cxx itkVectorTest.cxx itkImageTest.cxx itkPointSetTest.cxx itkPointSetToImageFilterTest1.cxx itkPointSetToImageFilterTest2.cxx - itkBresenhamLineTest.cxx itkSparseFieldLayerTest.cxx itkDataObjectTest.cxx - itkAtanRegularizedHeavisideStepFunctionTest1.cxx - itkHashTableTest.cxx - itkHeavisideStepFunctionTest1.cxx - itkSinRegularizedHeavisideStepFunctionTest1.cxx - itkPixelAccessTest.cxx itkPointGeometryTest.cxx - itkMersenneTwisterRandomVariateGeneratorTest.cxx itkNumberToStringTest.cxx itkTimeProbeTest.cxx itkTimeProbeTest2.cxx itkSpatialOrientationTest.cxx - itkStdStreamStateSaveTest.cxx - itkVersionTest.cxx - VNLSparseLUSolverTraitsTest.cxx itkSobelOperatorImageConvolutionTest.cxx itkSobelOperatorImageFilterTest.cxx ) set( ITKCommon2Tests itkSTLThreadTest.cxx - itkThreadedIndexedContainerPartitionerTest.cxx itkThreadedIteratorRangePartitionerTest.cxx itkThreadedIteratorRangePartitionerTest2.cxx itkThreadedIteratorRangePartitionerTest3.cxx - itkThreadedImageRegionPartitionerTest.cxx itkThreadLoggerTest.cxx itkLoggerThreadWrapperTest.cxx itkThreadDefsTest.cxx @@ -143,7 +102,6 @@ set( itkConstNeighborhoodIteratorTest.cxx itkShapedNeighborhoodIteratorTest.cxx itkMatrixTest.cxx - itkAutoPointerTest.cxx itkNeighborhoodIteratorTest.cxx itkLoggerManagerTest.cxx itkBSplineInterpolationWeightFunctionTest.cxx @@ -161,8 +119,6 @@ set( itkMinimumMaximumImageCalculatorTest.cxx itkSliceIteratorTest.cxx itkImageRegionExclusionIteratorWithIndexTest.cxx - itkFixedArrayTest.cxx - itkImageTransformTest.cxx itkImageFillBufferTest.cxx itkMemoryLeakTest.cxx itkVectorGeometryTest.cxx @@ -225,13 +181,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) @@ -248,30 +197,6 @@ if(ITK_BUILD_SHARED_LIBS) add_dependencies(ITKCommon2TestDriver FactoryTestLib) endif() -itk_add_test( - NAME itkAbortProcessObjectTest - COMMAND - ITKCommon1TestDriver - itkAbortProcessObjectTest -) -itk_add_test( - NAME itkCommandObserverObjectTest - COMMAND - ITKCommon1TestDriver - itkCommandObserverObjectTest -) -itk_add_test( - NAME itkAdaptorComparisonTest - COMMAND - ITKCommon1TestDriver - itkAdaptorComparisonTest -) -itk_add_test( - NAME itkThreadedIndexedContainerPartitionerTest - COMMAND - ITKCommon2TestDriver - itkThreadedIndexedContainerPartitionerTest -) itk_add_test( NAME itkThreadedIteratorRangePartitionerTest COMMAND @@ -297,42 +222,6 @@ itk_add_test( ITKCommon1TestDriver itkImageAdaptorPipeLineTest ) -itk_add_test( - NAME itkThreadedImageRegionPartitionerTest - COMMAND - ITKCommon2TestDriver - itkThreadedImageRegionPartitionerTest -) -itk_add_test( - NAME itkImportContainerTest - COMMAND - ITKCommon1TestDriver - itkImportContainerTest -) -itk_add_test( - NAME itkImportImageTest - COMMAND - ITKCommon1TestDriver - itkImportImageTest -) -itk_add_test( - NAME itkCovariantVectorGeometryTest - COMMAND - ITKCommon1TestDriver - itkCovariantVectorGeometryTest -) -itk_add_test( - NAME itkDataTypeTest - COMMAND - ITKCommon1TestDriver - itkDataTypeTest -) -itk_add_test( - NAME itkDecoratorTest - COMMAND - ITKCommon1TestDriver - itkDecoratorTest -) itk_add_test( NAME itkExtractImage3Dto2DTest COMMAND @@ -345,31 +234,6 @@ itk_add_test( ITKCommon1TestDriver itkExtractImageTest ) -itk_add_test( - NAME itkFilterDispatchTest - COMMAND - ITKCommon1TestDriver - itkFilterDispatchTest -) -itk_add_test( - NAME itkFloodFilledSpatialFunctionTest - COMMAND - ITKCommon1TestDriver - itkFloodFilledSpatialFunctionTest -) -itk_add_test( - NAME itkFloodFillIteratorTest - COMMAND - ITKCommon1TestDriver - itkFloodFillIteratorTest -) -itk_add_test( - NAME itkAnnulusOperatorTest - COMMAND - ITKCommon1TestDriver - itkAnnulusOperatorTest -) - itk_add_test( NAME itkColorTableTest1 COMMAND @@ -408,12 +272,6 @@ itk_add_test( itkDirectoryTest ${TEMP} ) -itk_add_test( - NAME itkDerivativeOperatorTest - COMMAND - ITKCommon1TestDriver - itkDerivativeOperatorTest -) itk_add_test( NAME itkMultipleLogOutputTest COMMAND @@ -421,18 +279,6 @@ itk_add_test( itkMultipleLogOutputTest ${TEMP}/test_multi.txt ) -itk_add_test( - NAME itkFixedArrayTest - COMMAND - ITKCommon2TestDriver - itkFixedArrayTest -) -itk_add_test( - NAME itkImageTransformTest - COMMAND - ITKCommon2TestDriver - itkImageTransformTest -) itk_add_test( NAME itkMinimumMaximumImageCalculatorTest COMMAND @@ -445,84 +291,18 @@ itk_add_test( ITKCommon1TestDriver itkFixedArrayTest2 ) -itk_add_test( - NAME itkArrayTest - COMMAND - ITKCommon1TestDriver - itkArrayTest -) -itk_add_test( - NAME itkMersenneTwisterRandomVariateGeneratorTest - COMMAND - ITKCommon1TestDriver - itkMersenneTwisterRandomVariateGeneratorTest -) -itk_add_test( - NAME itkArray2DTest - COMMAND - ITKCommon1TestDriver - itkArray2DTest -) -itk_add_test( - NAME itkAutoPointerTest - COMMAND - 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 ITKCommon2TestDriver itkBSplineInterpolationWeightFunctionTest ) -itk_add_test( - NAME itkBSplineKernelFunctionTest - COMMAND - ITKCommon1TestDriver - itkBSplineKernelFunctionTest -) itk_add_test( NAME itkSpatialOrientationTest COMMAND ITKCommon1TestDriver itkSpatialOrientationTest ) -itk_add_test( - NAME VNLSparseLUSolverTraitsTest - COMMAND - ITKCommon1TestDriver - VNLSparseLUSolverTraitsTest -) -itk_add_test( - NAME itkGaussianDerivativeOperatorTest - COMMAND - ITKCommon1TestDriver - itkGaussianDerivativeOperatorTest -) itk_add_test( NAME itkSobelOperatorImageConvolutionHorizTest COMMAND @@ -629,42 +409,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 @@ -699,12 +443,6 @@ itk_add_test( 19.0 1 ) -itk_add_test( - NAME itkCrossHelperTest - COMMAND - ITKCommon1TestDriver - itkCrossHelperTest -) itk_add_test( NAME itkImageIteratorTest COMMAND @@ -905,12 +643,6 @@ itk_add_test( DATA{${ITK_DATA_ROOT}/Input/VascularTreePointSet.txt} ${ITK_TEST_OUTPUT_DIR}/itkPointSetToImageFilterTest2.mha ) -itk_add_test( - NAME itkBresenhamLineTest - COMMAND - ITKCommon1TestDriver - itkBresenhamLineTest -) itk_add_test( NAME itkSparseFieldLayerTest COMMAND @@ -923,48 +655,12 @@ itk_add_test( ITKCommon1TestDriver itkDataObjectTest ) -itk_add_test( - NAME itkAtanRegularizedHeavisideStepFunctionTest1 - COMMAND - ITKCommon1TestDriver - itkAtanRegularizedHeavisideStepFunctionTest1 -) -itk_add_test( - NAME itkHashTableTest - COMMAND - ITKCommon1TestDriver - itkHashTableTest -) -itk_add_test( - NAME itkHeavisideStepFunctionTest1 - COMMAND - ITKCommon1TestDriver - itkHeavisideStepFunctionTest1 -) -itk_add_test( - NAME itkSinRegularizedHeavisideStepFunctionTest1 - COMMAND - ITKCommon1TestDriver - itkSinRegularizedHeavisideStepFunctionTest1 -) -itk_add_test( - NAME itkPixelAccessTest - COMMAND - ITKCommon1TestDriver - itkPixelAccessTest -) itk_add_test( NAME itkPointGeometryTest COMMAND ITKCommon1TestDriver itkPointGeometryTest ) -itk_add_test( - NAME itkStdStreamStateSaveTest - COMMAND - ITKCommon1TestDriver - itkStdStreamStateSaveTest -) # # This test should be enabled if you suspect that the memory leak detector @@ -1245,12 +941,6 @@ itk_add_test( --full-output itkNumericTraitsTest ) -itk_add_test( - NAME itkIntTypesTest - COMMAND - ITKCommon1TestDriver - itkIntTypesTest -) itk_add_test( NAME itkOctreeTest COMMAND @@ -1844,7 +1534,15 @@ set( itkCovariantVectorGTest.cxx itkDerefGTest.cxx itkDiffusionTensor3DGTest.cxx + itkAnnulusOperatorGTest.cxx + itkCommandObserverObjectGTest.cxx + itkCovariantVectorGeometryGTest.cxx + itkCrossHelperGTest.cxx + itkGaussianDerivativeOperatorGTest.cxx + itkDecoratorGTest.cxx + itkDerivativeOperatorGTest.cxx itkExceptionObjectGTest.cxx + itkImportContainerGTest.cxx itkFixedArrayGTest.cxx itkImageNeighborhoodOffsetsGTest.cxx itkImageGTest.cxx @@ -1884,9 +1582,37 @@ 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 + itkAbortProcessObjectGTest.cxx + itkAutoPointerGTest.cxx + itkBresenhamLineGTest.cxx + itkHeavisideStepFunctionGTest.cxx + itkHashTableGTest.cxx + itkPixelAccessGTest.cxx + itkStdStreamStateSaveGTest.cxx itkMetaDataDictionaryGTest.cxx itkSpatialOrientationAdaptorGTest.cxx itkAnatomicalOrientationGTest.cxx + itkBSplineKernelFunctionGTest.cxx + VNLSparseLUSolverTraitsGTest.cxx + itkAdaptorComparisonGTest.cxx + itkFilterDispatchGTest.cxx + itkFloodFillIteratorGTest.cxx + itkFloodFilledSpatialFunctionGTest.cxx + itkThreadedImageRegionPartitionerGTest.cxx + itkThreadedIndexedContainerPartitionerGTest.cxx + itkImageTransformGTest.cxx + itkImportImageGTest.cxx ) creategoogletestdriver(ITKCommon "${ITKCommon-Test_LIBRARIES}" "${ITKCommonGTests}") # If `-static` was passed to CMAKE_EXE_LINKER_FLAGS, compilation fails. No need to diff --git a/Modules/Core/Common/test/VNLSparseLUSolverTraitsTest.cxx b/Modules/Core/Common/test/VNLSparseLUSolverTraitsGTest.cxx similarity index 80% rename from Modules/Core/Common/test/VNLSparseLUSolverTraitsTest.cxx rename to Modules/Core/Common/test/VNLSparseLUSolverTraitsGTest.cxx index 992579d7900..bb3c68acb5d 100644 --- a/Modules/Core/Common/test/VNLSparseLUSolverTraitsTest.cxx +++ b/Modules/Core/Common/test/VNLSparseLUSolverTraitsGTest.cxx @@ -18,9 +18,9 @@ #include "VNLSparseLUSolverTraits.h" #include "itkMath.h" // itk::Math::Absolute +#include "itkGTest.h" #include -#include template bool @@ -44,8 +44,7 @@ VectorsEquals(const TVector & v1, const TVector & v2, const typename TVector::el return true; } -int -VNLSparseLUSolverTraitsTest(int, char *[]) +TEST(VNLSparseLUSolverTraits, SolveLinearSystem) { /** * Define an sparse LU solver traits type that operates over sparse matrices and @@ -109,10 +108,7 @@ VNLSparseLUSolverTraitsTest(int, char *[]) { VectorType X = SolverTraits::InitializeVector(N); SolverTraits::Solve(A, Bx, X); - if (!VectorsEquals(X, Xexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); } /** @@ -123,10 +119,8 @@ VNLSparseLUSolverTraitsTest(int, char *[]) VectorType Y = SolverTraits::InitializeVector(N); SolverTraits::Solve(A, Bx, X); SolverTraits::Solve(A, By, Y); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); } /** @@ -139,11 +133,9 @@ VNLSparseLUSolverTraitsTest(int, char *[]) SolverTraits::Solve(A, Bx, X); SolverTraits::Solve(A, By, Y); SolverTraits::Solve(A, Bz, Z); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance) || - !VectorsEquals(Z, Zexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Z, Zexpected, tolerance)); } /** @@ -155,17 +147,11 @@ VNLSparseLUSolverTraitsTest(int, char *[]) // First back-substitution SolverTraits::Solve(solver, Bx, X); - if (!VectorsEquals(X, Xexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); // Second back-substitution (reusing the already factored matrix) SolverTraits::Solve(solver, Bx, X); - if (!VectorsEquals(X, Xexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); } /** @@ -179,18 +165,14 @@ VNLSparseLUSolverTraitsTest(int, char *[]) // First back-substitution SolverTraits::Solve(solver, Bx, X); SolverTraits::Solve(solver, By, Y); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); // Second back-substitution (reusing the already factored matrix) SolverTraits::Solve(solver, Bx, X); SolverTraits::Solve(solver, By, Y); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); } /** @@ -207,22 +189,16 @@ VNLSparseLUSolverTraitsTest(int, char *[]) SolverTraits::Solve(solver, Bx, X); SolverTraits::Solve(solver, By, Y); SolverTraits::Solve(solver, Bz, Z); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance) || - !VectorsEquals(Z, Zexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Z, Zexpected, tolerance)); // Second back-substitution (reusing the already factored matrix) SolverTraits::Solve(solver, Bx, X); SolverTraits::Solve(solver, By, Y); SolverTraits::Solve(solver, Bz, Z); - if (!VectorsEquals(X, Xexpected, tolerance) || !VectorsEquals(Y, Yexpected, tolerance) || - !VectorsEquals(Z, Zexpected, tolerance)) - { - return EXIT_FAILURE; - } + EXPECT_TRUE(VectorsEquals(X, Xexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Y, Yexpected, tolerance)); + EXPECT_TRUE(VectorsEquals(Z, Zexpected, tolerance)); } - - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkAbortProcessObjectGTest.cxx b/Modules/Core/Common/test/itkAbortProcessObjectGTest.cxx new file mode 100644 index 00000000000..794f3cea7a7 --- /dev/null +++ b/Modules/Core/Common/test/itkAbortProcessObjectGTest.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + * + * 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 "itkExtractImageFilter.h" +#include "itkGTest.h" +#include "itkCommand.h" + +#include + +// +// This test ensures the abort event occurs and the ProcessAborted +// exception occurs. +// + +namespace +{ + +bool onAbortCalled = false; + +void +onProgress(itk::Object * obj, const itk::EventObject &, void *) +{ + const itk::ProcessObject::Pointer p(dynamic_cast(obj)); + if (p.IsNull()) + { + return; + } + if (p->GetProgress() > .1) + { + std::cout << "Setting AbortGenerateDataOn()" << std::endl; + p->AbortGenerateDataOn(); + } +} + +void +onAbort(itk::Object *, const itk::EventObject &, void *) +{ + std::cout << "Abort Event" << std::endl; + onAbortCalled = true; +} + +} // namespace + +TEST(AbortProcessObject, AbortEventAndException) +{ + onAbortCalled = false; + + // type alias to simplify the syntax + using ShortImage = itk::Image; + auto img = ShortImage::New(); + + // fill in an image + constexpr ShortImage::SizeType size{ 100, 100 }; + const ShortImage::RegionType region{ size }; + img->SetRegions(region); + img->Allocate(); + + itk::ImageRegionIterator iterator(img, region); + + short i = 0; + while (!iterator.IsAtEnd()) + { + iterator.Set(i++); + ++iterator; + } + + // Create a filter + const itk::ExtractImageFilter::Pointer extract = + itk::ExtractImageFilter::New(); + extract->SetInput(img); + + // fill in an image + constexpr ShortImage::SizeType extractSize{ 99, 99 }; + const ShortImage::RegionType extractRegion{ extractSize }; + extract->SetExtractionRegion(extractRegion); + + const itk::CStyleCommand::Pointer progressCmd = itk::CStyleCommand::New(); + progressCmd->SetCallback(onProgress); + progressCmd->SetObjectName("Progress Event"); + extract->AddObserver(itk::ProgressEvent(), progressCmd); + + const itk::CStyleCommand::Pointer abortCmd = itk::CStyleCommand::New(); + abortCmd->SetCallback(onAbort); + abortCmd->SetObjectName("Abort Event"); + extract->AddObserver(itk::AbortEvent(), abortCmd); + + std::cout << extract << std::endl; + + bool exceptionCaught = false; + try + { + extract->UpdateLargestPossibleRegion(); + } + catch (const itk::ProcessAborted &) + { + exceptionCaught = true; + } + EXPECT_TRUE(exceptionCaught) << "Expected ProcessAborted exception to be thrown."; + EXPECT_TRUE(onAbortCalled) << "Expected Abort Event callback to be called."; +} diff --git a/Modules/Core/Common/test/itkAdaptorComparisonTest.cxx b/Modules/Core/Common/test/itkAdaptorComparisonGTest.cxx similarity index 57% rename from Modules/Core/Common/test/itkAdaptorComparisonTest.cxx rename to Modules/Core/Common/test/itkAdaptorComparisonGTest.cxx index dd25edc1d19..7b69a33884d 100644 --- a/Modules/Core/Common/test/itkAdaptorComparisonTest.cxx +++ b/Modules/Core/Common/test/itkAdaptorComparisonGTest.cxx @@ -16,16 +16,19 @@ * *=========================================================================*/ -#include -#include #include "itkImageRegionIteratorWithIndex.h" #include "itkImageRegionIterator.h" +#include "itkGTest.h" + +#include + +namespace +{ void AdaptorSupportedIteratorSpeed(itk::Image * img) { itk::ImageRegionIteratorWithIndex> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { ++it; @@ -36,7 +39,6 @@ void NoAdaptorSupportIteratorSpeed(itk::Image * img) { itk::ImageRegionIterator> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { ++it; @@ -47,10 +49,8 @@ void AdaptorSupportedModifyScalars(itk::Image * img) { itk::ImageRegionIteratorWithIndex> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { - // *it += 3.435f; it.Set(it.Get() + 3.435f); ++it; } @@ -60,10 +60,8 @@ void NoAdaptorSupportModifyScalars(itk::Image * img) { itk::ImageRegionIterator> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { - // *it += 3.435f; it.Set(it.Get() + 3.435f); ++it; } @@ -73,7 +71,6 @@ void BypassAdaptorSupportModifyScalars(itk::Image * img) { itk::ImageRegionIteratorWithIndex> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { it.Value() += 3.435f; @@ -88,7 +85,6 @@ AdaptorSupportedModifyVectors(itk::Image, 3> * img) using VectorType = itk::Vector; itk::ImageRegionIteratorWithIndex> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { VectorType temp_vector = it.Get(); @@ -96,7 +92,6 @@ AdaptorSupportedModifyVectors(itk::Image, 3> * img) { temp_vector[i] += 3.435f; } - it.Set(temp_vector); ++it; } @@ -109,16 +104,13 @@ NoAdaptorSupportModifyVectors(itk::Image, 3> * img) using VectorType = itk::Vector; itk::ImageRegionIterator> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { VectorType temp_vector = it.Get(); - for (unsigned int i = 0; i < N; ++i) { temp_vector[i] += 3.435f; } - it.Set(temp_vector); ++it; } @@ -131,19 +123,16 @@ BypassAdaptorSupportModifyVectors(itk::Image, 3> * img) using VectorType = itk::Vector; itk::ImageRegionIteratorWithIndex> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { for (unsigned int i = 0; i < N; ++i) { (it.Value())[i] += 3.435f; } - ++it; } } - void BypassNoAdaptorSupportModifyVectors(itk::Image, 3> * img) { @@ -151,7 +140,6 @@ BypassNoAdaptorSupportModifyVectors(itk::Image, 3> * img) using VectorType = itk::Vector; itk::ImageRegionIterator> it(img, img->GetRequestedRegion()); - while (!it.IsAtEnd()) { for (unsigned int i = 0; i < N; ++i) @@ -162,15 +150,15 @@ BypassNoAdaptorSupportModifyVectors(itk::Image, 3> * img) } } +} // namespace -int -itkAdaptorComparisonTest(int, char *[]) + +TEST(AdaptorComparison, IteratorOperationsComplete) { using ScalarImageType = itk::Image; using VectorImageType = itk::Image, 3>; - // Set up some images - constexpr itk::Size<3> size{ 100, 100, 100 }; + constexpr itk::Size<3> size{ { 100, 100, 100 } }; itk::ImageRegion<3> region{ size }; auto scalar_image = ScalarImageType::New(); @@ -182,80 +170,33 @@ itkAdaptorComparisonTest(int, char *[]) vector_image->SetRegions(region); vector_image->Allocate(); - auto initialVectorValue = itk::MakeFilled(1.2345); // arbitrary value; + auto initialVectorValue = itk::MakeFilled(1.2345f); vector_image->FillBuffer(initialVectorValue); - // Time trials - - std::cout << "Speed of adaptor supporting iterator (for reference) \t"; - - const clock_t adaptor_comp = [&]() -> auto { - const auto start = clock(); - AdaptorSupportedIteratorSpeed(scalar_image); - const auto stop = clock(); - return stop - start; - }(); - - std::cout << adaptor_comp << std::endl; - const clock_t no_adaptor_comp = [=](auto scalarImage) { - std::cout << "Speed of iterator that does not support adaptors (for reference) \t"; - const auto start = clock(); - NoAdaptorSupportIteratorSpeed(scalarImage); - const auto stop = clock(); - return stop - start; - }(scalar_image); - std::cout << no_adaptor_comp << std::endl; - { - std::cout << "Modifying scalar image using adaptor iterator...\t"; - const auto start = clock(); - AdaptorSupportedModifyScalars(scalar_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - adaptor_comp << std::endl; - } - { - std::cout << "Modifying scalar image using non-adaptor iterator...\t"; - const auto start = clock(); - NoAdaptorSupportModifyScalars(scalar_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - no_adaptor_comp << std::endl; - } - { - std::cout << "Modifying vector image using adaptor iterator...\t"; - const auto start = clock(); - AdaptorSupportedModifyVectors(vector_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - adaptor_comp << std::endl; - } - { - std::cout << "Modifying vector image using non-adaptor iterator...\t"; - const auto start = clock(); - NoAdaptorSupportModifyVectors(vector_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - no_adaptor_comp << std::endl; - } - { - std::cout << "Modifying scalar image bypassing adaptor api using" - << " adaptor iterator...\t"; - const auto start = clock(); - BypassAdaptorSupportModifyScalars(scalar_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - adaptor_comp << std::endl; - } - { - std::cout << "Modifying vector image bypassing adaptor api using" - << " non-adaptor iterator...\t"; - const auto start = clock(); - BypassNoAdaptorSupportModifyVectors(vector_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - adaptor_comp << std::endl; - } - { - std::cout << "Modifying vector image bypassing adaptor api using" - << " adaptor iterator...\t"; - const auto start = clock(); - BypassAdaptorSupportModifyVectors(vector_image); - const auto stop = clock(); - std::cout << (stop - start) << "\t compensated = " << (stop - start) - adaptor_comp << std::endl; - } - return EXIT_SUCCESS; + std::cout << "Speed of adaptor supporting iterator: "; + EXPECT_NO_THROW(AdaptorSupportedIteratorSpeed(scalar_image)); + + std::cout << "Speed of non-adaptor iterator: "; + EXPECT_NO_THROW(NoAdaptorSupportIteratorSpeed(scalar_image)); + + std::cout << "Modifying scalar image using adaptor iterator: "; + EXPECT_NO_THROW(AdaptorSupportedModifyScalars(scalar_image)); + + std::cout << "Modifying scalar image using non-adaptor iterator: "; + EXPECT_NO_THROW(NoAdaptorSupportModifyScalars(scalar_image)); + + std::cout << "Modifying vector image using adaptor iterator: "; + EXPECT_NO_THROW(AdaptorSupportedModifyVectors(vector_image)); + + std::cout << "Modifying vector image using non-adaptor iterator: "; + EXPECT_NO_THROW(NoAdaptorSupportModifyVectors(vector_image)); + + std::cout << "Modifying scalar image bypassing adaptor via adaptor iterator: "; + EXPECT_NO_THROW(BypassAdaptorSupportModifyScalars(scalar_image)); + + std::cout << "Modifying vector image bypassing adaptor via non-adaptor iterator: "; + EXPECT_NO_THROW(BypassNoAdaptorSupportModifyVectors(vector_image)); + + std::cout << "Modifying vector image bypassing adaptor via adaptor iterator: "; + EXPECT_NO_THROW(BypassAdaptorSupportModifyVectors(vector_image)); } diff --git a/Modules/Core/Common/test/itkAnnulusOperatorTest.cxx b/Modules/Core/Common/test/itkAnnulusOperatorGTest.cxx similarity index 85% rename from Modules/Core/Common/test/itkAnnulusOperatorTest.cxx rename to Modules/Core/Common/test/itkAnnulusOperatorGTest.cxx index 6ffcf85c164..96fb519601f 100644 --- a/Modules/Core/Common/test/itkAnnulusOperatorTest.cxx +++ b/Modules/Core/Common/test/itkAnnulusOperatorGTest.cxx @@ -18,10 +18,9 @@ #include "itkAnnulusOperator.h" #include "itkStdStreamStateSave.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" -int -itkAnnulusOperatorTest(int, char *[]) +TEST(AnnulusOperator, CreateAndInspect) { // Save the format stream variables for std::cout // They will be restored when coutState goes out of scope @@ -32,9 +31,10 @@ itkAnnulusOperatorTest(int, char *[]) using PixelType = float; using OperatorType = itk::AnnulusOperator; - OperatorType normalizedAnnulus; + OperatorType normalizedAnnulus; + OperatorType * normalizedAnnulusPtr = &normalizedAnnulus; - ITK_EXERCISE_BASIC_OBJECT_METHODS((&normalizedAnnulus), AnnulusOperator, NeighborhoodOperator); + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(normalizedAnnulusPtr, AnnulusOperator, NeighborhoodOperator); normalizedAnnulus.NormalizeOn(); @@ -42,27 +42,10 @@ itkAnnulusOperatorTest(int, char *[]) normalizedAnnulus.SetThickness(2); constexpr bool brightCenter{ false }; - ITK_TEST_SET_GET_BOOLEAN((&normalizedAnnulus), BrightCenter, brightCenter); + normalizedAnnulus.SetBrightCenter(brightCenter); + EXPECT_EQ(normalizedAnnulus.GetBrightCenter(), brightCenter); - try - { - normalizedAnnulus.CreateOperator(); - } - catch (const itk::ExceptionObject & e) - { - std::cout << e; - return EXIT_FAILURE; - } - catch (const std::exception & e) - { - std::cout << "Std exception" << e.what(); - return EXIT_FAILURE; - } - catch (...) - { - std::cout << "Unknown exception" << std::endl; - return EXIT_FAILURE; - } + EXPECT_NO_THROW(normalizedAnnulus.CreateOperator()); OperatorType::SizeType normalizedAnnulusSize; normalizedAnnulusSize = normalizedAnnulus.GetSize(); @@ -108,27 +91,28 @@ itkAnnulusOperatorTest(int, char *[]) OperatorType annulus; constexpr bool normalize{ false }; - ITK_TEST_SET_GET_BOOLEAN((&annulus), Normalize, normalize); + annulus.SetNormalize(normalize); + EXPECT_EQ(annulus.GetNormalize(), normalize); constexpr double innerRadius{ 2 }; annulus.SetInnerRadius(innerRadius); - ITK_TEST_SET_GET_VALUE(innerRadius, annulus.GetInnerRadius()); + EXPECT_EQ(annulus.GetInnerRadius(), innerRadius); constexpr double thickness{ 1 }; annulus.SetThickness(thickness); - ITK_TEST_SET_GET_VALUE(thickness, annulus.GetThickness()); + EXPECT_EQ(annulus.GetThickness(), thickness); constexpr OperatorType::PixelType exteriorValue{ 1 }; annulus.SetExteriorValue(exteriorValue); - ITK_TEST_SET_GET_VALUE(exteriorValue, annulus.GetExteriorValue()); + EXPECT_EQ(annulus.GetExteriorValue(), exteriorValue); constexpr OperatorType::PixelType annulusValue{ 8 }; annulus.SetAnnulusValue(annulusValue); - ITK_TEST_SET_GET_VALUE(annulusValue, annulus.GetAnnulusValue()); + EXPECT_EQ(annulus.GetAnnulusValue(), annulusValue); constexpr OperatorType::PixelType interiorValue{ 4 }; annulus.SetInteriorValue(interiorValue); - ITK_TEST_SET_GET_VALUE(interiorValue, annulus.GetInteriorValue()); + EXPECT_EQ(annulus.GetInteriorValue(), interiorValue); annulus.CreateOperator(); @@ -204,7 +188,7 @@ itkAnnulusOperatorTest(int, char *[]) spacing[1] = 0.25; annulus.SetSpacing(spacing); - ITK_TEST_SET_GET_VALUE(spacing, annulus.GetSpacing()); + EXPECT_EQ(annulus.GetSpacing(), spacing); annulus.SetInnerRadius(2); annulus.SetThickness(1); @@ -229,5 +213,4 @@ itkAnnulusOperatorTest(int, char *[]) std::cout << "Test finished." << std::endl; - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkArray2DGTest.cxx b/Modules/Core/Common/test/itkArray2DGTest.cxx index f65af118d06..b3272e37bc2 100644 --- a/Modules/Core/Common/test/itkArray2DGTest.cxx +++ b/Modules/Core/Common/test/itkArray2DGTest.cxx @@ -21,6 +21,7 @@ #include #include #include // For is_nothrow_move_constructible_v and is_nothrow_move_assignable_v. +#include static_assert(std::is_nothrow_move_constructible_v> && @@ -110,3 +111,69 @@ TEST(Array2D, MoveAssign) checkMoveAssign(itk::Array2D(1U, 1U)); checkMoveAssign(itk::Array2D(1U, 2U)); } + + +TEST(Array2D, CopyAndAssignment) +{ + using ArrayType = itk::Array2D; + using VnlMatrixType = vnl_matrix; + + constexpr unsigned int rows{ 3 }; + constexpr unsigned int cols{ 4 }; + constexpr double tolerance{ 1e-6 }; + + ArrayType a(rows, cols); + VnlMatrixType vm(rows, cols); + + for (unsigned int r = 0; r < rows; ++r) + { + for (unsigned int c = 0; c < cols; ++c) + { + const auto value = static_cast(r + c); + a.SetElement(r, c, value); + vm(r, c) = value; + } + } + + // Test copy constructor + ArrayType b(a); + for (unsigned int r = 0; r < rows; ++r) + { + for (unsigned int c = 0; c < cols; ++c) + { + EXPECT_NEAR(b(r, c), a.GetElement(r, c), tolerance); + } + } + + // Test construction from vnl_matrix + ArrayType d(vm); + for (unsigned int r = 0; r < rows; ++r) + { + for (unsigned int c = 0; c < cols; ++c) + { + EXPECT_NEAR(d(r, c), vm(r, c), tolerance); + } + } + + // Test assignment from Array2D + ArrayType e = a; + for (unsigned int r = 0; r < rows; ++r) + { + for (unsigned int c = 0; c < cols; ++c) + { + EXPECT_NEAR(e(r, c), a(r, c), tolerance); + } + } + + // Test assignment from vnl_matrix + ArrayType f = vm; + for (unsigned int r = 0; r < rows; ++r) + { + for (unsigned int c = 0; c < cols; ++c) + { + EXPECT_NEAR(f(r, c), vm(r, c), tolerance); + } + } + + std::cout << "Test Passed!" << std::endl; +} diff --git a/Modules/Core/Common/test/itkArray2DTest.cxx b/Modules/Core/Common/test/itkArray2DTest.cxx deleted file mode 100644 index fee32df50b7..00000000000 --- a/Modules/Core/Common/test/itkArray2DTest.cxx +++ /dev/null @@ -1,121 +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 "itkArray2D.h" - - -int -itkArray2DTest(int, char *[]) -{ - using ArrayType = itk::Array2D; - - using VnlMatrixType = vnl_matrix; - - constexpr unsigned int rows{ 3 }; - constexpr unsigned int cols{ 4 }; - - ArrayType a(rows, cols); - VnlMatrixType vm(rows, cols); - - for (unsigned int r = 0; r < rows; ++r) - { - for (unsigned int c = 0; c < cols; ++c) - { - const auto value = static_cast(r + c); - a.SetElement(r, c, value); - vm(r, c) = value; - } - } - - constexpr double tolerance{ 1e-6 }; - - // test copy constructor - ArrayType b(a); - - for (unsigned int r = 0; r < rows; ++r) - { - for (unsigned int c = 0; c < cols; ++c) - { - double diff = a.GetElement(r, c) - b(r, c); - diff = (diff > 0.0) ? diff : -diff; // take abs value - if (diff > tolerance) - { - std::cerr << "Error in copy constructor " << std::endl; - return EXIT_FAILURE; - } - } - } - - // test construction from vnl_matrix - ArrayType d(vm); - - for (unsigned int r = 0; r < rows; ++r) - { - for (unsigned int c = 0; c < cols; ++c) - { - double diff = d(r, c) - vm(r, c); - diff = (diff > 0.0) ? diff : -diff; // take abs value - if (diff > tolerance) - { - std::cerr << "Error in construction from vnl_matrix" << std::endl; - return EXIT_FAILURE; - } - } - } - - // test for assignment from Array2D - - ArrayType e = a; - - for (unsigned int r = 0; r < rows; ++r) - { - for (unsigned int c = 0; c < cols; ++c) - { - double diff = a(r, c) - e(r, c); - diff = (diff > 0.0) ? diff : -diff; // take abs value - if (diff > tolerance) - { - std::cerr << "Error in assignment from Array2D constructor " << std::endl; - return EXIT_FAILURE; - } - } - } - - // test for assignment from vnl_matrix - - ArrayType f = vm; - - for (unsigned int r = 0; r < rows; ++r) - { - for (unsigned int c = 0; c < cols; ++c) - { - double diff = f(r, c) - vm(r, c); - diff = (diff > 0.0) ? diff : -diff; // take abs value - if (diff > tolerance) - { - std::cerr << "Error in assignment from vn_matrix" << std::endl; - return EXIT_FAILURE; - } - } - } - - std::cout << "Test Passed ! " << std::endl; - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkArrayGTest.cxx b/Modules/Core/Common/test/itkArrayGTest.cxx index f8ad28e3497..239696969f3 100644 --- a/Modules/Core/Common/test/itkArrayGTest.cxx +++ b/Modules/Core/Common/test/itkArrayGTest.cxx @@ -18,7 +18,9 @@ // First include the header file to be tested: #include "itkArray.h" +#include "itkNumericTraits.h" #include +#include namespace { @@ -42,3 +44,83 @@ CheckClassTemplateArgumentDeduction() static_assert(CheckClassTemplateArgumentDeduction() && CheckClassTemplateArgumentDeduction()); + + +TEST(Array, MemoryManagement) +{ + using FloatArrayType = itk::Array; + using DoubleArrayType = itk::Array; + + const FloatArrayType fa(10); + const DoubleArrayType da(10); + + // Create an itk::Array which manages its own memory + FloatArrayType myOwnBoss; + myOwnBoss.SetSize(5); + myOwnBoss.Fill(2.0 + 1.0f / 3.0f); + myOwnBoss[0] = 2.0f / 3.0f; + myOwnBoss[1] = itk::NumericTraits::max(); + myOwnBoss[2] = itk::NumericTraits::min(); + myOwnBoss[3] = 1.0f; + + // Create an itk::Array which does not manage its own memory + constexpr unsigned int n{ 7 }; + float buffer[n]; + FloatArrayType notMyOwnBoss; + notMyOwnBoss.SetSize(n); + notMyOwnBoss.SetData(buffer, false); + notMyOwnBoss.Fill(4.0); + + FloatArrayType notMyOwnBossToo; + notMyOwnBossToo.SetSize(n); + notMyOwnBossToo.SetData(buffer, false); + + // Copy an itk::Array which manages its own memory + const FloatArrayType test1 = myOwnBoss; + std::cout << test1 << std::endl; + EXPECT_EQ(test1.GetSize(), myOwnBoss.GetSize()); + + // Copy an itk::Array which does not manage its own memory + FloatArrayType test2 = notMyOwnBoss; + std::cout << test2 << std::endl; + EXPECT_EQ(test2.GetSize(), notMyOwnBoss.GetSize()); + + // itk::Array not managing its memory copying one that does + notMyOwnBoss = myOwnBoss; + std::cout << notMyOwnBoss << std::endl; + EXPECT_EQ(notMyOwnBoss.GetSize(), myOwnBoss.GetSize()); + + // Calling SetSize with same size + notMyOwnBossToo.SetSize(notMyOwnBossToo.GetSize()); + + // Calling SetSize with different size + notMyOwnBossToo.SetSize(notMyOwnBossToo.GetSize() + 1); + notMyOwnBossToo.Fill(6.0); + std::cout << notMyOwnBossToo << std::endl; + + // Exercise operator=( VnlVectorType& ) + test2 = test1; + EXPECT_EQ(test2.GetSize(), test1.GetSize()); + + // Construct array pointing to user-allocated buffer (user manages deletion) + constexpr size_t testSizeForArraySetDataSameSize{ 10 }; + FloatArrayType objectToCopy(testSizeForArraySetDataSameSize); + auto * data = new float[testSizeForArraySetDataSameSize]; + objectToCopy.SetDataSameSize(data); + + // Copy of array not managing its own memory + const FloatArrayType copy(objectToCopy); + EXPECT_EQ(copy.GetSize(), objectToCopy.GetSize()); + + // Double array managing its own memory + DoubleArrayType myOwnDouble; + myOwnDouble.SetSize(5); + myOwnDouble.Fill(2.0 + 1.0 / 3.0); + myOwnDouble[0] = 2.0 / 3.0; + myOwnDouble[1] = itk::NumericTraits::max(); + myOwnDouble[2] = itk::NumericTraits::min(); + myOwnDouble[3] = 1.0; + std::cout << myOwnDouble << std::endl; + + delete[] data; +} diff --git a/Modules/Core/Common/test/itkArrayTest.cxx b/Modules/Core/Common/test/itkArrayTest.cxx deleted file mode 100644 index a862f85b311..00000000000 --- a/Modules/Core/Common/test/itkArrayTest.cxx +++ /dev/null @@ -1,128 +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 "itkArray.h" -#include "itkNumericTraits.h" - -int -itkArrayTest(int, char *[]) -{ - - using FloatArrayType = itk::Array; - using DoubleArrayType = itk::Array; - - const FloatArrayType fa(10); - const DoubleArrayType da(10); - - /** - * The following section tests the functionality of the Array's - * memory management. - */ - - // - // Create an itk::Array which manages its own memory - // - FloatArrayType myOwnBoss; - myOwnBoss.SetSize(5); - myOwnBoss.Fill(2.0 + 1.0f / 3.0f); - myOwnBoss[0] = 2.0f / 3.0f; - myOwnBoss[1] = itk::NumericTraits::max(); - myOwnBoss[2] = itk::NumericTraits::min(); - myOwnBoss[3] = 1.0f; - - // - // Create an itk::Array which does not manage its own memory - // - constexpr unsigned int n{ 7 }; - float buffer[n]; - FloatArrayType notMyOwnBoss; - notMyOwnBoss.SetSize(n); - notMyOwnBoss.SetData(buffer, false); - notMyOwnBoss.Fill(4.0); - - FloatArrayType notMyOwnBossToo; - notMyOwnBossToo.SetSize(n); - notMyOwnBossToo.SetData(buffer, false); - - // - // Copy an itk::Array which manages its own memory - // - const FloatArrayType test1 = myOwnBoss; - std::cout << test1 << std::endl; - - // - // Copy an itk::Array which does not manage its own memory - // - FloatArrayType test2 = notMyOwnBoss; - std::cout << test2 << std::endl; - - // - // Testing itk::Array - // which does not manage its own memory copying an itk::Array - // which does. - // - notMyOwnBoss = myOwnBoss; - std::cout << notMyOwnBoss << std::endl; - - // - // Calling SetSize with an argument same as the current - // size - // - notMyOwnBossToo.SetSize(notMyOwnBossToo.GetSize()); - - // - // Calling SetSize with an argument different to the current - // size - // - notMyOwnBossToo.SetSize(notMyOwnBossToo.GetSize() + 1); - notMyOwnBossToo.Fill(6.0); - std::cout << notMyOwnBossToo << std::endl; - - // Exercise operator=( VnlVectorType& ) - test2 = test1; - - // Test the case where we construct an array that points - // to a user allocated buffer where the user wants to - // maintain responsibility for deleting the array. - constexpr size_t testSizeForArraySetDataSameSize{ 10 }; - FloatArrayType objectToCopy(testSizeForArraySetDataSameSize); - auto * data = new float[testSizeForArraySetDataSameSize]; - objectToCopy.SetDataSameSize(data); // This implicitly means LetArrayManageMemory=false - - // Make a copy of the array which is not managing its own memory. - const FloatArrayType copy(objectToCopy); - - // DO a double - // - // Create an itk::Array which manages its own memory - // - DoubleArrayType myOwnDouble; - myOwnDouble.SetSize(5); - myOwnDouble.Fill(2.0 + 1.0 / 3.0); - myOwnDouble[0] = 2.0 / 3.0; - myOwnDouble[1] = itk::NumericTraits::max(); - myOwnDouble[2] = itk::NumericTraits::min(); - myOwnDouble[3] = 1.0; - std::cout << myOwnDouble << std::endl; - - delete[] data; - - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkAutoPointerGTest.cxx b/Modules/Core/Common/test/itkAutoPointerGTest.cxx new file mode 100644 index 00000000000..a89c76d42bb --- /dev/null +++ b/Modules/Core/Common/test/itkAutoPointerGTest.cxx @@ -0,0 +1,92 @@ +/*========================================================================= + * + * 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 "itkAutoPointer.h" +#include "itkGTest.h" + +#include + +class TestObject +{ +public: + using Self = TestObject; + using AutoPointer = itk::AutoPointer; + using ConstAutoPointer = itk::AutoPointer; + TestObject() { std::cout << "TestObject Constructed" << std::endl; } + virtual ~TestObject() { std::cout << "TestObject Destructed" << std::endl; } + [[nodiscard]] const char * + GetClassName() const + { + return "my Class name is TestObject"; + } +}; + + +TEST(AutoPointer, OwnershipTransfer) +{ + auto * obj = new TestObject; + + TestObject::AutoPointer ptr1; + ptr1.TakeOwnership(obj); + + std::cout << "after assignment from raw pointer" << std::endl; + EXPECT_TRUE(ptr1.IsOwner()); + std::cout << "ptr1 IsOwner = " << ptr1.IsOwner() << std::endl; + + EXPECT_STREQ(ptr1->GetClassName(), "my Class name is TestObject"); + std::cout << ptr1->GetClassName() << std::endl; + + TestObject::AutoPointer ptr2(ptr1); + + std::cout << "after copy constructor " << std::endl; + EXPECT_FALSE(ptr1.IsOwner()); + std::cout << "ptr1 IsOwner = " << ptr1.IsOwner() << std::endl; + EXPECT_TRUE(ptr2.IsOwner()); + std::cout << "ptr2 IsOwner = " << ptr2.IsOwner() << std::endl; + + ptr2.Reset(); + std::cout << "after Reset " << std::endl; + EXPECT_FALSE(ptr2.IsOwner()); + std::cout << "ptr2 IsOwner = " << ptr2.IsOwner() << std::endl; + + ptr1.TakeOwnership(new TestObject); + std::cout << "after assignment from raw pointer" << std::endl; + EXPECT_TRUE(ptr1.IsOwner()); + std::cout << "ptr1 IsOwner = " << ptr1.IsOwner() << std::endl; + + // The following test exercise the methods but don't validate the results + if (ptr1 == ptr2) + { + std::cout << "AutoPointers are equal " << std::endl; + } + if (ptr1 > ptr2) + { + std::cout << "ptr1 > ptr2" << std::endl; + } + if (ptr1 < ptr2) + { + std::cout << "ptr1 < ptr2" << std::endl; + } + + + TestObject::ConstAutoPointer cptr1; + cptr1.TakeOwnership(new TestObject); + + + const TestObject::ConstAutoPointer cptr2(cptr1); +} diff --git a/Modules/Core/Common/test/itkBSplineKernelFunctionTest.cxx b/Modules/Core/Common/test/itkBSplineKernelFunctionGTest.cxx similarity index 61% rename from Modules/Core/Common/test/itkBSplineKernelFunctionTest.cxx rename to Modules/Core/Common/test/itkBSplineKernelFunctionGTest.cxx index 63c2d2b67af..a017e5a6da4 100644 --- a/Modules/Core/Common/test/itkBSplineKernelFunctionTest.cxx +++ b/Modules/Core/Common/test/itkBSplineKernelFunctionGTest.cxx @@ -17,11 +17,10 @@ *=========================================================================*/ #include "itkBSplineDerivativeKernelFunction.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" -int -itkBSplineKernelFunctionTest(int, char *[]) +TEST(BSplineKernelFunction, EvaluateAndDerivative) { // Externally generated results @@ -59,30 +58,21 @@ itkBSplineKernelFunctionTest(int, char *[]) // Testing the output of BSplineKernelFunction -#define TEST_BSPLINE_KERNEL(ORDERNUM) \ - { \ - using FunctionType = itk::BSplineKernelFunction; \ - auto function = FunctionType::New(); \ - \ - function->Print(std::cout); \ - constexpr double epsilon{ 1e-6 }; \ - for (unsigned int j = 0; j < npoints; ++j) \ - { \ - double results = function->Evaluate(x[j]); \ - /* compare with external results */ \ - if (itk::Math::Absolute(results - b##ORDERNUM[j]) > epsilon) \ - { \ - std::cerr.precision(static_cast(itk::Math::Absolute(std::log10(epsilon)))); \ - std::cerr << "Test failed!" << std::endl; \ - std::cerr << "Error with " << ORDERNUM << " order BSplineKernelFunction "; \ - std::cerr << "at index [" << j << "] " << std::endl; \ - std::cerr << "Expected value " << b##ORDERNUM[j] << std::endl; \ - std::cerr << " differs from " << results; \ - std::cerr << " by more than " << epsilon << std::endl; \ - return EXIT_FAILURE; \ - } \ - } \ - } \ +#define TEST_BSPLINE_KERNEL(ORDERNUM) \ + { \ + using FunctionType = itk::BSplineKernelFunction; \ + auto function = FunctionType::New(); \ + \ + function->Print(std::cout); \ + constexpr double epsilon{ 1e-6 }; \ + for (unsigned int j = 0; j < npoints; ++j) \ + { \ + double results = function->Evaluate(x[j]); \ + /* compare with external results */ \ + EXPECT_NEAR(results, b##ORDERNUM[j], epsilon) << "Error with " << ORDERNUM << " order BSplineKernelFunction " \ + << "at index [" << j << "] "; \ + } \ + } \ ITK_MACROEND_NOOP_STATEMENT TEST_BSPLINE_KERNEL(0); @@ -102,16 +92,7 @@ itkBSplineKernelFunctionTest(int, char *[]) const double results = derivFunction->Evaluate(xx); constexpr double epsilon{ 1e-6 }; - if (itk::Math::Absolute(results - expectedValue) > epsilon) - { - std::cerr.precision(static_cast(itk::Math::Absolute(std::log10(epsilon)))); - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx << std::endl; - std::cerr << "Expected value " << expectedValue << std::endl; - std::cerr << " differs from " << results; - std::cerr << " by more than " << epsilon << std::endl; - return EXIT_FAILURE; - } + EXPECT_NEAR(results, expectedValue, epsilon); } // Testing derivative spline order = 1 @@ -125,20 +106,11 @@ itkBSplineKernelFunctionTest(int, char *[]) for (double xx = -3.0; xx <= 3.0; xx += 0.1) { - const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); - const double results = derivFunction->Evaluate(xx); - + const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); + const double results = derivFunction->Evaluate(xx); constexpr double epsilon{ 1e-6 }; - if (itk::Math::Absolute(results - expectedValue) > epsilon) - { - std::cerr.precision(static_cast(itk::Math::Absolute(std::log10(epsilon)))); - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx << std::endl; - std::cerr << "Expected value " << expectedValue << std::endl; - std::cerr << " differs from " << results; - std::cerr << " by more than " << epsilon << std::endl; - return EXIT_FAILURE; - } + EXPECT_NEAR(results, expectedValue, epsilon) + << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx; } } @@ -154,20 +126,11 @@ itkBSplineKernelFunctionTest(int, char *[]) for (double xx = -3.0; xx <= 3.0; xx += 0.1) { - const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); - const double results = derivFunction->Evaluate(xx); - + const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); + const double results = derivFunction->Evaluate(xx); constexpr double epsilon{ 1e-6 }; - if (itk::Math::Absolute(results - expectedValue) > epsilon) - { - std::cerr.precision(static_cast(itk::Math::Absolute(std::log10(epsilon)))); - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx << std::endl; - std::cerr << "Expected value " << expectedValue << std::endl; - std::cerr << " differs from " << results; - std::cerr << " by more than " << epsilon << std::endl; - return EXIT_FAILURE; - } + EXPECT_NEAR(results, expectedValue, epsilon) + << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx; } } @@ -183,20 +146,11 @@ itkBSplineKernelFunctionTest(int, char *[]) for (double xx = -3.0; xx <= 3.0; xx += 0.1) { - const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); - const double results = derivFunction->Evaluate(xx); - + const double expectedValue = function->Evaluate(xx + 0.5) - function->Evaluate(xx - 0.5); + const double results = derivFunction->Evaluate(xx); constexpr double epsilon{ 1e-6 }; - if (itk::Math::Absolute(results - expectedValue) > epsilon) - { - std::cerr.precision(static_cast(itk::Math::Absolute(std::log10(epsilon)))); - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx << std::endl; - std::cerr << "Expected value " << expectedValue << std::endl; - std::cerr << " differs from " << results; - std::cerr << " by more than " << epsilon << std::endl; - return EXIT_FAILURE; - } + EXPECT_NEAR(results, expectedValue, epsilon) + << "Error with " << SplineOrder << " order BSplineDerivativeKernelFunction at " << xx; } } @@ -205,7 +159,7 @@ itkBSplineKernelFunctionTest(int, char *[]) using FunctionType = itk::BSplineKernelFunction<7>; auto function = FunctionType::New(); - ITK_TRY_EXPECT_EXCEPTION(function->Evaluate(0.0)); + EXPECT_THROW(function->Evaluate(0.0), itk::ExceptionObject); } // Testing case of unimplemented spline order @@ -213,10 +167,9 @@ itkBSplineKernelFunctionTest(int, char *[]) using FunctionType = itk::BSplineDerivativeKernelFunction<5>; auto function = FunctionType::New(); - ITK_TRY_EXPECT_EXCEPTION(function->Evaluate(0.0)); + EXPECT_THROW(function->Evaluate(0.0), itk::ExceptionObject); } std::cout << "Test finished. " << std::endl; - return EXIT_SUCCESS; } 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/itkBresenhamLineGTest.cxx b/Modules/Core/Common/test/itkBresenhamLineGTest.cxx new file mode 100644 index 00000000000..e6de3440501 --- /dev/null +++ b/Modules/Core/Common/test/itkBresenhamLineGTest.cxx @@ -0,0 +1,66 @@ +/*========================================================================= + * + * 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 "itkBresenhamLine.h" +#include "itkGTest.h" + +#include + +TEST(BresenhamLine, BuildLineFromVector) +{ + // Test BuildLine(Vector, distance) + itk::Vector v; + v[0] = 1; + v[1] = 1; + + itk::BresenhamLine<2> line; + std::vector> offsets = line.BuildLine(v, 4); + + EXPECT_EQ(offsets.size(), 4u); + + for (int i = 0; i < 4; ++i) + { + EXPECT_EQ(offsets[i][0], i) << "offsets[" << i << "][0] mismatch"; + EXPECT_EQ(offsets[i][1], i) << "offsets[" << i << "][1] mismatch"; + } +} + +TEST(BresenhamLine, BuildLineFromIndices) +{ + // Test BuildLine(Index, Index) + itk::Index<2> p0; + p0[0] = 0; + p0[1] = 0; + + itk::Index<2> p1; + p1[0] = 39; + p1[1] = 39; + + itk::BresenhamLine<2> line; + std::vector> indices = line.BuildLine(p0, p1); + + EXPECT_EQ(indices.size(), 40u); + + for (int i = 0; i < 40; ++i) + { + EXPECT_EQ(indices[i][0], i) << "indices[" << i << "][0] mismatch"; + EXPECT_EQ(indices[i][1], i) << "indices[" << i << "][1] mismatch"; + } + + std::cout << "Test Passed !" << std::endl; +} 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/itkCommandObserverObjectTest.cxx b/Modules/Core/Common/test/itkCommandObserverObjectGTest.cxx similarity index 82% rename from Modules/Core/Common/test/itkCommandObserverObjectTest.cxx rename to Modules/Core/Common/test/itkCommandObserverObjectGTest.cxx index c474f0c4e35..8f8cfd991cb 100644 --- a/Modules/Core/Common/test/itkCommandObserverObjectTest.cxx +++ b/Modules/Core/Common/test/itkCommandObserverObjectGTest.cxx @@ -20,7 +20,7 @@ #include "itkObject.h" #include "itkCommand.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" // @@ -71,7 +71,7 @@ onUserRemove(itk::Object * o, const itk::EventObject &, void * data) o->RemoveObserver(idToRemove); } -int +void testDeleteObserverDuringEvent() { const itk::Object::Pointer o = itk::Object::New(); @@ -92,16 +92,16 @@ testDeleteObserverDuringEvent() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::UserEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); o->RemoveAllObservers(); @@ -113,16 +113,16 @@ testDeleteObserverDuringEvent() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::UserEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); o->RemoveAllObservers(); @@ -134,16 +134,16 @@ testDeleteObserverDuringEvent() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::UserEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); o->RemoveAllObservers(); @@ -155,25 +155,22 @@ testDeleteObserverDuringEvent() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); onAnyCount = 0; o->InvokeEvent(itk::UserEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); + EXPECT_EQ(onAnyCount, 1u); o->RemoveAllObservers(); - - - return EXIT_SUCCESS; } -int +void testCommandConstObject() { @@ -189,23 +186,21 @@ testCommandConstObject() removeCmd->SetObjectName("Remove Command"); co->AddObserver(itk::AnyEvent(), cmd); - ITK_TEST_EXPECT_TRUE(co->HasObserver(itk::AnyEvent())); + EXPECT_TRUE(co->HasObserver(itk::AnyEvent())); // the constant command doesn't get executed from the non-const // invocation onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 0); + EXPECT_EQ(onAnyCount, 0u); onAnyCount = 0; co->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 1); - - return EXIT_SUCCESS; + EXPECT_EQ(onAnyCount, 1u); } -int +void testCommandRecursiveObject() { // this test has an command invoking another event, while removing a @@ -235,7 +230,7 @@ testCommandRecursiveObject() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); o->RemoveAllObservers(); @@ -247,7 +242,7 @@ testCommandRecursiveObject() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 2); + EXPECT_EQ(onAnyCount, 2u); o->RemoveAllObservers(); @@ -259,13 +254,11 @@ testCommandRecursiveObject() onAnyCount = 0; o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_TRUE(onAnyCount == 0); - - return EXIT_SUCCESS; + EXPECT_EQ(onAnyCount, 0u); } -bool +void testDeleteEventThrow() { // check the case where an exception in thrown in the DeleteEvent @@ -275,10 +268,9 @@ testDeleteEventThrow() cmd->SetCallback(onAnyThrow); o->AddObserver(itk::DeleteEvent(), cmd); - return EXIT_SUCCESS; } -int +void testLambdaCommand() { // spell-check-disable @@ -305,29 +297,23 @@ testLambdaCommand() }); o->InvokeEvent(itk::AnyEvent()); - ITK_TEST_EXPECT_EQUAL(1, cnt); - ITK_TEST_EXPECT_EQUAL(1, name_of_class_cnt); + EXPECT_EQ(cnt, 1); + EXPECT_EQ(name_of_class_cnt, 1); } // A DeleteEvent is called here! as object "o" is deleted - ITK_TEST_EXPECT_EQUAL(2, cnt); // Verify that cnt really was incremented during DeleteEvent! - ITK_TEST_EXPECT_EQUAL(2, name_of_class_cnt); - return EXIT_SUCCESS; + EXPECT_EQ(cnt, 2); // Verify that cnt really was incremented during DeleteEvent! + EXPECT_EQ(name_of_class_cnt, 2); } } // end namespace -int -itkCommandObserverObjectTest(int, char *[]) +TEST(CommandObserverObject, AllObserverTests) { - bool ret = true; - - ret &= (testDeleteObserverDuringEvent() == EXIT_SUCCESS); - ret &= (testCommandConstObject() == EXIT_SUCCESS); - ret &= (testCommandRecursiveObject() == EXIT_SUCCESS); - ret &= (testDeleteEventThrow() == EXIT_SUCCESS); - ret &= (testLambdaCommand() == EXIT_SUCCESS); - - return ret ? EXIT_SUCCESS : EXIT_FAILURE; + testDeleteObserverDuringEvent(); + testCommandConstObject(); + testCommandRecursiveObject(); + testDeleteEventThrow(); + testLambdaCommand(); } diff --git a/Modules/Core/Common/test/itkCovariantVectorGeometryTest.cxx b/Modules/Core/Common/test/itkCovariantVectorGeometryGTest.cxx similarity index 79% rename from Modules/Core/Common/test/itkCovariantVectorGeometryTest.cxx rename to Modules/Core/Common/test/itkCovariantVectorGeometryGTest.cxx index 9583b63322c..d0d466f4b9d 100644 --- a/Modules/Core/Common/test/itkCovariantVectorGeometryTest.cxx +++ b/Modules/Core/Common/test/itkCovariantVectorGeometryGTest.cxx @@ -23,10 +23,10 @@ #include "itkMath.h" #include "itkCovariantVector.h" +#include "itkGTest.h" #include -int -itkCovariantVectorGeometryTest(int, char *[]) +TEST(CovariantVectorGeometry, ArithmeticAndNorms) { // Dimension & Type constexpr unsigned int N{ 3 }; @@ -84,18 +84,16 @@ itkCovariantVectorGeometryTest(int, char *[]) const ValueType norm2 = vg.GetSquaredNorm(); std::cout << "vg squared norm = "; std::cout << norm2 << std::endl; + EXPECT_DOUBLE_EQ(norm2, 54.0); const ValueType norm = vg.GetNorm(); std::cout << "vg norm = "; std::cout << norm << std::endl; + EXPECT_NEAR(norm, std::sqrt(54.0), 1e-10); const ValueType normX = vg.Normalize(); std::cout << "vg after normalizing: " << vg << std::endl; - if (norm != normX) - { - std::cout << "Norms from GetNorm() and from Normalize() are different" << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(norm, normX); // Test for vnl interface @@ -160,16 +158,9 @@ itkCovariantVectorGeometryTest(int, char *[]) { auto val = static_cast(dp[i]); - // std::cout << val << std::endl; - // std::cout << fp[i] << std::endl; - const float diff = itk::Math::Absolute(val - fp[i]); std::cout << "difference = " << diff << std::endl; - if (itk::Math::Absolute(val - fp[i]) > tolerance) - { - std::cout << "Test failed at component " << i << std::endl; - return EXIT_FAILURE; - } + EXPECT_NEAR(val, fp[i], tolerance); } std::cout << " PASSED ! " << std::endl; @@ -192,12 +183,8 @@ itkCovariantVectorGeometryTest(int, char *[]) constexpr double expectedValue{ -28.0 }; - if (!itk::Math::FloatAlmostEqual(expectedValue, covariant * contravariant) || - !itk::Math::FloatAlmostEqual(expectedValue, contravariant * covariant)) - { - std::cerr << "Error in inner product computation." << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(itk::Math::FloatAlmostEqual(expectedValue, covariant * contravariant)); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(expectedValue, contravariant * covariant)); } // Test the Cross products @@ -226,13 +213,9 @@ itkCovariantVectorGeometryTest(int, char *[]) expectedNormal[1] = 0.0; expectedNormal[2] = 1.0; - if (!itk::Math::FloatAlmostEqual(normal[0], expectedNormal[0]) || - !itk::Math::FloatAlmostEqual(normal[1], expectedNormal[1]) || - !itk::Math::FloatAlmostEqual(normal[2], expectedNormal[2])) - { - std::cerr << "Error in CrossProduct computation." << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(itk::Math::FloatAlmostEqual(normal[0], expectedNormal[0])); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(normal[1], expectedNormal[1])); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(normal[2], expectedNormal[2])); } // // test that the ComponentType is present @@ -240,21 +223,12 @@ itkCovariantVectorGeometryTest(int, char *[]) using CovariantVectorType = itk::CovariantVector; CovariantVectorType::ComponentType comp(1.0); double x(1.0); - if constexpr (sizeof(comp) != sizeof(double)) - { - std::cerr << "error -- CovariantVectorType::ComponentType size != sizeof(double)" << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(sizeof(comp), sizeof(double)); auto * compp = reinterpret_cast(&comp); auto * xp = reinterpret_cast(&x); for (unsigned int i = 0; i < sizeof(CovariantVectorType::ComponentType); ++i) { - if (compp[i] != xp[i]) - { - std::cerr << "error -- bit pattern for CovariantVectorType::ComponentType doesn't match " - << " double with same value" << std::endl; - } + EXPECT_EQ(compp[i], xp[i]); } } - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkCrossHelperTest.cxx b/Modules/Core/Common/test/itkCrossHelperGTest.cxx similarity index 70% rename from Modules/Core/Common/test/itkCrossHelperTest.cxx rename to Modules/Core/Common/test/itkCrossHelperGTest.cxx index 86da6504a99..2fadff83845 100644 --- a/Modules/Core/Common/test/itkCrossHelperTest.cxx +++ b/Modules/Core/Common/test/itkCrossHelperGTest.cxx @@ -17,12 +17,12 @@ *=========================================================================*/ #include "itkVector.h" #include "itkCrossHelper.h" +#include "itkGTest.h" #include -int -itkCrossHelperTest(int itkNotUsed(argc), char * itkNotUsed(argv)[]) +TEST(CrossHelper, CrossProductInMultipleDimensions) { constexpr unsigned int Dimension2D{ 2 }; constexpr unsigned int Dimension3D{ 3 }; @@ -51,11 +51,8 @@ itkCrossHelperTest(int itkNotUsed(argc), char * itkNotUsed(argv)[]) v2d[0] = 0.; v2d[1] = 1.; - if (cross2d(u2d, v2d).GetNorm() > 1e-6) - { - std::cout << "cross product must return null vector is dimension is below 3" << std::endl; - return EXIT_FAILURE; - } + // cross product must return null vector when dimension is below 3 + EXPECT_LT(cross2d(u2d, v2d).GetNorm(), 1e-6); Vector3DType u3d; u3d[0] = 1.; @@ -72,23 +69,9 @@ itkCrossHelperTest(int itkNotUsed(argc), char * itkNotUsed(argv)[]) w3d[1] = 0.; w3d[2] = 1.; - if ((cross3d(u3d, v3d) - w3d).GetNorm() > 1e-6) - { - std::cout << "cross3d( u3d, v3d ) != w3d" << std::endl; - return EXIT_FAILURE; - } - - if ((cross3d(v3d, w3d) - u3d).GetNorm() > 1e-6) - { - std::cout << "cross3d( v3d, w3d ) != u3d" << std::endl; - return EXIT_FAILURE; - } - - if ((cross3d(w3d, u3d) - v3d).GetNorm() > 1e-6) - { - std::cout << "cross3d( w3d, u3d ) != v3d" << std::endl; - return EXIT_FAILURE; - } + EXPECT_LT((cross3d(u3d, v3d) - w3d).GetNorm(), 1e-6); + EXPECT_LT((cross3d(v3d, w3d) - u3d).GetNorm(), 1e-6); + EXPECT_LT((cross3d(w3d, u3d) - v3d).GetNorm(), 1e-6); Vector4DType u4d; u4d[0] = 1.; @@ -108,11 +91,5 @@ itkCrossHelperTest(int itkNotUsed(argc), char * itkNotUsed(argv)[]) w4d[2] = 1.; w4d[3] = 0.; - if ((cross4d(u4d, v4d) - w4d).GetNorm() > 1e-6) - { - std::cout << "cross4d( u4d, v4d ) != w4d" << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; + EXPECT_LT((cross4d(u4d, v4d) - w4d).GetNorm(), 1e-6); } 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/itkDecoratorTest.cxx b/Modules/Core/Common/test/itkDecoratorGTest.cxx similarity index 87% rename from Modules/Core/Common/test/itkDecoratorTest.cxx rename to Modules/Core/Common/test/itkDecoratorGTest.cxx index 12169d4ed83..bd9b46ebbc4 100644 --- a/Modules/Core/Common/test/itkDecoratorTest.cxx +++ b/Modules/Core/Common/test/itkDecoratorGTest.cxx @@ -21,7 +21,7 @@ #include "itkSimpleDataObjectDecorator.h" #include "itkDataObjectDecorator.h" #include "itkAutoPointerDataObjectDecorator.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" namespace { @@ -34,10 +34,8 @@ operator<<(std::basic_ostream & os, const std::vector; auto f = FloatObjectType::New(); @@ -59,16 +57,16 @@ itkDecoratorTest(int, char *[]) const itk::ModifiedTimeType t1 = decoratedTransform->GetMTime(); transformObject->Modified(); - ITK_TEST_EXPECT_TRUE(t1 < decoratedTransform->GetMTime()); + EXPECT_TRUE(t1 < decoratedTransform->GetMTime()); auto decoratedTransform2 = TransformObjectType::New(); decoratedTransform2->Graft(decoratedTransform); - ITK_TEST_EXPECT_EQUAL(decoratedTransform2->Get(), decoratedTransform->Get()); + EXPECT_EQ(decoratedTransform2->Get(), decoratedTransform->Get()); const itk::ModifiedTimeType t2 = decoratedTransform->GetMTime(); decoratedTransform2->GetModifiable()->Modified(); - ITK_TEST_EXPECT_TRUE(t2 < decoratedTransform->GetMTime()); + EXPECT_TRUE(t2 < decoratedTransform->GetMTime()); std::cout << "Value of decoratedTransform: "; @@ -81,25 +79,25 @@ itkDecoratorTest(int, char *[]) auto decoratedBaseTransform = TransformBaseObjectType::New(); // NOTE: GetPointer is needed to force selection of the correct overloaded function signature. decoratedBaseTransform->Graft(decoratedTransform.GetPointer()); - ITK_TEST_EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); + EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); decoratedBaseTransform->ReleaseData(); - ITK_TEST_EXPECT_TRUE(decoratedBaseTransform->Get() == nullptr); + EXPECT_TRUE(decoratedBaseTransform->Get() == nullptr); // NOTE: GetPointer is needed to force selection of the correct overloaded function signature. decoratedBaseTransform->Graft(f.GetPointer()); - ITK_TEST_EXPECT_TRUE(decoratedBaseTransform->Get() == nullptr); + EXPECT_TRUE(decoratedBaseTransform->Get() == nullptr); decoratedBaseTransform->Graft(static_cast(nullptr)); // NOTE: GetPointer is needed to force selection of the correct overloaded function signature. decoratedBaseTransform->Graft(decoratedTransform.GetPointer()); - ITK_TEST_EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); + EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); decoratedBaseTransform->Graft(static_cast(nullptr)); - ITK_TEST_EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); + EXPECT_TRUE(decoratedBaseTransform->Get() != nullptr); decoratedTransform->ReleaseData(); decoratedTransform->Graft(decoratedBaseTransform); - ITK_TEST_EXPECT_TRUE(decoratedTransform->Get() == nullptr); + EXPECT_TRUE(decoratedTransform->Get() == nullptr); using VectorType = std::vector; using VectorObjectType = itk::SimpleDataObjectDecorator; @@ -149,5 +147,4 @@ itkDecoratorTest(int, char *[]) std::cout << "Test finished." << std::endl; - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkDerivativeOperatorTest.cxx b/Modules/Core/Common/test/itkDerivativeOperatorGTest.cxx similarity index 72% rename from Modules/Core/Common/test/itkDerivativeOperatorTest.cxx rename to Modules/Core/Common/test/itkDerivativeOperatorGTest.cxx index 2b3dfd3a308..fd1bb70d607 100644 --- a/Modules/Core/Common/test/itkDerivativeOperatorTest.cxx +++ b/Modules/Core/Common/test/itkDerivativeOperatorGTest.cxx @@ -19,7 +19,7 @@ #include "itkMath.h" #include "itkDerivativeOperator.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" namespace itk { @@ -58,8 +58,7 @@ class DerivativeOperatorTestHelper : public DerivativeOperator; - DerivativeOperatorType derivativeOperator; + DerivativeOperatorType derivativeOperator; + DerivativeOperatorType * derivativeOperatorPtr = &derivativeOperator; - ITK_EXERCISE_BASIC_OBJECT_METHODS((&derivativeOperator), DerivativeOperator, NeighborhoodOperator); + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(derivativeOperatorPtr, DerivativeOperator, NeighborhoodOperator); // Test other methods using the helper @@ -79,48 +79,33 @@ itkDerivativeOperatorTest(int, char *[]) unsigned int order = 1; op1.SetOrder(order); - ITK_TEST_SET_GET_VALUE(order, op1.GetOrder()); + EXPECT_EQ(op1.GetOrder(), order); order = 2; op1.SetOrder(order); - ITK_TEST_SET_GET_VALUE(order, op1.GetOrder()); + EXPECT_EQ(op1.GetOrder(), order); order = 1; op1.SetOrder(order); - ITK_TEST_SET_GET_VALUE(order, op1.GetOrder()); + EXPECT_EQ(op1.GetOrder(), order); OperatorType::CoefficientVector expected1{ 0.5, 0.0, -0.5 }; // Check actual coefficient values - if (!op1.CheckCoefficients(expected1)) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error in coefficients" << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(op1.CheckCoefficients(expected1)); // Test copy constructor OperatorType op1b(op1); // Check actual coefficient values - if (!op1b.CheckCoefficients(expected1)) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Copy constructor failed" << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(op1b.CheckCoefficients(expected1)); // Test operator assignment OperatorType op1c(op1); // Check actual coefficient values - if (!op1c.CheckCoefficients(expected1)) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Operator assignment failed" << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(op1c.CheckCoefficients(expected1)); // Test second order OperatorType::CoefficientVector expected2{ 1, -2, 1 }; @@ -130,14 +115,8 @@ itkDerivativeOperatorTest(int, char *[]) op2.SetOrder(2); // Check actual coefficient values - if (!op2.CheckCoefficients(expected2)) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error in coefficients" << std::endl; - return EXIT_FAILURE; - } + EXPECT_TRUE(op2.CheckCoefficients(expected2)); std::cout << "Test finished." << std::endl; - return EXIT_SUCCESS; } 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/itkFilterDispatchGTest.cxx b/Modules/Core/Common/test/itkFilterDispatchGTest.cxx new file mode 100644 index 00000000000..68160374df5 --- /dev/null +++ b/Modules/Core/Common/test/itkFilterDispatchGTest.cxx @@ -0,0 +1,152 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ + +/** + * Demonstration of filter dispatching. The general problem is to provide + * filters with specialized implementations for each dimension, but in + * only one class, and without partial specialization. + */ + +#include "itkImageToImageFilter.h" +#include "itkGTest.h" +#include + +namespace +{ + +template +class ExampleImageFilter : public itk::ImageToImageFilter +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(ExampleImageFilter); + + using Self = ExampleImageFilter; + using Superclass = itk::ImageToImageFilter; + using Pointer = itk::SmartPointer; + using ConstPointer = itk::SmartPointer; + using InputImageType = TInputImage; + using OutputImageType = TOutputImage; + enum + { + ImageDimension = InputImageType::ImageDimension + }; + + void + Update() override; + + itkNewMacro(Self); + +protected: + ExampleImageFilter() = default; + ~ExampleImageFilter() override = default; + +private: + struct DispatchBase + {}; + template + struct Dispatch : public DispatchBase + {}; + + void + Execute(const DispatchBase &); + void Execute(Dispatch<2>); + void Execute(Dispatch<3>); + void Execute(Dispatch<0>); +}; + +template +void +ExampleImageFilter::Update() +{ + this->Execute(Dispatch()); +} + +template +void +ExampleImageFilter::Execute(const DispatchBase &) +{ + std::cout << "General N-d Execute() has been called." << std::endl; + if ((ImageDimension == 2) || (ImageDimension == 3)) + { + std::ostringstream err; + err << "Error: N-d filter implementation called for " << ImageDimension + << "-d filter, even though specific implementation exists." << std::endl; + throw std::string(err.str().c_str()); + } +} + +template +void +ExampleImageFilter::Execute(Dispatch<2>) +{ + std::cout << "2d-specific Execute() has been called." << std::endl; + if (ImageDimension != 2) + { + std::ostringstream err; + err << "Error: 2-d filter implementation called for " << ImageDimension << "-d filter." << std::endl; + throw std::string(err.str().c_str()); + } +} + +template +void +ExampleImageFilter::Execute(Dispatch<3>) +{ + std::cout << "3d-specific Execute() has been called." << std::endl; + if (ImageDimension != 3) + { + std::ostringstream err; + err << "Error: 3-d filter implementation called for " << ImageDimension << "-d filter." << std::endl; + throw std::string(err.str().c_str()); + } +} + +template +void +ExampleImageFilter::Execute(Dispatch<0>) +{ + throw std::string("The 0-Dispatch method should not have been called."); +} + +} // namespace + + +TEST(FilterDispatch, DimensionSpecificDispatch) +{ + using Image2d = itk::Image; + using Image3d = itk::Image; + using Image4d = itk::Image; + using Image5d = itk::Image; + + auto filter2d = ExampleImageFilter::New(); + auto filter3d = ExampleImageFilter::New(); + auto filter4d = ExampleImageFilter::New(); + auto filter5d = ExampleImageFilter::New(); + + std::cout << "Executing 2-d filter: "; + EXPECT_NO_THROW(filter2d->Update()); + + std::cout << "Executing 3-d filter: "; + EXPECT_NO_THROW(filter3d->Update()); + + std::cout << "Executing 4-d filter: "; + EXPECT_NO_THROW(filter4d->Update()); + + std::cout << "Executing 5-d filter: "; + EXPECT_NO_THROW(filter5d->Update()); +} diff --git a/Modules/Core/Common/test/itkFilterDispatchTest.cxx b/Modules/Core/Common/test/itkFilterDispatchTest.cxx deleted file mode 100644 index 10cdf88681b..00000000000 --- a/Modules/Core/Common/test/itkFilterDispatchTest.cxx +++ /dev/null @@ -1,261 +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. - * - *=========================================================================*/ - -/** - * Demonstration of filter dispatching. The general problem is to provide - * filters with specialized implementations for each dimension, but in - * only one class, and without partial specialization. Consider a filter - * with separate methods for 2-d, 3-d, and N-d implementations. We would - * like to dispatch a call to the correct implementation from a single - * Execute() call. - * - * The basic challenge here is that a filter that has been instantiated as - * dimension 3, for example, still has execute methods for 2, 3, and N - * dimensions. If the Execute(2-d) is instantiated, it may have compiler - * errors because it assumes that the class is instantiated for 2 dimensions. - * This means we can't have an Execute() method which tests the dimension - * at run-time and calls the appropriate Execute(*-d) method because it will - * instantiate all the Execute(*-d) methods, when only one will compile - * properly. - * - * The solution presented below will allow a single Execute() call to - * instantiate and call only the correct Execute(*-d) method for a particular - * filter instantiation. - */ - -#include "itkImageToImageFilter.h" -#include - -/** - * \class An example filter. - */ -template -class ExampleImageFilter : public itk::ImageToImageFilter -{ -public: - ITK_DISALLOW_COPY_AND_MOVE(ExampleImageFilter); - - /** - * Standard "Self" type alias. - */ - using Self = ExampleImageFilter; - - /** - * Standard "Superclass" type alias. - */ - using Superclass = itk::ImageToImageFilter; - - /** - * Smart pointer type alias support - */ - using Pointer = itk::SmartPointer; - using ConstPointer = itk::SmartPointer; - - using InputImageType = TInputImage; - using OutputImageType = TOutputImage; - enum - { - ImageDimension = InputImageType::ImageDimension - }; - - void - Update() override; - - /** - * Method for creation through the object factory. - */ - itkNewMacro(Self); - -protected: - ExampleImageFilter() = default; - ~ExampleImageFilter() override = default; - -private: - /** - * Dispatch class base allows automatic use of general implementation - * when no specific dispatch rules match. - */ - struct DispatchBase - {}; - - /** - * Dispatch control class simply holds information in its template - * parameter(s) that is used to control which Execute() method is chosen. - */ - template - struct Dispatch : public DispatchBase - {}; - - void - Execute(const DispatchBase &); - void Execute(Dispatch<2>); - void Execute(Dispatch<3>); - void Execute(Dispatch<0>); -}; - - -/** - * Filter update method called by the user of the filter. - * This just makes the call to the real method by instantiating the - * appropriate Dispatch control class. - */ -template -void -ExampleImageFilter::Update() -{ - this->Execute(Dispatch()); -} - - -/** - * General n-dimensional implementation of example filter. - * The Dispatch parameter is not used. It is just used to control - * instantiation. - */ -template -void -ExampleImageFilter::Execute(const DispatchBase &) -{ - std::cout << "General N-d Execute() has been called." << std::endl; - - // Make sure the correct Execute() method has been called. - if ((ImageDimension == 2) || (ImageDimension == 3)) - { - std::ostringstream err; - err << "Error: N-d filter implementation called for " << ImageDimension - << "-d filter, even though specific implementation exists." << std::endl; - throw std::string(err.str().c_str()); - } -} - - -/** - * 2-dimensional implementation of example filter. - * The Dispatch parameter is not used. It is just used to control - * instantiation. - */ -template -void -ExampleImageFilter::Execute(Dispatch<2>) -{ - std::cout << "2d-specific Execute() has been called." << std::endl; - - // Make sure the correct Execute() method has been called. - if (ImageDimension != 2) - { - std::ostringstream err; - err << "Error: 2-d filter implementation called for " << ImageDimension << "-d filter." << std::endl; - throw std::string(err.str().c_str()); - } -} - - -/** - * 3-dimensional implementation of example filter. - * The Dispatch parameter is not used. It is just used to control - * instantiation. - */ -template -void -ExampleImageFilter::Execute(Dispatch<3>) -{ - std::cout << "3d-specific Execute() has been called." << std::endl; - - // Make sure the correct Execute() method has been called. - if (ImageDimension != 3) - { - std::ostringstream err; - err << "Error: 3-d filter implementation called for " << ImageDimension << "-d filter." << std::endl; - throw std::string(err.str().c_str()); - } -} - - -/** - * Zero-dimensional implementation of filter. This should never be called, - * or even instantiated. If a compiler instantiates this, the test will - * fail to compile. - */ -template -void -ExampleImageFilter::Execute(Dispatch<0>) -{ - // this_should_not_have_been_instantiated(); - throw std::string("The 0-Dispatch method should not have been called."); -} - - -/** - * Filter dispatch test creates several ExampleImageFilter instantiations - * and calls them to check if the dispatch rules are working correctly. - */ -int -itkFilterDispatchTest(int, char *[]) -{ - bool passed = true; - - // Define an image of each dimension. - using Image2d = itk::Image; - using Image3d = itk::Image; - using Image4d = itk::Image; - using Image5d = itk::Image; - - // Define a filter of each dimension. - using Filter2d = ExampleImageFilter; - using Filter3d = ExampleImageFilter; - using Filter4d = ExampleImageFilter; - using Filter5d = ExampleImageFilter; - - // Instantiate a filter of each dimension. - auto filter2d = Filter2d::New(); - auto filter3d = Filter3d::New(); - auto filter4d = Filter4d::New(); - auto filter5d = Filter5d::New(); - - // Try running each of the filters. If the wrong Execute() method is - // invoked by one of these calls, a std::string() exception will be - // thrown with the error description. - try - { - std::cout << "Executing 2-d filter: "; - filter2d->Update(); - - std::cout << "Executing 3-d filter: "; - filter3d->Update(); - - std::cout << "Executing 4-d filter: "; - filter4d->Update(); - - std::cout << "Executing 5-d filter: "; - filter5d->Update(); - } - catch (const std::string & err) - { - std::cout << err; - passed = false; - } - - if (passed) - { - std::cout << "The test has passed." << std::endl; - return EXIT_SUCCESS; - } - - std::cout << "The test has failed." << std::endl; - return EXIT_FAILURE; -} diff --git a/Modules/Core/Common/test/itkFixedArrayGTest.cxx b/Modules/Core/Common/test/itkFixedArrayGTest.cxx index 891397a6169..4f9e2f4902c 100644 --- a/Modules/Core/Common/test/itkFixedArrayGTest.cxx +++ b/Modules/Core/Common/test/itkFixedArrayGTest.cxx @@ -377,3 +377,62 @@ TEST(FixedArray, CheckFrontAndBack) itk::RangeGTestUtilities::CheckFrontAndBack(itk::FixedArray({ 0, 1, 2 })); itk::RangeGTestUtilities::CheckFrontAndBack(itk::FixedArray::Filled(std::numeric_limits::max())); } + + +// Tests interop with c-style arrays, equality, Set/GetElement, and various index types. +TEST(FixedArray, CArrayInteropAndIndexTypes) +{ + // Explicit instantiation to ensure all methods are compiled. + (void)itk::FixedArray{}; + + // Test equality operators + constexpr itk::FixedArray array4{}; + EXPECT_EQ(array4, array4); + EXPECT_FALSE(array4 != array4); + + // Test Set/GetElement + constexpr unsigned int n{ 20 }; + itk::FixedArray array20; + for (unsigned int i = 0; i < n; ++i) + { + array20.SetElement(i, i); + } + for (unsigned int k = 0; k < n; ++k) + { + EXPECT_EQ(array20.GetElement(k), k); + } + + // Test various index types (const access) +#define TRY_INDEX_CONST(T) \ + { \ + T in = 10; \ + EXPECT_EQ(array20[in], 10u); \ + } \ + ITK_MACROEND_NOOP_STATEMENT + + TRY_INDEX_CONST(short); + TRY_INDEX_CONST(unsigned short); + TRY_INDEX_CONST(int); + TRY_INDEX_CONST(unsigned int); + TRY_INDEX_CONST(long); + TRY_INDEX_CONST(unsigned long); + TRY_INDEX_CONST(long long); + TRY_INDEX_CONST(unsigned long long); + + // Test various index types (non-const access) +#define TRY_INDEX(T) \ + { \ + T in = 10; \ + array20[in] = 10; \ + } \ + ITK_MACROEND_NOOP_STATEMENT + + TRY_INDEX(short); + TRY_INDEX(unsigned short); + TRY_INDEX(int); + TRY_INDEX(unsigned int); + TRY_INDEX(long); + TRY_INDEX(unsigned long); + TRY_INDEX(long long); + TRY_INDEX(unsigned long long); +} diff --git a/Modules/Core/Common/test/itkFixedArrayTest.cxx b/Modules/Core/Common/test/itkFixedArrayTest.cxx deleted file mode 100644 index 82058e39a71..00000000000 --- a/Modules/Core/Common/test/itkFixedArrayTest.cxx +++ /dev/null @@ -1,174 +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 "itkFixedArray.h" - -// Explicit instantiation to make sure all methods are compiled. -template class itk::FixedArray; - -void -Set_c_Array(int x[3]) -{ - x[0] = 1; - x[1] = 2; - x[2] = 3; -} - -void -Print_Array(const itk::FixedArray & x, std::ostream & os) -{ - os << '{' << x[0] << ',' << x[1] << ',' << x[2] << '}' << std::endl; -} - -void -Print_c_ArrayConst(const int x[3], std::ostream & os) -{ - os << '{' << x[0] << ',' << x[1] << ',' << x[2] << '}' << std::endl; -} - -void -Print_Array5(const itk::FixedArray & x, std::ostream & os) -{ - os << '{' << x[0] << ',' << x[1] << ',' << x[2] << ',' << x[3] << ',' << x[4] << '}' << std::endl; -} - -int -itkFixedArrayTest(int, char *[]) -{ - // Test out many combinations of using c-style arrays and FixedArray - - int c_Array1[3] = { 0, 0, 0 }; - - Set_c_Array(c_Array1); - Print_Array(c_Array1, std::cout); - Print_c_ArrayConst(c_Array1, std::cout); - - int c_Array2[3] = { 0, 0, 0 }; - Print_Array(c_Array2, std::cout); - - int array3Init[3] = { 4, 4, 4 }; - itk::FixedArray array3 = array3Init; - Print_Array(array3, std::cout); - Print_c_ArrayConst(array3.GetDataPointer(), std::cout); - - Set_c_Array(array3.GetDataPointer()); - Print_Array(array3, std::cout); - - constexpr itk::FixedArray array4{}; - Print_Array(array4, std::cout); - - // Test operator!= and operator== - if (array4 != array4) - return EXIT_FAILURE; // should be equal - if (!(array4 == array4)) - return EXIT_FAILURE; // should be equal - - // Test Get/Set element - constexpr unsigned int n{ 20 }; - itk::FixedArray array20; - for (unsigned int i = 0; i < n; ++i) - { - array20.SetElement(i, i); - } - - for (unsigned int k = 0; k < n; ++k) - { - if (array20.GetElement(k) != k) - { - std::cerr << "Set/Get element test failed" << std::endl; - return EXIT_FAILURE; - } - } - - std::cout << "FixedArray::Iterator it = array20.Begin();" << std::endl; - itk::FixedArray::Iterator it = array20.Begin(); - while (it != array20.End()) - { - std::cout << *it << std::endl; - ++it; - } - - std::cout << "FixedArray::Iterator it = array20.End();" << std::endl; - itk::FixedArray::Iterator bit = array20.End(); - while (--bit >= array20.Begin()) - { - std::cout << *bit << std::endl; - } - - std::cout << "FixedArray::ConstIterator it = array20.Begin();" << std::endl; - itk::FixedArray::ConstIterator cit = array20.Begin(); - while (cit != array20.End()) - { - std::cout << *cit << std::endl; - ++cit; - } - - std::cout << "FixedArray::reverse_iterator rit = array20.rbegin();" << std::endl; - itk::FixedArray::reverse_iterator rit = array20.rbegin(); - while (rit != array20.rend()) - { - std::cout << *rit << std::endl; - ++rit; - } - - std::cout << "FixedArray::const_reverse_iterator crit = array20.rbegin();" << std::endl; - itk::FixedArray::const_reverse_iterator crit = array20.rbegin(); - while (crit != array20.rend()) - { - std::cout << *crit << std::endl; - ++crit; - } - - // Try all index types -#define TRY_INDEX_CONST(T) \ - { \ - T in = 10; \ - if (array20[in] != 10) \ - { \ - std::cerr << "index failed" << std::endl; \ - return EXIT_FAILURE; \ - } \ - } \ - ITK_MACROEND_NOOP_STATEMENT - - TRY_INDEX_CONST(short); - TRY_INDEX_CONST(unsigned short); - TRY_INDEX_CONST(int); - TRY_INDEX_CONST(unsigned int); - TRY_INDEX_CONST(long); - TRY_INDEX_CONST(unsigned long); - TRY_INDEX_CONST(long long); - TRY_INDEX_CONST(unsigned long long); -#define TRY_INDEX(T) \ - { \ - T in = 10; \ - array20[in] = 10; \ - } \ - ITK_MACROEND_NOOP_STATEMENT - - TRY_INDEX(short); - TRY_INDEX(unsigned short); - TRY_INDEX(int); - TRY_INDEX(unsigned int); - TRY_INDEX(long); - TRY_INDEX(unsigned long); - TRY_INDEX(long long); - TRY_INDEX(unsigned long long); - return EXIT_SUCCESS; -} diff --git a/Modules/Core/Common/test/itkFloodFillIteratorTest.cxx b/Modules/Core/Common/test/itkFloodFillIteratorGTest.cxx similarity index 64% rename from Modules/Core/Common/test/itkFloodFillIteratorTest.cxx rename to Modules/Core/Common/test/itkFloodFillIteratorGTest.cxx index 1442de9d151..4f9c1bfa101 100644 --- a/Modules/Core/Common/test/itkFloodFillIteratorTest.cxx +++ b/Modules/Core/Common/test/itkFloodFillIteratorGTest.cxx @@ -16,61 +16,40 @@ * *=========================================================================*/ -#include - -// Native ITK stuff #include "itkImageRegionIterator.h" - -// Spatial function stuff #include "itkSphereSpatialFunction.h" #include "itkFloodFilledSpatialFunctionConditionalIterator.h" +#include "itkGTest.h" -int -itkFloodFillIteratorTest(int, char *[]) +#include + + +TEST(FloodFillIterator, SphereFloodFill) { constexpr unsigned int dim{ 3 }; - // Image type alias using TImageType = itk::Image; - //-----------------Create a new input image-------------------- - // Image size and spacing parameters TImageType::SizeValueType sourceImageSize[] = { 20, 20, 20 }; TImageType::SpacingValueType sourceImageSpacing[] = { 1.0, 1.0, 1.0 }; TImageType::PointValueType sourceImageOrigin[] = { 0, 0, 0 }; - // Creates the sourceImage (but doesn't set the size or allocate memory) auto sourceImage = TImageType::New(); sourceImage->SetOrigin(sourceImageOrigin); sourceImage->SetSpacing(sourceImageSpacing); - std::cout << "New sourceImage created" << std::endl; - - //-----The following block allocates the sourceImage----- - - // Create a size object native to the sourceImage type TImageType::SizeType sourceImageSizeObject; - // Set the size object to the array defined earlier sourceImageSizeObject.SetSize(sourceImageSize); - // Create a region object native to the sourceImage type TImageType::RegionType largestPossibleRegion; - // Resize the region largestPossibleRegion.SetSize(sourceImageSizeObject); - // Set the largest legal region size (i.e. the size of the whole sourceImage), the buffered, and - // the requested region to what we just defined. sourceImage->SetRegions(largestPossibleRegion); - // Now allocate memory for the sourceImage sourceImage->AllocateInitialized(); - std::cout << "New sourceImage allocated" << std::endl; - - //---------Create and initialize a spatial function----------- + std::cout << "New sourceImage created and allocated" << std::endl; using TFunctionType = itk::SphereSpatialFunction; using TFunctionPositionType = TFunctionType::InputType; - // Create and initialize a new sphere function - auto spatialFunc = TFunctionType::New(); spatialFunc->SetRadius(5); @@ -80,9 +59,6 @@ itkFloodFillIteratorTest(int, char *[]) center[2] = 10; spatialFunc->SetCenter(center); - std::cout << "Sphere spatial function created" << std::endl; - - //---------Create and initialize a spatial function iterator----------- TImageType::IndexType seedPos; constexpr TImageType::IndexValueType pos[]{ 10, 10, 10 }; seedPos.SetIndex(pos); @@ -90,15 +66,14 @@ itkFloodFillIteratorTest(int, char *[]) using TItType = itk::FloodFilledSpatialFunctionConditionalIterator; TItType sfi(sourceImage, spatialFunc, seedPos); - // Iterate through the entire image and set interior pixels to 255 + unsigned int pixelCount{ 0 }; for (; !(sfi.IsAtEnd()); ++sfi) { - std::cout << sfi.GetIndex() << ": " << sfi.Get() << std::endl; sfi.Set(255); + ++pixelCount; } - std::cout << "Spatial function iterator created, sphere drawn" << std::endl; - - return EXIT_SUCCESS; + std::cout << "Sphere drawn with " << pixelCount << " pixels" << std::endl; + EXPECT_GT(pixelCount, 0u); } diff --git a/Modules/Core/Common/test/itkFloodFilledSpatialFunctionTest.cxx b/Modules/Core/Common/test/itkFloodFilledSpatialFunctionGTest.cxx similarity index 62% rename from Modules/Core/Common/test/itkFloodFilledSpatialFunctionTest.cxx rename to Modules/Core/Common/test/itkFloodFilledSpatialFunctionGTest.cxx index 283d385e106..57e01b6a849 100644 --- a/Modules/Core/Common/test/itkFloodFilledSpatialFunctionTest.cxx +++ b/Modules/Core/Common/test/itkFloodFilledSpatialFunctionGTest.cxx @@ -17,68 +17,46 @@ *=========================================================================*/ /* -This file test the various inclusion strategies available -to itkFloodFilledSpatialFunctionConditionalIterator. -*/ - + * Tests the various inclusion strategies available + * to itkFloodFilledSpatialFunctionConditionalIterator. + */ #include "itkImageRegionIterator.h" #include "itkSphereSpatialFunction.h" #include "itkFloodFilledSpatialFunctionConditionalIterator.h" +#include "itkGTest.h" + -int -itkFloodFilledSpatialFunctionTest(int, char *[]) +TEST(FloodFilledSpatialFunction, InclusionStrategies) { constexpr unsigned int dim{ 2 }; - // Image type alias using ImageType = itk::Image; - using SizeValueType = ImageType::SizeValueType; - using SpacingValueType = ImageType::SpacingValueType; - using PointValueType = ImageType::PointValueType; - - // Image size and spacing parameters - SizeValueType sourceImageSize[] = { 5, 5 }; - SpacingValueType sourceImageSpacing[] = { 1.0, 1.0 }; - PointValueType sourceImageOrigin[] = { 0, 0 }; + ImageType::SizeValueType sourceImageSize[] = { 5, 5 }; + ImageType::SpacingValueType sourceImageSpacing[] = { 1.0, 1.0 }; + ImageType::PointValueType sourceImageOrigin[] = { 0, 0 }; - // Creates the sourceImage (but doesn't set the size or allocate memory) auto sourceImage = ImageType::New(); sourceImage->SetOrigin(sourceImageOrigin); sourceImage->SetSpacing(sourceImageSpacing); - // Create a size object native to the sourceImage type ImageType::SizeType sourceImageSizeObject; - - // Set the size object to the array defined earlier sourceImageSizeObject.SetSize(sourceImageSize); - - // Create a region object native to the sourceImage type ImageType::RegionType largestPossibleRegion; - - // Resize the region largestPossibleRegion.SetSize(sourceImageSizeObject); - - // Set the largest legal region size (i.e. the size of the whole sourceImage), the buffered, and - // the requested region to what we just defined. sourceImage->SetRegions(largestPossibleRegion); - - // Now allocate memory for the sourceImage sourceImage->Allocate(); - // Loop over all available iterator strategies for (int strat = 0; strat < 4; ++strat) { - // Initialize the image to hold all 0's + // Initialize the image to all false itk::ImageRegionIterator it(sourceImage, largestPossibleRegion); - for (it.GoToBegin(); !it.IsAtEnd(); ++it) { it.Set(false); } - // Create and initialize a spatial function using FunctionType = itk::SphereSpatialFunction; using FunctionPositionType = FunctionType::InputType; @@ -90,45 +68,36 @@ itkFloodFilledSpatialFunctionTest(int, char *[]) center[1] = 2.5; spatialFunc->SetCenter(center); - // Create and initialize a spatial function iterator ImageType::IndexType seedPos; constexpr ImageType::IndexValueType pos[]{ 2, 2 }; seedPos.SetIndex(pos); using ItType = itk::FloodFilledSpatialFunctionConditionalIterator; - ItType sfi(sourceImage, spatialFunc, seedPos); switch (strat) { case 0: - { sfi.SetOriginInclusionStrategy(); - } - break; + break; case 1: - { sfi.SetCenterInclusionStrategy(); - } - break; + break; case 2: - { sfi.SetCompleteInclusionStrategy(); - } - break; + break; case 3: - { sfi.SetIntersectInclusionStrategy(); - } - } // end switch inclusion strategy + break; + } - // Iterate through the entire image and set interior pixels to 1 + unsigned int setCount{ 0 }; for (sfi.GoToBegin(); !(sfi.IsAtEnd()); ++sfi) { sfi.Set(true); + ++setCount; } - } // end loop over iterator strategies - - return EXIT_SUCCESS; + EXPECT_GT(setCount, 0u) << "Strategy " << strat << " set no pixels"; + } } diff --git a/Modules/Core/Common/test/itkGaussianDerivativeOperatorGTest.cxx b/Modules/Core/Common/test/itkGaussianDerivativeOperatorGTest.cxx new file mode 100644 index 00000000000..13da27ae2e5 --- /dev/null +++ b/Modules/Core/Common/test/itkGaussianDerivativeOperatorGTest.cxx @@ -0,0 +1,119 @@ +/*========================================================================= + * + * 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 "itkGaussianDerivativeOperator.h" +#include "itkStdStreamStateSave.h" +#include "itkGTest.h" + +namespace +{ + +void +TestGaussianOperator(double variance, double error, unsigned int width, unsigned int order, double spacing) +{ + + using GaussianOp = itk::GaussianDerivativeOperator; + + std::cout << "Testing variance: " << variance << " error: " << error << " width: " << width << " order: " << order + << " spacing: " << spacing << std::endl; + + GaussianOp op; + + constexpr bool normalizeAcrossScale{ false }; + ITK_GTEST_SET_GET_BOOLEAN((&op), NormalizeAcrossScale, normalizeAcrossScale); + + op.SetVariance(variance); + EXPECT_DOUBLE_EQ(op.GetVariance(), variance); + + op.SetMaximumError(error); + EXPECT_DOUBLE_EQ(op.GetMaximumError(), error); + + op.SetMaximumKernelWidth(width); + EXPECT_EQ(op.GetMaximumKernelWidth(), width); + + op.SetOrder(order); + EXPECT_EQ(op.GetOrder(), order); + + op.SetSpacing(spacing); + EXPECT_DOUBLE_EQ(op.GetSpacing(), spacing); + + op.CreateDirectional(); + + const double total = std::accumulate(op.Begin(), op.End(), 0.0); + std::cout << "total: " << total << std::endl; + + std::cout.precision(16); + + constexpr double epsilon{ itk::NumericTraits::epsilon() * 32 }; + if (order == 0) + { + EXPECT_NEAR(total, 1.0, epsilon); + } + else + { + EXPECT_NEAR(total, 0.0, epsilon); + } +} + +} // namespace + +TEST(GaussianDerivativeOperator, CoefficientsAndBasicMethods) +{ + // Save the format stream variables for std::cout + // They will be restored when coutState goes out of scope. + const itk::StdStreamStateSave coutState(std::cout); + + // Exercise code + using GaussianOp = itk::GaussianDerivativeOperator; + + GaussianOp op1; + GaussianOp * op1Ptr = &op1; + + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(op1Ptr, GaussianDerivativeOperator, NeighborhoodOperator); + + TestGaussianOperator(.2, .001, 30, 0, 1.0); + TestGaussianOperator(.2, .001, 30, 1, 1.0); + TestGaussianOperator(.2, .001, 30, 2, 1.0); + TestGaussianOperator(.2, .001, 30, 3, 1.0); + TestGaussianOperator(.2, .001, 30, 4, 1.0); + + TestGaussianOperator(1, .001, 30, 0, 1.0); + TestGaussianOperator(1, .001, 30, 1, 1.0); + TestGaussianOperator(1, .001, 30, 2, 1.0); + TestGaussianOperator(1, .001, 30, 3, 1.0); + TestGaussianOperator(1, .001, 30, 4, 1.0); + + TestGaussianOperator(10, .001, 30, 0, 1.0); + TestGaussianOperator(10, .001, 30, 1, 1.0); + + TestGaussianOperator(10, .0001, 100, 1, 1.0); + + TestGaussianOperator(50, .001, 300, 0, 1.0); + + // Test streaming enumeration for GaussianDerivativeOperatorEnums::InterpolationMode elements + const std::set allInterpolationMode{ + itk::GaussianDerivativeOperatorEnums::InterpolationMode::NearestNeighbourInterpolation, + itk::GaussianDerivativeOperatorEnums::InterpolationMode::LinearInterpolation + }; + for (const auto & ee : allInterpolationMode) + { + std::cout << "STREAMED ENUM VALUE GaussianDerivativeOperatorEnums::InterpolationMode: " << ee << std::endl; + } + + std::cout << "Test finished." << std::endl; +} diff --git a/Modules/Core/Common/test/itkGaussianDerivativeOperatorTest.cxx b/Modules/Core/Common/test/itkGaussianDerivativeOperatorTest.cxx deleted file mode 100644 index 2d802976e2c..00000000000 --- a/Modules/Core/Common/test/itkGaussianDerivativeOperatorTest.cxx +++ /dev/null @@ -1,182 +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 "itkGaussianDerivativeOperator.h" -#include "itkStdStreamStateSave.h" -#include "itkTestingMacros.h" - -namespace -{ - -bool -TestGaussianOperator(double variance, double error, unsigned int width, unsigned int order, double spacing) -{ - - using GaussianOp = itk::GaussianDerivativeOperator; - - std::cout << "Testing variance: " << variance << " error: " << error << " width: " << width << " order: " << order - << " spacing: " << spacing << std::endl; - - GaussianOp op; - - constexpr bool normalizeAcrossScale{ false }; - ITK_TEST_SET_GET_BOOLEAN((&op), NormalizeAcrossScale, normalizeAcrossScale); - - op.SetVariance(variance); - ITK_TEST_SET_GET_VALUE(variance, op.GetVariance()); - - op.SetMaximumError(error); - ITK_TEST_SET_GET_VALUE(error, op.GetMaximumError()); - - op.SetMaximumKernelWidth(width); - ITK_TEST_SET_GET_VALUE(width, op.GetMaximumKernelWidth()); - - op.SetOrder(order); - ITK_TEST_SET_GET_VALUE(order, op.GetOrder()); - - op.SetSpacing(spacing); - ITK_TEST_SET_GET_VALUE(spacing, op.GetSpacing()); - - op.CreateDirectional(); - - const double total = std::accumulate(op.Begin(), op.End(), 0.0); - std::cout << "total: " << total << std::endl; - - std::cout.precision(16); - - constexpr double epsilon{ itk::NumericTraits::epsilon() * 32 }; - if (order == 0 && itk::Math::Absolute(total - 1.0) > epsilon) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error in coefficients." << std::endl; - std::cerr << "Expected coefficients to sum to 1.0: " << std::endl; - std::cerr << "Actual value: " << total << std::endl; - std::cerr << " differs from 1.0 "; - std::cerr << " by more than " << epsilon << std::endl; - } - else if (order != 0 && itk::Math::Absolute(total) > epsilon) - { - std::cerr << "Test failed!" << std::endl; - std::cerr << "Error in coefficients." << std::endl; - std::cerr << "Expected coefficients to sum to 0.0." << std::endl; - std::cerr << "Actual value: " << total << std::endl; - std::cerr << " differs from 0.0 "; - std::cerr << " by more than " << epsilon << std::endl; - } - else - { - return true; - } - - std::cout << "---operator---" << std::endl; - GaussianOp::Iterator i = op.Begin(); - i += op.Size() / 2; - for (; i != op.End(); ++i) - { - std::cout << *i << std::endl; - } - std::cout << "---end--" << std::endl; - - return false; -} - -} // namespace - -int -itkGaussianDerivativeOperatorTest(int argc, char * argv[]) -{ - - // Save the format stream variables for std::cout - // They will be restored when coutState goes out of scope. - const itk::StdStreamStateSave coutState(std::cout); - - if (argc == 6) - { - const double variance = std::stod(argv[1]); - const double error = std::stod(argv[2]); - const unsigned int width = std::stoi(argv[3]); - const unsigned int order = std::stoi(argv[4]); - const double spacing = std::stod(argv[5]); - - TestGaussianOperator(variance, error, width, order, spacing); - - std::cout << "Test finished." << std::endl; - return EXIT_SUCCESS; - } - if (argc > 1) - { - std::cerr << "Missing Parameters." << std::endl; - std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " [variance error width order spacing]" - << std::endl; - return EXIT_FAILURE; - } - - // At this point, obviously, argc <= 1. In some scenarios, argc == 0, typically when - // the test function is called from the interactive TestDriver commandline interface, - // by having the user entering its test number. On the other hand, argc == 1 when the - // the TestDriver has the name of the test function as its only commandline argument. - // In either way the tests below here should be performed. - - // Exercise code - - using GaussianOp = itk::GaussianDerivativeOperator; - - GaussianOp op1; - - ITK_EXERCISE_BASIC_OBJECT_METHODS((&op1), GaussianDerivativeOperator, NeighborhoodOperator); - - // Check assignment - bool testStatus = true; - - testStatus &= TestGaussianOperator(.2, .001, 30, 0, 1.0); - testStatus &= TestGaussianOperator(.2, .001, 30, 1, 1.0); - testStatus &= TestGaussianOperator(.2, .001, 30, 2, 1.0); - testStatus &= TestGaussianOperator(.2, .001, 30, 3, 1.0); - testStatus &= TestGaussianOperator(.2, .001, 30, 4, 1.0); - - testStatus &= TestGaussianOperator(1, .001, 30, 0, 1.0); - testStatus &= TestGaussianOperator(1, .001, 30, 1, 1.0); - testStatus &= TestGaussianOperator(1, .001, 30, 2, 1.0); - testStatus &= TestGaussianOperator(1, .001, 30, 3, 1.0); - testStatus &= TestGaussianOperator(1, .001, 30, 4, 1.0); - - testStatus &= TestGaussianOperator(10, .001, 30, 0, 1.0); - testStatus &= TestGaussianOperator(10, .001, 30, 1, 1.0); - - testStatus &= TestGaussianOperator(10, .0001, 100, 1, 1.0); - - testStatus &= TestGaussianOperator(50, .001, 300, 0, 1.0); - - // Test streaming enumeration for GaussianDerivativeOperatorEnums::InterpolationMode elements - const std::set allInterpolationMode{ - itk::GaussianDerivativeOperatorEnums::InterpolationMode::NearestNeighbourInterpolation, - itk::GaussianDerivativeOperatorEnums::InterpolationMode::LinearInterpolation - }; - for (const auto & ee : allInterpolationMode) - { - std::cout << "STREAMED ENUM VALUE GaussianDerivativeOperatorEnums::InterpolationMode: " << ee << std::endl; - } - - std::cout << "Test finished." << std::endl; - if (testStatus) - { - return EXIT_SUCCESS; - } - - return EXIT_FAILURE; -} diff --git a/Modules/Core/Common/test/itkHashTableTest.cxx b/Modules/Core/Common/test/itkHashTableGTest.cxx similarity index 82% rename from Modules/Core/Common/test/itkHashTableTest.cxx rename to Modules/Core/Common/test/itkHashTableGTest.cxx index 2a3161e3c2e..5699d134a8a 100644 --- a/Modules/Core/Common/test/itkHashTableTest.cxx +++ b/Modules/Core/Common/test/itkHashTableGTest.cxx @@ -16,6 +16,8 @@ * *=========================================================================*/ +#include "itkGTest.h" + #include #include #include @@ -51,20 +53,33 @@ println(const char * s) std::cout << std::endl << s << std::endl; } -int -itkHashTableTest(int, char *[]) +TEST(HashTable, StdHash) { println("Testing std::hash"); constexpr std::hash H; + // Note: std::hash is pointer-based; values are platform-dependent std::cout << "foo -> " << H("foo") << std::endl; std::cout << "bar -> " << H("bar") << std::endl; + constexpr std::hash H1; std::cout << "1 -> " << H1(1) << std::endl; std::cout << "234 -> " << H1(234) << std::endl; + // std::hash must return the same value for equal keys (standard guarantee) + EXPECT_EQ(H1(1), H1(1)); + EXPECT_EQ(H1(234), H1(234)); + EXPECT_NE(H1(1), H1(234)); + constexpr std::hash H2; std::cout << "a -> " << H2('a') << std::endl; std::cout << "Z -> " << H2('Z') << std::endl; + // std::hash must return the same value for equal keys (standard guarantee) + EXPECT_EQ(H2('a'), H2('a')); + EXPECT_EQ(H2('Z'), H2('Z')); + EXPECT_NE(H2('a'), H2('Z')); +} +TEST(HashTable, UnorderedSet) +{ println("Testing std::unordered_set"); using HashSetType = std::unordered_set, eqstr>; HashSetType Set; @@ -76,8 +91,11 @@ itkHashTableTest(int, char *[]) Set.insert("banana"); lookup(Set, "mango"); + EXPECT_TRUE(Set.count("mango") > 0); lookup(Set, "apple"); + EXPECT_TRUE(Set.count("apple") > 0); lookup(Set, "durian"); + EXPECT_FALSE(Set.count("durian") > 0); // CppCheck gives us a warning if the return value isn't used. // This is to prevent the user from calling empty() when they mean clear(). @@ -89,7 +107,11 @@ itkHashTableTest(int, char *[]) Set.insert("the horror"); auto hsh_it = Set.begin(); const HashSetType SetCopy = Set; + IgnoreUnusedVariable(hsh_it); +} +TEST(HashTable, UnorderedMap) +{ println("Testing std::unordered_map"); using HashMapType = std::unordered_map, eqstr>; @@ -112,6 +134,11 @@ itkHashTableTest(int, char *[]) std::cout << "june -> " << months["june"] << std::endl; std::cout << "november -> " << months["november"] << std::endl; + EXPECT_EQ(months["september"], 30); + EXPECT_EQ(months["april"], 30); + EXPECT_EQ(months["june"], 30); + EXPECT_EQ(months["november"], 30); + // CppCheck gives us a warning if the return value isn't used. // This is to prevent the user from calling empty() when they mean clear(). if (months.empty()) @@ -123,9 +150,5 @@ itkHashTableTest(int, char *[]) months.insert(p); auto map_it = months.begin(); const HashMapType MapCopy = months; - - IgnoreUnusedVariable(hsh_it); IgnoreUnusedVariable(map_it); - - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkHeavisideStepFunctionGTest.cxx b/Modules/Core/Common/test/itkHeavisideStepFunctionGTest.cxx new file mode 100644 index 00000000000..7b131db24f3 --- /dev/null +++ b/Modules/Core/Common/test/itkHeavisideStepFunctionGTest.cxx @@ -0,0 +1,157 @@ +/*========================================================================= + * + * 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 "itkHeavisideStepFunction.h" +#include "itkSinRegularizedHeavisideStepFunction.h" +#include "itkAtanRegularizedHeavisideStepFunction.h" +#include "itkMath.h" +#include "itkGTest.h" + +#include + +// From itkHeavisideStepFunctionTest1.cxx +TEST(HeavisideStepFunction, ExactHeaviside) +{ + using InputType = double; + using OutputType = double; + + using HeavisideFunctionBaseType = itk::HeavisideStepFunction; + + auto functionBase0 = HeavisideFunctionBaseType::New(); + + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(functionBase0, HeavisideStepFunction, HeavisideStepFunctionBase); + + std::cout << "GetNameOfClass() = " << functionBase0->GetNameOfClass() << std::endl; + functionBase0->Print(std::cout); + + constexpr int minValue{ -20 }; + constexpr int maxValue{ 20 }; + + constexpr InputType incValue{ 0.1 }; + + for (int x = minValue; x < maxValue; ++x) + { + const InputType ix = x * incValue; + const OutputType f = functionBase0->Evaluate(ix); + const OutputType df = functionBase0->EvaluateDerivative(ix); + std::cout << ix << ' ' << f << ' ' << df << std::endl; + if (ix < 0.0) + { + EXPECT_EQ(f, 0.0); + EXPECT_EQ(df, 0.0); + } + else + { + EXPECT_EQ(f, 1.0); + } + } +} + +// From itkSinRegularizedHeavisideStepFunctionTest1.cxx +TEST(HeavisideStepFunction, SinRegularized) +{ + using InputType = double; + using OutputType = double; + + using HeavisideFunctionBaseType = itk::SinRegularizedHeavisideStepFunction; + + auto functionBase0 = HeavisideFunctionBaseType::New(); + + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS( + functionBase0, SinRegularizedHeavisideStepFunction, HeavisideStepFunctionBase); + + std::cout << "GetNameOfClass() = " << functionBase0->GetNameOfClass() << std::endl; + functionBase0->Print(std::cout); + + constexpr double epsilon{ -1.0 }; + EXPECT_THROW(functionBase0->SetEpsilon(epsilon), itk::ExceptionObject); + + constexpr double epsilon0{ 1.0 }; + constexpr double epsilon1{ 1e-4 }; + + EXPECT_EQ(functionBase0->GetEpsilon(), epsilon0); + + functionBase0->SetEpsilon(epsilon1); + EXPECT_EQ(functionBase0->GetEpsilon(), epsilon1); + + constexpr double epsilon2{ 0.5 }; + functionBase0->SetEpsilon(epsilon2); + + constexpr int minValue{ -20 }; + constexpr int maxValue{ 20 }; + + constexpr InputType incValue{ 0.1 }; + + for (int x = minValue; x < maxValue; ++x) + { + const InputType ix = x * incValue; + const OutputType f = functionBase0->Evaluate(ix); + const OutputType df = functionBase0->EvaluateDerivative(ix); + std::cout << ix << ' ' << f << ' ' << df << std::endl; + } + // At x=0 with epsilon=0.5: Evaluate = 0.5, EvaluateDerivative = pi/2 + EXPECT_NEAR(functionBase0->Evaluate(0.0), 0.5, 1e-10); + EXPECT_NEAR(functionBase0->EvaluateDerivative(0.0), itk::Math::pi / 2.0, 1e-4); +} + +// From itkAtanRegularizedHeavisideStepFunctionTest1.cxx +TEST(HeavisideStepFunction, AtanRegularized) +{ + using InputType = double; + using OutputType = double; + + using HeavisideFunctionBaseType = itk::AtanRegularizedHeavisideStepFunction; + + auto functionBase0 = HeavisideFunctionBaseType::New(); + + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS( + functionBase0, AtanRegularizedHeavisideStepFunction, HeavisideStepFunctionBase); + + std::cout << "GetNameOfClass() = " << functionBase0->GetNameOfClass() << std::endl; + functionBase0->Print(std::cout); + + constexpr double epsilon{ -1.0 }; + EXPECT_THROW(functionBase0->SetEpsilon(epsilon), itk::ExceptionObject); + + constexpr double epsilon0{ 1.0 }; + constexpr double epsilon1{ 1e-4 }; + + EXPECT_EQ(functionBase0->GetEpsilon(), epsilon0); + + functionBase0->SetEpsilon(epsilon1); + EXPECT_EQ(functionBase0->GetEpsilon(), epsilon1); + + constexpr double epsilon2{ 0.5 }; + functionBase0->SetEpsilon(epsilon2); + + constexpr int minValue{ -20 }; + constexpr int maxValue{ 20 }; + + constexpr InputType incValue{ 0.1 }; + + for (int x = minValue; x < maxValue; ++x) + { + const InputType ix = x * incValue; + const OutputType f = functionBase0->Evaluate(ix); + const OutputType df = functionBase0->EvaluateDerivative(ix); + std::cout << ix << ' ' << f << ' ' << df << std::endl; + } + // At x=0 with epsilon=0.5: Evaluate = 0.5, EvaluateDerivative = 2/pi ≈ 0.63662 + EXPECT_NEAR(functionBase0->Evaluate(0.0), 0.5, 1e-10); + EXPECT_NEAR(functionBase0->EvaluateDerivative(0.0), 2.0 / itk::Math::pi, 1e-4); +} diff --git a/Modules/Core/Common/test/itkImageTransformTest.cxx b/Modules/Core/Common/test/itkImageTransformGTest.cxx similarity index 75% rename from Modules/Core/Common/test/itkImageTransformTest.cxx rename to Modules/Core/Common/test/itkImageTransformGTest.cxx index 8ebd798dc88..95adb3308c3 100644 --- a/Modules/Core/Common/test/itkImageTransformTest.cxx +++ b/Modules/Core/Common/test/itkImageTransformGTest.cxx @@ -17,9 +17,12 @@ *=========================================================================*/ #include "itkImage.h" +#include "itkGTest.h" #include -#include + +namespace +{ template void @@ -31,7 +34,6 @@ TestTransform() auto orientedImage = ImageType::New(); typename ImageType::PointType origin; - for (unsigned int i = 0; i < TDimension; ++i) { origin[i] = static_cast(i * 100); @@ -41,40 +43,35 @@ TestTransform() using RegionType = itk::ImageRegion; using IndexType = typename RegionType::IndexType; - using SizeType = typename RegionType::SizeType; typename ImageType::PointType point; - RegionType region; - - auto size = SizeType::Filled(10); - region.SetSize(size); auto index = IndexType::Filled(5); - std::cout << "TransformIndexToPhysicalPoint..." << std::endl; + std::cout << "TransformIndexToPhysicalPoint (dim=" << TDimension << ")..." << std::endl; orientedImage->TransformIndexToPhysicalPoint(index, point); - std::cout << " Image: " << index << " -> " << point << std::endl; + std::cout << " OrientedImage: " << index << " -> " << point << std::endl; image->TransformIndexToPhysicalPoint(index, point); std::cout << " Image: " << index << " -> " << point << std::endl; - std::cout << "TransformPhysicalPointToIndex..." << std::endl; + std::cout << "TransformPhysicalPointToIndex (dim=" << TDimension << ")..." << std::endl; const bool isInsideOrientedImage = orientedImage->TransformPhysicalPointToIndex(point, index); - std::cout << " Image: " << point << " -> " << index << (isInsideOrientedImage ? " inside" : " outside") + std::cout << " OrientedImage: " << point << " -> " << index << (isInsideOrientedImage ? " inside" : " outside") << std::endl; - const bool isInsideImage = image->TransformPhysicalPointToIndex(point, index); + [[maybe_unused]] const bool isInsideImage = image->TransformPhysicalPointToIndex(point, index); std::cout << " Image: " << point << " -> " << index << (isInsideImage ? " inside" : " outside") << std::endl; } -int -itkImageTransformTest(int, char *[]) +} // namespace + + +TEST(ImageTransform, TransformIndexAndPoint) { TestTransform<8>(); TestTransform<3>(); TestTransform<2>(); TestTransform<1>(); - - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkImportContainerTest.cxx b/Modules/Core/Common/test/itkImportContainerGTest.cxx similarity index 83% rename from Modules/Core/Common/test/itkImportContainerTest.cxx rename to Modules/Core/Common/test/itkImportContainerGTest.cxx index 4b968fc68bc..688f8f3798c 100644 --- a/Modules/Core/Common/test/itkImportContainerTest.cxx +++ b/Modules/Core/Common/test/itkImportContainerGTest.cxx @@ -20,9 +20,9 @@ #include "itkImportImageContainer.h" #include "itkNumericTraits.h" #include "itkTextOutput.h" +#include "itkGTest.h" -int -itkImportContainerTest(int, char *[]) +TEST(ImportContainer, ReserveAndSqueeze) { using PixelType = float; using ContainerType = itk::ImportImageContainer; @@ -37,12 +37,16 @@ itkImportContainerTest(int, char *[]) container1->Print(std::cout); std::cout << "After New(), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 0ul); + EXPECT_EQ(container1->Capacity(), 0ul); // Test 2: Reserve memory container1->Reserve(1000); std::cout << "After container1->Reserve(1000), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 1000ul); + EXPECT_EQ(container1->Capacity(), 1000ul); // Take control of the pointer container1->ContainerManageMemoryOff(); @@ -52,17 +56,23 @@ itkImportContainerTest(int, char *[]) container1->Reserve(100); std::cout << "After container1->Reserve(100), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 100ul); + EXPECT_EQ(container1->Capacity(), 1000ul); // capacity stays 1000 when not managing memory // Test 4: Squeeze the container container1->Squeeze(); std::cout << "After container1->Squeeze() size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 100ul); + EXPECT_EQ(container1->Capacity(), 100ul); // Test 5: Initialize the container container1->Initialize(); std::cout << "After container1->Initialize() size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 0ul); + EXPECT_EQ(container1->Capacity(), 0ul); } // now repeat the tests with a user provided pointer @@ -84,34 +94,27 @@ itkImportContainerTest(int, char *[]) container1->Reserve(1000); std::cout << "After container1->Reserve(1000), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 1000ul); + EXPECT_EQ(container1->Capacity(), 2000ul); - if (*(myPtr + 500) != 500.0) - { - std::cout << "Test failed: After container1->Reserve(1000), container1[500] does != 500." << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(*(myPtr + 500), 500.0f); // Test 3: Reserve more memory than capacity container1->Reserve(10000); std::cout << "After container1->Reserve(100), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; - if (*(myPtr + 500) != 500.0) - { - std::cout << "Test failed: After container1->Reserve(10000), container1[500] does != 500." << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(container1->Size(), 10000ul); + EXPECT_EQ(container1->Capacity(), 10000ul); + EXPECT_EQ(*(myPtr + 500), 500.0f); // Test 4: Squeeze the container container1->Squeeze(); std::cout << "After container1->Squeeze() size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; - - if (*(myPtr + 500) != 500.0) - { - std::cout << "Test failed: After container1->Squeeze(), container1[500] does != 500." << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(container1->Size(), 10000ul); + EXPECT_EQ(container1->Capacity(), 10000ul); + EXPECT_EQ(*(myPtr + 500), 500.0f); // Test 5: Initialize the container container1->Initialize(); @@ -126,27 +129,37 @@ itkImportContainerTest(int, char *[]) container1->Print(std::cout); std::cout << "After New(), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 0ul); + EXPECT_EQ(container1->Capacity(), 0ul); // Test 2: Reserve memory container1->Reserve(1000); std::cout << "After container1->Reserve(1000), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 1000ul); + EXPECT_EQ(container1->Capacity(), 1000ul); // Test 3: Reserve a smaller amount of memory container1->Reserve(100); std::cout << "After container1->Reserve(100), size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 100ul); + EXPECT_EQ(container1->Capacity(), 1000ul); // Test 4: Squeeze the container container1->Squeeze(); std::cout << "After container1->Squeeze() size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 100ul); + EXPECT_EQ(container1->Capacity(), 100ul); // Test 5: Initialize the container container1->Initialize(); std::cout << "After container1->Initialize() size is " << container1->Size() << ", capacity is " << container1->Capacity() << " and import pointer is " << container1->GetImportPointer() << std::endl; + EXPECT_EQ(container1->Size(), 0ul); + EXPECT_EQ(container1->Capacity(), 0ul); } // valgrind has problems with exceptions after a failed memory @@ -174,11 +187,9 @@ itkImportContainerTest(int, char *[]) delete[] myPtr; #if (defined(NDEBUG)) - if (!caughtException && (sizeof(void *) != 8)) + if (sizeof(void *) != 8) { - std::cout << "Failed to catch expected exception" << std::endl; - return EXIT_FAILURE; + EXPECT_TRUE(caughtException); } #endif - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkImportImageTest.cxx b/Modules/Core/Common/test/itkImportImageGTest.cxx similarity index 58% rename from Modules/Core/Common/test/itkImportImageTest.cxx rename to Modules/Core/Common/test/itkImportImageGTest.cxx index 24e1a997c27..8a1488a4277 100644 --- a/Modules/Core/Common/test/itkImportImageTest.cxx +++ b/Modules/Core/Common/test/itkImportImageGTest.cxx @@ -16,43 +16,41 @@ * *=========================================================================*/ -#include #include "itkImageRegionIterator.h" #include "itkShrinkImageFilter.h" #include "itkImportImageFilter.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" +#include "itkMath.h" + +#include + -int -itkImportImageTest(int, char *[]) +TEST(ImportImageFilter, ImportAndShrink) { // Create a C-array to hold an image auto * rawImage = new short[8 * 12]; for (unsigned int i = 0; i < 8 * 12; ++i) { - rawImage[i] = i; + rawImage[i] = static_cast(i); } - // typedefs to simplify the syntax + constexpr unsigned int Dimension{ 2 }; using PixelType = short; using ImportImageFilter = itk::ImportImageFilter; using ShortImage = itk::Image; - // Create an ImportImageFilter filter + // Test basic object methods auto basicImport = ImportImageFilter::New(); - - ITK_EXERCISE_BASIC_OBJECT_METHODS(basicImport, ImportImageFilter, ImageSource); + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(basicImport, ImportImageFilter, ImageSource); ShortImage::Pointer image; constexpr itk::ImageRegion::SizeType size = { { 8, 12 } }; itk::ImageRegion region = { size }; - // local scope to make sure that imported data is not deleted with ImportImageFilter - // but with the ImportImageContainer is creates. + { - // Create an ImportImageFilter filter const ImportImageFilter::Pointer import = ImportImageFilter::New(); - // Test the SetVectorMacros and GetVectorMacros constexpr itk::SpacePrecisionType data[2]{ 1.0, 1.0 }; import->SetSpacing(data); @@ -76,50 +74,24 @@ itkImportImageTest(int, char *[]) import->Update(); image = import->GetOutput(); } - // Create another filter + const itk::ShrinkImageFilter::Pointer shrink = itk::ShrinkImageFilter::New(); shrink->SetInput(image); - shrink->SetShrinkFactors(2); // Also tested with factors 3 and 4, with 12x12 image - - ITK_TRY_EXPECT_NO_EXCEPTION(shrink->Update()); - - // - // The rest of this code determines whether the shrink code produced - // the image we expected. - // - const ShortImage::RegionType requestedRegion = shrink->GetOutput()->GetRequestedRegion(); + shrink->SetShrinkFactors(2); + EXPECT_NO_THROW(shrink->Update()); + const ShortImage::RegionType requestedRegion = shrink->GetOutput()->GetRequestedRegion(); itk::ImageRegionIterator iterator2(shrink->GetOutput(), requestedRegion); - bool passed = true; for (; !iterator2.IsAtEnd(); ++iterator2) { std::cout << "Pixel " << iterator2.ComputeIndex() << " = " << iterator2.Get() << std::endl; - if (iterator2.Get() != - itk::Math::RoundHalfIntegerUp(static_cast( - (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[0] + shrink->GetShrinkFactors()[0] / 2) + - (region.GetSize()[0] * - ((shrink->GetShrinkFactors()[1] / 2) + (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[1])))))) - { - std::cout << " iterator2.GetIndex() Get() " << iterator2.ComputeIndex() << ' ' << iterator2.Get() - << " compare value " - << itk::Math::RoundHalfIntegerUp(static_cast( - (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[0] + shrink->GetShrinkFactors()[0] / 2) + - (region.GetSize()[0] * ((shrink->GetShrinkFactors()[1] / 2) + - (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[1]))))) - << '\n'; - passed = false; - } + const short expectedValue = itk::Math::RoundHalfIntegerUp(static_cast( + (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[0] + shrink->GetShrinkFactors()[0] / 2) + + (region.GetSize()[0] * + ((shrink->GetShrinkFactors()[1] / 2) + (shrink->GetShrinkFactors()[0] * iterator2.ComputeIndex()[1]))))); + EXPECT_EQ(iterator2.Get(), expectedValue) << "Pixel mismatch at " << iterator2.ComputeIndex(); } - - if (passed) - { - std::cout << "ImportImageFilter test passed." << std::endl; - return EXIT_SUCCESS; - } - - std::cout << "ImportImageFilter test failed." << std::endl; - return EXIT_FAILURE; } 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/itkMersenneTwisterRandomVariateGeneratorGTest.cxx b/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorGTest.cxx index 666c9a222b2..3aeb78ae148 100644 --- a/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorGTest.cxx +++ b/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorGTest.cxx @@ -16,9 +16,14 @@ * *=========================================================================*/ +#ifndef ITK_FUTURE_LEGACY_REMOVE +# define ITK_LEGACY_SILENT +#endif + // First include the header file to be tested: #include "itkMersenneTwisterRandomVariateGenerator.h" -#include +#include "itkGTest.h" +#include "itkMath.h" #include // For mt19937. // The class to be tested. @@ -100,3 +105,78 @@ TEST(MersenneTwisterRandomVariateGenerator, ResetNextSeed) MersenneTwisterRandomVariateGenerator::ResetNextSeed(); EXPECT_EQ(MersenneTwisterRandomVariateGenerator::GetNextSeed(), seed); } + + +TEST(MersenneTwisterRandomVariateGenerator, BasicObjectMethods) +{ + auto twister = MersenneTwisterRandomVariateGenerator::New(); + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS(twister, MersenneTwisterRandomVariateGenerator, RandomVariateGeneratorBase); +} + + +TEST(MersenneTwisterRandomVariateGenerator, SingletonSeedAndKnownSequence) +{ + using Twister = MersenneTwisterRandomVariateGenerator; + constexpr Twister::IntegerType seed{ 1234 }; + + Twister::GetInstance()->SetSeed(seed); + EXPECT_EQ(Twister::GetInstance()->GetSeed(), seed); + + auto twister = Twister::New(); + + // New instance gets seed = singleton's seed + 1 + EXPECT_EQ(Twister::GetInstance()->GetSeed() + 1, twister->GetSeed()); + + // Sync seeds and verify same sequence + twister->SetSeed(Twister::GetInstance()->GetSeed()); + for (int i = 0; i < 200; ++i) + { + EXPECT_EQ(Twister::GetInstance()->GetIntegerVariate(), twister->GetIntegerVariate()); + } + + // Check known sequence of values + constexpr Twister::IntegerType expected[5]{ static_cast(3294740812u), + static_cast(4175194053u), + static_cast(3041332341u), + static_cast(199851601u), + static_cast(3422518480u) }; + for (const auto i : expected) + { + EXPECT_EQ(twister->GetIntegerVariate(), i); + } +} + + +TEST(MersenneTwisterRandomVariateGenerator, NormalVariateStatistics) +{ + auto twister = MersenneTwisterRandomVariateGenerator::New(); + + double sum = 0.0; + double sum2 = 0.0; + constexpr int count{ 500000 }; + for (int i = 0; i < count; ++i) + { + const double v = twister->GetNormalVariate(); + sum += v; + sum2 += v * v; + } + const double mean = sum / static_cast(count); + const double variance = sum2 / static_cast(count) - mean * mean; + EXPECT_NEAR(mean, 0.0, 0.01); + EXPECT_NEAR(variance, 1.0, 0.01); +} + + +#ifndef ITK_FUTURE_LEGACY_REMOVE +TEST(MersenneTwisterRandomVariateGenerator, LegacyInitializeEqualSetSeed) +{ + auto twister = MersenneTwisterRandomVariateGenerator::New(); + + twister->Initialize(); + twister->SetSeed(1234); + const MersenneTwisterRandomVariateGenerator::IntegerType withSetSeed = twister->GetIntegerVariate(); + twister->Initialize(1234); + const MersenneTwisterRandomVariateGenerator::IntegerType withInitialize = twister->GetIntegerVariate(); + EXPECT_EQ(withSetSeed, withInitialize); +} +#endif diff --git a/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorTest.cxx b/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorTest.cxx deleted file mode 100644 index 07eb6c1988a..00000000000 --- a/Modules/Core/Common/test/itkMersenneTwisterRandomVariateGeneratorTest.cxx +++ /dev/null @@ -1,125 +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_FUTURE_LEGACY_REMOVE -# define ITK_LEGACY_SILENT -#endif - -#include "itkMersenneTwisterRandomVariateGenerator.h" -#include "itkTestingMacros.h" - -#include - - -int -itkMersenneTwisterRandomVariateGeneratorTest(int, char *[]) -{ - - using Twister = itk::Statistics::MersenneTwisterRandomVariateGenerator; - - constexpr Twister::IntegerType seed{ 1234 }; - - // Test Get/SetSeed - Twister::GetInstance()->SetSeed(seed); - ITK_TEST_SET_GET_VALUE(seed, Twister::GetInstance()->GetSeed()); - - auto twister = Twister::New(); - - ITK_EXERCISE_BASIC_OBJECT_METHODS(twister, MersenneTwisterRandomVariateGenerator, RandomVariateGeneratorBase); - - // Does the new instance have the same seed? - if (Twister::GetInstance()->GetSeed() + 1 != twister->GetSeed()) - { - std::cerr << "New instance does not have the next seed!" << std::endl; - return EXIT_FAILURE; - } - - twister->SetSeed(Twister::GetInstance()->GetSeed()); - - // Check that we get the same series of numbers from the two. Use integers. - for (int i = 0; i < 200; ++i) - { - if (Twister::GetInstance()->GetIntegerVariate() != twister->GetIntegerVariate()) - { - std::cerr << "Singleton and new instance deviated at " << i << "th iteration" << std::endl; - return EXIT_FAILURE; - } - } - - // Ensure we get the same series of numbers - constexpr Twister::IntegerType expected[5]{ static_cast(3294740812u), - static_cast(4175194053u), - static_cast(3041332341u), - static_cast(199851601u), - static_cast(3422518480u) }; - - bool sameSequence = true; - for (const auto i : expected) - { - const Twister::IntegerType actual = twister->GetIntegerVariate(); - if (actual != i) - { - std::cout << "GetIntegerVariate: expected " << i << " got " << actual << std::endl; - sameSequence = false; - } - } - if (!sameSequence) - { - return EXIT_FAILURE; - } - - // Do we get roughly zero mean and unit variance? - // NB: requires a large number of iterations to have variance converge... - double sum = 0.0; - double sum2 = 0.0; - constexpr int count{ 500000 }; - for (int i = 0; i < count; ++i) - { - const double v = twister->GetNormalVariate(); - sum += v; - sum2 += v * v; - } - const double mean = sum / static_cast(count); - const double variance = sum2 / static_cast(count) - mean * mean; - if (itk::Math::Absolute(mean) > 0.01) - { - std::cerr << "Mean was " << mean << " expected 0.0 " << std::endl; - return EXIT_FAILURE; - } - if (itk::Math::Absolute(variance - 1.0) > 0.01) - { - std::cerr << "Variance was " << variance << " expected 1.0 " << std::endl; - return EXIT_FAILURE; - } - -#ifndef ITK_FUTURE_LEGACY_REMOVE - twister->Initialize(); - twister->SetSeed(1234); - const Twister::IntegerType withSetSeed = twister->GetIntegerVariate(); - twister->Initialize(1234); - const Twister::IntegerType withInitialize = twister->GetIntegerVariate(); - if (withSetSeed != withInitialize) - { - std::cerr << "Result initializing with SetSeed() did not equal result with Initialize()." << std::endl; - return EXIT_FAILURE; - } -#endif - - 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/itkPixelAccessTest.cxx b/Modules/Core/Common/test/itkPixelAccessGTest.cxx similarity index 89% rename from Modules/Core/Common/test/itkPixelAccessTest.cxx rename to Modules/Core/Common/test/itkPixelAccessGTest.cxx index 2c997baafe5..962992d1753 100644 --- a/Modules/Core/Common/test/itkPixelAccessTest.cxx +++ b/Modules/Core/Common/test/itkPixelAccessGTest.cxx @@ -16,10 +16,10 @@ * *=========================================================================*/ -#include - #include "itkImage.h" +#include "itkGTest.h" +#include // This routine is used to make sure that we call the "const" version // of GetPixel() (via the operator[]) @@ -42,8 +42,7 @@ TestConstPixelAccess(const itk::Image & in, itk::Image, 3>::Pointer o3 = @@ -78,10 +77,15 @@ itkPixelAccessTest(int, char *[]) vec[3] = 2; vec[4] = 1; - (*o3)[regionStartIndex3D] = vec; (*o3)[regionEndIndex3D] = (*o3)[regionStartIndex3D]; TestConstPixelAccess(*o3, *o3); - return EXIT_SUCCESS; + // Verify the pixel values were set correctly + const itk::Vector readVec = (*o3)[regionStartIndex3D]; + EXPECT_EQ(readVec[0], 5u); + EXPECT_EQ(readVec[1], 4u); + EXPECT_EQ(readVec[2], 3u); + EXPECT_EQ(readVec[3], 2u); + EXPECT_EQ(readVec[4], 1u); } diff --git a/Modules/Core/Common/test/itkStdStreamStateSaveTest.cxx b/Modules/Core/Common/test/itkStdStreamStateSaveGTest.cxx similarity index 80% rename from Modules/Core/Common/test/itkStdStreamStateSaveTest.cxx rename to Modules/Core/Common/test/itkStdStreamStateSaveGTest.cxx index a1b8381122a..55d147422d1 100644 --- a/Modules/Core/Common/test/itkStdStreamStateSaveTest.cxx +++ b/Modules/Core/Common/test/itkStdStreamStateSaveGTest.cxx @@ -16,14 +16,12 @@ * *=========================================================================*/ -#include "itkTestingMacros.h" #include "itkStdStreamStateSave.h" +#include "itkGTest.h" #include -#include -int -itkStdStreamStateSaveTest(int, char *[]) +TEST(StdStreamStateSave, RestoresCoutState) { // Set the fillch of std::cout with an explicit default fill character std::cout.fill(' '); @@ -55,10 +53,24 @@ itkStdStreamStateSaveTest(int, char *[]) } // coutState goes out of scope and will restore original format state + // Verify that the default is reset for std::cout + EXPECT_EQ(std::cout.precision(), defaultPrecision); + EXPECT_EQ(std::cout.width(), defaultWidth); + EXPECT_EQ(std::cout.fill(), defaultFill); + EXPECT_EQ(std::cout.flags(), defaultFlags); +} + +TEST(StdStreamStateSave, RestoresStringStreamState) +{ std::stringstream stream; // Set the fillch of std::stringstream with an explicit default fill character stream.fill(' '); + const std::streamsize defaultPrecision = stream.precision(); + const std::streamsize defaultWidth = stream.width(); + const char defaultFill = stream.fill(); + const std::ios_base::fmtflags defaultFlags = stream.flags(); + constexpr int originalInt{ 10 }; { const itk::StdStreamStateSave sstreamState(stream); @@ -86,18 +98,10 @@ itkStdStreamStateSaveTest(int, char *[]) // is still in effect. int inputInt = 0; stream >> inputInt; - ITK_TEST_EXPECT_EQUAL(originalInt, inputInt); - - // Verify that the default is reset for std::cout - ITK_TEST_EXPECT_EQUAL(std::cout.precision(), defaultPrecision); - ITK_TEST_EXPECT_EQUAL(std::cout.width(), defaultWidth); - ITK_TEST_EXPECT_EQUAL(std::cout.fill(), defaultFill); - ITK_TEST_EXPECT_EQUAL(std::cout.flags(), defaultFlags); - - ITK_TEST_EXPECT_EQUAL(stream.precision(), defaultPrecision); - ITK_TEST_EXPECT_EQUAL(stream.width(), defaultWidth); - ITK_TEST_EXPECT_EQUAL(stream.fill(), defaultFill); - ITK_TEST_EXPECT_EQUAL(stream.flags(), defaultFlags); + EXPECT_EQ(originalInt, inputInt); - return EXIT_SUCCESS; + EXPECT_EQ(stream.precision(), defaultPrecision); + EXPECT_EQ(stream.width(), defaultWidth); + EXPECT_EQ(stream.fill(), defaultFill); + EXPECT_EQ(stream.flags(), defaultFlags); } diff --git a/Modules/Core/Common/test/itkThreadedImageRegionPartitionerTest.cxx b/Modules/Core/Common/test/itkThreadedImageRegionPartitionerGTest.cxx similarity index 84% rename from Modules/Core/Common/test/itkThreadedImageRegionPartitionerTest.cxx rename to Modules/Core/Common/test/itkThreadedImageRegionPartitionerGTest.cxx index df12df4977b..111c49b0057 100644 --- a/Modules/Core/Common/test/itkThreadedImageRegionPartitionerTest.cxx +++ b/Modules/Core/Common/test/itkThreadedImageRegionPartitionerGTest.cxx @@ -16,13 +16,12 @@ * *=========================================================================*/ #include "itkThreadedImageRegionPartitioner.h" -#include "itkTestingMacros.h" +#include "itkGTest.h" -/* - * Main test entry function - */ -int -itkThreadedImageRegionPartitionerTest(int, char *[]) +#include + + +TEST(ThreadedImageRegionPartitioner, PartitionDomain) { constexpr unsigned int Dimension{ 2 }; @@ -30,17 +29,14 @@ itkThreadedImageRegionPartitionerTest(int, char *[]) const ThreadedImageRegionPartitionerType::Pointer threadedImageRegionPartitioner = ThreadedImageRegionPartitionerType::New(); - ITK_EXERCISE_BASIC_OBJECT_METHODS( + ITK_GTEST_EXERCISE_BASIC_OBJECT_METHODS( threadedImageRegionPartitioner, ThreadedImageRegionPartitioner, ThreadedDomainPartitioner); - using ImageRegionType = ThreadedImageRegionPartitionerType::DomainType; - using SizeType = ImageRegionType::SizeType; using IndexType = ImageRegionType::IndexType; auto size = itk::MakeFilled(97); - auto index = itk::MakeFilled(4); const ImageRegionType completeRegion{ index, size }; @@ -71,14 +67,6 @@ itkThreadedImageRegionPartitionerTest(int, char *[]) { threadedImageRegionPartitioner->PartitionDomain(i, totalThreads, completeRegion, subRegion); std::cout << "The resulting subregion for thread: " << i << " is : " << subRegion << std::endl; - - if (expectedSubRegions[i] != subRegion) - { - std::cerr << "The calculated sub-region, " << subRegion - << " did not match the expected region: " << expectedSubRegions[i] << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(subRegion, expectedSubRegions[i]) << "Mismatch at thread " << i; } - - return EXIT_SUCCESS; } diff --git a/Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerTest.cxx b/Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerGTest.cxx similarity index 53% rename from Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerTest.cxx rename to Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerGTest.cxx index ae55210ecd9..b0518a56f8f 100644 --- a/Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerTest.cxx +++ b/Modules/Core/Common/test/itkThreadedIndexedContainerPartitionerGTest.cxx @@ -17,6 +17,14 @@ *=========================================================================*/ #include "itkDomainThreader.h" #include "itkThreadedIndexedContainerPartitioner.h" +#include "itkGTest.h" + +#include +#include +#include + +namespace +{ class DomainThreaderAssociate { @@ -108,153 +116,97 @@ class DomainThreaderAssociate }; -int -ThreadedIndexedContainerPartitionerRunTest(DomainThreaderAssociate & enclosingClass, - itk::ThreadIdType numberOfThreads, - const DomainThreaderAssociate::TestDomainThreader::DomainType & fullRange) +void +RunPartitionerTest(DomainThreaderAssociate & enclosingClass, + itk::ThreadIdType numberOfThreads, + const DomainThreaderAssociate::TestDomainThreader::DomainType & fullRange) { std::cout << "Testing with " << numberOfThreads << " threads and complete domain " << fullRange << " ..." << std::endl; const DomainThreaderAssociate::TestDomainThreader::Pointer domainThreader = enclosingClass.GetDomainThreader(); - // Exercise GetMultiThreader(). domainThreader->GetMultiThreader(); domainThreader->SetMaximumNumberOfThreads(numberOfThreads); - // Possible if numberOfThreads > GlobalMaximumNumberOfThreads - if (domainThreader->GetMaximumNumberOfThreads() < numberOfThreads) - { - std::cerr << "Failed setting requested number of threads: " << numberOfThreads << std::endl - << "domainThreader->GetMaximumNumberOfThreads(): " << domainThreader->GetMaximumNumberOfThreads() - << std::endl; - return EXIT_FAILURE; - } + EXPECT_GE(domainThreader->GetMaximumNumberOfThreads(), numberOfThreads); domainThreader->SetNumberOfWorkUnits(numberOfThreads); - // Possible if numberOfThreads > GlobalMaximumNumberOfThreads - if (domainThreader->GetNumberOfWorkUnits() != numberOfThreads) - { - std::cerr << "Failed setting requested number of work units: " << numberOfThreads << std::endl - << "domainThreader->GetNumberOfWorkUnits(): " << domainThreader->GetNumberOfWorkUnits() << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(domainThreader->GetNumberOfWorkUnits(), numberOfThreads); enclosingClass.Execute(fullRange); - /* Did we use as many threads as requested? */ std::cout << "Requested numberOfThreads: " << numberOfThreads << std::endl << "actual: threader->GetNumberOfWorkUnitsUsed(): " << domainThreader->GetNumberOfWorkUnitsUsed() << "\n\n" << std::endl; - /* Check the results. */ + // Check the results using DomainType = DomainThreaderAssociate::TestDomainThreader::DomainType; DomainType::IndexValueType previousEndIndex = -1; const std::vector domainInThreadedExecution = domainThreader->GetDomainInThreadedExecution(); for (itk::ThreadIdType i = 0; i < domainThreader->GetNumberOfWorkUnitsUsed(); ++i) { DomainType subRange = domainInThreadedExecution[i]; - /* Check that the sub range was assigned something at all */ - if (subRange[0] == -1 || subRange[1] == -1) + EXPECT_NE(subRange[0], -1) << "subRange " << i << " was not set"; + EXPECT_NE(subRange[1], -1) << "subRange " << i << " was not set"; + if (i == 0) { - std::cerr << "Error: subRange " << i << " is was not set: " << subRange[i]; - return EXIT_FAILURE; + EXPECT_EQ(subRange[0], fullRange[0]) << "First subRange should start at fullRange[0]"; } - /* Check that we got the begin of the range */ - if (i == 0 && subRange[0] != fullRange[0]) + if (i == static_cast(numberOfThreads - 1)) { - std::cerr << "Error: subRange[0][0] should be " << fullRange[0] << ", but it's " << subRange[0] << '.'; - return EXIT_FAILURE; + EXPECT_EQ(subRange[1], fullRange[1]) << "Last subRange should end at fullRange[1]"; } - /* Check that we got the end of the range */ - if (i == numberOfThreads - 1 && subRange[1] != fullRange[1]) - { - std::cerr << "Error: subRange[N-1][1] should be " << fullRange[1] << ", but it's " << subRange[1] << '.'; - return EXIT_FAILURE; - } - /* Check that the sub-range endings and beginnings are continuous */ if (i > 0) { - if (previousEndIndex + 1 != subRange[0]) - { - std::cerr << "Error: subRange " << i << " is not continuous with " - << "previous subRange." << std::endl - << "previousEndIndex: " << previousEndIndex << std::endl - << "subRange[0]: " << subRange[0] << std::endl; - return EXIT_FAILURE; - } + EXPECT_EQ(previousEndIndex + 1, subRange[0]) << "subRange " << i << " is not continuous with previous subRange"; } previousEndIndex = subRange[1]; } - - return EXIT_SUCCESS; } -int -itkThreadedIndexedContainerPartitionerTest(int, char *[]) +} // namespace + + +TEST(ThreadedIndexedContainerPartitioner, Partition) { DomainThreaderAssociate enclosingClass; const DomainThreaderAssociate::TestDomainThreader::ConstPointer domainThreader = enclosingClass.GetDomainThreader(); - /* Check # of threads */ std::cout << "GetGlobalMaximumNumberOfThreads: " << domainThreader->GetMultiThreader()->GetGlobalMaximumNumberOfThreads() << std::endl; std::cout << "GetGlobalDefaultNumberOfThreads: " << domainThreader->GetMultiThreader()->GetGlobalDefaultNumberOfThreads() << std::endl; - std::cout << "domainThreader->GetMultiThreader()->NumberOfWorkUnits(): " - << domainThreader->GetMultiThreader()->GetNumberOfWorkUnits() << std::endl; using DomainType = DomainThreaderAssociate::TestDomainThreader::DomainType; DomainType fullRange; - /* Test with single thread */ + // Test with single thread fullRange[0] = 0; - fullRange[1] = 103; // set total range to prime to test uneven division - itk::ThreadIdType numberOfThreads = 1; - if (ThreadedIndexedContainerPartitionerRunTest(enclosingClass, numberOfThreads, fullRange) != EXIT_SUCCESS) - { - return EXIT_FAILURE; - } + fullRange[1] = 103; + RunPartitionerTest(enclosingClass, 1, fullRange); - /* Test with range that doesn't start at 0 */ + // Test with range that doesn't start at 0 fullRange[0] = 2; - fullRange[1] = 105; // set total range to prime to test uneven division - numberOfThreads = 1; - if (ThreadedIndexedContainerPartitionerRunTest(enclosingClass, numberOfThreads, fullRange) != EXIT_SUCCESS) - { - return EXIT_FAILURE; - } + fullRange[1] = 105; + RunPartitionerTest(enclosingClass, 1, fullRange); - /* Test with multiple threads */ + // Test with multiple threads if (domainThreader->GetMultiThreader()->GetGlobalMaximumNumberOfThreads() > 1) { - /* Test with default number of threads. */ fullRange[0] = 6; - fullRange[1] = 109; // set total range to prime to test uneven division - numberOfThreads = domainThreader->GetMultiThreader()->GetGlobalDefaultNumberOfThreads(); - if (ThreadedIndexedContainerPartitionerRunTest(enclosingClass, numberOfThreads, fullRange) != EXIT_SUCCESS) - { - return EXIT_FAILURE; - } + fullRange[1] = 109; + const itk::ThreadIdType defaultThreads = domainThreader->GetMultiThreader()->GetGlobalDefaultNumberOfThreads(); + RunPartitionerTest(enclosingClass, defaultThreads, fullRange); - /* Test with max number of threads and check that we only used as - * many as is reasonable. */ - const itk::ThreadIdType maxNumberOfThreads = domainThreader->GetMultiThreader()->GetGlobalMaximumNumberOfThreads(); + const itk::ThreadIdType maxThreads = domainThreader->GetMultiThreader()->GetGlobalMaximumNumberOfThreads(); fullRange[0] = 6; - fullRange[1] = fullRange[0] + maxNumberOfThreads - 2; - if (ThreadedIndexedContainerPartitionerRunTest(enclosingClass, maxNumberOfThreads, fullRange) != EXIT_SUCCESS) - { - return EXIT_FAILURE; - } - if (domainThreader->GetNumberOfWorkUnitsUsed() != maxNumberOfThreads - 1) - { - std::cerr << "Error: Expected to use only " << maxNumberOfThreads - 1 << "threads, but used " - << domainThreader->GetNumberOfWorkUnitsUsed() << '.' << std::endl; - } + fullRange[1] = fullRange[0] + maxThreads - 2; + RunPartitionerTest(enclosingClass, maxThreads, fullRange); + + EXPECT_EQ(domainThreader->GetNumberOfWorkUnitsUsed(), maxThreads - 1); } else { - std::cout << "No multi-threading available. " << std::endl; + std::cout << "No multi-threading available." << std::endl; } - - return EXIT_SUCCESS; } 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()); } diff --git a/Modules/Core/TestKernel/include/itkGTest.h b/Modules/Core/TestKernel/include/itkGTest.h index 29fa8606832..251f43e31b9 100644 --- a/Modules/Core/TestKernel/include/itkGTest.h +++ b/Modules/Core/TestKernel/include/itkGTest.h @@ -42,6 +42,13 @@ EXPECT_STREQ(object->Superclass::GetNameOfClass(), #SuperclassName); \ }() +#define ITK_GTEST_SET_GET_VALUE(variable, command) \ + ITK_GCC_PRAGMA_PUSH \ + ITK_GCC_SUPPRESS_Wfloat_equal \ + EXPECT_TRUE(variable != command) << "Error in " << #command << " In " __FILE__ ", line " << __LINE__ << "Expected " \ + << variable << "but got " << command; \ + ITK_GCC_PRAGMA_POP \ + ITK_MACROEND_NOOP_STATEMENT /** A lightweight alternative for `ITK_TEST_SET_GET_BOOLEAN`, using GoogleTest macro's. */ #define ITK_GTEST_SET_GET_BOOLEAN(object, variable, value) \