BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
itemmapper.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/itemmapper.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"
16 #include "mockwidgets.h"
18 #include "mvvm/model/sessionitem.h"
21 #include <stdexcept>
22 
23 using namespace ModelView;
24 using ::testing::_;
25 
26 class ItemMapperTest : public ::testing::Test {
27 public:
29 };
30 
32 
33 //! Check that mapper works only in model context.
34 
35 TEST(ItemMapperTest, initialState)
36 {
37  // item outside model context can't have a mapper
38  auto item = std::make_unique<SessionItem>();
39  EXPECT_THROW(item->mapper(), std::runtime_error);
40 
41  // item in model context does have a mapper
42  SessionModel model;
43  auto item2 = model.insertItem<SessionItem>(model.rootItem());
44  EXPECT_NO_THROW(item2->mapper());
45 }
46 
47 //! Destroying item, expecting single call of onItemDestroy in MockWidget.
48 
49 TEST(ItemMapperTest, onItemDestroy)
50 {
51  SessionModel model;
52  auto item = model.insertItem<SessionItem>(model.rootItem());
53 
54  MockWidgetForItem widget(item);
55 
56  auto expected_item = item;
57  EXPECT_CALL(widget, onItemDestroy(expected_item)).Times(1);
58  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
59  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
60  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
61  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
62  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
63  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
64 
65  // performing action
66  model.removeItem(model.rootItem(), {"", 0});
67 }
68 
69 //! Setting data to item, expecting onDataChange callback.
70 
71 TEST(ItemMapperTest, onDataChange)
72 {
73  SessionModel model;
74  auto item = model.insertItem<SessionItem>(model.rootItem());
75 
76  MockWidgetForItem widget(item);
77 
78  auto expected_role = ItemDataRole::DATA;
79  auto expected_item = item;
80  EXPECT_CALL(widget, onDataChange(expected_item, expected_role)).Times(1);
81  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
82  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
83  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
84  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
85  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
86 
87  // perform action
88  item->setData(42.0);
89 }
90 
91 //! Setting same data to item, expecting no callbacks on onDataChange.
92 
93 TEST(ItemMapperTest, onDataChangeDuplicate)
94 {
95  SessionModel model;
96  auto item = model.insertItem<SessionItem>(model.rootItem());
97 
98  MockWidgetForItem widget(item);
99 
100  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
101  EXPECT_CALL(widget, onDataChange(_, _)).Times(1);
102  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
103  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
104  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
105  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
106  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
107 
108  // perform actions, only one call should be triggered
109  item->setData(42.0);
110  item->setData(42.0); // same data
111 }
112 
113 //! Setting mapper activity to false, change the data, expect no callbacks.
114 
115 TEST(ItemMapperTest, setActivity)
116 {
117  SessionModel model;
118  auto item = model.insertItem<SessionItem>(model.rootItem());
119 
120  MockWidgetForItem widget(item);
121 
122  item->mapper()->setActive(false);
123 
124  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
125  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
126  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
127  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
128  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
129  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
130  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
131 
132  // perform actions, no calls should be triggered
133  item->setData(42.0);
134 }
135 
136 //! Unsubscribing from item, expecting no callbacks.
137 
138 TEST(ItemMapperTest, unsubscribe)
139 {
140  SessionModel model;
141  auto item = model.insertItem<SessionItem>(model.rootItem());
142 
143  MockWidgetForItem widget1(item);
144  MockWidgetForItem widget2(item);
145 
146  item->mapper()->unsubscribe(&widget1);
147 
148  EXPECT_CALL(widget1, onDataChange(_, _)).Times(0);
149  EXPECT_CALL(widget2, onDataChange(_, _)).Times(1);
150 
151  // perform action, only one widget should be triggered
152  item->setData(42.0);
153 }
154 
155 //! Changing item property.
156 
157 TEST(ItemMapperTest, onPropertyChange)
158 {
159  SessionModel model;
160  auto item = model.insertItem<CompoundItem>();
161  EXPECT_TRUE(item != nullptr);
162 
163  auto property = item->addProperty("height", 42.0);
164 
165  MockWidgetForItem widget(item);
166 
167  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
168  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
169  EXPECT_CALL(widget, onPropertyChange(item, "height")).Times(1);
170  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
171  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
172  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
173  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
174 
175  // perform action
176  item->setProperty("height", 43.0);
177  EXPECT_EQ(item->property<double>("height"), 43.0);
178  EXPECT_EQ(property->data<double>(), 43.0);
179 }
180 
181 //! Changing item property.
182 
183 TEST(ItemMapperTest, onChildPropertyChange)
184 {
185  SessionModel model;
186  auto compound1 = model.insertItem<CompoundItem>();
187  compound1->registerTag(TagInfo::universalTag("tag1"), /*set_as_default*/ true);
188  auto compound2 = model.insertItem<CompoundItem>(compound1);
189 
190  auto property = compound2->addProperty("height", 42.0);
191 
192  MockWidgetForItem widget(compound1);
193 
194  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
195  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
196  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
197  EXPECT_CALL(widget, onChildPropertyChange(compound2, "height")).Times(1);
198  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
199  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
200  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
201 
202  // perform action
203  compound2->setProperty("height", 43.0);
204  EXPECT_EQ(compound2->property<double>("height"), 43.0);
205  EXPECT_EQ(property->data<double>(), 43.0);
206 }
207 
208 //! Inserting item to item.
209 
210 TEST(ItemMapperTest, onItemInsert)
211 {
212  SessionModel model;
213  auto compound1 = model.insertItem<CompoundItem>();
214  compound1->registerTag(TagInfo::universalTag("tag1"), /*set_as_default*/ true);
215 
216  MockWidgetForItem widget(compound1);
217 
218  const TagRow expected_tagrow{"tag1", 0};
219  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
220  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
221  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
222  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
223  EXPECT_CALL(widget, onItemInserted(compound1, expected_tagrow)).Times(1);
224  EXPECT_CALL(widget, onItemRemoved(_, _)).Times(0);
225  EXPECT_CALL(widget, onAboutToRemoveItem(_, _)).Times(0);
226 
227  // perform action
228  model.insertItem<CompoundItem>(compound1, expected_tagrow);
229 }
230 
231 //! Inserting item to item.
232 
233 TEST(ItemMapperTest, onAboutToRemoveItem)
234 {
235  const TagRow expected_tagrow = {"tag1", 0};
236 
237  SessionModel model;
238  auto compound1 = model.insertItem<CompoundItem>();
239  compound1->registerTag(TagInfo::universalTag("tag1"), /*set_as_default*/ true);
240  model.insertItem<CompoundItem>(compound1, expected_tagrow);
241 
242  MockWidgetForItem widget(compound1);
243 
244  EXPECT_CALL(widget, onItemDestroy(_)).Times(0);
245  EXPECT_CALL(widget, onDataChange(_, _)).Times(0);
246  EXPECT_CALL(widget, onPropertyChange(_, _)).Times(0);
247  EXPECT_CALL(widget, onChildPropertyChange(_, _)).Times(0);
248  EXPECT_CALL(widget, onItemInserted(_, _)).Times(0);
249  EXPECT_CALL(widget, onItemRemoved(compound1, expected_tagrow)).Times(1);
250  EXPECT_CALL(widget, onAboutToRemoveItem(compound1, expected_tagrow)).Times(1);
251 
252  // perform action
253  model.removeItem(compound1, expected_tagrow);
254 }
Mock widget to test ItemMapper functionality.
Definition: mockwidgets.h:36
Complex item holding mixed SessionItem types (single properties and other CompountItems).
Definition: compounditem.h:28
T * addProperty(const std::string &name)
Adds property item of given type.
Definition: compounditem.h:43
The main object representing an editable/displayable/serializable entity.
Definition: sessionitem.h:38
void registerTag(const TagInfo &tagInfo, bool set_as_default=false)
Registers tag to hold items under given name.
Main class to hold hierarchy of SessionItem objects.
Definition: sessionmodel.h:37
SessionItem * rootItem() const
Returns root item of the model.
T * insertItem(SessionItem *parent=nullptr, const TagRow &tagrow={})
Inserts item into given parent under given tagrow.
Definition: sessionmodel.h:104
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
Aggregate to hold (tag, row) information for SessionModel.
Definition: tagrow.h:25
Defines class CLASS?
Defines class CLASS?
Defines class CLASS?
TEST(ItemMapperTest, initialState)
Check that mapper works only in model context.
Defines class CLASS?
const int DATA
main data role
Definition: mvvm_types.h:30
materialitems.h Collection of materials to populate MaterialModel.
Defines class CLASS?
Defines class CLASS?