File: kcombobox_unittest.cpp

package info (click to toggle)
kcompletion 5.116.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 21,760 kB
  • sloc: cpp: 5,947; sh: 14; makefile: 7
file content (231 lines) | stat: -rw-r--r-- 8,826 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
    This file is part of the KDE libraries
    SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include <QSignalSpy>
#include <QTest>
#include <khistorycombobox.h>
#include <klineedit.h>

class KTestComboBox : public KComboBox
{
public:
    KTestComboBox(bool rw, QWidget *parent = nullptr)
        : KComboBox(rw, parent)
    {
    }
    KCompletionBase *delegate() const
    {
        return KCompletionBase::delegate();
    }
};

class KComboBox_UnitTest : public QObject
{
    Q_OBJECT

private:
    void testComboReturnPressed(bool ctorArg)
    {
        KComboBox w(ctorArg /*initial value for editable*/);
        w.setEditable(true);
        w.setCompletionMode(KCompletion::CompletionPopup);
        w.addItem(QStringLiteral("Hello world"));
        QVERIFY(w.lineEdit());
        auto lineEdit = qobject_cast<KLineEdit *>(w.lineEdit());
        QVERIFY(lineEdit);

        // set editable again, don't recreate the line edit
        w.setEditable(true);
        QCOMPARE(w.lineEdit(), lineEdit);
        // KLineEdit signals
        QSignalSpy qReturnPressedSpy(w.lineEdit(), &QLineEdit::returnPressed);

#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QSignalSpy kEditReturnPressedSpy(lineEdit, qOverload<const QString &>(&KLineEdit::returnPressed));
#endif
        QSignalSpy kEditReturnKeyPressedSpy(lineEdit, &KLineEdit::returnKeyPressed);

        // KComboBox signals
#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QSignalSpy comboReturnPressedSpy(&w, qOverload<>(&KComboBox::returnPressed));
#endif
        QSignalSpy comboReturnPressedStringSpy(&w, qOverload<const QString &>(&KComboBox::returnPressed));

        QSignalSpy comboActivatedSpy(&w, &QComboBox::textActivated);
        QTest::keyClick(&w, Qt::Key_Return);
        QCOMPARE(qReturnPressedSpy.count(), 1);

#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QCOMPARE(kEditReturnPressedSpy.count(), 1);
        QCOMPARE(kEditReturnPressedSpy[0][0].toString(), QString("Hello world"));
#endif
        QCOMPARE(kEditReturnKeyPressedSpy.count(), 1);
        QCOMPARE(kEditReturnKeyPressedSpy.at(0).at(0).toString(), QStringLiteral("Hello world"));

#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QCOMPARE(comboReturnPressedSpy.count(), 1);
#endif
        QCOMPARE(comboReturnPressedStringSpy.count(), 1);
        QCOMPARE(comboReturnPressedStringSpy[0][0].toString(), QString("Hello world"));

        QCOMPARE(comboActivatedSpy.count(), 1);
        QCOMPARE(comboActivatedSpy[0][0].toString(), QString("Hello world"));
    }

private Q_SLOTS:
    void testComboReturnPressed()
    {
        testComboReturnPressed(false);
        testComboReturnPressed(true);
    }

    void testHistoryComboReturnPressed()
    {
        KHistoryComboBox w;
        QVERIFY(qobject_cast<KLineEdit *>(w.lineEdit()));
#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QSignalSpy comboReturnPressedSpy(&w, qOverload<>(&KComboBox::returnPressed));
#endif
        QSignalSpy comboReturnPressedStringSpy(&w, qOverload<const QString &>(&KComboBox::returnPressed));
        connect(&w, &KHistoryComboBox::textActivated, &w, &KHistoryComboBox::addToHistory);
        QSignalSpy comboActivatedSpy(&w, &QComboBox::textActivated);
        QTest::keyClicks(&w, QStringLiteral("Hello world"));
        QTest::keyClick(&w, Qt::Key_Return);
        qApp->processEvents(); // QueuedConnection in KHistoryComboBox
#if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81)
        QCOMPARE(comboReturnPressedSpy.count(), 1);
#endif
        QCOMPARE(comboReturnPressedStringSpy.count(), 1);
        QCOMPARE(comboReturnPressedStringSpy[0][0].toString(), QString("Hello world"));

        QCOMPARE(comboActivatedSpy.count(), 1);
        QCOMPARE(comboActivatedSpy[0][0].toString(), QString("Hello world"));
    }

