Move ChatDocumentHandler to use QmlTextItemWrapper and create test

This commit is contained in:
James Graham
2025-12-26 16:40:15 +00:00
parent 416d85af3b
commit f31e9062e6
8 changed files with 341 additions and 233 deletions

View File

@@ -120,7 +120,8 @@ macro(add_qml_tests)
endforeach()
endmacro()
add_executable(qmltest qmltest.cpp)
add_executable(qmltest qmltest.cpp qmltextitemwrappertestwrapper.h)
qt_add_qml_module(qmltest URI NeoChatTestUtils)
target_link_libraries(qmltest
PRIVATE
@@ -132,4 +133,5 @@ target_link_libraries(qmltest
add_qml_tests(
chatdocumenthelpertest.qml
qmltextitemwrappertest.qml
)

View File

@@ -6,4 +6,4 @@
#include <quicktest.h>
QUICK_TEST_MAIN(Kirigami)
QUICK_TEST_MAIN(NeoChat)

View File

@@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: 2024 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtTest
import NeoChatTestUtils
TestCase {
name: "QmlTextItemWrapperTest"
TextEdit {
id: textEdit
}
TextEdit {
id: textEdit2
}
QmlTextItemWrapperTestWrapper {
id: qmlTextItemWrapper
textItem: textEdit
}
SignalSpy {
id: spyItem
target: qmlTextItemWrapper
signalName: "textItemChanged"
}
SignalSpy {
id: spyContentsChanged
target: qmlTextItemWrapper
signalName: "textDocumentContentsChanged"
}
SignalSpy {
id: spyContentsChange
target: qmlTextItemWrapper
signalName: "textDocumentContentsChange"
}
SignalSpy {
id: spyCursor
target: qmlTextItemWrapper
signalName: "textDocumentCursorPositionChanged"
}
function test_item(): void {
spyItem.clear();
compare(qmlTextItemWrapper.textItem, textEdit);
compare(spyItem.count, 0);
qmlTextItemWrapper.textItem = textEdit2;
compare(qmlTextItemWrapper.textItem, textEdit2);
compare(spyItem.count, 1);
qmlTextItemWrapper.textItem = textEdit;
compare(qmlTextItemWrapper.textItem, textEdit);
compare(spyItem.count, 2);
}
function test_document(): void {
// We can't get to the QTextDocument from QML so we have to use a helper function.
compare(qmlTextItemWrapper.compareDocuments(textEdit.textDocument), true);
}
function test_cursor(): void {
spyContentsChange.clear();
spyContentsChanged.clear();
spyCursor.clear();
// We can't get to the QTextCursor from QML so we have to use a helper function.
compare(qmlTextItemWrapper.compareCursor(textEdit.cursorPosition, textEdit.selectionStart, textEdit.selectionEnd), true);
textEdit.insert(0, "test text")
compare(spyContentsChange.count, 1);
compare(spyContentsChange.signalArguments[0][0], 0);
compare(spyContentsChange.signalArguments[0][1], 0);
compare(spyContentsChange.signalArguments[0][2], 9);
compare(spyContentsChanged.count, 1);
compare(spyCursor.count, 1);
compare(qmlTextItemWrapper.compareCursor(textEdit.cursorPosition, textEdit.selectionStart, textEdit.selectionEnd), true);
textEdit.selectAll();
compare(spyContentsChanged.count, 1);
compare(spyCursor.count, 1);
compare(qmlTextItemWrapper.compareCursor(textEdit.cursorPosition, textEdit.selectionStart, textEdit.selectionEnd), true);
textEdit.clear();
compare(spyContentsChange.count, 2);
compare(spyContentsChange.signalArguments[1][0], 0);
compare(spyContentsChange.signalArguments[1][1], 9);
compare(spyContentsChange.signalArguments[1][2], 0);
compare(spyContentsChanged.count, 2);
compare(spyCursor.count, 2);
}
function test_setCursor(): void {
spyCursor.clear();
textEdit.insert(0, "test text");
compare(textEdit.cursorPosition, 9);
compare(spyCursor.count, 1);
qmlTextItemWrapper.setCursorPosition(5);
compare(textEdit.cursorPosition, 5);
compare(spyCursor.count, 2);
qmlTextItemWrapper.setCursorPosition(1);
compare(textEdit.cursorPosition, 1);
compare(spyCursor.count, 3);
textEdit.cursorVisible = false;
compare(textEdit.cursorVisible, false);
qmlTextItemWrapper.setCursorVisible(true);
compare(textEdit.cursorVisible, true);
qmlTextItemWrapper.setCursorVisible(false);
compare(textEdit.cursorVisible, false);
textEdit.clear();
compare(spyCursor.count, 4);
}
function test_forceActiveFocus(): void {
textEdit2.forceActiveFocus();
compare(textEdit.activeFocus, false);
qmlTextItemWrapper.forceActiveFocus();
compare(textEdit.activeFocus, true);
}
}

View File

@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QObject>
#include <QQuickItem>
#include <QQuickTextDocument>
#include <QTextCursor>
#include "qmltextitemwrapper.h"
class QmlTextItemWrapperTestWrapper : public QObject
{
Q_OBJECT
QML_ELEMENT
/**
* @brief The QML text Item the ChatDocumentHandler is handling.
*/
Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged)
public:
explicit QmlTextItemWrapperTestWrapper(QObject *parent = nullptr)
: QObject(parent)
, m_textItemWrapper(new QmlTextItemWrapper(this))
{
Q_ASSERT(m_textItemWrapper);
connect(m_textItemWrapper, &QmlTextItemWrapper::textItemChanged, this, &QmlTextItemWrapperTestWrapper::textItemChanged);
connect(m_textItemWrapper, &QmlTextItemWrapper::textDocumentContentsChange, this, &QmlTextItemWrapperTestWrapper::textDocumentContentsChange);
connect(m_textItemWrapper, &QmlTextItemWrapper::textDocumentContentsChanged, this, &QmlTextItemWrapperTestWrapper::textDocumentContentsChanged);
connect(m_textItemWrapper,
&QmlTextItemWrapper::textDocumentCursorPositionChanged,
this,
&QmlTextItemWrapperTestWrapper::textDocumentCursorPositionChanged);
}
QQuickItem *textItem() const
{
return m_textItemWrapper->textItem();
}
void setTextItem(QQuickItem *textItem)
{
m_textItemWrapper->setTextItem(textItem);
}
Q_INVOKABLE bool compareDocuments(QQuickTextDocument *document)
{
return document->textDocument() == m_textItemWrapper->document();
}
Q_INVOKABLE bool compareCursor(int cursorPosition, int selectionStart, int selectionEnd)
{
const auto cursor = m_textItemWrapper->textCursor();
if (cursor.isNull()) {
return false;
}
const auto posSame = cursor.position() == cursorPosition;
const auto startSame = cursor.selectionStart() == selectionStart;
const auto endSame = cursor.selectionEnd() == selectionEnd;
return posSame && startSame && endSame;
}
Q_INVOKABLE void setCursorPosition(int pos)
{
m_textItemWrapper->setCursorPosition(pos);
}
Q_INVOKABLE void setCursorVisible(bool visible)
{
m_textItemWrapper->setCursorVisible(visible);
}
Q_INVOKABLE void forceActiveFocus() const
{
m_textItemWrapper->forceActiveFocus();
}
Q_SIGNALS:
void textItemChanged();
void textDocumentContentsChange(int position, int charsRemoved, int charsAdded);
void textDocumentContentsChanged();
void textDocumentCursorPositionChanged();
private:
QPointer<QmlTextItemWrapper> m_textItemWrapper;
};