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