    void testHistoryComboKeyUp()
    {
        KHistoryComboBox w;
        QStringList items;
        items << QStringLiteral("One") << QStringLiteral("Two") << QStringLiteral("Three") << QStringLiteral("Four");
        w.addItems(items);
        QSignalSpy currentIndexChangedSpy(&w, &QComboBox::currentIndexChanged);
        w.completionObject()->setItems(items);
        QCOMPARE(w.currentIndex(), 0);
        QTest::keyClick(&w, Qt::Key_Up);
        QCOMPARE(w.currentIndex(), 1);
        QCOMPARE(currentIndexChangedSpy.count(), 1);
        QCOMPARE(currentIndexChangedSpy[0][0].toInt(), 1);
    }

    void testHistoryComboInsertItems()
    {
        KHistoryComboBox combo;
        // uic generates code like this, let's make sure it compiles
        combo.insertItems(0, QStringList() << QStringLiteral("foo"));
    }

    void testHistoryComboReset()
    {
        // It only tests that it doesn't crash
        // TODO: Finish
        KHistoryComboBox combo;
        QStringList items;
        items << QStringLiteral("One") << QStringLiteral("Two");
        combo.addItems(items);
        combo.reset();
    }

    void testDeleteLineEdit()
    {
        // Test for KCombo's KLineEdit destruction
        KTestComboBox *testCombo = new KTestComboBox(true, nullptr); // rw, with KLineEdit
        testCombo->setEditable(false); // destroys our KLineEdit, with deleteLater
        qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
        QVERIFY(testCombo->KTestComboBox::delegate() == nullptr);
        delete testCombo; // not needed anymore
    }

    void testLineEditCompletion()
    {
        QFETCH(bool, editable);
        QPointer<KCompletion> completion;
        QPointer<KLineEdit> lineEdit;
        QPointer<KLineEdit> lineEdit2;

        {
            // Test for KCombo's KLineEdit inheriting the completion object of the parent
            KTestComboBox testCombo(editable, nullptr);

            // we only have a line edit when we are editable already
            QCOMPARE(static_cast<bool>(testCombo.lineEdit()), editable);

            // we can always get a completion object
            // NOTE: for an editable combo, this refers to the completion object of
            // the internal line edit
            // NOTE: for a not-yet-editable combo, this refers to the completion object
            // that belongs to the combo directly
            completion = testCombo.completionObject();
            QVERIFY(completion);

            // make editable
            testCombo.setEditable(true);
            QVERIFY(completion); // completion is still alive

            // verify that the completion object was set on the line edit
            lineEdit = qobject_cast<KLineEdit *>(testCombo.lineEdit());
            QVERIFY(lineEdit);
            QVERIFY(lineEdit->compObj());
            QCOMPARE(lineEdit->compObj(), completion.data());
            QCOMPARE(testCombo.completionObject(), completion.data());

            // don't lose the completion and don't crash when we set a new line edit
            // NOTE: only reuse the completion when it belongs to the combo box
            lineEdit2 = new KLineEdit(&testCombo);
            QVERIFY(!lineEdit2->compObj());
            testCombo.setLineEdit(lineEdit2);
            QVERIFY(!lineEdit); // first line edit got deleted now
            if (editable) {
                QVERIFY(!completion); // got deleted with the line edit
                // but we get a new one from the second line edit
                completion = testCombo.completionObject();
            }
            QVERIFY(completion);
            QCOMPARE(lineEdit2->compObj(), completion.data());
            QCOMPARE(testCombo.completionObject(), completion.data());
        }

        // ensure nothing gets leaked
        QVERIFY(!completion);
        QVERIFY(!lineEdit2);
    }

    void testLineEditCompletion_data()
    {
        QTest::addColumn<bool>("editable");
        QTest::newRow("deferred-editable") << false;
        QTest::newRow("editable") << true;
    }

    void testSelectionResetOnReturn()
    {
        // void QComboBoxPrivate::_q_returnPressed() calls lineEdit->deselect()
        KHistoryComboBox *testCombo = new KHistoryComboBox(true, nullptr);
        QCOMPARE(testCombo->insertPolicy(), QComboBox::NoInsert); // not the Qt default; KHistoryComboBox changes that
        QTest::keyClicks(testCombo, QStringLiteral("Hello world"));
        testCombo->lineEdit()->setSelection(5, 3);
        QVERIFY(testCombo->lineEdit()->hasSelectedText());
        QTest::keyClick(testCombo, Qt::Key_Return);
        // Changed in Qt5: it only does that if insertionPolicy isn't NoInsert.
        // Should we add a lineEdit()->deselect() in KHistoryComboBox? Why does this matter?
        QEXPECT_FAIL("", "Qt5: QComboBox doesn't deselect text anymore on returnPressed", Continue);
        QVERIFY(!testCombo->lineEdit()->hasSelectedText());
    }
};

QTEST_MAIN(KComboBox_UnitTest)

#include "kcombobox_unittest.moc"