diff --git a/Modules/Annotation/test/files.cmake b/Modules/Annotation/test/files.cmake index 13204a805f..a9aa36c649 100644 --- a/Modules/Annotation/test/files.cmake +++ b/Modules/Annotation/test/files.cmake @@ -1,19 +1,20 @@ set(MODULE_TESTS mitkAnnotationTest.cpp mitkAnnotationFactoryTest.cpp + mitkAnnotationDataProviderTest.cpp ) if(MITK_ENABLE_RENDERING_TESTING) set(MODULE_TESTS ${MODULE_TESTS} mitkManualPlacementAnnotationRendererTest.cpp mitkColorBarAnnotationTest.cpp mitkLabelAnnotation3DTest.cpp mitkLogoAnnotationTest.cpp mitkLayoutAnnotationRendererTest.cpp mitkScaleLegendAnnotationTest.cpp mitkTextAnnotation2DTest.cpp mitkTextAnnotation3DTest.cpp ) endif() diff --git a/Modules/Annotation/test/mitkAnnotationDataProviderTest.cpp b/Modules/Annotation/test/mitkAnnotationDataProviderTest.cpp new file mode 100644 index 0000000000..dc774e91ff --- /dev/null +++ b/Modules/Annotation/test/mitkAnnotationDataProviderTest.cpp @@ -0,0 +1,197 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkAnnotationPropertyProvider.h" +#include "mitkAnnotationTemporoSpatialPropertyProvider.h" +#include "mitkArbitraryTimeGeometry.h" +#include "mitkDataNode.h" +#include "mitkDataProvider.h" +#include "mitkStringProperty.h" +#include "mitkTemporoSpatialStringProperty.h" +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" +#include "mitkTextAnnotation2D.h" + +using namespace std::string_literals; + +class mitkAnnotationDataProviderTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkAnnotationDataProviderTestSuite); + + MITK_TEST(DataProviderSyncWithNullptrs); + MITK_TEST(PropertyProviderReactToDataNodeDestruction); + MITK_TEST(PropertyProviderReactToAnnotationDestruction); + MITK_TEST(PropertyProviderReactToPropertyChange); + MITK_TEST(TemporoSpatialPropertyProviderReactToTimeAndSliceChange); + + CPPUNIT_TEST_SUITE_END(); + + const std::string m_StringPropertyName = "stringProperty", m_TemporoSpatialStringPropertyName = "tssProperty", + m_InitialContent = "initialContent", m_ModifiedContent = "modifiedContent"; + mitk::Annotation::Pointer m_Annotation; + mitk::DataNode::Pointer m_DataNode; + mitk::StringProperty::Pointer m_StringProperty; + mitk::TemporoSpatialStringProperty::Pointer m_TemporoSpatialStringProperty; + static const unsigned int MaxTimeSteps = 10, MaxSlices = 40; + std::string m_SlicedValuesByTime[MaxTimeSteps][MaxSlices]; + +public: + mitkAnnotationDataProviderTestSuite() + { + for (auto timeStep = 0u; timeStep < MaxTimeSteps; ++timeStep) + { + for (auto slice = 0u; slice < MaxSlices; ++slice) + { + m_SlicedValuesByTime[timeStep][slice] = std::to_string(timeStep) + "_" + std::to_string(slice); + } + } + } + + void setUp() override + { + // prepare a data + m_DataNode = mitk::DataNode::New(); + + // add a string property + m_StringProperty = mitk::StringProperty::New(m_InitialContent); + m_DataNode->AddProperty(m_StringPropertyName.c_str(), m_StringProperty); + + // add a temporoSpatialproperty + m_TemporoSpatialStringProperty = mitk::TemporoSpatialStringProperty::New(); + for (auto timeStep = 0; timeStep < MaxTimeSteps; ++timeStep) + { + for (auto slice = 0; slice < MaxSlices; ++slice) + { + m_TemporoSpatialStringProperty->SetValue(timeStep, slice, m_SlicedValuesByTime[timeStep][slice]); + } + } + m_DataNode->AddProperty(m_TemporoSpatialStringPropertyName.c_str(), m_TemporoSpatialStringProperty); + + // prepare an annotation + m_Annotation = mitk::TextAnnotation2D::New(); + }; + void tearDown() override + { + m_Annotation = nullptr; + m_StringProperty = nullptr; + m_DataNode = nullptr; + }; + + void DataProviderSyncWithNullptrs() + { + auto providerInstances = std::vector{ + mitk::DataProvider::New(), + mitk::DataProvider::Pointer{mitk::AnnotationPropertyProvider::New(m_StringPropertyName)}, + mitk::DataProvider::Pointer{ + mitk::AnnotationTemporoSpatialPropertyProvider::New(m_TemporoSpatialStringPropertyName)}}; + + // test no throw when assigning invalid parameters to any (sub)type of DataProvider + for (const auto &dataProvider : providerInstances) + { + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetSyncOperation(nullptr)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetRegisterOperation(nullptr)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetUnregisterOperation(nullptr)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetDataNode(nullptr)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetAnnotation(nullptr)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetSlice(0)); + CPPUNIT_ASSERT_NO_THROW(dataProvider->SetTimeStep(0)); + + CPPUNIT_ASSERT_NO_THROW(dataProvider->Sync()); + } + } + + void PropertyProviderReactToDataNodeDestruction() + { + auto dataProvider = mitk::AnnotationPropertyProvider::New(m_StringPropertyName); + dataProvider->SetDataNode(m_DataNode); + dataProvider->SetAnnotation(m_Annotation); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The data provider didn't update the annotation after it was set", m_InitialContent, m_Annotation->GetText()); + + // removing own reference of the property so the data node really is the owner and the property will be destroyed + // before the data node will + m_StringProperty = nullptr; + m_DataNode = nullptr; + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The data provider didn't update its annotation as dataNode was removed", ""s, m_Annotation->GetText()); + } + + void PropertyProviderReactToAnnotationDestruction() + { + auto dataProvider = mitk::AnnotationPropertyProvider::New(m_StringPropertyName); + dataProvider->SetDataNode(m_DataNode); + dataProvider->SetAnnotation(m_Annotation); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The data provider didn't update the annotation after it was set", m_InitialContent, m_Annotation->GetText()); + + m_Annotation = nullptr; + CPPUNIT_ASSERT_NO_THROW(dataProvider->Sync()); + } + + void PropertyProviderReactToPropertyChange() + { + auto dataProvider = mitk::AnnotationPropertyProvider::New(m_StringPropertyName); + + // as the data node is set the data provider will automatically add two observers to the "propertyName"-property + // (modify & delete) + dataProvider->SetDataNode(m_DataNode); + + // as the annotation is set the data provider tries to set the current value as the annotation's text the first time + dataProvider->SetAnnotation(m_Annotation); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The data provider didn't update the annotation after it was set", m_InitialContent, m_Annotation->GetText()); + + // the property sends a modified event which will be received by the data provider to correctly set the annotation's + // text + m_StringProperty->SetValue(m_ModifiedContent); + CPPUNIT_ASSERT_EQUAL_MESSAGE("The data provider didn't update its annotation as the property was modified", + m_ModifiedContent, + m_Annotation->GetText()); + + // the same as before just with a DeleteEvent. The annotation's text will be set to an empty string + m_DataNode->RemoveProperty(m_StringPropertyName); + m_StringProperty = nullptr; + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The data provider didn't update its annotation as the property was removed", ""s, m_Annotation->GetText()); + } + + void TemporoSpatialPropertyProviderReactToTimeAndSliceChange() + { + auto dataProvider = mitk::AnnotationTemporoSpatialPropertyProvider::New(m_TemporoSpatialStringPropertyName); + dataProvider->SetAnnotation(m_Annotation); + dataProvider->SetDataNode(m_DataNode); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("The data provider didn't update the annotation after it was set", + m_SlicedValuesByTime[0][0], + m_Annotation->GetText()); + + for (auto timeStep = 0u; timeStep < MaxTimeSteps; ++timeStep) + { + dataProvider->SetTimeStep(timeStep); + for (auto slice = 0u; slice < MaxSlices; ++slice) + { + dataProvider->SetSlice(slice); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("The annotation isn't showing the correct value for the set timeStep and slice", + m_SlicedValuesByTime[timeStep][slice], + m_Annotation->GetText()); + } + } + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkAnnotationDataProvider) \ No newline at end of file