BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
sessionmodel.test.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // qt-mvvm: Model-view-view-model framework for large GUI applications
4 //
5 //! @file mvvm/tests/testmodel/sessionmodel.test.cpp
6 //! @brief Implements class CLASS?
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2020
11 //! @authors Gennady Pospelov et al, Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #include "google_test.h"
17 #include "mvvm/model/itempool.h"
18 #include "mvvm/model/itemutils.h"
20 #include "mvvm/model/sessionitem.h"
22 #include "mvvm/model/taginfo.h"
23 #include <memory>
24 #include <stdexcept>
25 
26 using namespace ModelView;
27 
28 class SessionModelTest : public ::testing::Test {
29 public:
31 
32  class TestItem : public SessionItem {
33  public:
34  TestItem() : SessionItem("TestItemType"){};
35  };
36 };
37 
39 
40 TEST_F(SessionModelTest, initialState)
41 {
42  SessionModel model;
43  EXPECT_EQ(model.rootItem()->model(), &model);
44  EXPECT_EQ(model.rootItem()->parent(), nullptr);
45 }
46 
48 {
49  auto pool = std::make_shared<ItemPool>();
50  SessionModel model("Test", pool);
51 
52  const model_type modelType = Constants::BaseType;
53 
54  // inserting single item
55  auto item = model.insertItem<SessionItem>();
56  EXPECT_TRUE(item != nullptr);
57  EXPECT_EQ(item->parent(), model.rootItem());
58  EXPECT_EQ(item->model(), &model);
59  EXPECT_EQ(item->modelType(), modelType);
60 
61  // checking registration
62  auto item_key = item->identifier();
63  EXPECT_EQ(pool->item_for_key(item_key), item);
64 
65  // registering tag
66  item->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
67 
68  // adding child to it
69  auto child = model.insertItem<SessionItem>(item);
70  auto child_key = child->identifier();
71  EXPECT_EQ(pool->item_for_key(child_key), child);
72 
73  EXPECT_TRUE(child != nullptr);
74  EXPECT_EQ(child->parent(), item);
75  EXPECT_EQ(child->model(), &model);
76  EXPECT_EQ(child->modelType(), modelType);
77 
78  // taking child back
79  auto taken = item->takeItem({"", 0});
80  EXPECT_EQ(taken, child);
81  EXPECT_EQ(child->model(), nullptr);
82 
83  // childitem not registered anymore
84  EXPECT_EQ(pool->item_for_key(child_key), nullptr);
85 
86  delete taken;
87 }
88 
89 TEST_F(SessionModelTest, insertNewItem)
90 {
91  auto pool = std::make_shared<ItemPool>();
92  SessionModel model("Test", pool);
93 
94  const model_type modelType = Constants::BaseType;
95 
96  // inserting single item
97  auto item = model.insertNewItem(modelType);
98  EXPECT_TRUE(item != nullptr);
99  EXPECT_EQ(item->parent(), model.rootItem());
100  EXPECT_EQ(item->model(), &model);
101  EXPECT_EQ(item->modelType(), modelType);
102 
103  // checking registration
104  auto item_key = item->identifier();
105  EXPECT_EQ(pool->item_for_key(item_key), item);
106 
107  // registering tag
108  item->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
109 
110  // adding child to it
111  auto child = model.insertNewItem(modelType, item);
112  auto child_key = child->identifier();
113  EXPECT_EQ(pool->item_for_key(child_key), child);
114 
115  EXPECT_TRUE(child != nullptr);
116  EXPECT_EQ(child->parent(), item);
117  EXPECT_EQ(child->model(), &model);
118  EXPECT_EQ(child->modelType(), modelType);
119 
120  // taking child back
121  auto taken = item->takeItem({"", 0});
122  EXPECT_EQ(taken, child);
123  EXPECT_EQ(child->model(), nullptr);
124 
125  // childitem not registered anymore
126  EXPECT_EQ(pool->item_for_key(child_key), nullptr);
127 
128  delete taken;
129 }
130 
131 TEST_F(SessionModelTest, insertNewItemWithTag)
132 {
133  const std::string tag1("tag1");
134  SessionModel model;
135  auto parent = model.insertItem<SessionItem>();
136  parent->registerTag(TagInfo::universalTag(tag1));
137  auto child1 = model.insertItem<PropertyItem>(parent, {tag1, -1});
138 
139  EXPECT_EQ(parent->tagRowOfItem(child1).tag, tag1);
140  EXPECT_EQ(Utils::IndexOfChild(parent, child1), 0);
141 
142  // adding second child
143  auto child2 = model.insertItem<PropertyItem>(parent, {tag1, 0});
144 
145  EXPECT_EQ(parent->tagRowOfItem(child2).tag, tag1);
146  EXPECT_EQ(Utils::IndexOfChild(parent, child1), 1);
147  EXPECT_EQ(Utils::IndexOfChild(parent, child2), 0);
148 }
149 
151 {
152  SessionModel model;
153 
154  // inserting single item
155  auto item = model.insertItem<SessionItem>();
156  EXPECT_TRUE(model.data(item, ItemDataRole::DISPLAY).isValid());
157 
158  // setting wrong type of data
159  QVariant value(42.0);
160  EXPECT_THROW(model.setData(item, value, ItemDataRole::DISPLAY), std::runtime_error);
161 
162  // setting new data
163  EXPECT_TRUE(model.setData(item, value, ItemDataRole::DATA));
164  EXPECT_EQ(model.data(item, ItemDataRole::DATA), value);
165 
166  // setting same data twice should return false
167  EXPECT_FALSE(model.setData(item, value, ItemDataRole::DATA));
168 }
169 
171 {
172  auto pool = std::make_shared<ItemPool>();
173  SessionModel model("Test", pool);
174 
175  auto parent = model.insertItem<SessionItem>();
176  parent->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
177 
178  auto child1 = model.insertItem<SessionItem>(parent);
179  auto child2 = model.insertItem<SessionItem>(parent, {"", 0}); // before child1
180  Q_UNUSED(child2)
181 
182  // removing child2
183  model.removeItem(parent, {"", 0}); // removing child2
184  EXPECT_EQ(parent->childrenCount(), 1);
185  EXPECT_EQ(Utils::ChildAt(parent, 0), child1);
186 
187  // child2 shouldn't be registered anymore
188  EXPECT_EQ(pool->key_for_item(child2), "");
189 }
190 
191 TEST_F(SessionModelTest, removeNonExistingItem)
192 {
193  auto pool = std::make_shared<ItemPool>();
194  SessionModel model("Test", pool);
195 
196  auto parent = model.insertItem<SessionItem>();
197  parent->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
198 
199  // removing non existing child
200  EXPECT_NO_THROW(model.removeItem(parent, {"", 0}));
201 }
202 
203 TEST_F(SessionModelTest, takeRowFromRootItem)
204 {
205  auto pool = std::make_shared<ItemPool>();
206  SessionModel model("Test", pool);
207 
208  auto parent = model.insertItem<SessionItem>();
209  parent->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
210  auto parent_key = parent->identifier();
211 
212  auto child = model.insertItem<SessionItem>(parent);
213  auto child_key = child->identifier();
214 
215  EXPECT_EQ(pool->item_for_key(parent_key), parent);
216  EXPECT_EQ(pool->item_for_key(child_key), child);
217 
218  // taking parent
219  auto taken = model.rootItem()->takeItem({"", 0});
220  EXPECT_EQ(pool->item_for_key(parent_key), nullptr);
221  EXPECT_EQ(pool->item_for_key(child_key), nullptr);
222  delete taken;
223 }
224 
226 {
227  SessionModel model;
228 
229  // parent with child
230  auto parent0 = model.insertItem<SessionItem>();
231  parent0->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
232  auto child0 = model.insertItem<PropertyItem>(parent0);
233 
234  // another parent with child
235  auto parent1 = model.insertItem<SessionItem>();
236  parent1->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
237  auto child1 = model.insertItem<PropertyItem>(parent1);
238 
239  // moving child0 from parent0 to parent 1
240  model.moveItem(child0, parent1, {"", 0});
241 
242  std::vector<SessionItem*> expected = {child0, child1};
243  EXPECT_EQ(parent1->children(), expected);
244  EXPECT_EQ(parent0->children().size(), 0);
245 }
246 
248 {
249  auto pool = std::make_shared<ItemPool>();
250  SessionModel model("test", pool);
251 
252  EXPECT_EQ(pool->size(), 1);
253 
254  auto first_root = model.rootItem();
255 
256  EXPECT_EQ(model.rootItem()->childrenCount(), 0);
257  model.insertItem<SessionItem>();
258  model.insertItem<SessionItem>();
259  EXPECT_EQ(model.rootItem()->childrenCount(), 2);
260 
261  model.clear();
262  EXPECT_EQ(model.rootItem()->childrenCount(), 0);
263  EXPECT_FALSE(model.rootItem() == first_root);
264  EXPECT_EQ(pool->key_for_item(first_root), "");
265  EXPECT_EQ(pool->size(), 1);
266 }
267 
268 TEST_F(SessionModelTest, clearRebuildModel)
269 {
270  auto pool = std::make_shared<ItemPool>();
271  SessionModel model("test", pool);
272 
273  EXPECT_EQ(pool->size(), 1);
274 
275  auto first_root = model.rootItem();
276 
277  EXPECT_EQ(model.rootItem()->childrenCount(), 0);
278  model.insertItem<SessionItem>();
279  model.insertItem<SessionItem>();
280  EXPECT_EQ(model.rootItem()->childrenCount(), 2);
281 
282  auto new_item = new SessionItem;
283  auto rebuild = [new_item](auto parent) { parent->insertItem(new_item, TagRow::append()); };
284 
285  model.clear(rebuild);
286  EXPECT_EQ(model.rootItem()->childrenCount(), 1);
287  EXPECT_FALSE(model.rootItem() == first_root);
288  EXPECT_EQ(pool->key_for_item(first_root), "");
289  EXPECT_EQ(pool->size(), 2);
290  EXPECT_EQ(pool->key_for_item(new_item), new_item->identifier());
291 }
292 
293 //! Tests item copy when from root item to root item.
294 
295 TEST_F(SessionModelTest, copyModelItemRootContext)
296 {
297  SessionModel model;
298 
299  // create single item with value
300  auto item = model.insertItem<SessionItem>();
301  item->setData(42.0);
302 
303  // copying to root item
304  auto copy = model.copyItem(item, model.rootItem());
305 
306  // checking copy
307  ASSERT_TRUE(copy != nullptr);
308  ASSERT_TRUE(copy != item);
309  EXPECT_FALSE(copy->identifier().empty());
310  EXPECT_TRUE(copy->identifier() != item->identifier());
311  EXPECT_EQ(copy->data<double>(), 42.0);
312  EXPECT_EQ(model.rootItem()->children().size(), 2);
313  EXPECT_TRUE(item != copy);
314  std::vector<SessionItem*> expected = {item, copy};
315  EXPECT_EQ(model.rootItem()->children(), expected);
316 }
317 
318 //! Tests item copy from parent to root item.
319 
320 TEST_F(SessionModelTest, copyParentWithProperty)
321 {
322  SessionModel model;
323 
324  // parent with single child and data on ite
325  auto parent0 = model.insertItem<SessionItem>();
326  parent0->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
327  auto child0 = model.insertItem<SessionItem>(parent0);
328  child0->setData(42.0);
329 
330  // copying whole parent to root
331  auto copy = model.copyItem(parent0, model.rootItem());
332  auto copy_child = copy->getItem("defaultTag");
333 
334  ASSERT_TRUE(copy != nullptr);
335  ASSERT_TRUE(copy_child != nullptr);
336  EXPECT_FALSE(copy->identifier().empty());
337  EXPECT_TRUE(copy->identifier() != parent0->identifier());
338  EXPECT_EQ(copy_child->data<double>(), 42.0);
339 }
340 
341 //! Tests item copy for property item.
342 
343 TEST_F(SessionModelTest, copyFreeItem)
344 {
345  SessionModel model;
346 
347  // single parent in a model
348  auto parent0 = model.insertItem<SessionItem>();
349  parent0->registerTag(TagInfo::universalTag("defaultTag"), /*set_as_default*/ true);
350 
351  // free item
352  auto item = std::make_unique<PropertyItem>();
353  item->setData(42.0);
354 
355  // copying to parent
356  auto copy = model.copyItem(item.get(), parent0);
357  EXPECT_EQ(copy->data<double>(), 42.0);
358 }
359 
360 //! Attempt to copy property item into the same tag.
361 
362 TEST_F(SessionModelTest, forbiddenCopy)
363 {
364  SessionModel model;
365 
366  // single parent in a model
367  auto parent0 = model.insertItem<SessionItem>();
368  parent0->registerTag(TagInfo::propertyTag("property", "Property"));
369  auto property = model.insertItem<PropertyItem>(parent0, "property");
370 
371  // copying property to same property tag is not allowed
372  auto copy = model.copyItem(property, parent0, {"property", -1});
373  EXPECT_EQ(parent0->childrenCount(), 1);
374  EXPECT_EQ(copy, nullptr);
375 }
376 
377 //! Test item find using identifier.
378 
380 {
381  SessionModel model;
382  auto parent = model.insertItem<SessionItem>();
383 
384  // check that we can find item using its own identofoer
385  const identifier_type id = parent->identifier();
386  EXPECT_EQ(model.findItem(id), parent);
387 
388  // check that we can't find deleted item.
389  model.removeItem(model.rootItem(), {"", 0});
390  EXPECT_EQ(model.findItem(id), nullptr);
391 }
392 
393 //! Test items in different models.
394 
395 TEST_F(SessionModelTest, findItemInAlienModel)
396 {
397  // two models with common pool
398  auto pool = std::make_shared<ItemPool>();
399  SessionModel model1("Test1", pool);
400  SessionModel model2("Test2", pool);
401 
402  // inserting items in both models
403  auto parent1 = model1.insertItem<SessionItem>();
404  auto parent2 = model2.insertItem<SessionItem>();
405  const identifier_type id1 = parent1->identifier();
406  const identifier_type id2 = parent2->identifier();
407 
408  // checking that we can access items from both models
409  EXPECT_EQ(model1.findItem(id1), parent1);
410  EXPECT_EQ(model2.findItem(id1), parent1);
411  EXPECT_EQ(model1.findItem(id2), parent2);
412  EXPECT_EQ(model2.findItem(id2), parent2);
413 
414  // check that we can't find deleted item.
415  model1.removeItem(model1.rootItem(), {"", 0});
416  EXPECT_EQ(model1.findItem(id1), nullptr);
417  EXPECT_EQ(model2.findItem(id1), nullptr);
418  EXPECT_EQ(model1.findItem(id2), parent2);
419  EXPECT_EQ(model2.findItem(id2), parent2);
420 }
421 
423 {
424  SessionModel model;
425  EXPECT_EQ(model.topItem<>(), nullptr);
426  EXPECT_EQ(model.topItem(), nullptr);
427 
428  auto property = model.insertItem<PropertyItem>();
429  auto compound = model.insertItem<CompoundItem>();
430  EXPECT_EQ(model.topItem<>(), property);
431  EXPECT_EQ(model.topItem(), property);
432  EXPECT_EQ(model.topItem<CompoundItem>(), compound);
433 }
434 
436 {
437  std::vector<SessionItem*> expected;
438 
439  SessionModel model;
440  EXPECT_EQ(model.topItems<>(), expected);
441  EXPECT_EQ(model.topItems(), expected);
442 
443  auto property1 = model.insertItem<PropertyItem>();
444  auto compound1 = model.insertItem<CompoundItem>();
445  auto property2 = model.insertItem<PropertyItem>();
446  auto compound2 = model.insertItem<CompoundItem>();
447 
448  expected = {property1, compound1, property2, compound2};
449  EXPECT_EQ(model.topItems<>(), expected);
450  EXPECT_EQ(model.topItems(), expected);
451 
452  std::vector<CompoundItem*> expected2 = {compound1, compound2};
453  EXPECT_EQ(model.topItems<CompoundItem>(), expected2);
454 }
455 
456 TEST_F(SessionModelTest, registerItem)
457 {
458  const std::string expectedModelType("TestItemType");
459 
460  SessionModel model;
461  model.registerItem<TestItem>();
462 
463  auto item = model.insertNewItem(expectedModelType);
464  ASSERT_TRUE(item != nullptr);
465  ASSERT_TRUE(dynamic_cast<TestItem*>(item) != nullptr);
466  EXPECT_EQ(item->modelType(), expectedModelType);
467 }
Complex item holding mixed SessionItem types (single properties and other CompountItems).
Definition: compounditem.h:28
Item to carry concrete editable entity (e.g.
Definition: propertyitem.h:27
The main object representing an editable/displayable/serializable entity.
Definition: sessionitem.h:38
std::string identifier() const
Returns unique identifier.
Definition: sessionitem.cpp:87
TagRow tagRowOfItem(const SessionItem *item) const
Returns pair of tag and row corresponding to given item.
SessionItem * takeItem(const TagRow &tagrow)
Removes item from given row from given tag, returns it to the caller.
void registerTag(const TagInfo &tagInfo, bool set_as_default=false)
Registers tag to hold items under given name.
bool setData(const T &value, int role=ItemDataRole::DATA, bool direct=false)
Sets data for a given role.
Definition: sessionitem.h:141
SessionItem * parent() const
Returns parent item. Will return nullptr if item doesn't have a parent.
SessionModel * model() const
Returns the model to which given item belongs to.
int childrenCount() const
Returns total number of children in all tags.
std::vector< SessionItem * > children() const
Returns vector of children formed from all chidlren from all tags.
bool insertItem(SessionItem *item, const TagRow &tagrow)
Insert item into given tag under the given row.
Main class to hold hierarchy of SessionItem objects.
Definition: sessionmodel.h:37
T * topItem() const
Returns top item of the given type.
Definition: sessionmodel.h:126
bool setData(SessionItem *item, const Variant &value, int role)
Sets the data for given item.
std::vector< T * > topItems() const
Returns top items of the given type.
Definition: sessionmodel.h:112
SessionItem * insertNewItem(const model_type &modelType, SessionItem *parent=nullptr, const TagRow &tagrow={})
Insert new item using item's modelType.
void moveItem(SessionItem *item, SessionItem *new_parent, const TagRow &tagrow)
Move item from it's current parent to a new parent under given tag and row.
SessionItem * findItem(const identifier_type &id)
Returns SessionItem for given identifier.
SessionItem * copyItem(const SessionItem *item, SessionItem *parent, const TagRow &tagrow={})
Copy item and insert it in parent's tag and row. Item could belong to any model/parent.
SessionItem * rootItem() const
Returns root item of the model.
void registerItem(const std::string &label={})
Register used defined item to use with the model.
Definition: sessionmodel.h:135
T * insertItem(SessionItem *parent=nullptr, const TagRow &tagrow={})
Inserts item into given parent under given tagrow.
Definition: sessionmodel.h:104
Variant data(SessionItem *item, int role) const
Returns the data for given item and role.
void clear(std::function< void(SessionItem *)> callback={})
Removes all items from the model.
void removeItem(SessionItem *parent, const TagRow &tagrow)
Removes given row from parent.
static TagInfo universalTag(std::string name, std::vector< std::string > modelTypes={})
Constructs universal tag intended for unlimited amount of various items.
Definition: taginfo.cpp:34
static TagInfo propertyTag(std::string name, std::string model_type)
Constructs tag intended for single property.
Definition: taginfo.cpp:40
static TagRow append(const std::string &tag_name={})
Returns TagRow corresponding to the append to tag_name.
Definition: tagrow.cpp:36
std::string tag
Definition: tagrow.h:27
Defines class CLASS?
Defines class CLASS?
Defines class CLASS?
Defines class CLASS?
const model_type BaseType
Definition: mvvm_types.h:45
const int DATA
main data role
Definition: mvvm_types.h:30
const int DISPLAY
display name
Definition: mvvm_types.h:31
MVVM_MODEL_EXPORT int IndexOfChild(const SessionItem *parent, const SessionItem *child)
Returns index in children array corresponding to given child.
Definition: itemutils.cpp:81
MVVM_MODEL_EXPORT SessionItem * ChildAt(const SessionItem *parent, int index)
Returns child at given index of parent.
Definition: itemutils.cpp:70
materialitems.h Collection of materials to populate MaterialModel.
std::string identifier_type
Definition: types.h:22
@ copy
full deep copying with item identifiers regenerated
std::string model_type
Definition: types.h:23
Defines class CLASS?
Defines class CLASS?
Defines class CLASS?
TEST_F(SessionModelTest, initialState)
Defines class CLASS?