forked from qt-creator/qt-creator
Add rewriter testing
Adding only the framework to write the rewriter tests. Task-number: QDS-13406 Change-Id: If4a7476d09595624c3a752411d516f4d9f3d601a Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -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)
|
||||
|
@@ -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<TextModifier> 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<void(bool)> m_setWidgetStatusCallback;
|
||||
bool m_hasIncompleteTypeInformation = false;
|
||||
bool m_restoringAuxData = false;
|
||||
|
@@ -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;
|
||||
|
@@ -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<ModelNodePositionStorage>())
|
||||
, m_modelToTextMerger(std::make_unique<Internal::ModelToTextMerger>(this))
|
||||
, m_textToModelMerger(std::make_unique<Internal::TextToModelMerger>(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)) {
|
||||
|
@@ -40,4 +40,5 @@ add_qtc_library(TestMocks OBJECT
|
||||
sqlitetransactionbackendmock.h
|
||||
sqlitewritestatementmock.cpp
|
||||
sqlitewritestatementmock.h
|
||||
textmodifiermock.h
|
||||
)
|
||||
|
31
tests/unit/tests/mocks/textmodifiermock.h
Normal file
31
tests/unit/tests/mocks/textmodifiermock.h
Normal file
@@ -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 <textmodifier.h>
|
||||
|
||||
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));
|
||||
};
|
@@ -7,4 +7,5 @@ extend_qtc_test(unittest
|
||||
modelnode-test.cpp
|
||||
modelresourcemanagement-test.cpp
|
||||
nodelistproperty-test.cpp
|
||||
rewriterview-test.cpp
|
||||
)
|
||||
|
45
tests/unit/tests/unittests/model/rewriterview-test.cpp
Normal file
45
tests/unit/tests/unittests/model/rewriterview-test.cpp
Normal file
@@ -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 <externaldependenciesmock.h>
|
||||
#include <mocks/abstractviewmock.h>
|
||||
#include <mocks/modelresourcemanagementmock.h>
|
||||
#include <mocks/projectstoragemock.h>
|
||||
#include <mocks/sourcepathcachemock.h>
|
||||
#include <rewriterview.h>
|
||||
#include <textmodifiermock.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using QmlDesigner::AbstractView;
|
||||
|
||||
class RewriterView : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
RewriterView()
|
||||
{
|
||||
rewriter.setTextModifier(&textModifierMock);
|
||||
}
|
||||
|
||||
~RewriterView() { model.setRewriterView(nullptr); }
|
||||
|
||||
protected:
|
||||
NiceMock<ExternalDependenciesMock> externalDependenciesMock;
|
||||
NiceMock<TextModifierMock> textModifierMock;
|
||||
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
|
||||
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
|
||||
NiceMock<ModelResourceManagementMock> resourceManagementMock;
|
||||
QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")};
|
||||
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
|
||||
"Item",
|
||||
imports,
|
||||
QUrl::fromLocalFile(pathCacheMock.path.toQString()),
|
||||
std::make_unique<ModelResourceManagementMockWrapper>(
|
||||
resourceManagementMock)};
|
||||
QmlDesigner::RewriterView rewriter{externalDependenciesMock};
|
||||
NiceMock<AbstractViewMock> view;
|
||||
};
|
||||
|
||||
} // namespace
|
Reference in New Issue
Block a user