File indexing completed on 2024-06-09 04:22:11
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_node_test.h" 0008 #include <simpletest.h> 0009 #include <limits.h> 0010 #include "kis_types.h" 0011 #include "kis_global.h" 0012 #include "kis_node_graph_listener.h" 0013 #include <KoProperties.h> 0014 #include <testutil.h> 0015 0016 0017 void KisNodeTest::testCreation() 0018 { 0019 TestUtil::TestGraphListener graphListener; 0020 0021 KisNode * node = new TestNodeA(); 0022 QVERIFY(node->graphListener() == 0); 0023 0024 node->setGraphListener(&graphListener); 0025 QVERIFY(node->graphListener() != 0); 0026 0027 // Test contract for initial state 0028 QVERIFY(node->parent() == 0); 0029 QVERIFY(node->firstChild() == 0); 0030 QVERIFY(node->lastChild() == 0); 0031 QVERIFY(node->prevSibling() == 0); 0032 QVERIFY(node->nextSibling() == 0); 0033 QVERIFY(node->childCount() == 0); 0034 QVERIFY(node->at(0) == 0); 0035 QVERIFY(node->at(UINT_MAX) == 0); 0036 QVERIFY(node->index(0) == -1); 0037 0038 delete node; 0039 } 0040 0041 0042 void KisNodeTest::testOrdering() 0043 { 0044 TestUtil::TestGraphListener graphListener; 0045 0046 KisNodeSP root = new TestNodeA(); 0047 root->setGraphListener(&graphListener); 0048 KisNodeSP node1 = new TestNodeA(); 0049 KisNodeSP node2 = new TestNodeA(); 0050 KisNodeSP node3 = new TestNodeA(); 0051 KisNodeSP node4 = new TestNodeA(); 0052 0053 /* 0054 +---------+ 0055 | node 4 | 0056 | node 2 | 0057 | node 3 | 0058 | node 1 | 0059 |root | 0060 +---------+ 0061 */ 0062 0063 graphListener.resetBools(); 0064 QVERIFY(root->lastChild() == 0); 0065 root->add(node1, root->lastChild()); 0066 QVERIFY(graphListener.beforeInsertRow == true); 0067 QVERIFY(graphListener.afterInsertRow == true); 0068 QVERIFY(graphListener.beforeRemoveRow == false); 0069 QVERIFY(graphListener.afterRemoveRow == false); 0070 QVERIFY(root->firstChild() == node1); 0071 QVERIFY(root->lastChild() == node1); 0072 graphListener.resetBools(); 0073 0074 QVERIFY(root->lastChild() == node1); 0075 root->add(node2, root->lastChild()); 0076 QVERIFY(graphListener.beforeInsertRow == true); 0077 QVERIFY(graphListener.afterInsertRow == true); 0078 QVERIFY(graphListener.beforeRemoveRow == false); 0079 QVERIFY(graphListener.afterRemoveRow == false); 0080 QVERIFY(root->firstChild() == node1); 0081 QVERIFY(root->lastChild() == node2); 0082 graphListener.resetBools(); 0083 0084 QVERIFY(root->lastChild() == node2); 0085 root->add(node3, node1); 0086 QVERIFY(root->lastChild() == node2); 0087 QVERIFY(graphListener.beforeInsertRow == true); 0088 QVERIFY(graphListener.afterInsertRow == true); 0089 QVERIFY(graphListener.beforeRemoveRow == false); 0090 QVERIFY(graphListener.afterRemoveRow == false); 0091 QVERIFY(root->firstChild() == node1); 0092 QVERIFY(root->lastChild() == node2); 0093 graphListener.resetBools(); 0094 0095 root->add(node4, root->lastChild()); 0096 QVERIFY(graphListener.beforeInsertRow == true); 0097 QVERIFY(graphListener.afterInsertRow == true); 0098 QVERIFY(graphListener.beforeRemoveRow == false); 0099 QVERIFY(graphListener.afterRemoveRow == false); 0100 QVERIFY(root->firstChild() == node1); 0101 QVERIFY(root->lastChild() == node4); 0102 graphListener.resetBools(); 0103 0104 QVERIFY(root->childCount() == 4); 0105 0106 QVERIFY(node1->parent() == root); 0107 QVERIFY(node2->parent() == root); 0108 QVERIFY(node3->parent() == root); 0109 QVERIFY(node4->parent() == root); 0110 0111 QVERIFY(root->firstChild() == node1); 0112 QVERIFY(root->lastChild() == node4); 0113 0114 QVERIFY(root->at(0) == node1); 0115 QVERIFY(root->at(1) == node3); 0116 QVERIFY(root->at(2) == node2); 0117 QVERIFY(root->at(3) == node4); 0118 0119 QVERIFY(root->index(node1) == 0); 0120 QVERIFY(root->index(node3) == 1); 0121 QVERIFY(root->index(node2) == 2); 0122 QVERIFY(root->index(node4) == 3); 0123 0124 QVERIFY(node4->prevSibling() == node2); 0125 QVERIFY(node3->prevSibling() == node1); 0126 QVERIFY(node2->prevSibling() == node3); 0127 QVERIFY(node1->prevSibling() == 0); 0128 0129 QVERIFY(node4->nextSibling() == 0); 0130 QVERIFY(node3->nextSibling() == node2); 0131 QVERIFY(node2->nextSibling() == node4); 0132 QVERIFY(node1->nextSibling() == node3); 0133 0134 /* 0135 +---------+ 0136 | node 3 | 0137 | node 4 | 0138 | node 2 | 0139 | node 1 | 0140 |root | 0141 +---------+ 0142 */ 0143 graphListener.resetBools(); 0144 QVERIFY(root->remove(root->at(3)) == true); 0145 QVERIFY(node4->parent() == 0); 0146 QVERIFY(graphListener.beforeInsertRow == false); 0147 QVERIFY(graphListener.afterInsertRow == false); 0148 QVERIFY(graphListener.beforeRemoveRow == true); 0149 QVERIFY(graphListener.afterRemoveRow == true); 0150 QVERIFY(root->childCount() == 3); 0151 QVERIFY(root->lastChild() == node2); 0152 QVERIFY(root->firstChild() == node1); 0153 QVERIFY(node4->prevSibling() == 0); 0154 QVERIFY(node4->nextSibling() == 0); 0155 graphListener.resetBools(); 0156 0157 node3->add(node4, node3->lastChild()); 0158 QVERIFY(graphListener.beforeInsertRow == true); 0159 QVERIFY(graphListener.afterInsertRow == true); 0160 QVERIFY(graphListener.beforeRemoveRow == false); 0161 QVERIFY(graphListener.afterRemoveRow == false); 0162 QVERIFY(root->childCount() == 3); 0163 QVERIFY(root->lastChild() == node2); 0164 QVERIFY(root->firstChild() == node1); 0165 QVERIFY(node3->childCount() == 1); 0166 QVERIFY(node3->firstChild() == node4); 0167 QVERIFY(node3->lastChild() == node4); 0168 QVERIFY(node4->prevSibling() == 0); 0169 QVERIFY(node4->nextSibling() == 0); 0170 QVERIFY(root->remove(node4) == false); 0171 graphListener.resetBools(); 0172 0173 node3->remove(node4); 0174 QVERIFY(graphListener.beforeInsertRow == false); 0175 QVERIFY(graphListener.afterInsertRow == false); 0176 QVERIFY(graphListener.beforeRemoveRow == true); 0177 QVERIFY(graphListener.afterRemoveRow == true); 0178 QVERIFY(node3->childCount() == 0); 0179 QVERIFY(node4->parent() == 0); 0180 QVERIFY(root->childCount() == 3); 0181 QVERIFY(root->lastChild() == node2); 0182 QVERIFY(root->firstChild() == node1); 0183 QVERIFY(node4->prevSibling() == 0); 0184 QVERIFY(node4->nextSibling() == 0); 0185 } 0186 0187 void KisNodeTest::testSetDirty() 0188 { 0189 // Create a node graph with two branches 0190 0191 /* 0192 node2 0193 node4 0194 node6 0195 node5 0196 node5 0197 node3 0198 node1 0199 root 0200 */ 0201 KisNodeSP root = new TestNode(); 0202 root->setName("root"); 0203 0204 KisNodeSP node1 = new TestNode(); 0205 node1->setName("node1"); 0206 QVERIFY(root->add(node1, 0)); 0207 0208 KisNodeSP node2 = new TestNode(); 0209 node2->setName("node2"); 0210 QVERIFY(root->add(node2, node1)); 0211 0212 KisNodeSP node3 = new TestNode(); 0213 node3->setName("node3"); 0214 QVERIFY(node1->add(node3, 0)); 0215 0216 KisNodeSP node4 = new TestNode(); 0217 node4->setName("node4"); 0218 QVERIFY(node1->add(node4, node3)); 0219 0220 KisNodeSP node5 = new TestNode(); 0221 node5->setName("node5"); 0222 QVERIFY(node3->add(node5, 0)); 0223 0224 KisNodeSP node6 = new TestNode(); 0225 node6->setName("node6"); 0226 QVERIFY(node5->add(node6, 0)); 0227 0228 KisNodeSP node7 = new TestNode(); 0229 node7->setName("node7"); 0230 QVERIFY(node6->add(node7, 0)); 0231 #if 0 // XXX: rewrite tests after redesign to update strategies 0232 node1->setDirty(); 0233 QVERIFY(node1->isDirty()); 0234 QVERIFY(!node2->isDirty()); 0235 QVERIFY(root->isDirty()); 0236 root->setClean(); 0237 QVERIFY(!root->isDirty()); 0238 node1->setClean(); 0239 QVERIFY(!node1->isDirty()); 0240 0241 node7->setDirty(QRect(10, 10, 100, 100)); 0242 QVERIFY(node7->isDirty()); 0243 QVERIFY(node7->isDirty(QRect(5, 5, 15, 15))); 0244 QVERIFY(root->isDirty(QRect(5, 5, 15, 15))); 0245 QVERIFY(!root->isDirty(QRect(-10, -10, 20, 20))); 0246 QVERIFY(!node2->isDirty()); 0247 0248 node7->setClean(QRect(10, 10, 10, 10)); 0249 QVERIFY(!node7->isDirty(QRect(10, 10, 10, 10))); 0250 QVERIFY(node7->isDirty()); 0251 QVERIFY(node7->isDirty(QRect(0, 0, 50, 50))); 0252 #endif 0253 0254 } 0255 0256 0257 void KisNodeTest::testChildNodes() 0258 { 0259 KisNodeSP root = new TestNodeA(); 0260 KisNodeSP a = new TestNodeA(); 0261 root->add(a, 0); 0262 a->setVisible(true); 0263 a->setUserLocked(true); 0264 0265 KisNodeSP b = new TestNodeB(); 0266 root->add(b, 0); 0267 b->setVisible(false); 0268 b->setUserLocked(true); 0269 0270 KisNodeSP c = new TestNodeC(); 0271 root->add(c, 0); 0272 c->setVisible(false); 0273 c->setVisible(false); 0274 0275 QList<KisNodeSP> allNodes = root->childNodes(QStringList(), KoProperties()); 0276 QCOMPARE((int) allNodes.count(), 3); // a, b, c 0277 0278 QStringList nodeTypes; 0279 nodeTypes << "TestNodeA" << "TestNodeB"; 0280 QList<KisNodeSP> subSetOfNodeTypes = root->childNodes(nodeTypes, KoProperties()); 0281 QCOMPARE(subSetOfNodeTypes.count(), 2); // a, b 0282 0283 nodeTypes.clear(); 0284 nodeTypes << "TestNodeB" << "TestNodeC"; 0285 KoProperties props; 0286 props.setProperty("visible", false); 0287 props.setProperty("locked", true); 0288 QList<KisNodeSP> subsetOfTypesAndProps = root->childNodes(nodeTypes, props); 0289 QCOMPARE(subsetOfTypesAndProps.count(), 1); // b 0290 0291 KoProperties props2; 0292 props2.setProperty("visible", false); 0293 QList<KisNodeSP> subSetOfProps = root->childNodes(QStringList(), props2); 0294 QCOMPARE(subSetOfProps.count(), 2); // b, c 0295 } 0296 0297 #define NUM_CYCLES 100000 0298 #define NUM_THREADS 30 0299 0300 class KisNodeTest::VisibilityKiller : public QRunnable { 0301 public: 0302 VisibilityKiller(KisNodeSP victimNode, KisNodeSP nastyChild, bool /*isWriter*/) 0303 : m_victimNode(victimNode), 0304 m_nastyChild(nastyChild) 0305 {} 0306 0307 void run() override { 0308 0309 int visibility = 0; 0310 0311 for(int i = 0; i < NUM_CYCLES; i++) { 0312 if(i % 3 == 0) { 0313 m_nastyChild->setVisible(visibility++ & 0x1); 0314 // dbgKrita << "visibility" << i << m_nastyChild->visible(); 0315 } 0316 else if (i%3 == 1){ 0317 KoProperties props; 0318 props.setProperty("visible", true); 0319 0320 QList<KisNodeSP> visibleNodes = 0321 m_victimNode->childNodes(QStringList("TestNodeB"), props); 0322 0323 Q_FOREACH (KisNodeSP node, visibleNodes) { 0324 m_nastyChild->setVisible(visibility++ & 0x1); 0325 } 0326 // dbgKrita << visibleNodes; 0327 } 0328 else { 0329 Q_ASSERT(m_victimNode->firstChild()); 0330 Q_ASSERT(m_victimNode->lastChild()); 0331 0332 m_victimNode->firstChild()->setVisible(visibility++ & 0x1); 0333 m_victimNode->lastChild()->setVisible(visibility++ & 0x1); 0334 } 0335 } 0336 } 0337 0338 private: 0339 KisNodeSP m_victimNode; 0340 KisNodeSP m_nastyChild; 0341 }; 0342 0343 0344 template <class KillerClass> 0345 void KisNodeTest::propertiesStressTestImpl() { 0346 KisNodeSP root = new TestNodeA(); 0347 0348 KisNodeSP a = new TestNodeA(); 0349 KisNodeSP b = new TestNodeB(); 0350 KisNodeSP c = new TestNodeC(); 0351 root->add(a, 0); 0352 root->add(b, 0); 0353 root->add(c, 0); 0354 a->setVisible(true); 0355 b->setVisible(true); 0356 c->setVisible(true); 0357 a->setUserLocked(true); 0358 b->setUserLocked(true); 0359 c->setUserLocked(true); 0360 0361 QThreadPool threadPool; 0362 threadPool.setMaxThreadCount(NUM_THREADS); 0363 0364 for(int i = 0; i< NUM_THREADS; i++) { 0365 KillerClass *killer = new KillerClass(root, b, i == 0); 0366 0367 threadPool.start(killer); 0368 } 0369 0370 threadPool.waitForDone(); 0371 } 0372 0373 void KisNodeTest::propertiesStressTest() { 0374 propertiesStressTestImpl<VisibilityKiller>(); 0375 } 0376 0377 class KisNodeTest::GraphKiller : public QRunnable { 0378 public: 0379 GraphKiller(KisNodeSP parentNode, KisNodeSP childNode, bool isWriter) 0380 : m_parentNode(parentNode), 0381 m_childNode(childNode), 0382 m_isWriter(isWriter) 0383 {} 0384 0385 void run() override { 0386 int numCycles = qMax(10000, NUM_CYCLES / 100); 0387 0388 for(int i = 0; i < numCycles; i++) { 0389 if (m_isWriter) { 0390 m_parentNode->remove(m_childNode); 0391 m_parentNode->add(m_childNode, 0); 0392 } else { 0393 KisNodeSP a = m_parentNode->firstChild(); 0394 KisNodeSP b = m_parentNode->lastChild(); 0395 0396 if (a) { 0397 a->parent(); 0398 a->nextSibling(); 0399 a->prevSibling(); 0400 } 0401 0402 if (b) { 0403 b->parent(); 0404 b->nextSibling(); 0405 b->prevSibling(); 0406 } 0407 0408 m_parentNode->at(0); 0409 m_parentNode->index(m_childNode); 0410 } 0411 0412 if (i % 1000 == 0) { 0413 //dbgKrita << "Alive"; 0414 } 0415 } 0416 } 0417 0418 private: 0419 KisNodeSP m_parentNode; 0420 KisNodeSP m_childNode; 0421 bool m_isWriter; 0422 }; 0423 0424 void KisNodeTest::graphStressTest() { 0425 propertiesStressTestImpl<GraphKiller>(); 0426 } 0427 0428 SIMPLE_TEST_MAIN(KisNodeTest) 0429 0430