File indexing completed on 2024-04-14 03:54:53

0001 /*
0002     This file is part of the Kate project.
0003     SPDX-FileCopyrightText: 2013 Dominik Haumann <dhaumann@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "katefoldingtest.h"
0009 
0010 #include <katebuffer.h>
0011 #include <kateconfig.h>
0012 #include <katedocument.h>
0013 #include <kateglobal.h>
0014 #include <katetextfolding.h>
0015 #include <kateview.h>
0016 
0017 #include <QJsonDocument>
0018 #include <QTest>
0019 
0020 #include <memory>
0021 
0022 using namespace KTextEditor;
0023 
0024 QTEST_MAIN(KateFoldingTest)
0025 
0026 void KateFoldingTest::initTestCase()
0027 {
0028     KTextEditor::EditorPrivate::enableUnitTestMode();
0029 }
0030 
0031 void KateFoldingTest::cleanupTestCase()
0032 {
0033 }
0034 
0035 // This is a unit test for bug 311866 (https://bugs.kde.org/show_bug.cgi?id=311866)
0036 // It loads 5 lines of C++ code, places the cursor in line 4, and then folds
0037 // the code.
0038 // Expected behavior: the cursor should be moved so it stays visible
0039 // Buggy behavior: the cursor is hidden, and moving the hidden cursor crashes kate
0040 void KateFoldingTest::testCrash311866()
0041 {
0042     KTextEditor::DocumentPrivate doc;
0043     const QUrl url = QUrl::fromLocalFile(QStringLiteral(TEST_DATA_DIR "bug311866.cpp"));
0044     doc.openUrl(url);
0045     doc.setHighlightingMode(QStringLiteral("C++"));
0046     doc.buffer().ensureHighlighted(6);
0047 
0048     const std::unique_ptr<ViewPrivate> view{static_cast<KTextEditor::ViewPrivate *>(doc.createView(nullptr))};
0049     view->show();
0050     view->resize(400, 300);
0051     view->setCursorPosition(Cursor(3, 0));
0052     QTest::qWait(100);
0053 
0054     view->slotFoldToplevelNodes();
0055     doc.buffer().ensureHighlighted(6);
0056 
0057     qDebug() << "!!! Does the next line crash?";
0058     view->up();
0059 }
0060 
0061 // This test makes sure that,
0062 // - if you have selected text
0063 // - that spans a folded range,
0064 // - and the cursor is at the end of the text selection,
0065 // - and you type a char, e.g. 'x',
0066 // then the resulting text is correct, and changing region
0067 // visibility does not mess around with the text cursor.
0068 //
0069 // See https://bugs.kde.org/show_bug.cgi?id=295632
0070 void KateFoldingTest::testBug295632()
0071 {
0072     KTextEditor::DocumentPrivate doc;
0073     QString text = QStringLiteral(
0074         "oooossssssss\n"
0075         "{\n"
0076         "\n"
0077         "}\n"
0078         "ssssss----------");
0079     doc.setText(text);
0080 
0081     // view must be visible...
0082     const std::unique_ptr<ViewPrivate> view{static_cast<KTextEditor::ViewPrivate *>(doc.createView(nullptr))};
0083     view->show();
0084     view->resize(400, 300);
0085 
0086     qint64 foldId = view->textFolding().newFoldingRange(KTextEditor::Range(1, 0, 3, 1));
0087     view->textFolding().foldRange(foldId);
0088     QVERIFY(view->textFolding().isLineVisible(0));
0089     QVERIFY(view->textFolding().isLineVisible(1));
0090     QVERIFY(!view->textFolding().isLineVisible(2));
0091     QVERIFY(!view->textFolding().isLineVisible(3));
0092     QVERIFY(view->textFolding().isLineVisible(4));
0093 
0094     view->setSelection(Range(Cursor(0, 4), Cursor(4, 6)));
0095     view->setCursorPosition(Cursor(4, 6));
0096 
0097     QTest::qWait(100);
0098     doc.typeChars(view.get(), QStringLiteral("x"));
0099     QTest::qWait(100);
0100 
0101     QString line = doc.line(0);
0102     QCOMPARE(line, QStringLiteral("oooox----------"));
0103 }
0104 
0105 // This testcase tests the following:
0106 // - the cursor is first set into the word 'hello'
0107 // - then lines 0-3 are folded.
0108 // - the real text cursor is still in the word 'hello'
0109 // - the important issue is: The display cursor must be in the visible line range
0110 // --> if this test passes, KateViewInternal's m_displayCursor is properly adapted.
0111 void KateFoldingTest::testCrash367466()
0112 {
0113     KTextEditor::DocumentPrivate doc;
0114 
0115     // we use only x to have equal width characters, else we fail for non-fixed width fonts
0116     QString text = QStringLiteral(
0117         "xxxx xxxx\n"
0118         "\n"
0119         "\n"
0120         "xxxx xxx\n"
0121         "xxxxx\n"
0122         "xxxxx\n");
0123     doc.setText(text);
0124 
0125     // view must be visible...
0126     const std::unique_ptr<ViewPrivate> view{static_cast<KTextEditor::ViewPrivate *>(doc.createView(nullptr))};
0127     view->show();
0128     view->resize(400, 300);
0129     view->setCursorPosition(KTextEditor::Cursor(5, 2));
0130     QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(5, 2));
0131     qint64 foldId = view->textFolding().newFoldingRange(KTextEditor::Range(0, 0, 3, 8));
0132 
0133     view->textFolding().foldRange(foldId);
0134     QVERIFY(view->textFolding().isLineVisible(0));
0135     QVERIFY(!view->textFolding().isLineVisible(1));
0136     QVERIFY(!view->textFolding().isLineVisible(2));
0137     QVERIFY(!view->textFolding().isLineVisible(3));
0138     QVERIFY(view->textFolding().isLineVisible(4));
0139     QVERIFY(view->textFolding().isLineVisible(5));
0140 
0141     QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(5, 2));
0142     view->up();
0143     QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(4, 2));
0144 }
0145 
0146 void KateFoldingTest::testUnfoldingInImportFoldingRanges()
0147 {
0148     DocumentPrivate doc;
0149     const auto text = QStringLiteral(
0150         "int f(bool one) {\n"
0151         "    if (one) {\n"
0152         "        return 1;\n"
0153         "    } else {\n"
0154         "        return 0;\n"
0155         "    }\n"
0156         "}\n"
0157         "\n"
0158         "int g() {\n"
0159         "    return 123;\n"
0160         "}\n");
0161     doc.setText(text);
0162 
0163     // view must be visible...
0164     const std::unique_ptr<ViewPrivate> view{static_cast<ViewPrivate *>(doc.createView(nullptr))};
0165     view->show();
0166     view->resize(400, 300);
0167 
0168     auto &textFolding = view->textFolding();
0169 
0170     const auto addFoldedRange = [&textFolding](Range range, Kate::TextFolding::FoldingRangeFlags extraFlags = {}) {
0171         textFolding.newFoldingRange(range, Kate::TextFolding::Folded | extraFlags);
0172     };
0173     addFoldedRange(Range(0, 16, 6, 1)); // f()
0174     addFoldedRange(Range(8, 8, 10, 1)); // g()
0175     addFoldedRange(Range(1, 13, 3, 5), Kate::TextFolding::Persistent); // if
0176     addFoldedRange(Range(3, 11, 5, 5)); // else
0177 
0178     textFolding.importFoldingRanges(QJsonDocument{});
0179     // TextFolding::importFoldingRanges() should remove all existing folding ranges
0180     // - both top-level and nested -  before importing new ones.
0181     QCOMPARE(textFolding.debugDump(), QLatin1String("tree  - folded "));
0182 }
0183 
0184 #include "moc_katefoldingtest.cpp"