1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
17
** GNU General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU
19
** General Public License version 3 as published by the Free Software
20
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21
** included in the packaging of this file. Please review the following
22
** information to ensure the GNU General Public License requirements will
23
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
27
****************************************************************************/
30
#include <QtCore/QDir>
31
#include <QtCore/QString>
32
#include <QtTest/QtTest>
33
#include <QtCore/QProcess>
34
#include <QtCore/QByteArray>
35
#include <QtCore/QLibraryInfo>
36
#include <QtCore/QTemporaryDir>
37
#include <QtCore/QStandardPaths>
39
class tst_uic : public QObject
48
void cleanupTestCase();
53
void run_data() const;
55
void runTranslation();
58
void compare_data() const;
63
const QString m_command;
65
QTemporaryDir m_generated;
66
QRegExp m_versionRegexp;
70
: m_command(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/uic"))
71
, m_versionRegexp(QLatin1String("Created by: Qt User Interface Compiler version [.\\d]{5,5}"))
75
static QByteArray msgProcessStartFailed(const QString &command, const QString &why)
77
const QString result = QString::fromLatin1("Could not start %1: %2")
79
return result.toLocal8Bit();
82
void tst_uic::initTestCase()
84
QVERIFY2(m_generated.isValid(), qPrintable(m_generated.errorString()));
85
QVERIFY(m_versionRegexp.isValid());
86
m_baseline = QFINDTESTDATA("baseline");
87
QVERIFY2(!m_baseline.isEmpty(), "Could not find 'baseline'.");
89
process.start(m_command, QStringList(QLatin1String("-help")));
90
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString()));
91
QVERIFY(process.waitForFinished());
92
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
93
QCOMPARE(process.exitCode(), 0);
95
const QString out = QString::fromLocal8Bit(process.readAllStandardError()).remove(QLatin1Char('\r'));
96
const QStringList outLines = out.split(QLatin1Char('\n'));
98
QString msg = QString::fromLatin1("uic test running in '%1' using: ").
99
arg(QDir::currentPath());
100
if (!outLines.empty())
101
msg += outLines.front();
102
qDebug("%s", qPrintable(msg));
105
void tst_uic::cleanupTestCase()
107
static const char envVar[] = "UIC_KEEP_GENERATED_FILES";
108
if (qgetenv(envVar).isEmpty()) {
109
qDebug("Note: The environment variable '%s' can be set to keep the temporary files for error analysis.", envVar);
111
m_generated.setAutoRemove(false);
112
qDebug("Keeping generated files in '%s'", qPrintable(QDir::toNativeSeparators(m_generated.path())));
116
void tst_uic::stdOut()
118
// Checks of everything works when using stdout and whether
119
// the OS file format conventions regarding newlines are met.
120
QDir baseline(m_baseline);
121
const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList(QLatin1String("*.ui")), QDir::Files);
122
QVERIFY(!baselineFiles.isEmpty());
124
process.start(m_command, QStringList(baselineFiles.front().absoluteFilePath()));
125
process.closeWriteChannel();
126
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString()));
127
QVERIFY(process.waitForFinished());
128
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
129
QCOMPARE(process.exitCode(), 0);
130
const QByteArray output = process.readAllStandardOutput();
131
QByteArray expected = "/********************************************************************************";
138
QVERIFY2(output.startsWith(expected), (QByteArray("Got: ") + output.toHex()).constData());
143
QFETCH(QString, originalFile);
144
QFETCH(QString, generatedFile);
145
QFETCH(QStringList, options);
148
process.start(m_command, QStringList(originalFile)
149
<< QString(QLatin1String("-o")) << generatedFile << options);
150
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString()));
151
QVERIFY(process.waitForFinished());
152
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
153
QCOMPARE(process.exitCode(), 0);
154
QCOMPARE(QFileInfo(generatedFile).exists(), true);
157
void tst_uic::run_data() const
159
QTest::addColumn<QString>("originalFile");
160
QTest::addColumn<QString>("generatedFile");
161
QTest::addColumn<QStringList>("options");
163
QDir generated(m_generated.path());
164
QDir baseline(m_baseline);
165
const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.ui"), QDir::Files);
166
foreach (const QFileInfo &baselineFile, baselineFiles) {
167
const QString generatedFile = generated.absolutePath()
168
+ QLatin1Char('/') + baselineFile.fileName()
169
+ QLatin1String(".h");
172
if (baselineFile.fileName() == QLatin1String("qttrid.ui"))
173
options << QStringList(QLatin1String("-idbased"));
175
QTest::newRow(qPrintable(baselineFile.baseName()))
176
<< baselineFile.absoluteFilePath()
182
// Helpers to generate a diff using the standard diff tool if present for failures.
183
static inline QString diffBinary()
185
QString binary = QLatin1String("diff");
187
binary += QLatin1String(".exe");
189
return QStandardPaths::findExecutable(binary);
192
static QString generateDiff(const QString &originalFile, const QString &generatedFile)
194
static const QString diff = diffBinary();
197
const QStringList args = QStringList() << QLatin1String("-u")
198
<< QDir::toNativeSeparators(originalFile)
199
<< QDir::toNativeSeparators(generatedFile);
200
QProcess diffProcess;
201
diffProcess.start(diff, args);
202
return diffProcess.waitForStarted() && diffProcess.waitForFinished()
203
? QString::fromLocal8Bit(diffProcess.readAllStandardOutput()) : QString();
206
static QByteArray msgCannotReadFile(const QFile &file)
208
const QString result = QLatin1String("Could not read file: ")
209
+ QDir::toNativeSeparators(file.fileName())
210
+ QLatin1String(": ") + file.errorString();
211
return result.toLocal8Bit();
214
void tst_uic::compare()
216
QFETCH(QString, originalFile);
217
QFETCH(QString, generatedFile);
219
QFile orgFile(originalFile);
220
QFile genFile(generatedFile);
222
QVERIFY2(orgFile.open(QIODevice::ReadOnly | QIODevice::Text), msgCannotReadFile(orgFile));
224
QVERIFY2(genFile.open(QIODevice::ReadOnly | QIODevice::Text), msgCannotReadFile(genFile));
226
QString originalFileContents = orgFile.readAll();
227
originalFileContents.replace(m_versionRegexp, QString());
229
QString generatedFileContents = genFile.readAll();
230
generatedFileContents.replace(m_versionRegexp, QString());
232
if (generatedFileContents != originalFileContents) {
233
const QString diff = generateDiff(originalFile, generatedFile);
235
qWarning().noquote().nospace() << "Difference:\n" << diff;
238
QCOMPARE(generatedFileContents, originalFileContents);
241
void tst_uic::compare_data() const
243
QTest::addColumn<QString>("originalFile");
244
QTest::addColumn<QString>("generatedFile");
246
QDir generated(m_generated.path());
247
QDir baseline(m_baseline);
248
const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.h"), QDir::Files);
249
foreach (const QFileInfo &baselineFile, baselineFiles) {
250
const QString generatedFile = generated.absolutePath()
251
+ QLatin1Char('/') + baselineFile.fileName();
252
QTest::newRow(qPrintable(baselineFile.baseName()))
253
<< baselineFile.absoluteFilePath()
258
void tst_uic::runTranslation()
262
QDir baseline(m_baseline);
264
QDir generated(m_generated.path());
265
generated.mkdir(QLatin1String("translation"));
266
QString generatedFile = generated.absolutePath() + QLatin1String("/translation/Dialog_without_Buttons_tr.h");
268
process.start(m_command, QStringList(baseline.filePath("Dialog_without_Buttons.ui"))
269
<< QString(QLatin1String("-tr")) << "i18n"
270
<< QString(QLatin1String("-include")) << "ki18n.h"
271
<< QString(QLatin1String("-o")) << generatedFile);
272
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString()));
273
QVERIFY(process.waitForFinished());
274
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
275
QCOMPARE(process.exitCode(), 0);
276
QCOMPARE(QFileInfo(generatedFile).exists(), true);
280
void tst_uic::runCompare()
282
const QString dialogFile = QLatin1String("/translation/Dialog_without_Buttons_tr.h");
283
const QString originalFile = m_baseline + dialogFile;
284
QFile orgFile(originalFile);
286
QDir generated(m_generated.path());
287
const QString generatedFile = generated.absolutePath() + dialogFile;
288
QFile genFile(generatedFile);
290
QVERIFY2(orgFile.open(QIODevice::ReadOnly | QIODevice::Text), msgCannotReadFile(orgFile));
292
QVERIFY2(genFile.open(QIODevice::ReadOnly | QIODevice::Text), msgCannotReadFile(genFile));
294
QString originalFileContents = orgFile.readAll();
295
originalFileContents.replace(m_versionRegexp, QString());
297
QString generatedFileContents = genFile.readAll();
298
generatedFileContents.replace(m_versionRegexp, QString());
300
if (generatedFileContents != originalFileContents) {
301
const QString diff = generateDiff(originalFile, generatedFile);
303
qWarning().noquote().nospace() << "Difference:\n" << diff;
306
QCOMPARE(generatedFileContents, originalFileContents);
310
#include "tst_uic.moc"