1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef DIALOGSTESTUTILS_H
5#define DIALOGSTESTUTILS_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
19
20#include <QtQuickTestUtils/private/qmlutils_p.h>
21#include <QtQuickTestUtils/private/visualtestutils_p.h>
22
23// We need these for Windows, because FolderListModel returns a lowercase drive letter; e.g.:
24// "file:///c:/blah.txt", whereas other API returns "file:///C:/blah.txt".
25#define COMPARE_URL(url1, url2) \
26 QCOMPARE(QFileInfo(url1.toLocalFile()).absoluteFilePath(), QFileInfo(url2.toLocalFile()).absoluteFilePath());
27
28// Store a copy of the arguments in case { ... } list initializer syntax is used as an argument,
29// which could result in two different lists being created and passed to std::transform()
30// (and would also require it to be enclosed in parentheses everywhere it's used).
31#define COMPARE_URLS(actualUrls, expectedUrls) \
32{ \
33 const QList<QUrl> actualUrlsCopy = actualUrls; \
34 QList<QString> actualPaths; \
35 std::transform(actualUrlsCopy.begin(), actualUrlsCopy.end(), std::back_insert_iterator(actualPaths), \
36 [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
37 const QList<QUrl> expectedUrlsCopy = expectedUrls; \
38 QList<QString> expectedPaths; \
39 std::transform(expectedUrlsCopy.begin(), expectedUrlsCopy.end(), std::back_insert_iterator(expectedPaths), \
40 [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
41 QCOMPARE(actualPaths, expectedPaths); \
42}
43
44#define OPEN_QUICK_DIALOG() \
45QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage()); \
46QVERIFY(dialogHelper.waitForWindowActive()); \
47QVERIFY(dialogHelper.openDialog()); \
48QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
49
50#define CLOSE_QUICK_DIALOG() \
51 do { \
52 dialogHelper.dialog->close(); \
53 QVERIFY(!dialogHelper.dialog->isVisible()); \
54 QTRY_VERIFY(!dialogHelper.quickDialog->isVisible()); \
55 } while (false)
56
57QT_BEGIN_NAMESPACE
58class QWindow;
59
60class QQuickListView;
61
62class QQuickAbstractButton;
63
64class QQuickDialogButtonBox;
65class QQuickFolderBreadcrumbBar;
66
67namespace QQuickDialogTestUtils
68{
69
70// Saves duplicating a bunch of code in every test.
71template<typename DialogType, typename QuickDialogType>
72class DialogTestHelper
73{
74public:
75 DialogTestHelper(QQmlDataTest *testCase, const QString &testFilePath,
76 const QStringList &qmlImportPaths = {}, const QVariantMap &initialProperties = {}) :
77 appHelper(testCase, testFilePath, initialProperties, qmlImportPaths)
78 {
79 if (!appHelper.ready)
80 return;
81
82 dialog = appHelper.window->property(name: "dialog").value<DialogType*>();
83 if (!dialog) {
84 appHelper.errorMessage = "\"dialog\" property is not valid";
85 return;
86 }
87
88 appHelper.window->show();
89 appHelper.window->requestActivate();
90 }
91
92 Q_REQUIRED_RESULT bool isWindowInitialized() const
93 {
94 return appHelper.ready;
95 }
96
97 Q_REQUIRED_RESULT bool waitForWindowActive()
98 {
99 return QTest::qWaitForWindowActive(window: appHelper.window);
100 }
101
102 /*
103 Opens the dialog. For non-native dialogs, it is necessary to ensure that
104 isQuickDialogOpen() returns true before trying to access its internals.
105 */
106 virtual bool openDialog()
107 {
108 dialog->open();
109 if (!dialog->isVisible()) {
110 appHelper.errorMessage = "Dialog is not visible";
111 return false;
112 }
113
114 // We might want to call this function more than once,
115 // and we only need to get these members the first time.
116 if (!quickDialog) {
117 quickDialog = appHelper.window->findChild<QuickDialogType*>();
118 if (!quickDialog) {
119 appHelper.errorMessage = "Can't find Qt Quick-based dialog";
120 return false;
121 }
122 }
123
124 return true;
125 }
126
127 bool isQuickDialogOpen() const
128 {
129 return quickDialog->isOpened();
130 }
131
132 QQuickWindow *window() const
133 {
134 return appHelper.window;
135 }
136
137 const char *failureMessage() const
138 {
139 return appHelper.errorMessage.constData();
140 }
141
142 QQuickVisualTestUtils::QQuickApplicationHelper appHelper;
143 DialogType *dialog = nullptr;
144 QuickDialogType *quickDialog = nullptr;
145};
146
147bool verifyFileDialogDelegates(QQuickListView *fileDialogListView, const QStringList &expectedFiles, QString &failureMessage);
148
149bool verifyBreadcrumbDelegates(QQuickFolderBreadcrumbBar *breadcrumbBar, const QUrl &expectedFolder, QString &failureMessage);
150
151QQuickAbstractButton *findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText);
152
153void enterText(QWindow *window, const QString &textToEnter);
154}
155
156QT_END_NAMESPACE
157
158#endif // DIALOGSTESTUTILS_H
159

source code of qtdeclarative/src/quickcontrolstestutils/dialogstestutils_p.h