1 #include "catch.hpp"
2 
3 #include <QString>
4 #include <cmath>
5 #include <iostream>
6 #include <tuple>
7 #include <unordered_set>
8 
9 #define private public
10 #define protected public
11 #include "abstractmodel/abstracttreemodel.hpp"
12 #include "abstractmodel/treeitem.hpp"
13 
14 TEST_CASE("Basic tree testing", "[TreeModel]")
15 {
16     auto model = AbstractTreeModel::construct();
17 
18     REQUIRE(model->checkConsistency());
19     REQUIRE(model->rowCount() == 0);
20 
21     SECTION("Item creation Test")
22     {
23         auto item = TreeItem::construct(QList<QVariant>{QString("test")}, model, false);
24         int id = item->getId();
25         REQUIRE(item->depth() == 0);
26         REQUIRE(model->checkConsistency());
27 
28         // check that a valid Id has been assigned
29         REQUIRE(id != -1);
30 
31         // check that the item is not yet registered (not valid parent)
32         REQUIRE(model->m_allItems.size() == 1);
33 
34         // Assign this to a parent
35         model->getRoot()->appendChild(item);
36         REQUIRE(model->checkConsistency());
37         // Now the item should be registered, we query it
38         REQUIRE(model->m_allItems.size() == 2);
39         REQUIRE(model->getItemById(id) == item);
40         REQUIRE(item->depth() == 1);
41         REQUIRE(model->rowCount() == 1);
42         REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 0);
43 
44         // Retrieve data member
45         REQUIRE(model->data(model->getIndexFromItem(item), 0) == QStringLiteral("test"));
46 
47         // Try joint creation / assignation
48         auto item2 = item->appendChild(QList<QVariant>{QString("test2")});
__anona3b2930b0102() 49         auto state = [&]() {
50             REQUIRE(model->checkConsistency());
51             REQUIRE(item->depth() == 1);
52             REQUIRE(item2->depth() == 2);
53             REQUIRE(model->rowCount() == 1);
54             REQUIRE(item->row() == 0);
55             REQUIRE(item2->row() == 0);
56             REQUIRE(model->data(model->getIndexFromItem(item2), 0) == QStringLiteral("test2"));
57             REQUIRE(model->rowCount(model->getIndexFromItem(item2)) == 0);
58         };
59         state();
60         REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 1);
61         REQUIRE(model->m_allItems.size() == 3);
62 
63         // Add a second child to item to check if everything collapses
64         auto item3 = item->appendChild(QList<QVariant>{QString("test3")});
65         state();
66         REQUIRE(model->rowCount(model->getIndexFromItem(item3)) == 0);
67         REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 2);
68         REQUIRE(model->m_allItems.size() == 4);
69         REQUIRE(item3->depth() == 2);
70         REQUIRE(item3->row() == 1);
71         REQUIRE(model->data(model->getIndexFromItem(item3), 0) == QStringLiteral("test3"));
72     }
73 
74     SECTION("Invalid moves")
75     {
76         auto item = model->getRoot()->appendChild(QList<QVariant>{QString("test")});
__anona3b2930b0202() 77         auto state = [&]() {
78             REQUIRE(model->checkConsistency());
79             REQUIRE(model->rowCount() == 1);
80             REQUIRE(item->depth() == 1);
81             REQUIRE(item->row() == 0);
82             REQUIRE(model->data(model->getIndexFromItem(item), 0) == QStringLiteral("test"));
83         };
84         state();
85         REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 0);
86 
87         // Try to move the root
88         REQUIRE_FALSE(item->appendChild(model->getRoot()));
89         state();
90         REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 0);
91 
92         auto item2 = item->appendChild(QList<QVariant>{QString("test2")});
93         auto item3 = item2->appendChild(QList<QVariant>{QString("test3")});
94         auto item4 = item3->appendChild(QList<QVariant>{QString("test4")});
__anona3b2930b0302() 95         auto state2 = [&]() {
96             state();
97             REQUIRE(item2->depth() == 2);
98             REQUIRE(item2->row() == 0);
99             REQUIRE(model->data(model->getIndexFromItem(item2), 0) == QStringLiteral("test2"));
100             REQUIRE(item3->depth() == 3);
101             REQUIRE(item3->row() == 0);
102             REQUIRE(model->data(model->getIndexFromItem(item3), 0) == QStringLiteral("test3"));
103             REQUIRE(item4->depth() == 4);
104             REQUIRE(item4->row() == 0);
105             REQUIRE(model->data(model->getIndexFromItem(item4), 0) == QStringLiteral("test4"));
106         };
107         state2();
108 
109         // Try to make a loop
110         REQUIRE_FALSE(item->changeParent(item3));
111         state2();
112         REQUIRE_FALSE(item->changeParent(item4));
113         state2();
114 
115         // Try to append a child that already have a parent
116         REQUIRE_FALSE(item->appendChild(item4));
117         state2();
118 
119         // valid move
120         REQUIRE(item4->changeParent(item2));
121         REQUIRE(model->checkConsistency());
122     }
123 
124     SECTION("Deregistration tests")
125     {
126         // we construct a non trivial structure
127         auto item = model->getRoot()->appendChild(QList<QVariant>{QString("test")});
128         auto item2 = item->appendChild(QList<QVariant>{QString("test2")});
129         auto item3 = item2->appendChild(QList<QVariant>{QString("test3")});
130         auto item4 = item3->appendChild(QList<QVariant>{QString("test4")});
131         auto item5 = item2->appendChild(QList<QVariant>{QString("test5")});
__anona3b2930b0402() 132         auto state = [&]() {
133             REQUIRE(model->checkConsistency());
134             REQUIRE(model->rowCount() == 1);
135             REQUIRE(item->depth() == 1);
136             REQUIRE(item->row() == 0);
137             REQUIRE(model->data(model->getIndexFromItem(item), 0) == QStringLiteral("test"));
138             REQUIRE(model->rowCount(model->getIndexFromItem(item)) == 1);
139             REQUIRE(item2->depth() == 2);
140             REQUIRE(item2->row() == 0);
141             REQUIRE(model->data(model->getIndexFromItem(item2), 0) == QStringLiteral("test2"));
142             REQUIRE(model->rowCount(model->getIndexFromItem(item2)) == 2);
143             REQUIRE(item3->depth() == 3);
144             REQUIRE(item3->row() == 0);
145             REQUIRE(model->data(model->getIndexFromItem(item3), 0) == QStringLiteral("test3"));
146             REQUIRE(model->rowCount(model->getIndexFromItem(item3)) == 1);
147             REQUIRE(item4->depth() == 4);
148             REQUIRE(item4->row() == 0);
149             REQUIRE(model->data(model->getIndexFromItem(item4), 0) == QStringLiteral("test4"));
150             REQUIRE(model->rowCount(model->getIndexFromItem(item4)) == 0);
151             REQUIRE(item5->depth() == 3);
152             REQUIRE(item5->row() == 1);
153             REQUIRE(model->data(model->getIndexFromItem(item5), 0) == QStringLiteral("test5"));
154             REQUIRE(model->rowCount(model->getIndexFromItem(item5)) == 0);
155             REQUIRE(model->m_allItems.size() == 6);
156             REQUIRE(item->isInModel());
157             REQUIRE(item2->isInModel());
158             REQUIRE(item3->isInModel());
159             REQUIRE(item4->isInModel());
160             REQUIRE(item5->isInModel());
161         };
162         state();
163 
164         // deregister the topmost item, should also deregister its children
165         item->changeParent(std::shared_ptr<TreeItem>());
166         REQUIRE(model->m_allItems.size() == 1);
167         REQUIRE(model->rowCount() == 0);
168         REQUIRE(!item->isInModel());
169         REQUIRE(!item2->isInModel());
170         REQUIRE(!item3->isInModel());
171         REQUIRE(!item4->isInModel());
172         REQUIRE(!item5->isInModel());
173 
174         // reinsert
175         REQUIRE(model->getRoot()->appendChild(item));
176         state();
177 
178         item2->removeChild(item5);
179         REQUIRE(!item5->isInModel());
180         REQUIRE(model->rowCount(model->getIndexFromItem(item2)) == 1);
181         REQUIRE(model->m_allItems.size() == 5);
182 
183         // reinsert
184         REQUIRE(item5->changeParent(item2));
185         state();
186     }
187 }
188