aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qml/tst_qml.cpp
blob: befc68d443d0222d3ec358b7e8db555ebdb261e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <QtTest/qtest.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qprocess.h>
#include <QtCore/qloggingcategory.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>

Q_LOGGING_CATEGORY(lcQml, "qt.qml.tests");

class tst_qml : public QQmlDataTest
{
    Q_OBJECT
public:
    tst_qml() : QQmlDataTest(QT_QMLTEST_DATADIR) {}

private slots:
    void initTestCase() override;
    void nonWindow();
    void itemAndWindowGeometry_data();
    void itemAndWindowGeometry();

private:
    QString qmlPath;
};

void tst_qml::initTestCase()
{
    QQmlDataTest::initTestCase();
    qmlPath = QLibraryInfo::path(QLibraryInfo::BinariesPath);

#if defined(Q_OS_WIN)
    qmlPath += QLatin1String("/qml.exe");
#else
    qmlPath += QLatin1String("/qml");
#endif

    QVERIFY(QFileInfo(qmlPath).exists());
}

void tst_qml::nonWindow()
{
    QProcess qml;
    qml.start(qmlPath, { testFile("nonWindow.qml") });
    QVERIFY(qml.waitForFinished());
    QCOMPARE(qml.exitCode(), 0); // Should not exit with code 2
}

void tst_qml::itemAndWindowGeometry_data()
{
    QTest::addColumn<QString>("config");
    QTest::addColumn<QString>("geometry");
    QTest::addColumn<QString>("qmlfile");
    QTest::addColumn<QSize>("expectedWindowSize");
    QTest::addColumn<QSize>("expectedContentSize");

    const QString none; // empty string

    auto sizeOrInvalid = [](int w, int h) {
        static const bool wm = QGuiApplicationPrivate::platformIntegration()->
                hasCapability(QPlatformIntegration::WindowManagement);
        return wm ? QSize(w, h) : QSize();
    };

    QTest::newRow("default: unsized")
            << none << none << "unsizedItem.qml"
            << QSize() << QSize(); // default size depends on window system
    QTest::newRow("default: unsized with geometry")
            << none << "100x100+50+50" << "unsizedItem.qml"
            << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100);
    QTest::newRow("resizeToItem: unsized")
            << "resizeToItem" << none << "unsizedItem.qml"
            << QSize() << QSize(0, 0);
    QTest::newRow("resizeToItem: unsized with geometry")
            << "resizeToItem" << "100x100+50+50" << "unsizedItem.qml"
            << sizeOrInvalid(100, 100) << QSize(0, 0);

    QTest::newRow("default: sized")
            << none << none << "sizedItem.qml"
            << QSize() << QSize();
    QTest::newRow("default: sized with geometry")
            << none << "100x100+50+50" << "sizedItem.qml"
            << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100);
    QTest::newRow("resizeToItem: sized")
            << "resizeToItem" << none << "sizedItem.qml"
            << sizeOrInvalid(200, 150) << sizeOrInvalid(200, 150);
    QTest::newRow("resizeToItem: sized with geometry")
            << "resizeToItem" << "320x240+50+50" << "sizedItem.qml"
            << sizeOrInvalid(320, 240) << QSize(200, 150);

    QTest::newRow("default: resizing")
            << none << none << "resizeItem.qml"
            << QSize() << QSize();
    QTest::newRow("default: resizing with geometry")
            << none << "100x100+50+50" << "resizeItem.qml"
            << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100);
    QTest::newRow("resizeToItem: resizing")
            << "resizeToItem" << none << "resizeItem.qml"
            << sizeOrInvalid(100, 50) << sizeOrInvalid(100, 50);
    QTest::newRow("resizeToItem: resizing with geometry")
            << "resizeToItem" << "320x240+50+50" << "resizeItem.qml"
            << sizeOrInvalid(100, 50) << sizeOrInvalid(100, 50);
}

/*
    - A root Item will get put into a Window depending on config (implementations in
      tools/qml/ResizeItemToWindow.qml and ResizeWindowToItem.qml).
    - The window system will enforce a minimum size.
    - In the default configuration, the root Item should then get resized to fit
      (QTBUG-114068 / QTBUG-116753).
    - In resizeToItem configuration, if the item width/height are not set, the window would
      try to be 0x0, but the window system won't allow it.
    - This also tests the `--qwindowgeometry` argument: with the default config, the
      item should be resized to fit, but not with `-c resizeToItem`.
*/
void tst_qml::itemAndWindowGeometry()
{
#ifdef Q_OS_WIN
    QSKIP("console.info does not go to stderr on Windows.");
#endif

    QFETCH(QString, config);
    QFETCH(QString, geometry);
    QFETCH(QString, qmlfile);
    QFETCH(QSize, expectedWindowSize);
    QFETCH(QSize, expectedContentSize);

    QStringList args;
    if (!config.isEmpty())
        args << "-c" << config;
    if (!geometry.isEmpty())
        args << "--qwindowgeometry" << geometry;
    args << testFile(qmlfile);
    QProcess qml;
    qml.start(qmlPath, args);
    QVERIFY(qml.waitForFinished());
    QCOMPARE(qml.exitStatus(), QProcess::NormalExit);
    const QByteArray output = qml.readAllStandardError();
    const auto sizeLineIndex = output.lastIndexOf("window");
    QCOMPARE_GE(sizeLineIndex, 0);
    const auto newlineIndex = output.indexOf('\n', sizeLineIndex);
    QCOMPARE_GT(newlineIndex, sizeLineIndex);
    // expect a line like "window 120 120 content 120 120"
    const auto sizes = output.sliced(sizeLineIndex, newlineIndex - sizeLineIndex).split(' ');
    QCOMPARE_GE(sizes.size(), 6);
    QCOMPARE(sizes[0], "window");
    QCOMPARE(sizes[3], "content");
    const QSize windowSize(sizes[1].toInt(), sizes[2].toInt());
    const QSize contentSize(sizes[4].toInt(), sizes[5].toInt());
    qCDebug(lcQml) << sizes
                   << "window" << windowSize << "expect" << expectedWindowSize
                   << "content" << contentSize << "expect" << expectedContentSize;
    QVERIFY(!windowSize.isEmpty());
    if (config != "resizeToItem") {
        // default config:
        // ResizeItemToWindow.qml should have resized the item to its window
        QCOMPARE(contentSize, windowSize);
    }
    // windowSize can be off-by-one on hidpi (e.g. QT_SCALE_FACTOR=2 on xcb);
    // perhaps that's a bug somewhere, but so far we aren't testing hidpi on CI
    if (expectedWindowSize.isValid())
        QCOMPARE(windowSize, expectedWindowSize);
    if (expectedContentSize.isValid())
        QCOMPARE(contentSize, expectedContentSize);
}

QTEST_MAIN(tst_qml)

#include <tst_qml.moc>