Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkDataStorageTest.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include <algorithm>
14 #include <fstream>
15 
16 #include "mitkColorProperty.h"
17 #include "mitkDataNode.h"
18 #include "mitkGroupTagProperty.h"
19 #include "mitkImage.h"
21 #include "mitkStringProperty.h"
22 #include "mitkSurface.h"
23 
24 #include "mitkDataStorage.h"
25 #include "mitkIOUtil.h"
26 #include "mitkMessage.h"
27 #include "mitkNodePredicateAnd.h"
28 #include "mitkNodePredicateData.h"
31 #include "mitkNodePredicateNot.h"
32 #include "mitkNodePredicateOr.h"
36 //#include "mitkPicFileReader.h"
37 #include "mitkTestingMacros.h"
38 
39 void TestDataStorage(mitk::DataStorage *ds, std::string filename);
40 
41 namespace mitk
42 {
43  class TestStandaloneDataStorage : public StandaloneDataStorage
44  {
45  public:
46  mitkClassMacro(TestStandaloneDataStorage, mitk::DataStorage);
47  itkFactorylessNewMacro(Self)
48  itkCloneMacro(Self) std::map<const mitk::DataNode *, unsigned long> GetModifiedObserverTags() const
49  {
51  }
52  std::map<const mitk::DataNode *, unsigned long> GetDeletedObserverTags() const { return m_NodeDeleteObserverTags; }
53  protected:
54  TestStandaloneDataStorage() {}
55  };
56 }
57 
58 class DSEventReceiver // Helper class for event testing
59 {
60 public:
61  const mitk::DataNode *m_NodeAdded;
62  const mitk::DataNode *m_NodeRemoved;
63 
64  DSEventReceiver() : m_NodeAdded(nullptr), m_NodeRemoved(nullptr) {}
65  void OnAdd(const mitk::DataNode *node) { m_NodeAdded = node; }
66  void OnRemove(const mitk::DataNode *node) { m_NodeRemoved = node; }
67 };
68 
76 struct ItkDeleteEventListener
77 {
78  ItkDeleteEventListener(mitk::DataStorage *ds) : m_Node(nullptr), m_DataStorage(ds), m_DeleteObserverTag(0) {}
79  void SetNode(mitk::DataNode *_Node)
80  {
81  if (m_Node)
82  return;
83 
84  m_Node = _Node;
85  itk::MemberCommand<ItkDeleteEventListener>::Pointer onObjectDelete =
86  itk::MemberCommand<ItkDeleteEventListener>::New();
87 
88  onObjectDelete->SetCallbackFunction(this, &ItkDeleteEventListener::OnObjectDelete);
89  m_DeleteObserverTag = m_Node->AddObserver(itk::DeleteEvent(), onObjectDelete);
90  }
91 
92  void OnObjectDelete(const itk::Object * /*caller*/, const itk::EventObject &)
93  {
95  m_DataStorage->Add(node); // SHOULD NOT CAUSE A DEADLOCK!
96  m_DataStorage->Remove(node); // tidy up: remove the empty node again
97 
98  m_Node = nullptr;
99  }
100 
101 protected:
104  unsigned int m_DeleteObserverTag;
105 };
106 
107 //## Documentation
108 //## main testing method
109 //## NOTE: the current Singleton implementation of DataTreeStorage will lead to crashes if a testcase fails
110 //## and therefore mitk::DataStorage::ShutdownSingleton() is not called.
111 int mitkDataStorageTest(int argc, char *argv[])
112 {
113  MITK_TEST_BEGIN("DataStorageTest");
114 
115  // muellerm: test observer tag remove
116  mitk::TestStandaloneDataStorage::Pointer testDS = mitk::TestStandaloneDataStorage::New();
118  testDS->Add(n1);
119  MITK_TEST_CONDITION_REQUIRED(testDS->GetModifiedObserverTags().size() == 1,
120  "Testing if modified"
121  " observer was added.");
122  MITK_TEST_CONDITION_REQUIRED(testDS->GetDeletedObserverTags().size() == 1,
123  "Testing if delete"
124  " observer was added.");
125  testDS->Remove(n1);
126  MITK_TEST_CONDITION_REQUIRED(testDS->GetModifiedObserverTags().size() == 0,
127  "Testing if modified"
128  " observer was removed.");
129  MITK_TEST_CONDITION_REQUIRED(testDS->GetDeletedObserverTags().size() == 0,
130  "Testing if delete"
131  " observer was removed.");
132 
133  /* Create StandaloneDataStorage */
134  MITK_TEST_OUTPUT(<< "Create StandaloneDataStorage : ");
136  try
137  {
139  MITK_TEST_CONDITION_REQUIRED(sds.IsNotNull(), "Testing Instatiation");
140  }
141  catch (...)
142  {
143  MITK_TEST_FAILED_MSG(<< "Exception during creation of StandaloneDataStorage");
144  }
145 
146  MITK_TEST_OUTPUT(<< "Testing StandaloneDataStorage: ");
147  MITK_TEST_CONDITION_REQUIRED(argc > 1, "Testing correct test invocation");
148  TestDataStorage(sds, argv[1]);
149  // TODO: Add specific StandaloneDataStorage Tests here
150  sds = nullptr;
151 
152  MITK_TEST_END();
153 }
154 
155 //##Documentation
156 //## @brief Test for the DataStorage class and its associated classes (e.g. the predicate classes)
157 //## This method will be called once for each subclass of DataStorage
158 void TestDataStorage(mitk::DataStorage *ds, std::string filename)
159 {
160  /* DataStorage valid? */
161  MITK_TEST_CONDITION_REQUIRED(ds != nullptr, "DataStorage valid?");
162 
163  // Take the ItkImageFile Reader for the .nrrd data format.
164  // (was previously pic which is now deprecated format)
165  mitk::Image::Pointer image = mitk::IOUtil::Load<mitk::Image>(filename);
166 
167  // create some DataNodes to fill the ds
168  mitk::DataNode::Pointer n1 = mitk::DataNode::New(); // node with image and name property
169  // mitk::Image::Pointer image = mitk::Image::New();
170  // unsigned int imageDimensions[] = { 10, 10, 10, 10 };
171  // mitk::PixelType pt(typeid(int));
172  // image->Initialize( pt, 4, imageDimensions );
173  n1->SetData(image);
174  n1->SetProperty("name", mitk::StringProperty::New("Node 1 - Image Node"));
175  mitk::DataStorage::SetOfObjects::Pointer parents1 = mitk::DataStorage::SetOfObjects::New();
176 
177  mitk::DataNode::Pointer n2 = mitk::DataNode::New(); // node with surface and name and color properties
179  n2->SetData(surface);
180  n2->SetProperty("name", mitk::StringProperty::New("Node 2 - Surface Node"));
181  mitk::Color color;
182  color.Set(1.0f, 1.0f, 0.0f);
183  n2->SetColor(color);
184  n2->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New());
185  mitk::DataStorage::SetOfObjects::Pointer parents2 = mitk::DataStorage::SetOfObjects::New();
186  parents2->InsertElement(0, n1); // n1 (image node) is source of n2 (surface node)
187 
188  mitk::DataNode::Pointer n3 = mitk::DataNode::New(); // node without data but with name property
189  n3->SetProperty("name", mitk::StringProperty::New("Node 3 - Empty Node"));
190  n3->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New());
191  n3->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New());
192  mitk::DataStorage::SetOfObjects::Pointer parents3 = mitk::DataStorage::SetOfObjects::New();
193  parents3->InsertElement(0, n2); // n2 is source of n3
194 
195  mitk::DataNode::Pointer n4 = mitk::DataNode::New(); // node without data but with color property
196  n4->SetColor(color);
197  n4->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New());
198  mitk::DataStorage::SetOfObjects::Pointer parents4 = mitk::DataStorage::SetOfObjects::New();
199  parents4->InsertElement(0, n2);
200  parents4->InsertElement(1, n3); // n2 and n3 are sources of n4
201 
202  mitk::DataNode::Pointer n5 = mitk::DataNode::New(); // extra node
203  n5->SetProperty("name", mitk::StringProperty::New("Node 5"));
204 
205  try /* adding objects */
206  {
207  /* Add an object */
208  ds->Add(n1, parents1);
209  MITK_TEST_CONDITION_REQUIRED((ds->GetAll()->Size() == 1) && (ds->GetAll()->GetElement(0) == n1),
210  "Testing Adding a new object");
211 
212  /* Check exception on adding the same object again */
213  MITK_TEST_OUTPUT(<< "Check exception on adding the same object again: ");
214  MITK_TEST_FOR_EXCEPTION(std::exception, ds->Add(n1, parents1));
215  MITK_TEST_CONDITION(ds->GetAll()->Size() == 1, "Test if object count is correct after exception");
216 
217  /* Add an object that has a source object */
218  ds->Add(n2, parents2);
219  MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 2, "Testing Adding an object that has a source object");
220 
221  /* Add some more objects needed for further tests */
222  ds->Add(n3, parents3); // n3 object that has name property and one parent
223  ds->Add(n4, parents4); // n4 object that has color property
224  ds->Add(n5); // n5 has no parents
225  MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 5, "Adding some more objects needed for further tests");
226  }
227  catch (...)
228  {
229  MITK_TEST_FAILED_MSG(<< "Exeption during object creation");
230  }
231 
232  try /* object retrieval methods */
233  {
234  /* Requesting all Objects */
235  {
236  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll();
237  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
238 
239  MITK_TEST_CONDITION((stlAll.size() == 5) // check if all tree nodes are in resultset
240  &&
241  (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) &&
242  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
243  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) &&
244  (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) &&
245  (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()),
246  "Testing GetAll()");
247  }
248  /* Requesting a named object */
249  {
251  mitk::NodePredicateProperty::New("name", mitk::StringProperty::New("Node 2 - Surface Node")));
252  mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
253  MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2), "Requesting a named object");
254  }
255 
256  /* Requesting objects of specific data type */
257  {
259  mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
260  MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific data type")
261  }
262  /* Requesting objects of specific dimension */
263  {
265  mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
266  MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific dimension")
267  }
268  /* Requesting objects with specific data object */
269  {
271  mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
272  MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1),
273  "Requesting objects with specific data object")
274  }
275  /* Requesting objects with nullptr data */
276  {
278  mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
279  MITK_TEST_CONDITION((all->Size() == 3) && (std::find(all->begin(), all->end(), n3) != all->end()) &&
280  (std::find(all->begin(), all->end(), n4) != all->end()) &&
281  (std::find(all->begin(), all->end(), n5) != all->end()),
282  "Requesting objects with nullptr data");
283  }
284  /* Requesting objects that meet a conjunction criteria */
285  {
290  predicate->AddPredicate(p1);
291  predicate->AddPredicate(p2); // objects must be of datatype "Surface" and have red color (= n2)
292  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
293  MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2),
294  "Requesting objects that meet a conjunction criteria");
295  }
296  /* Requesting objects that meet a disjunction criteria */
297  {
302  predicate->AddPredicate(p1);
303  predicate->AddPredicate(p2); // objects must be of datatype "Surface" or have red color (= n1, n2, n4)
304  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
305  MITK_TEST_CONDITION((all->Size() == 3) && (std::find(all->begin(), all->end(), n1) != all->end()) &&
306  (std::find(all->begin(), all->end(), n2) != all->end()) &&
307  (std::find(all->begin(), all->end(), n4) != all->end()),
308  "Requesting objects that meet a disjunction criteria");
309  }
310  /* Requesting objects that do not meet a criteria */
311  {
315 
316  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate);
317  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
318  MITK_TEST_CONDITION((all->Size() == 3) // check if correct objects are in resultset
319  &&
320  (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) &&
321  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) &&
322  (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()),
323  "Requesting objects that do not meet a criteria");
324  }
325 
326  /* Requesting *direct* source objects */
327  {
328  const mitk::DataStorage::SetOfObjects::ConstPointer all =
329  ds->GetSources(n3, nullptr, true); // Get direct parents of n3 (=n2)
330  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
331  MITK_TEST_CONDITION((all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()),
332  "Requesting *direct* source objects");
333  }
334 
335  /* Requesting *all* source objects */
336  {
337  const mitk::DataStorage::SetOfObjects::ConstPointer all =
338  ds->GetSources(n3, nullptr, false); // Get all parents of n3 (= n1 + n2)
339  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
340  MITK_TEST_CONDITION((all->Size() == 2) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) &&
341  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()),
342  "Requesting *all* source objects"); // check if n1 and n2 are the resultset
343  }
344 
345  /* Requesting *all* sources of object with multiple parents */
346  {
347  const mitk::DataStorage::SetOfObjects::ConstPointer all =
348  ds->GetSources(n4, nullptr, false); // Get all parents of n4 (= n1 + n2 + n3)
349  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
351  (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) &&
352  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
353  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset
354  ,
355  "Requesting *all* sources of object with multiple parents");
356  }
357 
358  /* Requesting *direct* derived objects */
359  {
360  const mitk::DataStorage::SetOfObjects::ConstPointer all =
361  ds->GetDerivations(n1, nullptr, true); // Get direct childs of n1 (=n2)
362  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
363  MITK_TEST_CONDITION((all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) !=
364  stlAll.end()) // check if n1 is the resultset
365  ,
366  "Requesting *direct* derived objects");
367  }
368 
370 
371  {
372  const mitk::DataStorage::SetOfObjects::ConstPointer all =
373  ds->GetDerivations(n2, nullptr, true); // Get direct childs of n2 (=n3 + n4)
374  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
376  (all->Size() == 2) &&
377  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n3 is the resultset
378  &&
379  (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) // check if n4 is the resultset
380  ,
381  "Requesting *direct* derived objects with multiple parents/derivations");
382  }
383 
384  //* Requesting *all* derived objects */
385  {
386  const mitk::DataStorage::SetOfObjects::ConstPointer all =
387  ds->GetDerivations(n1, nullptr, false); // Get all childs of n1 (=n2, n3, n4)
388  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
389  MITK_TEST_CONDITION((all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
390  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) &&
391  (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()),
392  "Requesting *all* derived objects");
393  }
394 
395  /* Checking for circular source relationships */
396  {
397  parents1->InsertElement(0, n4); // make n1 derived from n4 (which is derived from n2, which is derived from n1)
398  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(
399  n4,
400  nullptr,
401  false); // Get all parents of n4 (= n1 + n2 + n3, not n4 itself and not multiple versions of the nodes!)
402  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
404  (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) &&
405  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
406  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset
407  ,
408  "Checking for circular source relationships");
409  }
410 
413  // can not be accessed from the outside. (Therefore it should not be possible to create these circular relations
414  // */
415 
416  //* Checking GroupTagProperty */
417  {
420  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred);
421  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
422  MITK_TEST_CONDITION((all->Size() == 2) // check if n2 and n3 are in resultset
423  &&
424  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
425  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()),
426  "Checking GroupTagProperty");
427  }
428 
429  /* Checking GroupTagProperty 2 */
430  {
433  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred);
434  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
435  MITK_TEST_CONDITION((all->Size() == 2) // check if n3 and n4 are in resultset
436  &&
437  (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) &&
438  (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()),
439  "Checking GroupTagProperty 2");
440  }
441 
442  /* Checking direct sources with condition */
443  {
445  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, true);
446  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
447  MITK_TEST_CONDITION((all->Size() == 1) // check if n2 is in resultset
448  &&
449  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()),
450  "checking direct sources with condition");
451  }
452 
453  /* Checking all sources with condition */
454  {
456  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false);
457  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
458  MITK_TEST_CONDITION((all->Size() == 1) // check if n1 is in resultset
459  &&
460  (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()),
461  "Checking all sources with condition");
462  }
463 
464  /* Checking all sources with condition with empty resultset */
465  {
467  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false);
468  MITK_TEST_CONDITION(all->Size() == 0,
469  "Checking all sources with condition with empty resultset"); // check if resultset is empty
470  }
471 
472  /* Checking direct derivations with condition */
473  {
475  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, true);
476  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
477  MITK_TEST_CONDITION((all->Size() == 1) // check if n2 is in resultset
478  &&
479  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()),
480  "Checking direct derivations with condition");
481  }
482 
483  /* Checking all derivations with condition */
484  {
486 
487  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, false);
488  std::vector<mitk::DataNode::Pointer> stlAll = all->CastToSTLConstContainer();
489  MITK_TEST_CONDITION((all->Size() == 2) // check if n2 and n4 are in resultset
490  &&
491  (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) &&
492  (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()),
493  "Checking direct derivations with condition");
494  }
495 
496  /* Checking named node method */
497  MITK_TEST_CONDITION(ds->GetNamedNode("Node 2 - Surface Node") == n2, "Checking named node method");
498  MITK_TEST_CONDITION(ds->GetNamedNode(std::string("Node 2 - Surface Node")) == n2,
499  "Checking named node(std::string) method");
500 
501  /* Checking named node method with wrong name */
502  MITK_TEST_CONDITION(ds->GetNamedNode("This name does not exist") == nullptr,
503  "Checking named node method with wrong name");
504 
505  /* Checking named object method */
506  MITK_TEST_CONDITION(ds->GetNamedObject<mitk::Image>("Node 1 - Image Node") == image,
507  "Checking named object method");
508  MITK_TEST_CONDITION(ds->GetNamedObject<mitk::Image>(std::string("Node 1 - Image Node")) == image,
509  "Checking named object(std::string) method");
510 
511  /* Checking named object method with wrong DataType */
512  MITK_TEST_CONDITION(ds->GetNamedObject<mitk::Surface>("Node 1 - Image Node") == nullptr,
513  "Checking named object method with wrong DataType");
514 
515  /* Checking named object method with wrong name */
516  MITK_TEST_CONDITION(ds->GetNamedObject<mitk::Image>("This name does not exist") == nullptr,
517  "Checking named object method with wrong name");
518 
519  /* Checking GetNamedDerivedNode with valid name and direct derivation only */
520  MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 2 - Surface Node", n1, true) == n2,
521  "Checking GetNamedDerivedNode with valid name & direct derivation only");
522 
523  /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */
524  MITK_TEST_CONDITION(ds->GetNamedDerivedNode("wrong name", n1, true) == nullptr,
525  "Checking GetNamedDerivedNode with invalid name & direct derivation only");
526 
527  /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */
528  MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, false) == n3,
529  "Checking GetNamedDerivedNode with invalid name & direct derivation only");
530 
531  /* Checking GetNamedDerivedNode with valid Name but direct derivation only */
532  MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, true) == nullptr,
533  "Checking GetNamedDerivedNode with valid Name but direct derivation only");
534 
535  /* Checking GetNode with valid predicate */
536  {
538  MITK_TEST_CONDITION(ds->GetNode(p) == n1, "Checking GetNode with valid predicate");
539  }
540  /* Checking GetNode with invalid predicate */
541  {
543  MITK_TEST_CONDITION(ds->GetNode(p) == nullptr, "Checking GetNode with invalid predicate");
544  }
545  } // object retrieval methods
546  catch (...)
547  {
548  MITK_TEST_FAILED_MSG(<< "Exeption during object retrieval (GetXXX() Methods)");
549  }
550 
551  try /* object removal methods */
552  {
553  /* Checking removal of a node without relations */
554  {
556  extra->SetProperty("name", mitk::StringProperty::New("extra"));
558  int refCountbeforeDS = watcher->GetReferenceCount();
559  ds->Add(extra);
560  MITK_TEST_CONDITION(ds->GetNamedNode("extra") == extra, "Adding extra node");
561  ds->Remove(extra);
562  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()),
563  "Checking removal of a node without relations");
564  extra = nullptr;
565  }
566 
567  /* Checking removal of a node with a parent */
568  {
570  extra->SetProperty("name", mitk::StringProperty::New("extra"));
571 
573  int refCountbeforeDS = watcher->GetReferenceCount();
574  ds->Add(extra, n1); // n1 is parent of extra
575 
576  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) &&
577  (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1
578  ,
579  "Adding extra node");
580  ds->Remove(extra);
581  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()) &&
582  (ds->GetDerivations(n1)->Size() == 1),
583  "Checking removal of a node with a parent");
584  extra = nullptr;
585  }
586 
587  /* Checking removal of a node with two parents */
588  {
590  extra->SetProperty("name", mitk::StringProperty::New("extra"));
591 
593  int refCountbeforeDS = watcher->GetReferenceCount();
594  mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New();
595  p->push_back(n1);
596  p->push_back(n2);
597  ds->Add(extra, p); // n1 and n2 are parents of extra
598 
599  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) &&
600  (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1
601  &&
602  (ds->GetDerivations(n2)->Size() == 3),
603  "add extra node");
604 
605  ds->Remove(extra);
607  (ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()) &&
608  (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1
609  &&
610  (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2
611  ,
612  "Checking removal of a node with two parents");
613  extra = nullptr;
614  }
615 
616  /* Checking removal of a node with two derived nodes */
617  {
619  extra->SetProperty("name", mitk::StringProperty::New("extra"));
621  int refCountbeforeDS = watcher->GetReferenceCount();
622  ds->Add(extra);
624  d1->SetProperty("name", mitk::StringProperty::New("d1"));
625  ds->Add(d1, extra);
627  d2->SetProperty("name", mitk::StringProperty::New("d2"));
628  ds->Add(d2, extra);
629 
630  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1") == d1) &&
631  (ds->GetNamedNode("d2") == d2) &&
632  (ds->GetSources(d1)->Size() == 1) // extra should be source of d1
633  &&
634  (ds->GetSources(d2)->Size() == 1) // extra should be source of d2
635  &&
636  (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra
637  ,
638  "add extra node");
639 
640  ds->Remove(extra);
641  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (ds->GetNamedNode("d1") == d1) &&
642  (ds->GetNamedNode("d2") == d2) && (refCountbeforeDS == watcher->GetReferenceCount()) &&
643  (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore
644  &&
645  (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore
646  ,
647  "Checking removal of a node with two derived nodes");
648  extra = nullptr;
649  }
650 
651  /* Checking removal of a node with two parents and two derived nodes */
652  {
654  extra->SetProperty("name", mitk::StringProperty::New("extra"));
657  int refCountbeforeDS = watcher->GetReferenceCount();
658 
659  mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New();
660  p->push_back(n1);
661  p->push_back(n2);
662  ds->Add(extra, p); // n1 and n2 are parents of extra
663 
665  d1->SetProperty("name", mitk::StringProperty::New("d1x"));
666  ds->Add(d1, extra);
668  d2->SetProperty("name", mitk::StringProperty::New("d2x"));
669  ds->Add(d2, extra);
670 
671  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1x") == d1) &&
672  (ds->GetNamedNode("d2x") == d2) &&
673  (ds->GetSources(d1)->Size() == 1) // extra should be source of d1
674  &&
675  (ds->GetSources(d2)->Size() == 1) // extra should be source of d2
676  &&
677  (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1
678  &&
679  (ds->GetDerivations(n2)->Size() == 3) // n3, n4 and extra should be derived from n2
680  &&
681  (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra
682  ,
683  "add extra node");
684 
685  ds->Remove(extra);
687  (ds->GetNamedNode("extra") == nullptr) && (ds->GetNamedNode("d1x") == d1) && (ds->GetNamedNode("d2x") == d2) &&
688  (refCountbeforeDS == watcher->GetReferenceCount()) &&
689  (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1
690  &&
691  (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2
692  &&
693  (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore
694  &&
695  (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore
696  ,
697  "Checking removal of a node with two parents and two derived nodes");
698  extra = nullptr;
699  }
700  }
701  catch (...)
702  {
703  MITK_TEST_FAILED_MSG(<< "Exeption during object removal methods");
704  }
705 
706  /* Checking for node is it's own parent exception */
707  {
708  MITK_TEST_FOR_EXCEPTION_BEGIN(std::exception);
710  extra->SetProperty("name", mitk::StringProperty::New("extra"));
711  mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New();
712  p->push_back(n1);
713  p->push_back(extra); // extra is parent of extra!!!
714  ds->Add(extra, p);
715  MITK_TEST_FOR_EXCEPTION_END(std::exception);
716  }
717 
718  /* Checking reference count of node after add and remove */
719  {
722  extra->SetProperty("name", mitk::StringProperty::New("extra"));
723  mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New();
724  p->push_back(n1);
725  p->push_back(n3);
726  ds->Add(extra, p);
727  extra = nullptr;
728  ds->Remove(ds->GetNamedNode("extra"));
729  MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Checking reference count of node after add and remove");
730  }
731 
732  /* Checking removal of a node with two derived nodes [ dataStorage->GetDerivations( rootNode )] see bug #3426 */
733  {
735  extra->SetProperty("name", mitk::StringProperty::New("extra"));
736 
737  ds->Add(extra);
739  d1y->SetProperty("name", mitk::StringProperty::New("d1y"));
741  int refCountbeforeDS = watcherD1y->GetReferenceCount();
742  ds->Add(d1y, extra);
744  d2y->SetProperty("name", mitk::StringProperty::New("d2y"));
745  ds->Add(d2y, extra);
746 
747  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1y") == d1y) &&
748  (ds->GetNamedNode("d2y") == d2y) &&
749  (ds->GetSources(d1y)->Size() == 1) // extra should be source of d1y
750  &&
751  (ds->GetSources(d2y)->Size() == 1) // extra should be source of d2y
752  &&
753  (ds->GetDerivations(extra)->Size() == 2) // d1y and d2y should be derived from extra
754  ,
755  "add extra node");
756 
757  ds->Remove(ds->GetDerivations(extra));
758  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) &&
759  (ds->GetNamedNode("d1y") == nullptr) // d1y should be nullptr now
760  &&
761  (ds->GetNamedNode("d2y") == nullptr) // d2y should be nullptr now
762  &&
763  (refCountbeforeDS == watcherD1y->GetReferenceCount()),
764  "Checking removal of subset of two derived nodes from one parent node");
765 
766  ds->Remove(extra);
767  MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr), "Checking removal of a parent node");
768  extra = nullptr;
769  }
770 
771  /* Checking GetGrouptags() */
772  {
773  const std::set<std::string> groupTags = ds->GetGroupTags();
774  MITK_TEST_CONDITION((groupTags.size() == 2) &&
775  (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 1") != groupTags.end()) &&
776  (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 2") != groupTags.end()),
777  "Checking GetGrouptags()");
778  }
779 
780  /* Checking Event handling */
781  DSEventReceiver listener;
782  try
783  {
784  ds->AddNodeEvent +=
785  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnAdd);
786  ds->RemoveNodeEvent +=
787  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnRemove);
788 
791  ds->Add(extra);
792 
793  MITK_TEST_CONDITION(listener.m_NodeAdded == extra.GetPointer(), "Checking AddEvent");
794 
795  ds->Remove(extra);
796  MITK_TEST_CONDITION(listener.m_NodeRemoved == extra.GetPointer(), "Checking RemoveEvent");
797 
798  /* RemoveListener */
799  ds->AddNodeEvent -=
800  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnAdd);
801  ds->RemoveNodeEvent -=
802  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnRemove);
803  listener.m_NodeAdded = nullptr;
804  listener.m_NodeRemoved = nullptr;
805  ds->Add(extra);
806  ds->Remove(extra);
807  MITK_TEST_CONDITION((listener.m_NodeRemoved == nullptr) && (listener.m_NodeAdded == nullptr), "Checking RemoveListener");
808 
809  std::cout << "Pointer handling after event handling: " << std::flush;
810  extra = nullptr; // delete reference to the node. its memory should be freed now
811  MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Pointer handling after event handling");
812  }
813  catch (...)
814  {
815  /* cleanup */
816  ds->AddNodeEvent -=
817  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnAdd);
818  ds->RemoveNodeEvent -=
819  mitk::MessageDelegate1<DSEventReceiver, const mitk::DataNode *>(&listener, &DSEventReceiver::OnRemove);
820  MITK_TEST_FAILED_MSG(<< "Exception during object removal methods");
821  }
822 
823  // Checking ComputeBoundingGeometry3D method*/
824  const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll();
825  auto geometry = ds->ComputeBoundingGeometry3D();
826  MITK_TEST_CONDITION(geometry->CountTimeSteps() == 4, "Test for number or time steps with ComputeBoundingGeometry()");
827  mitk::TimeBounds timebounds = geometry->GetTimeBounds();
828  MITK_TEST_CONDITION((timebounds[0] == 0) && (timebounds[1] == 4),
829  "Test for timebounds with ComputeBoundingGeometry()");
830  for (unsigned int i = 0; i < geometry->CountTimeSteps(); i++)
831  {
832  mitk::BaseGeometry::Pointer subGeometry = geometry->GetGeometryForTimeStep(i);
833  mitk::TimeBounds bounds = geometry->GetTimeBounds(i);
834  MITK_TEST_CONDITION((bounds[0] == i) && (bounds[1] == i + 1),
835  "Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()");
836  }
837  geometry = ds->ComputeBoundingGeometry3D(all);
838  MITK_TEST_CONDITION(geometry->CountTimeSteps() == 4,
839  "Test for number or time steps with ComputeBoundingGeometry(allNodes)");
840  timebounds = geometry->GetTimeBounds();
841  MITK_TEST_CONDITION((timebounds[0] == 0) && (timebounds[1] == 4),
842  "Test for timebounds with ComputeBoundingGeometry(allNodes)");
843  for (unsigned int i = 0; i < geometry->CountTimeSteps(); i++)
844  {
845  mitk::BaseGeometry::Pointer subGeometry = geometry->GetGeometryForTimeStep(i);
846  mitk::TimeBounds bounds = geometry->GetTimeBounds(i);
847  MITK_TEST_CONDITION((bounds[0] == i) && (bounds[1] == i + 1),
848  "Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()");
849  }
850 
851  // test for thread safety of DataStorage
852  try
853  {
855  ItkDeleteEventListener listener(standaloneDataStorage);
856  {
858  mitk::DataNode *pEmptyNode = emptyNode;
859  listener.SetNode(emptyNode);
860  standaloneDataStorage->Add(emptyNode);
861  emptyNode = nullptr; // emptyNode is still alive because standaloneDataStorage
862  // owns it
863  standaloneDataStorage->Remove(pEmptyNode); // this should not freeze the whole thing
864  }
865  }
866  catch (...)
867  {
868  MITK_TEST_FAILED_MSG(<< "Exception during testing DataStorage thread safe");
869  }
870 
871  /* Clear DataStorage */
872  ds->Remove(ds->GetAll());
873  MITK_TEST_CONDITION(ds->GetAll()->Size() == 0, "Checking Clear DataStorage");
874 }
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:28
Data management class that handles &#39;was created by&#39; relations.
static Pointer New()
DataNode * GetNode(const NodePredicateBase *condition=nullptr) const
Convenience method to get the first node that matches the predicate condition.
#define MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS)
virtual SetOfObjects::ConstPointer GetDerivations(const DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectDerivations=true) const =0
returns a set of derived objects for a given node.
int mitkDataStorageTest(int argc, char *argv[])
itk::FixedArray< ScalarType, 2 > TimeBounds
Standard typedef for time-bounds.
DataType * GetNamedObject(const char *name) const
Convenience method to get the first data object of a given data type with a given name...
std::map< const DataNode *, unsigned long > m_NodeDeleteObserverTags
Saves Delete-Observer Tags for each node in order to remove the event listeners again.
TimeGeometry::ConstPointer ComputeBoundingGeometry3D(const SetOfObjects *input, const char *boolPropertyKey=nullptr, const BaseRenderer *renderer=nullptr, const char *boolPropertyKey2=nullptr) const
Compute the axis-parallel bounding geometry of the input objects.
static Pointer New()
#define MITK_TEST_CONDITION_REQUIRED(COND, MSG)
static Pointer New()
DataCollection - Class to facilitate loading/accessing structured data.
virtual SetOfObjects::ConstPointer GetSources(const DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectSources=true) const =0
returns a set of source objects for a given node that meet the given condition(s).
section GeneralTestsDeprecatedOldTestingStyle Deprecated macros All tests with MITK_TEST_BEGIN()
static Pointer New(unsigned int _arg)
DataNode * GetNamedDerivedNode(const char *name, const DataNode *sourceNode, bool onlyDirectDerivations=true) const
Convenience method to get the first node with a given name that is derived from sourceNode.
virtual void Add(DataNode *node, const DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
#define MITK_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT)
Simplified version of MITK_TEST_FOR_EXCEPTION_BEGIN / END for a single statement. ...
#define MITK_TEST_OUTPUT(x)
Output some text.
mitk::DataNode::Pointer m_Node
static Pointer New()
virtual SetOfObjects::ConstPointer GetAll() const =0
returns a set of all data objects that are stored in the data storage
mitk::DataStorage::Pointer m_DataStorage
Keeps track of the reference count of an object even if it is destroyed.
static Pointer New(mitk::BaseData *_arg)
static Pointer New()
#define MITK_TEST_CONDITION(COND, MSG)
#define mitkClassMacro(className, SuperClassName)
Definition: mitkCommon.h:40
SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const
returns a set of data objects that meet the given condition(s)
void TestDataStorage(mitk::DataStorage *ds, std::string filename)
Test for the DataStorage class and its associated classes (e.g. the predicate classes) This method wi...
static Pointer New(const mitk::NodePredicateBase *_arg)
#define MITK_TEST_FAILED_MSG(MSG)
Fail and finish test with message MSG.
Image class for storing images.
Definition: mitkImage.h:72
#define MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS)
Begin block which should be checked for exceptions.
DataStorageEvent AddNodeEvent
AddEvent is emitted whenever a new node has been added to the DataStorage.
std::map< const DataNode *, unsigned long > m_NodeModifiedObserverTags
Saves Modified-Observer Tags for each node in order to remove the event listeners again...
mitk::Image::Pointer image
static Pointer New(const char *_arg)
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
static Pointer New(const char *_arg)
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
DataStorageEvent RemoveNodeEvent
RemoveEvent is emitted directly before a node is removed from the DataStorage.
const DataNode::GroupTagList GetGroupTags() const
Returns a list of used grouptags.
and MITK_TEST_END()
static Pointer New()
static Pointer New()
DataNode * GetNamedNode(const char *name) const
Convenience method to get the first node with a given name.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:64