.. _program_listing_file_Testing_Cxx_NodeReferenceObserverTest.cxx: Program Listing for File NodeReferenceObserverTest.cxx ====================================================== |exhale_lsh| :ref:`Return to documentation for file ` (``Testing/Cxx/NodeReferenceObserverTest.cxx``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // LayerDM includes #include "vtkMRMLLayerDMObjectEventObserver.h" #include "vtkMRMLLayerDMNodeReferenceObserver.h" // Slicer includes #include #include #include // VTK includes #include // CTK includes #include namespace { struct Spy { void OnRefModifiedCall(vtkMRMLNode* fromNode, vtkMRMLNode* toNode, const std::string& role, int eventType) { calls.emplace_back(std::make_tuple(fromNode, toNode, role, eventType)); callCount++; } bool WasCalled() const { return callCount > 0; } void Clear() { calls.clear(); callCount = 0; } using CallT = std::tuple; CallT GetCall(int iCall) { return calls[iCall]; } std::vector calls; std::vector removedCalls; int callCount{}; }; struct Test { Test(const vtkSmartPointer& inScene = nullptr) : scene{ inScene ? inScene : vtkSmartPointer::New() } { obs->SetReferenceModifiedCallBack([this](vtkMRMLNode* fromNode, vtkMRMLNode* toNode, const std::string& role, int eventType) { spy.OnRefModifiedCall(fromNode, toNode, role, eventType); }); obs->SetScene(scene); scene->AddNode(markups); scene->AddNode(d1); scene->AddNode(d2); scene->AddNode(d3); } vtkSmartPointer scene; vtkNew obs; Spy spy; vtkNew markups; vtkNew d1; vtkNew d2; vtkNew d3; }; } // namespace class NodeReferenceObserverTester : public QObject { Q_OBJECT private slots: void testOnNodesAddedToSceneDoesntTriggerRefAddedRemoved() const { Test test; QCOMPARE(test.markups->GetScene(), test.scene); QCOMPARE(test.d1->GetScene(), test.scene); QCOMPARE(test.d2->GetScene(), test.scene); QCOMPARE(test.spy.callCount, 0); } void testTriggersRefAddedOnRefAdded() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent); } void testTriggersRefRemovedOnRefRemoved() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.spy.Clear(); test.markups->SetAndObserveDisplayNodeID(""); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceRemovedEvent); } void testTriggersAddedWhenAddingAndNotReplacingExistingRef() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.markups->AddAndObserveDisplayNodeID(test.d2->GetID()); QCOMPARE(test.spy.callCount, 2); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent); auto [fromNode2, toNode2, role2, eventType2] = test.spy.GetCall(1); QCOMPARE(fromNode2, test.markups); QCOMPARE(toNode2, test.d2); QCOMPARE(role2, "display"); QCOMPARE(eventType2, vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent); } void testTriggersRemovedAndAddedOnReferenceModified() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.markups->AddAndObserveDisplayNodeID(test.d2->GetID()); test.spy.Clear(); test.markups->SetAndObserveNthDisplayNodeID(0, test.d3->GetID()); QCOMPARE(test.spy.callCount, 2); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceRemovedEvent); auto [fromNode3, toNode3, role3, eventType3] = test.spy.GetCall(1); QCOMPARE(fromNode3, test.markups); QCOMPARE(toNode3, test.d3); QCOMPARE(role3, "display"); QCOMPARE(eventType3, vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent); } void testTriggersRemovedOnToNodeRemovedFromScene() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.spy.Clear(); test.scene->RemoveNode(test.d1); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceRemovedEvent); } void testTriggersRemovedOnFromNodeRemovedFromScene() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.spy.Clear(); test.scene->RemoveNode(test.markups); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceRemovedEvent); } void testTriggersRemovedOnSceneClear() const { Test test; test.markups->SetAndObserveDisplayNodeID(test.d1->GetID()); test.spy.Clear(); test.scene->Clear(); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, test.markups); QCOMPARE(toNode, test.d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceRemovedEvent); } void testTriggersAddedWhenSettingAlreadyExistingScene() const { auto scene = vtkSmartPointer::New(); auto markups = vtkMRMLMarkupsFiducialNode::SafeDownCast(scene->AddNode(vtkNew{})); markups->CreateDefaultDisplayNodes(); auto d1 = vtkMRMLMarkupsFiducialDisplayNode::SafeDownCast(markups->GetDisplayNode()); QVERIFY(d1); Test test(scene); QCOMPARE(test.spy.callCount, 1); auto [fromNode, toNode, role, eventType] = test.spy.GetCall(0); QCOMPARE(fromNode, markups); QCOMPARE(toNode, d1); QCOMPARE(role, "display"); QCOMPARE(eventType, vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent); } void testNodesRemovedFromSceneAreCorrectlyRemovedFromObserver() { auto scene = vtkSmartPointer::New(); auto markups = vtkMRMLMarkupsFiducialNode::SafeDownCast(scene->AddNode(vtkNew{})); markups->CreateDefaultDisplayNodes(); // Verify that the number of nodes in the observer are consistent with the number of nodes present in the scene Test test(scene); int nNodes = test.obs->GetNumberOfNodes(); QCOMPARE(scene->GetNumberOfNodes(), nNodes); int nRefTo = test.obs->GetReferenceToSize(); QVERIFY(nRefTo <= nNodes); int nRefFrom = test.obs->GetReferenceFromSize(); QVERIFY(test.obs->GetReferenceFromSize() <= nNodes); // Verify that the references from / to the created markups is consistent with the current display node const auto refTo = test.obs->GetNodeToReferences(markups); QVERIFY(refTo.find({ markups->GetDisplayNode(), "display" }) != refTo.end()); const auto refFrom = test.obs->GetNodeFromReferences(markups->GetDisplayNode()); QVERIFY(refFrom.find({ markups, "display" }) != refFrom.end()); // Remove the markups and its display node from the scene scene->RemoveNode(markups->GetDisplayNode()); scene->RemoveNode(markups); // Expect the number of nodes tracked to have been reduced by 2 QCOMPARE(scene->GetNumberOfNodes(), nNodes - 2); QCOMPARE(test.obs->GetNumberOfNodes(), nNodes - 2); } }; CTK_TEST_MAIN(NodeReferenceObserverTest) #include "NodeReferenceObserverTest.moc"