File indexing completed on 2024-05-05 04:43:05

0001 #ifdef ENABLE_EXTRA_VALIDATION
0002 
0003 #include <private/statetracker/content_p.h>
0004 #include <private/statetracker/index_p.h>
0005 #include <private/statetracker/model_p.h>
0006 #include <private/statetracker/modelitem_p.h>
0007 #include <private/statetracker/viewitem_p.h>
0008 #include <private/statetracker/geometry_p.h>
0009 #include <viewport.h>
0010 
0011 /**
0012  * While this module is under development and the autotests are lacking,
0013  * always run strict tests at runtime.
0014  *
0015  * This is 3 ways to look at the same data:
0016  *
0017  *  * As a tree
0018  *  * As a linked list
0019  *  * As a "sliding window" (viewport)
0020  */
0021 
0022 void _test_validateTree(StateTracker::Content *self, StateTracker::Index* p)
0023 {
0024     // The asserts below only work on valid models with valid delegates.
0025     // If those conditions are not met, it *could* work anyway, but cannot be
0026     // validated.
0027     /*Q_ASSERT(m_FailedCount >= 0);
0028     if (m_FailedCount) {
0029         qWarning() << "The tree is fragmented and failed to self heal: disable validation";
0030         return;
0031     }*/
0032 
0033 //     if (p->parent() == self->root() && self->root()->firstChild() == p && p->metadata()->viewTracker()) {
0034 //         Q_ASSERT(!p->metadata()->viewTracker()->up());
0035 //     }
0036 
0037     // First, let's check the linked list to avoid running more test on really
0038     // corrupted data
0039     if (auto i = p->firstChild()) {
0040         auto idx = i->index();
0041         int count = 1;
0042         auto oldI = i;
0043 
0044         Q_ASSERT(idx.isValid());
0045 
0046         while ((oldI = i) && (i = i->nextSibling())) {
0047             // If this is a next, then there has to be a previous
0048             Q_ASSERT(i->parent() == p);
0049             Q_ASSERT(i->previousSibling());
0050             Q_ASSERT(i->previousSibling()->index() == idx);
0051             //Q_ASSERT(i->effectiveRow() == idx.row()+1); //FIXME
0052             Q_ASSERT(i->previousSibling()->nextSibling() == i);
0053             Q_ASSERT(i->previousSibling() == oldI);
0054             Q_ASSERT((!oldI->index().isValid()) || i->index().parent() == oldI->index().parent());
0055             Q_ASSERT((!oldI->index().isValid()) || i->effectiveRow() == oldI->effectiveRow()+1);
0056             idx = i->index();
0057             Q_ASSERT(idx.isValid());
0058             count++;
0059         }
0060 
0061         Q_ASSERT(p->lastChild());
0062         Q_ASSERT(p == p->firstChild()->parent());
0063         Q_ASSERT(p == p->lastChild()->parent());
0064         Q_ASSERT(p->loadedChildrenCount() == count);
0065     }
0066 
0067     // Do that again in the other direction
0068     if (auto i = p->lastChild()) {
0069         auto idx = i->index();
0070         auto oldI = i;
0071         int count = 1;
0072 
0073         Q_ASSERT(idx.isValid());
0074 
0075         while ((oldI = i) && (i = i->previousSibling())) {
0076             Q_ASSERT(i->nextSibling());
0077             Q_ASSERT(i->nextSibling()->index() == idx);
0078             Q_ASSERT(i->parent() == p);
0079             //Q_ASSERT(i->effectiveRow() == idx.row()-1); //FIXME
0080             Q_ASSERT(i->nextSibling()->previousSibling() == i);
0081             Q_ASSERT(i->nextSibling() == oldI);
0082             idx = i->index();
0083             Q_ASSERT(idx.isValid());
0084             count++;
0085         }
0086 
0087         Q_ASSERT(p->loadedChildrenCount() == count);
0088     }
0089 
0090     //TODO remove once stable
0091     // Brute force recursive validations
0092     StateTracker::Index *old(nullptr), *newest(nullptr);
0093 
0094     const auto children = p->allLoadedChildren();
0095 
0096     for (auto item : qAsConst(children)) {
0097         Q_ASSERT(item->parent() == p);
0098 
0099         if ((!newest) || item->effectiveRow() < newest->effectiveRow())
0100             newest = item;
0101 
0102         if ((!old) || item->effectiveRow() > old->effectiveRow())
0103             old = item;
0104 
0105         // Check that m_FailedCount is valid
0106         //Q_ASSERT(!item->metadata()->viewTracker()->hasFailed());
0107 
0108         // Test the indices
0109         Q_ASSERT(p == self->root() || item->index().internalPointer() == item->index().internalPointer());
0110         Q_ASSERT(p == self->root() || (p->index().isValid()) || p->index().internalPointer() != item->index().internalPointer());
0111         //Q_ASSERT(old == item || old->effectiveRow() > i->effectiveRow()); //FIXME
0112         //Q_ASSERT(newest == item || newest->effectiveRow() < i->effectiveRow()); //FIXME
0113 
0114         // Test that there is no trivial duplicate StateTracker::ModelItem for the same index
0115         if(item->previousSibling() && !item->previousSibling()->loadedChildrenCount()) {
0116             const auto prev = item->up();
0117             Q_ASSERT(prev == item->previousSibling());
0118 
0119             const auto next = prev->down();
0120             Q_ASSERT(next == item);
0121 
0122             if (prev == item->parent()) {
0123                 Q_ASSERT(item->effectiveRow() == 0);
0124                 Q_ASSERT(item->effectiveParentIndex() == prev->index());
0125             }
0126         }
0127 
0128         // Test the virtual linked list between the leafs and branches
0129         if(auto next = item->down()) {
0130             Q_ASSERT(next->up() == item);
0131             Q_ASSERT(next != item);
0132 
0133             if (next->effectiveParentIndex() == item->effectiveParentIndex()) {
0134                 const int rc = self->modelTracker()->modelCandidate()->rowCount(item->index());
0135                 Q_ASSERT(!rc);
0136             }
0137         }
0138         else {
0139             // There is always a next is those conditions are not met unless there
0140             // is failed elements creating (auto-corrected) holes in the chains.
0141             Q_ASSERT(!item->nextSibling());
0142             Q_ASSERT(!item->loadedChildrenCount());
0143         }
0144 
0145         if(auto prev = item->up()) {
0146             Q_ASSERT(prev->down() == item);
0147             Q_ASSERT(prev != item);
0148         }
0149         else {
0150             // There is always a previous if those conditions are not met unless there
0151             // is failed elements creating (auto-corrected) holes in the chains.
0152             Q_ASSERT(!item->previousSibling());
0153             Q_ASSERT(item->parent() == self->root());
0154         }
0155 
0156         _test_validateTree(self, item);
0157     }
0158 
0159     // Traverse as a list
0160     if (p == self->root()) {
0161         StateTracker::Index* oldTTI(nullptr);
0162 
0163         int count(0), count2(0);
0164         for (auto i = self->root()->firstChild(); i; i = i->down()) {
0165             Q_ASSERT((!oldTTI) || i->up());
0166             Q_ASSERT(i->up() == oldTTI);
0167             oldTTI = i;
0168             count++;
0169         }
0170 
0171         // Backward too
0172         oldTTI = nullptr;
0173         auto last = self->root()->lastChild();
0174         while (last && last->lastChild())
0175             last = last->lastChild();
0176 
0177         for (auto i = last; i; i = i->up()) {
0178             Q_ASSERT((!oldTTI) || i->down());
0179             Q_ASSERT(i->down() == oldTTI);
0180             oldTTI = i;
0181             count2++;
0182         }
0183 
0184         Q_ASSERT(count == count2);
0185     }
0186 
0187     // Test that the list edges are valid
0188     Q_ASSERT(!(!!p->lastChild() ^ !!p->firstChild()));
0189     Q_ASSERT(p->lastChild()  == old);
0190     Q_ASSERT(p->firstChild() == newest);
0191     Q_ASSERT((!old) || !old->nextSibling());
0192     Q_ASSERT((!newest) || !newest->previousSibling());
0193 }
0194 
0195 void _test_validateLinkedList(StateTracker::Content *self, bool skipVItemState)
0196 {
0197 #ifndef ENABLE_EXTRA_VALIDATION
0198     return;
0199 #endif
0200     _test_validateTree(self, self->root());
0201 
0202     if (!self->root()->firstChild()) {
0203         Q_ASSERT(!self->root()->lastChild());
0204         Q_ASSERT(!self->root()->loadedChildrenCount());
0205         Q_ASSERT(!self->root()->previousSibling());
0206         Q_ASSERT(!self->root()->nextSibling());
0207         return;
0208     }
0209     else {
0210         auto first = self->root()->firstChild();
0211         Q_ASSERT(first->metadata()->geometryTracker()->state() != StateTracker::Geometry::State::SIZE);
0212         Q_ASSERT(first->metadata()->geometryTracker()->state() != StateTracker::Geometry::State::INIT);
0213     }
0214 
0215     Q_ASSERT(!self->root()->firstChild()->up());
0216 
0217     StateTracker::Index *prev(nullptr), *cur(self->root()->firstChild());
0218 
0219     static const constexpr qreal maxReal = std::numeric_limits<qreal>::max();
0220     qreal maxY(0), maxX(0), minY(maxReal), minX(maxReal);
0221 
0222     bool hadVisible      = false;
0223     bool visibleFinished = false;
0224 
0225 //DEBUG
0226 //     qDebug() << "";
0227 //     while ((prev = cur) && (cur = TTI(cur->down()))) {
0228 //         qDebug() << "TREE"
0229 //             << (cur->m_State == StateTracker::ModelItem::State::VISIBLE);
0230 //     }
0231 //     qDebug() << "DONE";
0232 
0233     prev = nullptr;
0234     cur  = self->root()->firstChild();
0235 
0236     StateTracker::Index *firstVisible(nullptr), *lastVisible(nullptr);
0237 
0238     _test_validate_edges_simple(self);
0239 
0240     const auto tve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::TopEdge);
0241     const auto bve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::BottomEdge);
0242 
0243     do {
0244         Q_ASSERT(cur->up() == prev);
0245         Q_ASSERT(cur->index().isValid());
0246         Q_ASSERT(cur->index().model() == self->modelTracker()->modelCandidate());
0247 
0248         if (!visibleFinished) {
0249             // If hit, it means the visible rect wasn't refreshed.
0250             //Q_ASSERT(cur->metadata()->isValid()); //TODO THIS_COMMIT
0251         }
0252         else //FIXME wrong, only added to prevent forgetting
0253             Q_ASSERT(cur->metadata()->isValid());
0254 
0255         if (cur->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE && !hadVisible) {
0256             Q_ASSERT(!hadVisible);
0257             firstVisible = cur;
0258             hadVisible = true;
0259             Q_ASSERT(tve == cur);
0260         }
0261         else if (hadVisible && cur->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE) {
0262             visibleFinished = true;
0263             lastVisible = prev;
0264             Q_ASSERT(bve == lastVisible);
0265         }
0266 
0267 //         if (cur->state() == StateTracker::ModelItem::State::VISIBLE) {
0268 //             Q_ASSERT(cur->metadata()->isInSync());
0269 //         }
0270 
0271         Q_ASSERT(cur->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE || hadVisible);
0272 
0273         auto vi = cur->metadata()->viewTracker();
0274 
0275 //         if (vi) {
0276 //             if (vi->m_State == StateTracker::ViewItem::State::ACTIVE) {
0277 //                 Q_ASSERT(cur->state() == StateTracker::ModelItem::State::VISIBLE);
0278 //                 Q_ASSERT(self->viewport()->currentRect().isValid());
0279 //                 Q_ASSERT(self->viewport()->currentRect().intersects(
0280 //                     vi->geometry()
0281 //                 ));
0282 //             }
0283 //             else {
0284 //                 Q_ASSERT(vi->m_State == StateTracker::ViewItem::State::BUFFER);
0285 //                 Q_ASSERT(!self->viewport()->currentRect().intersects(
0286 //                     vi->geometry()
0287 //                 ));
0288 //             }
0289 //         }
0290 
0291         Q_ASSERT((!visibleFinished) || visibleFinished ^ (cur->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE));
0292 
0293         // skipVItemState is necessary to test some steps in between the tree and view
0294         if (!skipVItemState) {
0295             Q_ASSERT(cur->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE || !vi);
0296             Q_ASSERT((!visibleFinished) || !vi);
0297         }
0298 
0299         // Check the the previous sibling has no children
0300         if (prev && cur->parent() == prev->parent()) {
0301             Q_ASSERT(cur->effectiveRow() == prev->effectiveRow() + 1);
0302             Q_ASSERT(!self->modelTracker()->modelCandidate()->rowCount(prev->index()));
0303         }
0304 
0305         // Check that there it no missing children from the previous
0306         if ((!prev) || (cur->parent() != prev && cur->parent() != prev->parent() && prev->parent() != self->root())) {
0307             Q_ASSERT((!prev) || prev->parent()->index().isValid());
0308 //             const int prevParRc = prev->d_ptr->m_pModel->rowCount(prev->parent()->index());
0309 //             Q_ASSERT(prev->effectiveRow() == prevParRc - 1);
0310         }
0311 
0312         if (vi) {
0313             //Q_ASSERT(cur->metadata()->isValid()); //TODO THIS_COMMIT
0314             auto geo = cur->metadata()->decoratedGeometry();
0315 
0316             // Prevent accidental overlapping until a view with on-purpose
0317             // overlapping exists
0318 //             Q_ASSERT(geo.y() >= maxY); // The `=` because it starts at 0
0319 //             Q_ASSERT(cur->metadata()->viewTracker()->item()->y() >= maxY); // The `=` because it starts at 0
0320 //             Q_ASSERT(cur->metadata()->viewTracker()->item()->y() == cur->metadata()->geometry().y());
0321 
0322             // 0x0 elements are generally evil, but this is more about making
0323             // sure it works at all.
0324             //Q_ASSERT((geo.y() == 0 && cur->index().row() == 0) || geo.y()); //TODO THIS_COMMIT
0325 
0326             minX = std::min(minX, geo.x());
0327             minY = std::min(minY, geo.y());
0328             maxX = std::max(maxX, geo.bottomLeft().x());
0329             maxY = std::max(maxY, geo.bottomLeft().y());
0330         }
0331     } while ((prev = cur) && (cur = cur->down()));
0332 
0333     Q_ASSERT(maxY >= minY || !hadVisible);
0334     Q_ASSERT(maxX >= minX || !hadVisible);
0335     //TODO check buffer
0336 
0337     if (firstVisible && !skipVItemState) {
0338         //Q_ASSERT(prev->metadata()->geometry().y() < self->viewport()->currentRect().y());
0339     }
0340 
0341     if (lastVisible && !skipVItemState) {
0342         //Q_ASSERT(lastVisible->metadata()->decoratedGeometry().y() <= self->viewport()->currentRect().bottomLeft().y()); //TODO THIS_COMMIT
0343     }
0344 
0345 //     Q_ASSERT(maxY < self->viewport()->currentRect().bottomLeft().y() + 100);
0346 }
0347 
0348 void _test_validateViewport(StateTracker::Content *self, bool skipVItemState)
0349 {
0350 #ifndef ENABLE_EXTRA_VALIDATION
0351     return;
0352 #endif
0353     _test_validateLinkedList(self, skipVItemState);
0354     int activeCount = 0;
0355 
0356     Q_ASSERT(!((!self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::BottomEdge)) ^ (!self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge))));
0357     Q_ASSERT(!((!self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::LeftEdge)) ^ (!self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::RightEdge))));
0358 
0359     if (!self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge))
0360         return;
0361 
0362     if (self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge) == self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::BottomEdge)) {
0363         auto u1 = self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge)->up();
0364         auto d1 = self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge)->down();
0365         auto u2 = self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::BottomEdge)->up();
0366         auto d2 = self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::BottomEdge)->down();
0367         Q_ASSERT((!u1) || u1->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE);
0368         Q_ASSERT((!u2) || u2->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE);
0369         Q_ASSERT((!d1) || d1->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE);
0370         Q_ASSERT((!d2) || d2->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE);
0371     }
0372 
0373     auto item = self->edges(IndexMetadata::EdgeType::FREE)->getEdge(Qt::TopEdge);
0374     StateTracker::Index *old = nullptr;
0375 
0376     QRectF oldGeo;
0377 
0378     do {
0379         Q_ASSERT(old != item);
0380         Q_ASSERT(item->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE ||
0381             (skipVItemState && item->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::BUFFER)
0382         );
0383         if (!skipVItemState) {
0384             Q_ASSERT(item->metadata()->viewTracker());
0385             //Q_ASSERT(item->metadata()->viewTracker()->state() == StateTracker::ViewItem::State::ACTIVE);
0386         }
0387         Q_ASSERT(item->up() == old);
0388 
0389         //FIXME don't do this, its temporary so I can add more tests to catch
0390         // the cause of this failed (::move not updating the position)
0391 //         if (old)
0392 //             item->metadata()->m_State.setPosition(QPointF(0.0, oldGeo.y() + oldGeo.height()));
0393 
0394         auto geo =  item->metadata()->decoratedGeometry();
0395 
0396         if (geo.width() || geo.height()) {
0397             Q_ASSERT((!oldGeo.isValid()) || oldGeo.y() < geo.y());
0398             Q_ASSERT((!oldGeo.isValid()) || oldGeo.y() + oldGeo.height() == geo.y());
0399         }
0400 
0401 //         qDebug() << "TEST" << activeCount << geo;
0402 
0403         activeCount++;
0404         oldGeo = geo;
0405     } while ((old = item) && (item = item->down()));
0406 }
0407 
0408 void StateTracker::Index::_test_validate_chain() const
0409 {
0410 #ifndef ENABLE_EXTRA_VALIDATION
0411     return;
0412 #endif
0413     auto p = this; //FIXME due to refactor
0414 
0415     int count = 0;
0416 
0417     Q_ASSERT((!p->firstChild()) || p->lastChild());
0418     Q_ASSERT((!p->firstChild()) || !p->firstChild()->previousSibling());
0419     Q_ASSERT((!p->lastChild()) || !p->lastChild()->nextSibling());
0420     auto i = p->firstChild();
0421     StateTracker::Index *prev = nullptr;
0422     while(i) {
0423         Q_ASSERT(i->previousSibling() == prev);
0424         Q_ASSERT(i->parent() == p);
0425 
0426         //Q_ASSERT((!prev) || i->effectiveRow() == prev->effectiveRow()+1);
0427 
0428         prev = i;
0429         i = i->nextSibling();
0430         count++;
0431     }
0432 
0433     Q_ASSERT(count == loadedChildrenCount());
0434 
0435     if (!prev)
0436         Q_ASSERT(p->firstChild() == p->lastChild());
0437     else
0438         Q_ASSERT(prev == p->lastChild());
0439 }
0440 
0441 void _test_validate_edges(StateTracker::Content *self)
0442 {
0443 #ifndef ENABLE_EXTRA_VALIDATION
0444     return;
0445 #endif
0446     auto vStart = self->getEdge(IndexMetadata::EdgeType::VISIBLE, Qt::TopEdge);
0447     auto vEnd   = self->getEdge(IndexMetadata::EdgeType::VISIBLE, Qt::BottomEdge);
0448 
0449     Q_ASSERT((!vStart) || (vStart && vEnd));
0450 
0451     if (vStart) {
0452         Q_ASSERT(vStart->indexTracker()->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE);
0453         Q_ASSERT(vEnd->indexTracker()->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE);
0454         auto prev = vStart->indexTracker()->up();
0455         auto next = vEnd->indexTracker()->down();
0456 
0457         Q_ASSERT((!prev) || prev->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::REACHABLE);
0458         Q_ASSERT((!next) || next->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::REACHABLE);
0459     }
0460 }
0461 
0462 void _test_validate_move(
0463     StateTracker::Content *self,
0464     StateTracker::Index* parentTTI,
0465     StateTracker::Index* startTTI,
0466     StateTracker::Index* endTTI,
0467     StateTracker::Index* newPrevTTI,
0468     StateTracker::Index* newNextTTI,
0469     int row)
0470 {
0471     Q_UNUSED(self)
0472 #ifndef ENABLE_EXTRA_VALIDATION
0473     return;
0474 #endif
0475     Q_ASSERT((newPrevTTI || startTTI) && newPrevTTI != startTTI);
0476     Q_ASSERT((newNextTTI || endTTI  ) && newNextTTI != endTTI  );
0477 
0478     // Update the tree parent (if necessary)
0479     Q_ASSERT(startTTI->parent() == parentTTI);
0480     Q_ASSERT(endTTI->parent()   == parentTTI);
0481 
0482     //BEGIN debug
0483     if (newPrevTTI && newPrevTTI->parent())
0484         newPrevTTI->parent()->_test_validate_chain();
0485     if (startTTI && startTTI->parent())
0486         startTTI->parent()->_test_validate_chain();
0487     if (endTTI && endTTI->parent())
0488         endTTI->parent()->_test_validate_chain();
0489     if (newNextTTI && newNextTTI->parent())
0490         newNextTTI->parent()->_test_validate_chain();
0491     //END debug
0492 
0493     if (endTTI->nextSibling()) {
0494         Q_ASSERT(endTTI->nextSibling()->previousSibling() ==endTTI);
0495     }
0496 
0497     if (startTTI->previousSibling()) {
0498         Q_ASSERT(startTTI->previousSibling()->parent() == startTTI->parent());
0499         Q_ASSERT(startTTI->previousSibling()->nextSibling() ==startTTI);
0500     }
0501 
0502     Q_ASSERT(parentTTI->firstChild());
0503     Q_ASSERT(row || parentTTI->firstChild() == startTTI);
0504 }
0505 
0506 void _test_validate_edges_simple(StateTracker::Content *self)
0507 {
0508 #ifndef ENABLE_EXTRA_VALIDATION
0509     return;
0510 #endif
0511     //BEGIN test
0512     auto tve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::TopEdge);
0513 
0514     Q_ASSERT((!tve) || (tve->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE));
0515     Q_ASSERT((!tve) || (!tve->up()) || (tve->up()->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE));
0516 
0517     auto bve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::BottomEdge);
0518 
0519     Q_ASSERT((!bve) || (bve->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE));
0520     Q_ASSERT((!bve) || (!bve->down()) || bve->down()->metadata()->modelTracker()->state() != StateTracker::ModelItem::State::VISIBLE);
0521     //END test
0522 }
0523 
0524 void _test_validate_geometry_cache(StateTracker::Content *self)
0525 {
0526     auto bve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::BottomEdge);
0527     for (auto i = self->root()->firstChild(); i; i = i->down()) {
0528         Q_ASSERT(i->metadata()->geometryTracker()->state() == StateTracker::Geometry::State::VALID);
0529 
0530         if (i == bve)
0531             return;
0532     }
0533 }
0534 
0535 void _test_print_state(StateTracker::Content *self)
0536 {
0537 #ifndef ENABLE_EXTRA_VALIDATION
0538     return;
0539 #endif
0540     auto item = self->root()->firstChild();
0541 
0542     if (!item)
0543         return;
0544 
0545     int i = 0;
0546 
0547     do {
0548         qDebug() << i++
0549             << item
0550             << item->depth()
0551             << item->metadata()->isInSync()
0552             << (item->metadata()->modelTracker()->state() == StateTracker::ModelItem::State::VISIBLE);
0553     } while((item = item->down()));
0554 }
0555 
0556 void _test_validateUnloaded(StateTracker::Content *self, const QModelIndex& parent, int first, int last)
0557 {
0558 #ifndef ENABLE_EXTRA_VALIDATION
0559     return;
0560 #endif
0561     Q_ASSERT(self->modelTracker()->modelCandidate()); // This will assert in model_p.cpp
0562 
0563     for (int i = first; i <= last; i++) {
0564         const auto idx = self->modelTracker()->modelCandidate()->index(i, 0, parent);
0565         Q_ASSERT(idx.isValid());
0566         //Q_ASSERT(!self->ttiForIndex(idx));
0567     }
0568 }
0569 
0570 static QModelIndex getNextIndex(const QModelIndex& idx)
0571 {
0572     if (!idx.isValid())
0573         return {};
0574 
0575     // There is 2 possibilities, a sibling or a [[great]grand]uncle
0576 
0577     if (idx.model()->rowCount(idx))
0578         return idx.model()->index(0,0, idx);
0579 
0580     auto sib = idx.sibling(idx.row()+1, idx.column());
0581 
0582     if (sib.isValid())
0583         return sib;
0584 
0585     if (!idx.parent().isValid())
0586         return {};
0587 
0588     auto p = idx.parent();
0589 
0590     while (p.isValid()) {
0591         sib = p.sibling(p.row()+1, p.column());
0592         if (sib.isValid())
0593             return sib;
0594 
0595         p = p.parent();
0596     }
0597 
0598     return {};
0599 }
0600 
0601 // Validate that there is no holes in the view.
0602 void _test_validateContinuity(StateTracker::Content *self)
0603 {
0604 #ifndef ENABLE_EXTRA_VALIDATION
0605     return;
0606 #endif
0607     auto item = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::TopEdge);
0608     auto bve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::BottomEdge);
0609 
0610     if (!item)
0611         return;
0612 
0613     auto idx = item->index();
0614 
0615     do {
0616         const auto oldIdx = idx;
0617         volatile auto oldItem = item;
0618         Q_ASSERT(item->index() == idx);
0619         Q_ASSERT(oldIdx != (idx = getNextIndex(idx)));
0620         Q_ASSERT(oldItem != (item = item->down()));
0621     } while(item && item != bve);
0622 }
0623 
0624 void _test_validateAtEnd(StateTracker::Content *self)
0625 {
0626 #ifndef ENABLE_EXTRA_VALIDATION
0627     return;
0628 #endif
0629     _test_validateContinuity(self);
0630 
0631     auto bve = self->edges(IndexMetadata::EdgeType::VISIBLE)->getEdge(Qt::BottomEdge);
0632     Q_ASSERT((!self->root()->firstChild()) || bve); //TODO wrong
0633 
0634     if (!bve)
0635         return;
0636 
0637     const auto next = getNextIndex(bve->index());
0638 
0639     Q_ASSERT(!next.isValid());
0640 }
0641 
0642 void _test_validateModelAboutToReplace(StateTracker::Content *self)
0643 {
0644     Q_ASSERT(!self->modelTracker()->modelCandidate());
0645     Q_ASSERT(self->modelTracker()->state() == StateTracker::Model::State::NO_MODEL
0646         || self->modelTracker()->state() == StateTracker::Model::State::PAUSED);
0647 }
0648 
0649 void StateTracker::Index::_test_bridgeGap(StateTracker::Index *first, StateTracker::Index *second)
0650 {
0651     if (second && first && second->m_pParent && second->m_pParent->firstChild() ==second && second->m_pParent == first->m_pParent) {
0652         second->m_pParent->m_tChildren[0] = first;
0653         Q_ASSERT((!first) || second->m_pParent->lastChild());
0654         Q_ASSERT((!first) || !first->previousSibling());
0655     }
0656 
0657     if ((!first) && second->m_MoveToRow != -1) {
0658         Q_ASSERT(second->m_pParent->firstChild());
0659         Q_ASSERT(second->m_pParent->firstChild() ==second ||
0660             second->m_pParent->firstChild()->m_Index.row() < second->m_MoveToRow);
0661     }
0662 
0663     if (first)
0664         Q_ASSERT(first->m_pParent->firstChild());
0665     if (second)
0666         Q_ASSERT(second->m_pParent->firstChild());
0667 
0668     if (first)
0669         Q_ASSERT(first->m_pParent->lastChild());
0670     if (second)
0671         Q_ASSERT(second->m_pParent->lastChild());
0672 
0673 
0674     Q_ASSERT((!second) || (!second->m_pParent->firstChild()) || second->m_pParent->lastChild());
0675 
0676 
0677 //     if (first && second) { //Need to disable other asserts in down()
0678 //         Q_ASSERT(first->down() == second);
0679 //         Q_ASSERT(second->up() == first);
0680 //     }
0681 
0682     // Close the gap between the old previous and next elements
0683     Q_ASSERT((!first ) || first->nextSibling()      != first );
0684     Q_ASSERT((!first ) || first->previousSibling()  != first );
0685     Q_ASSERT((!second) || second->nextSibling()     != second);
0686     Q_ASSERT((!second) || second->previousSibling() != second);
0687 }
0688 
0689 #endif //ENABLE_EXTRA_VALIDATION