Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1,20 @@
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
remove_definitions(-DQT_NO_CAST_TO_ASCII)
find_package(Qt6Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
if(NOT Qt6Test_FOUND)
message(STATUS "Qt6Test not found, autotests will not be built.")
return()
endif()
include(ECMAddTests)
ecm_add_tests(
kcompletioncoretest.cpp
klineedit_unittest.cpp
kcombobox_unittest.cpp
ksortablelisttest.cpp
kemailvalidatortest.cpp
LINK_LIBRARIES Qt6::Test KF6::Completion
)
@@ -0,0 +1,212 @@
/*
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);
QSignalSpy kEditReturnKeyPressedSpy(lineEdit, &KLineEdit::returnKeyPressed);
// KComboBox signals
QSignalSpy comboReturnPressedStringSpy(&w, qOverload<const QString &>(&KComboBox::returnPressed));
QSignalSpy comboActivatedSpy(&w, &QComboBox::textActivated);
QTest::keyClick(&w, Qt::Key_Return);
QCOMPARE(qReturnPressedSpy.count(), 1);
QCOMPARE(kEditReturnKeyPressedSpy.count(), 1);
QCOMPARE(kEditReturnKeyPressedSpy.at(0).at(0).toString(), QStringLiteral("Hello world"));
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()));
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
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"
@@ -0,0 +1,377 @@
/*
This file is part of the KDE libraries
SPDX-FileCopyrightText: 2005 Thomas Braxton <brax108@cox.net>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kcompletioncoretest.h"
#include <QSignalSpy>
#include <QTest>
#define clampet strings[0]
#define coolcat strings[1]
#define carpet strings[2]
#define carp strings[3]
#define wclampet wstrings[0]
#define wcoolcat wstrings[1]
#define wcarpet wstrings[2]
#define wcarp wstrings[3]
void Test_KCompletion::initTestCase()
{
strings = QStringList{QStringLiteral("clampet@test.org"), //
QStringLiteral("coolcat@test.org"),
QStringLiteral("carpet@test.org"),
QStringLiteral("carp@test.org")};
wstrings = QStringList{QStringLiteral("clampet@test.org:30"),
QStringLiteral("coolcat@test.org:20"),
QStringLiteral("carpet@test.org:40"),
QStringLiteral("carp@test.org:7")};
qRegisterMetaType<QStringList>("QStringList");
}
void Test_KCompletion::isEmpty()
{
KCompletion completion;
QVERIFY(completion.isEmpty());
QVERIFY(completion.items().isEmpty());
}
void Test_KCompletion::insertionOrder()
{
KCompletion completion;
completion.setSoundsEnabled(false);
QSignalSpy spy1(&completion, &KCompletion::match);
QSignalSpy spy3(&completion, &KCompletion::multipleMatches);
completion.setOrder(KCompletion::Insertion);
QVERIFY(completion.order() == KCompletion::Insertion);
completion.setItems(strings);
QVERIFY(completion.items().count() == strings.count());
completion.setCompletionMode(KCompletion::CompletionShell);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), QStringLiteral("carp"));
QVERIFY(spy1.count() == 1);
QVERIFY(spy1.takeFirst().at(0).toString() == QLatin1String("carp"));
QVERIFY(spy3.count() == 1);
spy3.takeFirst();
QSignalSpy spy2(&completion, &KCompletion::matches);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(spy2.count(), 1);
QVERIFY(spy3.count() == 0); // shouldn't be signaled on 2nd call
QStringList matches = spy2.takeFirst().at(0).toStringList();
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
completion.setCompletionMode(KCompletion::CompletionAuto);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), carpet);
QVERIFY(spy1.count() == 1);
QVERIFY(spy1.takeFirst().at(0).toString() == carpet);
}
void Test_KCompletion::sortedOrder()
{
KCompletion completion;
completion.setSoundsEnabled(false);
QSignalSpy spy1(&completion, &KCompletion::match);
QSignalSpy spy3(&completion, &KCompletion::multipleMatches);
completion.setOrder(KCompletion::Sorted);
QVERIFY(completion.order() == KCompletion::Sorted);
completion.setItems(strings);
QVERIFY(completion.items().count() == 4);
completion.setCompletionMode(KCompletion::CompletionShell);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), QStringLiteral("carp"));
QVERIFY(spy1.count() == 1);
QCOMPARE(spy1.takeFirst().at(0).toString(), QStringLiteral("carp"));
QVERIFY(spy3.count() == 1);
spy3.takeFirst();
QSignalSpy spy2(&completion, &KCompletion::matches);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(spy2.count(), 1);
QVERIFY(spy3.count() == 0); // shouldn't be signaled on 2nd call
QStringList matches = spy2.takeFirst().at(0).toStringList();
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
completion.setCompletionMode(KCompletion::CompletionAuto);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), carp);
QVERIFY(spy1.count() == 1);
QCOMPARE(spy1.takeFirst().at(0).toString(), carp);
}
void Test_KCompletion::weightedOrder()
{
KCompletion completion;
completion.setSoundsEnabled(false);
QSignalSpy spy1(&completion, &KCompletion::match);
QSignalSpy spy3(&completion, &KCompletion::multipleMatches);
completion.setOrder(KCompletion::Weighted);
QVERIFY(completion.order() == KCompletion::Weighted);
completion.setItems(wstrings);
QVERIFY(completion.items().count() == 4);
completion.setCompletionMode(KCompletion::CompletionShell);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), QStringLiteral("carp"));
spy1.takeFirst(); // empty the list
QVERIFY(spy3.count() == 1);
spy3.takeFirst();
QSignalSpy spy2(&completion, &KCompletion::matches);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(spy2.count(), 1);
QVERIFY(spy3.count() == 0); // shouldn't be signaled on 2nd call
QStringList matches = spy2.takeFirst().at(0).toStringList();
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
completion.setCompletionMode(KCompletion::CompletionAuto);
QCOMPARE(completion.makeCompletion(QStringLiteral("ca")), carpet);
matches = completion.substringCompletion(QStringLiteral("ca"));
QVERIFY(matches.count() == 3);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], coolcat);
QCOMPARE(matches[2], carp);
}
void Test_KCompletion::substringCompletion_Insertion()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Insertion);
completion.setItems(strings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.substringCompletion(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], clampet);
QCOMPARE(matches[1], coolcat);
QCOMPARE(matches[2], carpet);
QCOMPARE(matches[3], carp);
matches = completion.substringCompletion(QStringLiteral("ca"));
QVERIFY(matches.count() == 3);
QCOMPARE(matches[0], coolcat);
QCOMPARE(matches[1], carpet);
QCOMPARE(matches[2], carp);
matches = completion.substringCompletion(QStringLiteral("car"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
matches = completion.substringCompletion(QStringLiteral("pet"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], clampet);
QCOMPARE(matches[1], carpet);
}
void Test_KCompletion::substringCompletion_Sorted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Sorted);
completion.setItems(strings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.substringCompletion(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
QCOMPARE(matches[2], clampet);
QCOMPARE(matches[3], coolcat);
matches = completion.substringCompletion(QStringLiteral("ca"));
QVERIFY(matches.count() == 3);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
QCOMPARE(matches[2], coolcat);
matches = completion.substringCompletion(QStringLiteral("car"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
matches = completion.substringCompletion(QStringLiteral("pet"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], clampet);
}
void Test_KCompletion::substringCompletion_Weighted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Weighted);
completion.setItems(wstrings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.substringCompletion(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], clampet);
QCOMPARE(matches[2], coolcat);
QCOMPARE(matches[3], carp);
matches = completion.substringCompletion(QStringLiteral("ca"));
QVERIFY(matches.count() == 3);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], coolcat);
QCOMPARE(matches[2], carp);
matches = completion.substringCompletion(QStringLiteral("car"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
matches = completion.substringCompletion(QStringLiteral("pet"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], clampet);
}
void Test_KCompletion::allMatches_Insertion()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Insertion);
completion.setItems(strings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.allMatches(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], clampet);
QCOMPARE(matches[1], coolcat);
QCOMPARE(matches[2], carpet);
QCOMPARE(matches[3], carp);
matches = completion.allMatches(QStringLiteral("ca"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
matches = completion.allMatches(QStringLiteral("pet"));
QVERIFY(matches.count() == 0);
}
void Test_KCompletion::allMatches_Sorted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Sorted);
completion.setItems(strings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.allMatches(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
QCOMPARE(matches[2], clampet);
QCOMPARE(matches[3], coolcat);
matches = completion.allMatches(QStringLiteral("ca"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carp);
QCOMPARE(matches[1], carpet);
matches = completion.allMatches(QStringLiteral("pet"));
QVERIFY(matches.count() == 0);
}
void Test_KCompletion::allMatches_Weighted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.setOrder(KCompletion::Weighted);
completion.setItems(wstrings);
QVERIFY(completion.items().count() == 4);
QStringList matches = completion.allMatches(QStringLiteral("c"));
QVERIFY(matches.count() == 4);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], clampet);
QCOMPARE(matches[2], coolcat);
QCOMPARE(matches[3], carp);
matches = completion.allMatches(QStringLiteral("ca"));
QVERIFY(matches.count() == 2);
QCOMPARE(matches[0], carpet);
QCOMPARE(matches[1], carp);
matches = completion.allMatches(QStringLiteral("pet"));
QVERIFY(matches.count() == 0);
}
void Test_KCompletion::cycleMatches_Insertion()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setOrder(KCompletion::Insertion);
completion.setItems(strings);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(completion.nextMatch(), carpet);
QCOMPARE(completion.nextMatch(), carp);
QCOMPARE(completion.previousMatch(), carpet);
QCOMPARE(completion.previousMatch(), carp);
}
void Test_KCompletion::cycleMatches_Sorted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setOrder(KCompletion::Sorted);
completion.setItems(strings);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(completion.nextMatch(), carp);
QCOMPARE(completion.nextMatch(), carpet);
QCOMPARE(completion.previousMatch(), carp);
QCOMPARE(completion.previousMatch(), carpet);
}
void Test_KCompletion::cycleMatches_Weighted()
{
KCompletion completion;
completion.setSoundsEnabled(false);
completion.setOrder(KCompletion::Weighted);
completion.setItems(wstrings);
completion.setCompletionMode(KCompletion::CompletionAuto);
completion.makeCompletion(QStringLiteral("ca"));
QCOMPARE(completion.nextMatch(), carpet);
QCOMPARE(completion.nextMatch(), carp);
QCOMPARE(completion.previousMatch(), carpet);
QCOMPARE(completion.previousMatch(), carp);
}
QTEST_MAIN(Test_KCompletion)
#include "moc_kcompletioncoretest.cpp"
@@ -0,0 +1,37 @@
/*
This file is part of the KDE libraries
SPDX-FileCopyrightText: 2005 Thomas Braxton <brax108@cox.net>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KCOMPLETIONCORETEST_H
#define KCOMPLETIONCORETEST_H
#include "kcompletion.h"
#include <QStringList>
class Test_KCompletion : public QObject
{
Q_OBJECT
QStringList strings;
QStringList wstrings;
private Q_SLOTS:
void initTestCase();
void isEmpty();
void insertionOrder();
void sortedOrder();
void weightedOrder();
void substringCompletion_Insertion();
void substringCompletion_Sorted();
void substringCompletion_Weighted();
void allMatches_Insertion();
void allMatches_Sorted();
void allMatches_Weighted();
void cycleMatches_Insertion();
void cycleMatches_Sorted();
void cycleMatches_Weighted();
};
#endif
@@ -0,0 +1,41 @@
/*
SPDX-FileCopyrightText: 2017-2023 Laurent Montel <montel@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include <KEmailValidator>
#include <QObject>
#include <QTest>
Q_DECLARE_METATYPE(QValidator::State)
class KEmailValidatorTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void shouldValidateEmail_data()
{
QTest::addColumn<QString>("email");
QTest::addColumn<QValidator::State>("state");
QTest::newRow("empty") << QString() << QValidator::Intermediate;
QTest::newRow("email") << QStringLiteral("foo@kde.org") << QValidator::Acceptable;
QTest::newRow("notanemail") << QStringLiteral("foo") << QValidator::Intermediate;
QTest::newRow("space") << QStringLiteral("foo ") << QValidator::Invalid;
QTest::newRow("space1") << QStringLiteral(" foo") << QValidator::Invalid;
QTest::newRow("email2") << QStringLiteral("<foo@kde.org>") << QValidator::Intermediate;
QTest::newRow("email3") << QStringLiteral("\"bla\" <foo@kde.org>") << QValidator::Invalid;
}
void shouldValidateEmail()
{
QFETCH(QString, email);
QFETCH(QValidator::State, state);
KEmailValidator validator;
int pos;
QCOMPARE(validator.validate(email, pos), state);
}
};
QTEST_GUILESS_MAIN(KEmailValidatorTest)
#include "kemailvalidatortest.moc"
@@ -0,0 +1,234 @@
/*
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 <QClipboard>
#include <QSignalSpy>
#include <QTest>
#include <QToolButton>
#include <kcompletionbox.h>
#include <klineedit.h>
class KLineEdit_UnitTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testReturnPressed()
{
KLineEdit w;
w.setText(QStringLiteral("Hello world"));
QSignalSpy qReturnPressedSpy(&w, &QLineEdit::returnPressed);
QSignalSpy returnKeyPressedSpy(&w, &KLineEdit::returnKeyPressed);
QTest::keyClick(&w, Qt::Key_Return);
QCOMPARE(qReturnPressedSpy.count(), 1);
QCOMPARE(returnKeyPressedSpy.count(), 1);
QCOMPARE(returnKeyPressedSpy.at(0).at(0).toString(), QStringLiteral("Hello world"));
}
void testTextEditedSignals()
{
KLineEdit w;
QVERIFY(!w.isModified());
// setText emits textChanged and userTextChanged, but not textEdited
QSignalSpy textChangedSpy(&w, &QLineEdit::textChanged);
QSignalSpy textEditedSpy(&w, &QLineEdit::textEdited);
w.setText(QStringLiteral("Hello worl"));
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textChangedSpy[0][0].toString(), w.text());
QCOMPARE(textEditedSpy.count(), 0);
QVERIFY(!w.isModified());
textChangedSpy.clear();
textEditedSpy.clear();
// calling clear should emit textChanged and userTextChanged, but not textEdited
w.clear();
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textEditedSpy.count(), 0);
// if text box is already empty, calling clear() shouldn't emit
// any more signals
w.clear();
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textEditedSpy.count(), 0);
// set the text back for further tests below
w.setText(QStringLiteral("Hello worl"));
textChangedSpy.clear();
textEditedSpy.clear();
// typing emits all three signals
QTest::keyClick(&w, Qt::Key_D);
QCOMPARE(w.text(), QString::fromLatin1("Hello world"));
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textChangedSpy[0][0].toString(), w.text());
QCOMPARE(textEditedSpy.count(), 1);
QCOMPARE(textEditedSpy[0][0].toString(), w.text());
QVERIFY(w.isModified());
w.setText(QStringLiteral("K")); // prepare for next test
textChangedSpy.clear();
textEditedSpy.clear();
QVERIFY(!w.isModified());
// the suggestion from auto completion emits textChanged but not userTextChanged nor textEdited
w.setCompletionMode(KCompletion::CompletionAuto);
KCompletion completion;
completion.setSoundsEnabled(false);
QStringList items;
items << QStringLiteral("KDE is cool") << QStringLiteral("KDE is really cool");
completion.setItems(items);
w.setCompletionObject(&completion);
w.doCompletion(w.text());
QCOMPARE(w.text(), items.at(0));
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textChangedSpy[0][0].toString(), w.text());
QCOMPARE(textEditedSpy.count(), 0);
QVERIFY(!w.isModified());
textChangedSpy.clear();
textEditedSpy.clear();
// accepting the completion suggestion now emits all three signals too
QTest::keyClick(&w, Qt::Key_Right);
QCOMPARE(w.text(), items.at(0));
QCOMPARE(textChangedSpy.count(), 1);
QCOMPARE(textChangedSpy[0][0].toString(), w.text());
QCOMPARE(textEditedSpy.count(), 1);
QCOMPARE(textEditedSpy[0][0].toString(), w.text());
QVERIFY(w.isModified());
textChangedSpy.clear();
textEditedSpy.clear();
// Now with popup completion
w.setCompletionMode(KCompletion::CompletionPopup);
w.setText(QStringLiteral("KDE"));
QVERIFY(!w.isModified());
textChangedSpy.clear();
textEditedSpy.clear();
w.doCompletion(w.text()); // popup appears
QCOMPARE(w.text(), QString::fromLatin1("KDE"));
QCOMPARE(textChangedSpy.count() + textEditedSpy.count(), 0);
w.completionBox()->down(); // select 1st item
QCOMPARE(w.text(), items.at(0));
QVERIFY(w.isModified());
w.completionBox()->down(); // select 2nd item
QCOMPARE(w.text(), items.at(1));
// Selecting an item in the popup completion changes the lineedit text
// and emits textChanged and userTextChanged, but not textEdited.
QCOMPARE(textChangedSpy.count(), 2);
QCOMPARE(textEditedSpy.count(), 0);
textChangedSpy.clear();
textEditedSpy.clear();
QTest::keyClick(&w, Qt::Key_Enter); // activate
QVERIFY(!w.completionBox()->isVisible());
QCOMPARE(w.text(), items.at(1));
QVERIFY(w.isModified());
// Nothing else happens, the text was already set in the lineedit
QCOMPARE(textChangedSpy.count(), 0);
QCOMPARE(textEditedSpy.count(), 0);
// Now when using the mouse in the popup completion
w.setText(QStringLiteral("KDE"));
w.doCompletion(w.text()); // popup appears
QCOMPARE(w.text(), QString::fromLatin1("KDE"));
// Selecting an item in the popup completion changes the lineedit text and emits all 3 signals
const QRect rect = w.completionBox()->visualRect(w.completionBox()->model()->index(1, 0));
QSignalSpy textActivatedSpy(w.completionBox(), &KCompletionBox::textActivated);
QTest::mouseClick(w.completionBox()->viewport(), Qt::LeftButton, Qt::NoModifier, rect.center());
QCOMPARE(textActivatedSpy.count(), 1);
QCOMPARE(w.text(), items.at(1));
QVERIFY(w.isModified());
}
void testCompletionBox()
{
KLineEdit w;
w.setText(QStringLiteral("/"));
w.setCompletionMode(KCompletion::CompletionPopup);
KCompletion completion;
completion.setSoundsEnabled(false);
w.setCompletionObject(&completion);
QStringList items;
items << QStringLiteral("/home/") << QStringLiteral("/hold/") << QStringLiteral("/hole/");
completion.setItems(items);
QTest::keyClick(&w, 'h');
QCOMPARE(w.text(), QString::fromLatin1("/h"));
QCOMPARE(w.completionBox()->currentRow(), -1);
QCOMPARE(w.completionBox()->items(), items);
QTest::keyClick(&w, 'o');
QCOMPARE(w.text(), QString::fromLatin1("/ho"));
QCOMPARE(w.completionBox()->currentRow(), -1);
w.completionBox()->down(); // select 1st item
QCOMPARE(w.text(), items.at(0));
w.completionBox()->down(); // select 2nd item
QCOMPARE(w.text(), items.at(1));
w.completionBox()->up(); // select 1st item again
QCOMPARE(w.text(), items.at(0));
w.completionBox()->up(); // select last item
QCOMPARE(w.text(), items.at(2));
w.completionBox()->down(); // select 1st item again
QCOMPARE(w.text(), items.at(0));
QStringList newItems;
newItems << QStringLiteral("/home/kde");
completion.setItems(newItems);
QTest::keyClick(&w, 'k');
QCOMPARE(w.text(), QString("/home/k"));
// QCOMPARE(w.completionBox()->currentRow(), -1); // #247552
w.completionBox()->down(); // select the item
QCOMPARE(w.completionBox()->items(), newItems);
QCOMPARE(w.text(), newItems.at(0));
}
void testPaste()
{
const QString origText = QApplication::clipboard()->text();
const QString pastedText = QStringLiteral("Test paste from klineedit_unittest");
QApplication::clipboard()->setText(pastedText);
KLineEdit w;
w.setText(QStringLiteral("Hello world"));
w.selectAll();
QTest::keyClick(&w, Qt::Key_V, Qt::ControlModifier);
QCOMPARE(w.text(), pastedText);
QApplication::clipboard()->setText(origText);
}
void testClearButtonClicked()
{
KLineEdit w;
w.setText(QStringLiteral("Hello world"));
w.setClearButtonEnabled(true);
w.setClearButtonEnabled(false);
w.setClearButtonEnabled(true);
QSignalSpy spy(&w, &KLineEdit::clearButtonClicked);
QToolButton *tb = w.findChild<QToolButton *>();
QTest::mouseClick(tb, Qt::LeftButton, Qt::NoModifier);
QCOMPARE(w.text(), QString());
QCOMPARE(spy.count(), 1);
}
};
QTEST_MAIN(KLineEdit_UnitTest)
#include "klineedit_unittest.moc"
@@ -0,0 +1,34 @@
#include <QString>
#include <ksortablelist.h>
int main(int /*argc*/, char ** /*argv*/)
{
KSortableList<QString> list;
list.insert(1, QStringLiteral("FOO (1)"));
list.insert(2, QStringLiteral("Test (2)"));
list.insert(1, QStringLiteral("Huba! (1)"));
list.insert(5, QStringLiteral("MAAOOAM! (5)"));
list.insert(10, QStringLiteral("Teeheeest (10)"));
list.insert(2, QStringLiteral("I was here :) (2)"));
list.insert(4, QStringLiteral("Yeehaa... (4)"));
QList<KSortableItem<QString>>::iterator it = list.begin();
qDebug("Insertion order:");
qDebug("================");
for (; it != list.end(); ++it) {
qDebug("%i: %s", (*it).key(), (*it).value().toLatin1().constData());
}
list.sort();
qDebug("\nSorted:");
qDebug("=======");
it = list.begin();
for (; it != list.end(); ++it) {
qDebug("%i: %s", (*it).key(), (*it).value().toLatin1().constData());
}
return 0;
}