File indexing completed on 2024-05-26 05:51:55

0001 /* This file is part of the KDE project
0002  *
0003  *  SPDX-License-Identifier: LGPL-2.0-or-later
0004  */
0005 #include "filetree_model_test.h"
0006 
0007 #include "katefiletreemodel.h"
0008 
0009 #include "document_dummy.h"
0010 
0011 #include <QAbstractItemModelTester>
0012 #include <QTest>
0013 
0014 QTEST_MAIN(FileTreeModelTest)
0015 
0016 // BEGIN ResultNode
0017 class ResultNode
0018 {
0019 public:
0020     ResultNode() = default; // root node
0021     ResultNode(const ResultNode &other) = default;
0022     ResultNode &operator=(const ResultNode &other) = default;
0023     ResultNode(const char *_name, const bool _dir = false)
0024         : ResultNode(QString::fromLatin1(_name), _dir)
0025     {
0026     }
0027     ResultNode(const QString &_name, const bool _dir = false)
0028         : name(_name)
0029         , dir(_dir)
0030     {
0031     }
0032 
0033     ResultNode &operator<<(const ResultNode &node)
0034     {
0035         children << node;
0036         return *this;
0037     }
0038 
0039     bool operator!=(const ResultNode &other) const
0040     {
0041         return !(*this == other);
0042     }
0043     bool operator==(const ResultNode &other) const
0044     {
0045         return (other.name == name) && (other.dir == dir) && (other.children == children);
0046     }
0047 
0048     friend QDebug operator<<(QDebug s, const ResultNode &node)
0049     {
0050         s << node.toString();
0051         return s;
0052     }
0053 
0054     friend void debugOutput(QString &s, const ResultNode &rootNode, const int level = 0)
0055     {
0056         for (int i = 0; i < level; i++) {
0057             s += QLatin1String("  ");
0058         }
0059 
0060         const QString name = rootNode.name.isEmpty() ? QStringLiteral("ROOT") : rootNode.name;
0061 
0062         s += QLatin1String("( ") + name;
0063         if (rootNode.dir) {
0064             s += QLatin1String(", {D}");
0065         }
0066 
0067         if (rootNode.children.isEmpty()) {
0068             s += QLatin1String(" )");
0069         } else {
0070             s += QLatin1String(",\n");
0071 
0072             for (int i = 0; i < rootNode.children.size(); i++) {
0073                 const ResultNode &node = rootNode.children[i];
0074 
0075                 debugOutput(s, node, level + 1);
0076 
0077                 if ((i + 1) < rootNode.children.size()) {
0078                     s += QLatin1Char('\n');
0079                 }
0080             }
0081             s += (level == 0) ? QLatin1String("\n);") : QLatin1String(")");
0082         }
0083     }
0084 
0085     QString toString() const
0086     {
0087         QString out;
0088         debugOutput(out, *this, 0);
0089         return out;
0090     }
0091 
0092     QString name;
0093     bool dir = true;
0094     QList<ResultNode> children;
0095 };
0096 
0097 Q_DECLARE_METATYPE(ResultNode)
0098 
0099 static const ResultNode openWidgetsNode("Open Widgets", false);
0100 
0101 namespace QTest
0102 {
0103 inline bool qCompare(const ResultNode &t1, const ResultNode &t2, const char *actual, const char *expected, const char *file, int line)
0104 {
0105     /* compare_helper is not helping that much, we need to prepare copy of data */
0106     const QByteArray a = t1.toString().toLatin1();
0107     const QByteArray b = t2.toString().toLatin1();
0108 
0109     char *val1 = new char[a.size() + 1];
0110     char *val2 = new char[b.size() + 1];
0111 
0112     memcpy(val1, a.constData(), a.size() + 1);
0113     memcpy(val2, b.constData(), b.size() + 1);
0114 
0115     return compare_helper(t1 == t2, "Compared ResultNode trees are not the same", val1, val2, actual, expected, file, line);
0116 }
0117 }
0118 // END ResultNode
0119 
0120 void FileTreeModelTest::initTestCase()
0121 {
0122 }
0123 
0124 void FileTreeModelTest::cleanupTestCase()
0125 {
0126 }
0127 
0128 void FileTreeModelTest::init()
0129 {
0130 }
0131 
0132 void FileTreeModelTest::cleanup()
0133 {
0134 }
0135 
0136 void FileTreeModelTest::basic()
0137 {
0138     DummyDocument d1;
0139     DummyDocument d2;
0140 
0141     KateFileTreeModel m(nullptr, this);
0142     // 1 because, there is always a "open widgets" node
0143     QCOMPARE(m.rowCount(QModelIndex()), 1);
0144 
0145     m.documentOpened(&d1);
0146     QCOMPARE(m.rowCount(QModelIndex()), 2);
0147 
0148     m.documentOpened(&d2);
0149     QCOMPARE(m.rowCount(QModelIndex()), 3);
0150 }
0151 
0152 void FileTreeModelTest::buildTree_data()
0153 {
0154     QTest::addColumn<QList<DummyDocument *>>("documents");
0155     QTest::addColumn<ResultNode>("nodes");
0156 
0157     QTest::newRow("easy") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt"))
0158                           << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")));
0159 
0160     QTest::newRow("two") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt"))
0161                          << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")));
0162 
0163     QTest::newRow("strangers") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///b/bar.txt"))
0164                                << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")));
0165 
0166     QTest::newRow("lvl1 strangers") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt"))
0167                                     << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")));
0168 
0169     QTest::newRow("multiples") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0170                                                             << new DummyDocument("file:///c/a/bar.txt"))
0171                                << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt"))
0172                                                 << (ResultNode("b", true) << ResultNode("bar.txt")));
0173 
0174     QTest::newRow("stairs") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/bar.txt"))
0175                             << (ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << ResultNode("bar.txt")));
0176 
0177     QTest::newRow("reverse stairs") << (QList<DummyDocument *>() << new DummyDocument("file:///c/bar.txt") << new DummyDocument("file:///c/a/foo.txt"))
0178                                     << (ResultNode() << (ResultNode("c", true) << ResultNode("bar.txt") << (ResultNode("a", true) << ResultNode("foo.txt"))));
0179 
0180     QTest::newRow("matching") << (QList<DummyDocument *>() << new DummyDocument("file:///a/x/foo.txt") << new DummyDocument("file:///b/x/bar.txt"))
0181                               << (ResultNode() << (ResultNode("a", true) << (ResultNode("x", true) << ResultNode("foo.txt")))
0182                                                << (ResultNode("b", true) << (ResultNode("x", true) << ResultNode("bar.txt"))));
0183 
0184     QTest::newRow("matching even more")
0185         << (QList<DummyDocument *>() << new DummyDocument("file:///a/x/y/z/foo.txt") << new DummyDocument("file:///b/x/y/z/bar.txt"))
0186         << (ResultNode() << (ResultNode("a", true) << (ResultNode("x", true) << (ResultNode("y", true) << (ResultNode("z", true) << ResultNode("foo.txt")))))
0187                          << (ResultNode("b", true) << (ResultNode("x", true) << (ResultNode("y", true) << (ResultNode("z", true) << ResultNode("bar.txt"))))));
0188 
0189     QTest::newRow("matching with booby trap") << (QList<DummyDocument *>()
0190                                                   << new DummyDocument("file:///x/y/foo.txt") << new DummyDocument("file:///c/x/bar.txt")
0191                                                   << new DummyDocument("file:///d/y/baz.txt"))
0192                                               << (ResultNode() << (ResultNode("x", true) << (ResultNode("y", true) << ResultNode("foo.txt")))
0193                                                                << (ResultNode("d", true) << (ResultNode("y", true) << ResultNode("baz.txt")))
0194                                                                << (ResultNode("c", true) << (ResultNode("x", true) << ResultNode("bar.txt"))));
0195 
0196     QTest::newRow("branches") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0197                                                            << new DummyDocument("file:///d/a/foo.txt"))
0198                               << (ResultNode() << (ResultNode("c", true)
0199                                                    << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")))
0200                                                << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))));
0201 
0202     QTest::newRow("branches (more)") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0203                                                                   << new DummyDocument("file:///c/c/bar.txt") << new DummyDocument("file:///d/a/foo.txt"))
0204                                      << (ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt"))
0205                                                                                 << (ResultNode("b", true) << ResultNode("bar.txt"))
0206                                                                                 << (ResultNode("c", true) << ResultNode("bar.txt")))
0207                                                       << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))));
0208 
0209     QTest::newRow("bug347578") << (QList<DummyDocument *>()
0210                                    << new DummyDocument("file:///f/g/a/b/c/d/e.txt") << new DummyDocument("file:///f/g/a/t/b/c/d/e.txt"))
0211                                << (ResultNode() << (ResultNode("a", true)
0212                                                     << (ResultNode("b", true) << (ResultNode("c", true) << (ResultNode("d", true) << ResultNode("e.txt"))))
0213                                                     << (ResultNode("t", true)
0214                                                         << (ResultNode("b", true)
0215                                                             << (ResultNode("c", true) << (ResultNode("d", true) << ResultNode("e.txt")))))));
0216 
0217     QTest::newRow("levels") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0218                                                          << new DummyDocument("file:///d/foo.txt"))
0219                             << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt"))
0220                                              << (ResultNode("d", true) << ResultNode("foo.txt")));
0221 
0222     QTest::newRow("remote simple") << (QList<DummyDocument *>() << new DummyDocument("http://example.org/foo.txt"))
0223                                    << (ResultNode() << (ResultNode("[example.org]", true) << ResultNode("foo.txt")));
0224 
0225     QTest::newRow("remote nested") << (QList<DummyDocument *>() << new DummyDocument("http://example.org/a/foo.txt"))
0226                                    << (ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt")));
0227 
0228     /* NOTE: this one is also not completely ok, is it?
0229      * on other hand, it would get confusing or overly leveled if opening
0230      * something like http://example.org/a/b/c/d/e/f/g.txt
0231      */
0232     QTest::newRow("remote diverge") << (QList<DummyDocument *>()
0233                                         << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt"))
0234                                     << (ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt"))
0235                                                      << (ResultNode("[example.org]b", true) << ResultNode("foo.txt")));
0236 }
0237 
0238 void FileTreeModelTest::buildTree()
0239 {
0240     KateFileTreeModel m(nullptr, this);
0241     QAbstractItemModelTester tester(&m, this);
0242     QFETCH(const QList<DummyDocument *>, documents);
0243     QFETCH(ResultNode, nodes);
0244 
0245     for (DummyDocument *doc : documents) {
0246         m.documentOpened(doc);
0247     }
0248 
0249     ResultNode root;
0250     walkTree(m, QModelIndex(), root);
0251 
0252     QCOMPARE(root, nodes);
0253     qDeleteAll(documents);
0254 }
0255 
0256 void FileTreeModelTest::buildTreeBatch_data()
0257 {
0258     // the easiest way to verify the equality of those two calls:)
0259     buildTree_data();
0260 }
0261 
0262 void FileTreeModelTest::buildTreeBatch()
0263 {
0264     KateFileTreeModel m(nullptr, this);
0265     QAbstractItemModelTester tester(&m, this);
0266     QFETCH(const QList<DummyDocument *>, documents);
0267     QFETCH(ResultNode, nodes);
0268 
0269     QList<KTextEditor::Document *> list;
0270 
0271     for (DummyDocument *doc : documents) {
0272         list << doc;
0273     }
0274 
0275     m.documentsOpened(list);
0276 
0277     ResultNode root;
0278     walkTree(m, QModelIndex(), root);
0279 
0280     QCOMPARE(root, nodes);
0281     qDeleteAll(documents);
0282 }
0283 
0284 void FileTreeModelTest::buildTreeBatchPrefill_data()
0285 {
0286     QTest::addColumn<QList<DummyDocument *>>("prefill");
0287     QTest::addColumn<QList<DummyDocument *>>("documents");
0288     QTest::addColumn<ResultNode>("nodes");
0289 
0290     QTest::newRow("easy") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt"))
0291                           << (QList<DummyDocument *>() << new DummyDocument("file:///a/bar.txt"))
0292                           << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")));
0293 
0294     QTest::newRow("split") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt"))
0295                            << (QList<DummyDocument *>() << new DummyDocument("file:///b/foo.txt"))
0296                            << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("foo.txt")));
0297 }
0298 
0299 void FileTreeModelTest::buildTreeBatchPrefill()
0300 {
0301     KateFileTreeModel m(nullptr, this);
0302     QAbstractItemModelTester tester(&m, this);
0303     QFETCH(const QList<DummyDocument *>, prefill);
0304     QFETCH(const QList<DummyDocument *>, documents);
0305     QFETCH(ResultNode, nodes);
0306 
0307     for (DummyDocument *doc : prefill) {
0308         m.documentOpened(doc);
0309     }
0310 
0311     QList<KTextEditor::Document *> list;
0312 
0313     for (DummyDocument *doc : documents) {
0314         list << doc;
0315     }
0316 
0317     m.documentsOpened(list);
0318 
0319     ResultNode root;
0320     walkTree(m, QModelIndex(), root);
0321 
0322     QCOMPARE(root, nodes);
0323     qDeleteAll(prefill);
0324     qDeleteAll(documents);
0325 }
0326 
0327 void FileTreeModelTest::walkTree(KateFileTreeModel &model, const QModelIndex &rootIndex, ResultNode &rootNode)
0328 {
0329     if (!model.hasChildren(rootIndex)) {
0330         return;
0331     }
0332 
0333     const int rows = model.rowCount(rootIndex);
0334     for (int i = 0; i < rows; i++) {
0335         const QModelIndex idx = model.index(i, 0, rootIndex);
0336         ResultNode node(model.data(idx).toString(), model.isDir(idx));
0337         walkTree(model, idx, node);
0338         rootNode << node;
0339     }
0340     rootNode.children.removeAll(openWidgetsNode);
0341 }
0342 
0343 void FileTreeModelTest::buildTreeFullPath_data()
0344 {
0345     QTest::addColumn<QList<DummyDocument *>>("documents");
0346     QTest::addColumn<ResultNode>("nodes");
0347 
0348     QTest::newRow("two") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt"))
0349                          << (ResultNode() << (ResultNode("/a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")));
0350 
0351     QTest::newRow("multiples") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0352                                                             << new DummyDocument("file:///c/a/bar.txt"))
0353                                << (ResultNode() << (ResultNode("/c/a", true) << ResultNode("foo.txt") << ResultNode("bar.txt"))
0354                                                 << (ResultNode("/c/b", true) << ResultNode("bar.txt")));
0355 
0356     /* This one and the case after can get a little bit tricky and
0357      * in some situation could end up in little bit confusing layout.
0358      * current root merge algorithm sees the divergent paths, so it
0359      * doesn't invoke merging.
0360     QTest::newRow("branches") << ( QList<DummyDocument *>()
0361       << new DummyDocument("file:///c/a/foo.txt")
0362       << new DummyDocument("file:///c/b/bar.txt")
0363     ) << (
0364       ResultNode()
0365         << (ResultNode("/c", true)
0366           << (ResultNode("a", true)
0367             << ResultNode("foo.txt"))
0368           << (ResultNode("b", true)
0369             << ResultNode("bar.txt")))
0370     );
0371     */
0372 
0373     /*
0374     QTest::newRow("levels") << ( QList<DummyDocument *>()
0375       << new DummyDocument("file:///c/a/foo.txt")
0376       << new DummyDocument("file:///c/b/bar.txt")
0377       << new DummyDocument("file:///d/foo.txt")
0378     ) << (
0379       ResultNode()
0380         << (ResultNode("/c", true)
0381           << (ResultNode("a", true)
0382             << ResultNode("foo.txt"))
0383           << (ResultNode("b", true)
0384             << ResultNode("bar.txt")))
0385         << (ResultNode("/d", true)
0386           << ResultNode("foo.txt"))
0387     );
0388     */
0389 
0390     QTest::newRow("remote simple") << (QList<DummyDocument *>() << new DummyDocument("http://example.org/foo.txt"))
0391                                    << (ResultNode() << (ResultNode("[example.org]", true) << ResultNode("foo.txt")));
0392 
0393     QTest::newRow("remote nested") << (QList<DummyDocument *>() << new DummyDocument("http://example.org/a/b/foo.txt"))
0394                                    << (ResultNode() << (ResultNode("[example.org]/a/b", true) << ResultNode("foo.txt")));
0395 
0396     /* NOTE: see the similar testcase in buildTree */
0397     QTest::newRow("remote diverge") << (QList<DummyDocument *>()
0398                                         << new DummyDocument("http://example.org/c/a/foo.txt") << new DummyDocument("http://example.org/c/b/foo.txt"))
0399                                     << (ResultNode() << (ResultNode("[example.org]/c/a", true) << ResultNode("foo.txt"))
0400                                                      << (ResultNode("[example.org]/c/b", true) << ResultNode("foo.txt")));
0401 }
0402 
0403 void FileTreeModelTest::buildTreeFullPath()
0404 {
0405     KateFileTreeModel m(nullptr, this);
0406     QAbstractItemModelTester tester(&m, this);
0407     m.setShowFullPathOnRoots(true);
0408 
0409     QFETCH(const QList<DummyDocument *>, documents);
0410     QFETCH(ResultNode, nodes);
0411 
0412     for (DummyDocument *doc : documents) {
0413         m.documentOpened(doc);
0414     }
0415 
0416     ResultNode root;
0417     walkTree(m, QModelIndex(), root);
0418 
0419     QCOMPARE(root, nodes);
0420     qDeleteAll(documents);
0421 }
0422 
0423 void FileTreeModelTest::listMode_data()
0424 {
0425     QTest::addColumn<QList<DummyDocument *>>("documents");
0426     QTest::addColumn<ResultNode>("nodes");
0427 
0428     QTest::newRow("easy") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt")) << (ResultNode() << ResultNode("foo.txt"));
0429 
0430     QTest::newRow("two") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt"))
0431                          << (ResultNode() << ResultNode("foo.txt") << ResultNode("bar.txt"));
0432 
0433     QTest::newRow("multiples") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0434                                                             << new DummyDocument("file:///c/a/bar.txt"))
0435                                << (ResultNode() << ResultNode("foo.txt") << ResultNode("bar.txt") << ResultNode("bar.txt"));
0436 
0437     QTest::newRow("remote diverge") << (QList<DummyDocument *>()
0438                                         << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt"))
0439                                     << (ResultNode() << ResultNode("[example.org]foo.txt") << ResultNode("[example.org]foo.txt"));
0440 }
0441 
0442 void FileTreeModelTest::listMode()
0443 {
0444     KateFileTreeModel m(nullptr, this);
0445     QAbstractItemModelTester tester(&m, this);
0446     m.setListMode(true);
0447 
0448     QFETCH(const QList<DummyDocument *>, documents);
0449     QFETCH(ResultNode, nodes);
0450 
0451     for (DummyDocument *doc : documents) {
0452         m.documentOpened(doc);
0453     }
0454 
0455     ResultNode root;
0456     walkTree(m, QModelIndex(), root);
0457 
0458     QCOMPARE(root, nodes);
0459     qDeleteAll(documents);
0460 }
0461 
0462 void FileTreeModelTest::deleteDocument_data()
0463 {
0464     QTest::addColumn<QList<DummyDocument *>>("documents");
0465     QTest::addColumn<QList<int>>("remove");
0466     QTest::addColumn<ResultNode>("nodes");
0467 
0468     QTest::newRow("empty") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt")) << (QList<int>() << 0) << (ResultNode());
0469 
0470     QTest::newRow("two") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt"))
0471                          << (QList<int>() << 0) << (ResultNode() << (ResultNode("a", true) << ResultNode("bar.txt")));
0472 
0473     QTest::newRow("multiple") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo0.txt") << new DummyDocument("file:///a/foo1.txt")
0474                                                            << new DummyDocument("file:///a/foo2.txt") << new DummyDocument("file:///a/foo3.txt")
0475                                                            << new DummyDocument("file:///a/foo4.txt") << new DummyDocument("file:///a/foo5.txt")
0476                                                            << new DummyDocument("file:///a/foo6.txt") << new DummyDocument("file:///a/foo7.txt"))
0477                               << (QList<int>() << 1 << 2 << 4 << 6)
0478                               << (ResultNode() << (ResultNode("a", true)
0479                                                    << ResultNode("foo0.txt") << ResultNode("foo3.txt") << ResultNode("foo5.txt") << ResultNode("foo7.txt")));
0480 
0481     QTest::newRow("strangers") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///b/bar.txt"))
0482                                << (QList<int>() << 1) << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")));
0483 
0484     QTest::newRow("branches") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0485                                                            << new DummyDocument("file:///d/a/foo.txt"))
0486                               << (QList<int>() << 1)
0487                               << (ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt")))
0488                                                << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))));
0489 
0490     QTest::newRow("levels") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0491                                                          << new DummyDocument("file:///d/foo.txt"))
0492                             << (QList<int>() << 0)
0493                             << (ResultNode() << (ResultNode("b", true) << ResultNode("bar.txt")) << (ResultNode("d", true) << ResultNode("foo.txt")));
0494 
0495     QTest::newRow("levels extra") << (QList<DummyDocument *>() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt")
0496                                                                << new DummyDocument("file:///d/foo.txt"))
0497                                   << (QList<int>() << 2)
0498                                   << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")));
0499 
0500     QTest::newRow("remote diverge") << (QList<DummyDocument *>()
0501                                         << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt"))
0502                                     << (QList<int>() << 1) << (ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt")));
0503 }
0504 
0505 void FileTreeModelTest::deleteDocument()
0506 {
0507     KateFileTreeModel m(nullptr, this);
0508     QAbstractItemModelTester tester(&m, this);
0509     QFETCH(const QList<DummyDocument *>, documents);
0510     QFETCH(const QList<int>, remove);
0511     QFETCH(ResultNode, nodes);
0512 
0513     for (DummyDocument *doc : documents) {
0514         m.documentOpened(doc);
0515     }
0516 
0517     for (const int &index : remove) {
0518         m.documentClosed(documents[index]);
0519     }
0520 
0521     ResultNode root;
0522     walkTree(m, QModelIndex(), root);
0523 
0524     QCOMPARE(root, nodes);
0525     qDeleteAll(documents);
0526 }
0527 
0528 void FileTreeModelTest::deleteDocumentBatch_data()
0529 {
0530     QTest::addColumn<QList<DummyDocument *>>("documents");
0531     QTest::addColumn<QList<int>>("remove");
0532     QTest::addColumn<QList<int>>("fail");
0533     QTest::addColumn<ResultNode>("nodes");
0534 
0535     QTest::newRow("neo") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo0.txt") << new DummyDocument("file:///a/foo1.txt")
0536                                                       << new DummyDocument("file:///a/foo2.txt") << new DummyDocument("file:///a/foo3.txt")
0537                                                       << new DummyDocument("file:///a/foo4.txt") << new DummyDocument("file:///a/foo5.txt")
0538                                                       << new DummyDocument("file:///a/foo6.txt") << new DummyDocument("file:///a/foo7.txt"))
0539                          << (QList<int>() << 1 << 2 << 4 << 6) << (QList<int>() << 2 << 4)
0540                          << (ResultNode() << (ResultNode("a", true) << ResultNode("foo0.txt") << ResultNode("foo2.txt") << ResultNode("foo3.txt")
0541                                                                     << ResultNode("foo4.txt") << ResultNode("foo5.txt") << ResultNode("foo7.txt")));
0542 }
0543 
0544 void FileTreeModelTest::deleteDocumentBatch()
0545 {
0546     KateFileTreeModel m(nullptr, this);
0547     QAbstractItemModelTester tester(&m, this);
0548     QFETCH(const QList<DummyDocument *>, documents);
0549     QFETCH(const QList<int>, remove);
0550     QFETCH(const QList<int>, fail);
0551     QFETCH(ResultNode, nodes);
0552 
0553     for (DummyDocument *doc : documents) {
0554         m.documentOpened(doc);
0555     }
0556 
0557     for (const int &index : remove) {
0558         if (!fail.contains(index)) {
0559             m.documentClosed(documents[index]);
0560         }
0561     }
0562 
0563     ResultNode root;
0564     walkTree(m, QModelIndex(), root);
0565 
0566     QCOMPARE(root, nodes);
0567     qDeleteAll(documents);
0568 }
0569 
0570 void FileTreeModelTest::rename_data()
0571 {
0572     QTest::addColumn<QList<DummyDocument *>>("documents");
0573     QTest::addColumn<int>("rename_idx");
0574     QTest::addColumn<QString>("rename_url");
0575     QTest::addColumn<ResultNode>("nodes");
0576 
0577     QTest::newRow("empty") << (QList<DummyDocument *>() << new DummyDocument()) << 0 << QStringLiteral("file:///a/foo.txt")
0578                            << (ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")));
0579 
0580     QTest::newRow("moving") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt")) << 0 << QStringLiteral("file:///b/foo.txt")
0581                             << (ResultNode() << (ResultNode("b", true) << ResultNode("foo.txt")));
0582 
0583     QTest::newRow("splitting") << (QList<DummyDocument *>() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt")) << 0
0584                                << QStringLiteral("file:///b/foo.txt")
0585                                << (ResultNode() << (ResultNode("a", true) << ResultNode("bar.txt")) << (ResultNode("b", true) << ResultNode("foo.txt")));
0586 }
0587 
0588 void FileTreeModelTest::rename()
0589 {
0590     KateFileTreeModel m(nullptr, this);
0591     QAbstractItemModelTester tester(&m, this);
0592     QFETCH(const QList<DummyDocument *>, documents);
0593     QFETCH(int, rename_idx);
0594     QFETCH(QString, rename_url);
0595     QFETCH(ResultNode, nodes);
0596 
0597     for (DummyDocument *doc : documents) {
0598         m.documentOpened(doc);
0599     }
0600 
0601     documents[rename_idx]->setUrl(rename_url);
0602     m.documentNameChanged(documents[rename_idx]);
0603 
0604     ResultNode root;
0605     walkTree(m, QModelIndex(), root);
0606 
0607     QCOMPARE(root, nodes);
0608     qDeleteAll(documents);
0609 }
0610 
0611 #include "moc_filetree_model_test.cpp"