From 09e5e133bb27bc08eb7a1b9ccfc8a493bf6d2a35 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 4 Sep 2024 18:58:12 +0200 Subject: [PATCH] Add rewriter testing Adding only the framework to write the rewriter tests. Task-number: QDS-13406 Change-Id: If4a7476d09595624c3a752411d516f4d9f3d601a Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../libs/designercore/include/rewriterview.h | 9 +++- .../libs/designercore/include/textmodifier.h | 6 +-- .../designercore/rewriter/rewriterview.cpp | 25 ++++++++--- tests/unit/tests/mocks/CMakeLists.txt | 1 + tests/unit/tests/mocks/textmodifiermock.h | 31 +++++++++++++ .../unit/tests/unittests/model/CMakeLists.txt | 1 + .../unittests/model/rewriterview-test.cpp | 45 +++++++++++++++++++ 8 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 tests/unit/tests/mocks/textmodifiermock.h create mode 100644 tests/unit/tests/unittests/model/rewriterview-test.cpp diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index e19d2e3c226..a4d41a5877a 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -10,6 +10,7 @@ option(QTC_USE_QML_DESIGNER_LITE "Use Qml Designer Lite" ${BUILD_NOT_DESIGNSTUDI add_feature_info("Qml Designer Lite" ${QTC_USE_QML_DESIGNER_LITE} "") option(USE_PROJECTSTORAGE "Use ProjectStorage" ${QTC_USE_QML_DESIGNER_LITE}) +add_feature_info("Use project storage" ${USE_PROJECTSTORAGE} "") option(DETACH_DISABLED_VIEWS "Detach disabled views" OFF) env_with_default("QTC_ENABLE_PROJECT_STORAGE_TRACING" ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING OFF) diff --git a/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h b/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h index 1fdb6837238..5960e8fb0a3 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h @@ -42,6 +42,8 @@ struct QmlTypeData bool isCppType = false; }; +enum class InstantQmlTextUpdate { No, Yes }; + class QMLDESIGNERCORE_EXPORT RewriterView : public AbstractView { Q_OBJECT @@ -54,7 +56,8 @@ public: public: RewriterView(ExternalDependenciesInterface &externalDependencies, - DifferenceHandling differenceHandling = RewriterView::Amend); + DifferenceHandling differenceHandling = RewriterView::Amend, + InstantQmlTextUpdate instantQmlTextUpdate = InstantQmlTextUpdate::Yes); ~RewriterView() override; void modelAttached(Model *model) override; @@ -189,8 +192,10 @@ protected: // functions private: //variables ModelNode nodeAtTextCursorPositionHelper(const ModelNode &root, int cursorPosition) const; void setupCanonicalHashes() const; +#ifndef QDS_USE_PROJECTSTORAGE void handleLibraryInfoUpdate(); void handleProjectUpdate(); +#endif bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } QPointer m_textModifier; @@ -209,7 +214,7 @@ private: //variables QString m_rewritingErrorMessage; QString m_lastCorrectQmlSource; QTimer m_amendTimer; - bool m_instantQmlTextUpdate = false; + InstantQmlTextUpdate m_instantQmlTextUpdate = InstantQmlTextUpdate::No; std::function m_setWidgetStatusCallback; bool m_hasIncompleteTypeInformation = false; bool m_restoringAuxData = false; diff --git a/src/plugins/qmldesigner/libs/designercore/include/textmodifier.h b/src/plugins/qmldesigner/libs/designercore/include/textmodifier.h index e361d806a16..e7ac2a23ce5 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/textmodifier.h +++ b/src/plugins/qmldesigner/libs/designercore/include/textmodifier.h @@ -23,8 +23,8 @@ class QMLDESIGNERCORE_EXPORT TextModifier: public QObject Q_OBJECT private: - TextModifier(const TextModifier &); - TextModifier &operator=(const TextModifier &); + TextModifier(const TextModifier &) = delete; + TextModifier &operator=(const TextModifier &) = delete; public: struct MoveInfo { @@ -42,7 +42,7 @@ public: public: TextModifier() = default; - ~TextModifier() override = 0; + ~TextModifier(); virtual void replace(int offset, int length, const QString& replacement) = 0; virtual void move(const MoveInfo &moveInfo) = 0; diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp index dd55bd2ef67..f7d4b5bc243 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp @@ -53,20 +53,25 @@ bool debugQmlPuppet(const DesignerSettings &settings) } RewriterView::RewriterView(ExternalDependenciesInterface &externalDependencies, - DifferenceHandling differenceHandling) + DifferenceHandling differenceHandling, + InstantQmlTextUpdate instantQmlTextUpdate) : AbstractView{externalDependencies} , m_differenceHandling(differenceHandling) , m_positionStorage(std::make_unique()) , m_modelToTextMerger(std::make_unique(this)) , m_textToModelMerger(std::make_unique(this)) + , m_instantQmlTextUpdate(instantQmlTextUpdate) { setKind(Kind::Rewriter); m_amendTimer.setSingleShot(true); - m_amendTimer.setInterval(800); - connect(&m_amendTimer, &QTimer::timeout, this, &RewriterView::amendQmlText); + if (m_instantQmlTextUpdate == InstantQmlTextUpdate::No) { + m_amendTimer.setInterval(800); + connect(&m_amendTimer, &QTimer::timeout, this, &RewriterView::amendQmlText); + } +#ifndef QDS_USE_PROJECTSTORAGE QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); connect(modelManager, &QmlJS::ModelManagerInterface::libraryInfoUpdated, @@ -83,6 +88,7 @@ RewriterView::RewriterView(ExternalDependenciesInterface &externalDependencies, this, &RewriterView::handleLibraryInfoUpdate, Qt::QueuedConnection); +#endif } RewriterView::~RewriterView() = default; @@ -112,7 +118,9 @@ void RewriterView::modelAttached(Model *model) if (!(m_errors.isEmpty() && m_warnings.isEmpty())) notifyErrorsAndWarnings(m_errors); - if (hasIncompleteTypeInformation()) { + if (m_instantQmlTextUpdate == InstantQmlTextUpdate::Yes) { + restoreAuxiliaryData(); + } else if (hasIncompleteTypeInformation()) { m_modelAttachPending = true; QTimer::singleShot(1000, this, [this, model]() { modelAttached(model); @@ -884,6 +892,7 @@ void RewriterView::setupCanonicalHashes() const } } +#ifndef QDS_USE_PROJECTSTORAGE void RewriterView::handleLibraryInfoUpdate() { // Trigger dummy amend to reload document when library info changes @@ -898,6 +907,7 @@ void RewriterView::handleProjectUpdate() { emit modelInterfaceProjectUpdated(); } +#endif ModelNode RewriterView::nodeAtTextCursorPosition(int cursorPosition) const { @@ -913,8 +923,8 @@ bool RewriterView::renameId(const QString &oldId, const QString &newId) && rootModelNode().hasBindingProperty(propertyName) && rootModelNode().bindingProperty(propertyName).isAliasExport(); - bool instant = m_instantQmlTextUpdate; - m_instantQmlTextUpdate = true; + auto instant = m_instantQmlTextUpdate; + m_instantQmlTextUpdate = InstantQmlTextUpdate::Yes; bool refactoring = textModifier()->renameId(oldId, newId); @@ -1158,7 +1168,8 @@ void RewriterView::qmlTextChanged() } case Amend: { - if (m_instantQmlTextUpdate || externalDependencies().instantQmlTextUpdate()) { + if (m_instantQmlTextUpdate == InstantQmlTextUpdate::Yes + || externalDependencies().instantQmlTextUpdate()) { amendQmlText(); } else { if (externalDependencies().viewManagerUsesRewriterView(this)) { diff --git a/tests/unit/tests/mocks/CMakeLists.txt b/tests/unit/tests/mocks/CMakeLists.txt index 0fdfa639c09..432a2ca2c54 100644 --- a/tests/unit/tests/mocks/CMakeLists.txt +++ b/tests/unit/tests/mocks/CMakeLists.txt @@ -40,4 +40,5 @@ add_qtc_library(TestMocks OBJECT sqlitetransactionbackendmock.h sqlitewritestatementmock.cpp sqlitewritestatementmock.h + textmodifiermock.h ) diff --git a/tests/unit/tests/mocks/textmodifiermock.h b/tests/unit/tests/mocks/textmodifiermock.h new file mode 100644 index 00000000000..773011a4571 --- /dev/null +++ b/tests/unit/tests/mocks/textmodifiermock.h @@ -0,0 +1,31 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "../utils/googletest.h" + +#include + +class TextModifierMock : public QmlDesigner::TextModifier +{ + MOCK_METHOD(void, replace, (int offset, int length, const QString &replacement), (override)); + MOCK_METHOD(void, move, (const MoveInfo &moveInfo), (override)); + MOCK_METHOD(void, indent, (int offset, int length), (override)); + MOCK_METHOD(void, indentLines, (int startLine, int endLine), (override)); + MOCK_METHOD(TextEditor::TabSettings, tabSettings, (), (const, override)); + MOCK_METHOD(void, startGroup, (), (override)); + MOCK_METHOD(void, flushGroup, (), (override)); + MOCK_METHOD(void, commitGroup, (), (override)); + MOCK_METHOD(QTextDocument *, textDocument, (), (const, override)); + MOCK_METHOD(QString, text, (), (const, override)); + MOCK_METHOD(QTextCursor, textCursor, (), (const, override)); + MOCK_METHOD(void, deactivateChangeSignals, (), (override)); + MOCK_METHOD(void, reactivateChangeSignals, (), (override)); + MOCK_METHOD(bool, renameId, (const QString &oldId, const QString &newId), (override)); + MOCK_METHOD(QStringList, + autoComplete, + (QTextDocument * textDocument, int positio, bool explicitComplete), + (override)); + MOCK_METHOD(bool, moveToComponent, (int nodeOffset, const QString &importData), (override)); +}; diff --git a/tests/unit/tests/unittests/model/CMakeLists.txt b/tests/unit/tests/unittests/model/CMakeLists.txt index b29eda3995f..37289ae6ddf 100644 --- a/tests/unit/tests/unittests/model/CMakeLists.txt +++ b/tests/unit/tests/unittests/model/CMakeLists.txt @@ -7,4 +7,5 @@ extend_qtc_test(unittest modelnode-test.cpp modelresourcemanagement-test.cpp nodelistproperty-test.cpp + rewriterview-test.cpp ) diff --git a/tests/unit/tests/unittests/model/rewriterview-test.cpp b/tests/unit/tests/unittests/model/rewriterview-test.cpp new file mode 100644 index 00000000000..8c62accd1d8 --- /dev/null +++ b/tests/unit/tests/unittests/model/rewriterview-test.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "../utils/googletest.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using QmlDesigner::AbstractView; + +class RewriterView : public ::testing::Test +{ +protected: + RewriterView() + { + rewriter.setTextModifier(&textModifierMock); + } + + ~RewriterView() { model.setRewriterView(nullptr); } + +protected: + NiceMock externalDependenciesMock; + NiceMock textModifierMock; + NiceMock pathCacheMock{"/path/foo.qml"}; + NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; + NiceMock resourceManagementMock; + QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + "Item", + imports, + QUrl::fromLocalFile(pathCacheMock.path.toQString()), + std::make_unique( + resourceManagementMock)}; + QmlDesigner::RewriterView rewriter{externalDependenciesMock}; + NiceMock view; +}; + +} // namespace