1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
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.
16**
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.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include "testcompiler.h"
32
33#include <QDir>
34#include <QDirIterator>
35#include <QObject>
36#include <QRegularExpression>
37#include <QStandardPaths>
38#include <QTemporaryDir>
39
40#if defined(DEBUG_BUILD)
41# define DIR_INFIX "debug/"
42#elif defined(RELEASE_BUILD)
43# define DIR_INFIX "release/"
44#else
45# define DIR_INFIX ""
46#endif
47
48class tst_qmake : public QObject
49{
50 Q_OBJECT
51
52public:
53 tst_qmake();
54
55private slots:
56 void initTestCase();
57 void cleanupTestCase();
58 void cleanup();
59 void simple_app();
60 void simple_app_shadowbuild();
61 void simple_app_shadowbuild2();
62 void simple_app_versioned();
63 void simple_lib();
64 void simple_dll();
65 void subdirs();
66 void subdir_via_pro_file_extra_target();
67 void duplicateLibraryEntries();
68 void export_across_file_boundaries();
69 void include_dir();
70 void include_pwd();
71 void install_files();
72 void install_depends();
73 void quotedfilenames();
74 void prompt();
75 void one_space();
76 void findMocs();
77 void findDeps();
78 void rawString();
79#if defined(Q_OS_DARWIN)
80 void bundle_spaces();
81#elif defined(Q_OS_WIN)
82 void windowsResources();
83#endif
84 void substitutes();
85 void project();
86 void proFileCache();
87 void qinstall();
88 void resources();
89 void conflictingTargets();
90
91private:
92 TestCompiler test_compiler;
93 QTemporaryDir tempWorkDir;
94 QString base_path;
95 const QString origCurrentDirPath;
96};
97
98tst_qmake::tst_qmake()
99 : tempWorkDir(QDir::tempPath() + "/tst_qmake"),
100 origCurrentDirPath(QDir::currentPath())
101{
102}
103
104static void copyDir(const QString &sourceDirPath, const QString &targetDirPath)
105{
106 QDir currentDir;
107 QDirIterator dit(sourceDirPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
108 while (dit.hasNext()) {
109 dit.next();
110 const QString targetPath = targetDirPath + QLatin1Char('/') + dit.fileName();
111 currentDir.mkpath(dirPath: targetPath);
112 copyDir(sourceDirPath: dit.filePath(), targetDirPath: targetPath);
113 }
114
115 QDirIterator fit(sourceDirPath, QDir::Files | QDir::Hidden);
116 while (fit.hasNext()) {
117 fit.next();
118 const QString targetPath = targetDirPath + QLatin1Char('/') + fit.fileName();
119 QFile::remove(fileName: targetPath); // allowed to fail
120 QFile src(fit.filePath());
121 QVERIFY2(src.copy(targetPath), qPrintable(src.errorString()));
122 }
123}
124
125void tst_qmake::initTestCase()
126{
127 QVERIFY2(tempWorkDir.isValid(), qPrintable(tempWorkDir.errorString()));
128 QString binpath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
129 QString cmd = QString("%1/qmake").arg(a: binpath);
130#ifdef Q_CC_MSVC
131 const QString jom = QStandardPaths::findExecutable(QLatin1String("jom.exe"));
132 if (jom.isEmpty()) {
133 test_compiler.setBaseCommands( QLatin1String("nmake"), cmd );
134 } else {
135 test_compiler.setBaseCommands( jom, cmd );
136 }
137#elif defined(Q_CC_MINGW)
138 test_compiler.setBaseCommands( "mingw32-make", cmd );
139#elif defined(Q_OS_WIN) && defined(Q_CC_GNU)
140 test_compiler.setBaseCommands( "mmmake", cmd );
141#else
142 test_compiler.setBaseCommands( makeCmd: "make", qmakeCmd: cmd );
143#endif
144 const QString testDataSubDir = QStringLiteral("testdata");
145 const QString subProgram = testDataSubDir + QLatin1String("/simple_app/main.cpp");
146 QString testDataPath = QFINDTESTDATA(subProgram);
147 if (!testDataPath.endsWith(s: subProgram))
148 QFAIL("Cannot find test data directory.");
149 testDataPath.chop(n: subProgram.length() - testDataSubDir.length());
150
151 QString userWorkDir = qgetenv(varName: "TST_QMAKE_BUILD_DIR");
152 if (userWorkDir.isEmpty()) {
153 base_path = tempWorkDir.path();
154 } else {
155 if (!QFile::exists(fileName: userWorkDir)) {
156 QFAIL(qUtf8Printable(QStringLiteral("TST_QMAKE_BUILD_DIR %1 does not exist.")
157 .arg(userWorkDir)));
158 }
159 base_path = userWorkDir;
160 }
161
162 copyDir(sourceDirPath: testDataPath, targetDirPath: base_path + QLatin1Char('/') + testDataSubDir);
163}
164
165void tst_qmake::cleanupTestCase()
166{
167 // On Windows, ~QTemporaryDir fails to remove the directory if we're still in there.
168 QDir::setCurrent(origCurrentDirPath);
169}
170
171void tst_qmake::cleanup()
172{
173 test_compiler.resetArguments();
174 test_compiler.resetEnvironment();
175 test_compiler.clearCommandOutput();
176}
177
178void tst_qmake::simple_app()
179{
180 QString workDir = base_path + "/testdata/simple_app";
181 QString destDir = workDir + "/dest dir";
182 QString installDir = workDir + "/dist";
183
184 QVERIFY( test_compiler.qmake( workDir, "simple_app", QString() ));
185 QVERIFY( test_compiler.make( workDir ));
186 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
187
188 QVERIFY(test_compiler.make(workDir, "install"));
189 QVERIFY(test_compiler.exists(installDir, "simple app", Exe, "1.0.0"));
190
191 QVERIFY( test_compiler.makeClean( workDir ));
192 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
193 QVERIFY( test_compiler.makeDistClean( workDir ));
194 QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
195 QVERIFY( test_compiler.removeMakefile( workDir ) );
196}
197
198void tst_qmake::simple_app_shadowbuild()
199{
200 QString workDir = base_path + "/testdata/simple_app";
201 QString buildDir = base_path + "/testdata/simple_app_build";
202 QString destDir = buildDir + "/dest dir";
203
204 QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
205 QVERIFY( test_compiler.make( buildDir ));
206 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
207 QVERIFY( test_compiler.makeClean( buildDir ));
208 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
209 QVERIFY( test_compiler.makeDistClean( buildDir ));
210 QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
211 QVERIFY( test_compiler.removeMakefile( buildDir ) );
212}
213
214void tst_qmake::simple_app_shadowbuild2()
215{
216 QString workDir = base_path + "/testdata/simple_app";
217 QString buildDir = base_path + "/testdata/simple_app/build";
218 QString destDir = buildDir + "/dest dir";
219
220 QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
221 QVERIFY( test_compiler.make( buildDir ));
222 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
223 QVERIFY( test_compiler.makeClean( buildDir ));
224 QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
225 QVERIFY( test_compiler.makeDistClean( buildDir ));
226 QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
227 QVERIFY( test_compiler.removeMakefile( buildDir ) );
228}
229
230void tst_qmake::simple_app_versioned()
231{
232 QString workDir = base_path + "/testdata/simple_app";
233 QString buildDir = base_path + "/testdata/simple_app_versioned_build";
234 QString destDir = buildDir + "/dest dir";
235 QString installDir = buildDir + "/dist";
236
237 QString version = "4.5.6";
238 QVERIFY(test_compiler.qmake(workDir, "simple_app", buildDir, QStringList{ "VERSION=" + version }));
239 QString qmakeOutput = test_compiler.commandOutput();
240 QVERIFY(test_compiler.make(buildDir));
241 QVERIFY(test_compiler.exists(destDir, "simple app", Exe, version));
242
243 QString pdbFilePath;
244 bool checkPdb = qmakeOutput.contains(s: "Project MESSAGE: check for pdb, please");
245 if (checkPdb) {
246 QString targetBase = QFileInfo(TestCompiler::targetName(buildMode: Exe, target: "simple app", version))
247 .completeBaseName();
248 pdbFilePath = destDir + '/' + targetBase + ".pdb";
249 QVERIFY2(QFile::exists(pdbFilePath), qPrintable(pdbFilePath));
250 QVERIFY(test_compiler.make(buildDir, "install"));
251 QString installedPdbFilePath = installDir + '/' + targetBase + ".pdb";
252 QVERIFY2(QFile::exists(installedPdbFilePath), qPrintable(installedPdbFilePath));
253 }
254
255 QVERIFY(test_compiler.makeClean(buildDir));
256 QVERIFY(test_compiler.exists(destDir, "simple app", Exe, version));
257 QVERIFY(test_compiler.makeDistClean(buildDir));
258 QVERIFY(!test_compiler.exists(destDir, "simple app", Exe, version));
259 if (checkPdb)
260 QVERIFY(!QFile::exists(pdbFilePath));
261 QVERIFY(test_compiler.removeMakefile(buildDir));
262}
263
264void tst_qmake::simple_dll()
265{
266 QString workDir = base_path + "/testdata/simple_dll";
267 QString destDir = workDir + "/dest dir";
268
269 QDir D;
270 D.remove( fileName: workDir + "/Makefile");
271 QVERIFY( test_compiler.qmake( workDir, "simple_dll" ));
272 QVERIFY( test_compiler.make( workDir ));
273 QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" ));
274 QVERIFY( test_compiler.makeClean( workDir ));
275 QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should still exist after a make clean
276 QVERIFY( test_compiler.makeDistClean( workDir ));
277 QVERIFY( !test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should not exist after a make distclean
278 QVERIFY( test_compiler.removeMakefile( workDir ) );
279}
280
281void tst_qmake::simple_lib()
282{
283 QString workDir = base_path + "/testdata/simple_lib";
284 QString destDir = workDir + "/dest dir";
285
286 QDir D;
287 D.remove( fileName: workDir + "/Makefile");
288 QVERIFY( test_compiler.qmake( workDir, "simple_lib" ));
289 QVERIFY( test_compiler.make( workDir ));
290 QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" ));
291 QVERIFY( test_compiler.makeClean( workDir ));
292 QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should still exist after a make clean
293 QVERIFY( test_compiler.makeDistClean( workDir ));
294 QVERIFY( !test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should not exist after a make distclean
295 QVERIFY( test_compiler.removeMakefile( workDir ) );
296}
297
298void tst_qmake::subdirs()
299{
300 QString workDir = base_path + "/testdata/subdirs";
301
302 QDir D;
303 D.remove( fileName: workDir + "/simple_app/Makefile");
304 D.remove( fileName: workDir + "/simple_dll/Makefile");
305 QVERIFY( test_compiler.qmake( workDir, "subdirs" ));
306 QVERIFY( test_compiler.make( workDir ));
307 QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
308 QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
309 QVERIFY( test_compiler.makeClean( workDir ));
310 // Should still exist after a make clean
311 QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
312 QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
313 // Since subdirs templates do not have a make dist clean, we should clean up ourselves
314 // properly
315 QVERIFY( test_compiler.makeDistClean( workDir ));
316 QVERIFY( test_compiler.removeMakefile( workDir ) );
317}
318
319void tst_qmake::subdir_via_pro_file_extra_target()
320{
321 QString workDir = base_path + "/testdata/subdir_via_pro_file_extra_target";
322
323 QDir D;
324 D.remove( fileName: workDir + "/Makefile");
325 D.remove( fileName: workDir + "/Makefile.subdir");
326 D.remove( fileName: workDir + "/simple/Makefile");
327 D.remove( fileName: workDir + "/simple/Makefile.subdir");
328 QVERIFY( test_compiler.qmake( workDir, "subdir_via_pro_file_extra_target" ));
329 QVERIFY( test_compiler.make( workDir, "extratarget" ));
330}
331
332void tst_qmake::duplicateLibraryEntries()
333{
334 QVERIFY(true);
335 /* TODO: this test does not work as the problem it tests doesn't happen
336 until after the parsing of the pro-file and thus has to be tested
337 by parsing the Makefile. This is not doable with the current
338 testcompiler framework and has as such been put on hold.
339
340 QString workDir = base_path + "/testdata/duplicateLibraryEntries";
341 QVERIFY(test_compiler.qmake(workDir, "duplicateLibraryEntries")); */
342}
343
344void tst_qmake::export_across_file_boundaries()
345{
346 // This relies on features so we need to set the QMAKEFEATURES environment variable
347 test_compiler.addToEnvironment(varAssignment: "QMAKEFEATURES=.");
348 QString workDir = base_path + "/testdata/export_across_file_boundaries";
349 QVERIFY( test_compiler.qmake( workDir, "foo" ));
350}
351
352void tst_qmake::include_dir()
353{
354#ifdef QT_NO_WIDGETS
355 QSKIP("This test depends on QtWidgets");
356#else
357 QString workDir = base_path + "/testdata/include_dir";
358 QVERIFY( test_compiler.qmake( workDir, "foo" ));
359 QVERIFY( test_compiler.make( workDir ));
360 QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
361 QVERIFY( test_compiler.makeDistClean( workDir ));
362
363 QString buildDir = base_path + "/testdata/include_dir_build";
364 QVERIFY( test_compiler.qmake( workDir, "foo", buildDir ));
365 QVERIFY( test_compiler.make( buildDir ));
366 QVERIFY( test_compiler.exists( buildDir, "foo", Exe, "1.0.0" ));
367 QVERIFY( test_compiler.makeDistClean( buildDir ));
368#endif
369}
370
371void tst_qmake::include_pwd()
372{
373 QString workDir = base_path + "/testdata/include_pwd";
374 QVERIFY( test_compiler.qmake( workDir, "include_pwd" ));
375 QVERIFY( test_compiler.make( workDir ));
376 QVERIFY( test_compiler.makeDistClean( workDir ));
377}
378
379void tst_qmake::install_files()
380{
381 QString workDir = base_path + "/testdata/shadow_files";
382 QVERIFY( test_compiler.qmake( workDir, "foo" ));
383 QVERIFY( test_compiler.make( workDir ));
384 QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
385 QVERIFY( test_compiler.make( workDir, "install" ));
386 QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
387 QVERIFY( test_compiler.exists( workDir + "/dist", "test.txt", Plain, "1.0.0" ));
388 QCOMPARE(QFileInfo(workDir + "/test.txt").lastModified(), QFileInfo(workDir + "/dist/test.txt").lastModified());
389 QVERIFY( test_compiler.make( workDir, "uninstall" ));
390 QVERIFY( test_compiler.makeDistClean( workDir ));
391
392 QString buildDir = base_path + "/testdata/shadow_files_build";
393 QVERIFY( test_compiler.qmake( workDir, "foo", buildDir ));
394 QVERIFY( test_compiler.make( buildDir ));
395 QVERIFY( test_compiler.exists( buildDir, "foo", Exe, "1.0.0" ));
396 QVERIFY( test_compiler.make( buildDir, "install" ));
397 QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
398 QVERIFY( test_compiler.exists( workDir + "/dist", "test.txt", Plain, "1.0.0" ));
399 QVERIFY( test_compiler.exists( workDir + "/dist", "foo.bar", Plain, "1.0.0" ));
400 QVERIFY( test_compiler.make( buildDir, "uninstall" ));
401 QVERIFY( test_compiler.makeDistClean( buildDir ));
402}
403
404void tst_qmake::install_depends()
405{
406 QString workDir = base_path + "/testdata/install_depends";
407 QVERIFY( test_compiler.qmake( workDir, "foo" ));
408 QVERIFY( test_compiler.make( workDir ));
409 QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
410 QVERIFY( test_compiler.make( workDir, "install" ));
411 QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
412 QVERIFY( test_compiler.exists( workDir + "/dist", "test1", Plain, "1.0.0" ));
413 QVERIFY( test_compiler.exists( workDir + "/dist", "test2", Plain, "1.0.0" ));
414 QVERIFY( test_compiler.make( workDir, "uninstall" ));
415 QVERIFY( test_compiler.makeDistClean( workDir ));
416}
417void tst_qmake::quotedfilenames()
418{
419 QString workDir = base_path + "/testdata/quotedfilenames";
420 QVERIFY( test_compiler.qmake( workDir, "quotedfilenames" ));
421 QVERIFY( test_compiler.makeClean( workDir ));
422 QVERIFY( test_compiler.make( workDir ));
423 QVERIFY( test_compiler.exists( workDir, "quotedfilenames", Exe, "1.0.0" ));
424}
425
426void tst_qmake::prompt()
427{
428#if 0
429 QProcess qmake;
430 qmake.setProcessChannelMode(QProcess::MergedChannels);
431 qmake.setWorkingDirectory(QLatin1String("testdata/prompt"));
432 qmake.start(QLatin1String("qmake CONFIG-=debug_and_release CONFIG-=debug CONFIG+=release"),
433 QIODevice::Text | QIODevice::ReadWrite);
434 QVERIFY(qmake.waitForStarted(20000));
435 QByteArray read = qmake.readAll();
436 qDebug() << read;
437 QCOMPARE(read, QByteArray("Project PROMPT: Prompteroo? "));
438 qmake.write("promptetiprompt\n");
439 QVERIFY(qmake.waitForFinished(20000));
440#endif
441}
442
443void tst_qmake::one_space()
444{
445 QString workDir = base_path + "/testdata/one_space";
446
447 QVERIFY( test_compiler.qmake( workDir, "one_space" ));
448 QVERIFY( test_compiler.make( workDir ));
449 QVERIFY( test_compiler.exists( workDir, "one space", Exe, "1.0.0" ));
450 QVERIFY( test_compiler.makeClean( workDir ));
451 QVERIFY( test_compiler.exists( workDir, "one space", Exe, "1.0.0" )); // Should still exist after a make clean
452 QVERIFY( test_compiler.makeDistClean( workDir ));
453 QVERIFY( !test_compiler.exists( workDir, "one space", Exe, "1.0.0" )); // Should not exist after a make distclean
454 QVERIFY( test_compiler.removeMakefile( workDir ) );
455}
456
457void tst_qmake::findMocs()
458{
459 QString workDir = base_path + "/testdata/findMocs";
460
461 QVERIFY( test_compiler.qmake(workDir, "findMocs") );
462 QVERIFY( test_compiler.make(workDir) );
463 QVERIFY( test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
464 QVERIFY( test_compiler.makeClean(workDir) );
465 QVERIFY( test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
466 QVERIFY( test_compiler.makeDistClean(workDir ) );
467 QVERIFY( !test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
468 QVERIFY( test_compiler.removeMakefile(workDir) );
469}
470
471void tst_qmake::findDeps()
472{
473 QString workDir = base_path + "/testdata/findDeps";
474
475 QVERIFY( test_compiler.qmake(workDir, "findDeps") );
476 QVERIFY( test_compiler.make(workDir) );
477 QVERIFY( test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
478 QVERIFY( test_compiler.makeClean(workDir) );
479 QVERIFY( test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
480 QVERIFY( test_compiler.makeDistClean(workDir ) );
481 QVERIFY( !test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
482 QVERIFY( test_compiler.removeMakefile(workDir) );
483}
484
485void tst_qmake::rawString()
486{
487#ifdef Q_COMPILER_RAW_STRINGS
488 QString workDir = base_path + "/testdata/rawString";
489
490 QVERIFY( test_compiler.qmake(workDir, "rawString") );
491 QVERIFY( test_compiler.make(workDir) );
492 QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
493 QVERIFY( test_compiler.makeClean(workDir) );
494 QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
495 QVERIFY( test_compiler.makeDistClean(workDir ) );
496 QVERIFY( !test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
497 QVERIFY( test_compiler.removeMakefile(workDir) );
498#else
499 QSKIP("Test for C++11 raw strings depends on compiler support for them");
500#endif
501}
502
503struct TempFile
504 : QFile
505{
506 TempFile(QString filename)
507 : QFile(filename)
508 {
509 }
510
511 ~TempFile()
512 {
513 if (this->exists())
514 this->remove();
515 }
516};
517
518#if defined(Q_OS_DARWIN)
519
520void tst_qmake::bundle_spaces()
521{
522 QString workDir = base_path + "/testdata/bundle-spaces";
523
524 // We set up alternate arguments here, to make sure we're testing Mac
525 // Bundles and since this might be the wrong output we rely on dry-running
526 // make (-n).
527
528 test_compiler.setArguments(QStringList() << "-n",
529 QStringList() << "-spec" << "macx-clang");
530
531 QVERIFY( test_compiler.qmake(workDir, "bundle-spaces") );
532
533 TempFile non_existing_file(workDir + "/non-existing file");
534 QVERIFY( !non_existing_file.exists() );
535
536 // Make fails: no rule to make "non-existing file"
537 QVERIFY( test_compiler.make(workDir, QString(), true) );
538
539 QVERIFY( non_existing_file.open(QIODevice::WriteOnly) );
540 QVERIFY( non_existing_file.exists() );
541
542 // Aha!
543 QVERIFY( test_compiler.make(workDir) );
544
545 // Cleanup
546 QVERIFY( non_existing_file.remove() );
547 QVERIFY( !non_existing_file.exists() );
548 QVERIFY( test_compiler.removeMakefile(workDir) );
549}
550
551#elif defined(Q_OS_WIN) // defined(Q_OS_DARWIN)
552
553void tst_qmake::windowsResources()
554{
555 QString workDir = base_path + "/testdata/windows_resources";
556 QVERIFY(test_compiler.qmake(workDir, "windows_resources"));
557 QVERIFY(test_compiler.make(workDir));
558
559 // Another "make" must not rebuild the .res file
560 test_compiler.clearCommandOutput();
561 QVERIFY(test_compiler.make(workDir));
562 QVERIFY(!test_compiler.commandOutput().contains("windows_resources.rc"));
563 test_compiler.clearCommandOutput();
564
565 // Wait a second to make sure we get a new timestamp in the touch below
566 QTest::qWait(1000);
567
568 // Touch the deepest include of the .rc file
569 QVERIFY(test_compiler.runCommand("cmd", QStringList{"/c",
570 "echo.>>" + QDir::toNativeSeparators(workDir + "/version.inc")}));
571
572 // The next "make" must rebuild the .res file
573 QVERIFY(test_compiler.make(workDir));
574 QVERIFY(test_compiler.commandOutput().contains("windows_resources.rc"));
575}
576
577#endif // defined(Q_OS_WIN)
578
579void tst_qmake::substitutes()
580{
581 QString workDir = base_path + "/testdata/substitutes";
582 QVERIFY( test_compiler.qmake( workDir, "test" ));
583 QVERIFY( test_compiler.exists( workDir, "test", Plain, "" ));
584 QVERIFY( test_compiler.exists( workDir, "sub/test2", Plain, "" ));
585 QVERIFY( test_compiler.exists( workDir, "sub/indirect_test.txt", Plain, "" ));
586 QVERIFY( test_compiler.makeDistClean( workDir ));
587
588 QString buildDir = base_path + "/testdata/substitutes_build";
589 QVERIFY( test_compiler.qmake( workDir, "test", buildDir ));
590 QVERIFY( test_compiler.exists( buildDir, "test", Plain, "" ));
591 QVERIFY( test_compiler.exists( buildDir, "sub/test2", Plain, "" ));
592 QVERIFY( test_compiler.exists( buildDir, "sub/indirect_test.txt", Plain, "" ));
593
594 QFile copySource(workDir + "/copy.txt");
595 QFile copyDestination(buildDir + "/copy_test.txt");
596
597 QVERIFY(copySource.open(QFile::ReadOnly));
598 QVERIFY(copyDestination.open(QFile::ReadOnly));
599 QCOMPARE(copySource.readAll(), copyDestination.readAll());
600
601 QVERIFY( test_compiler.makeDistClean( buildDir ));
602}
603
604void tst_qmake::project()
605{
606 QString workDir = base_path + "/testdata/project";
607
608 QVERIFY( test_compiler.qmakeProject( workDir, "project" ));
609 QVERIFY( test_compiler.exists( workDir, "project.pro", Plain, "" ));
610 QVERIFY( test_compiler.qmake( workDir, "project" ));
611 QVERIFY( test_compiler.exists( workDir, "Makefile", Plain, "" ));
612 QVERIFY( test_compiler.make( workDir ));
613 QVERIFY( test_compiler.exists( workDir, "project", Exe, "" ));
614 QVERIFY( test_compiler.makeDistClean( workDir ));
615 QVERIFY( test_compiler.removeProject( workDir, "project" ));
616}
617
618void tst_qmake::proFileCache()
619{
620 QString workDir = base_path + "/testdata/pro_file_cache";
621 QVERIFY( test_compiler.qmake( workDir, "pro_file_cache" ));
622}
623
624void tst_qmake::qinstall()
625{
626 const QString testName = "qinstall";
627 QDir testDataDir = base_path + "/testdata";
628 if (testDataDir.exists(name: testName))
629 testDataDir.rmdir(dirName: testName);
630 QVERIFY(testDataDir.mkdir(testName));
631 const QString workDir = testDataDir.filePath(fileName: testName);
632 auto qinstall = [&](const QString &src, const QString &dst, bool executable = false) {
633 QStringList args = {"-install", "qinstall"};
634 if (executable)
635 args << "-exe";
636 args << src << dst;
637 return test_compiler.qmake(workDir, arguments: args);
638 };
639 const QFileDevice::Permissions readFlags
640 = QFileDevice::ReadOwner | QFileDevice::ReadUser
641 | QFileDevice::ReadGroup | QFileDevice::ReadOther;
642 const QFileDevice::Permissions writeFlags
643 = QFileDevice::WriteOwner | QFileDevice::WriteUser
644 | QFileDevice::WriteGroup | QFileDevice::WriteOther;
645 const QFileDevice::Permissions exeFlags
646 = QFileDevice::ExeOwner | QFileDevice::ExeUser
647 | QFileDevice::ExeGroup | QFileDevice::ExeOther;
648
649 // install a regular file
650 {
651 QFileInfo src(testDataDir.filePath(fileName: "project/main.cpp"));
652 QFileInfo dst("foo.cpp");
653 QVERIFY(qinstall(src.filePath(), dst.filePath()));
654 QVERIFY(dst.exists());
655 QCOMPARE(src.size(), dst.size());
656 QVERIFY(dst.permissions() & readFlags);
657 QVERIFY(dst.permissions() & writeFlags);
658 QVERIFY(!(dst.permissions() & exeFlags));
659 test_compiler.clearCommandOutput();
660 }
661
662 // install an executable file
663 {
664 const QString mocFilePath = QLibraryInfo::location(QLibraryInfo::BinariesPath)
665 + "/moc"
666#ifdef Q_OS_WIN
667 + ".exe"
668#endif
669 ;
670 QFileInfo src(mocFilePath);
671 QVERIFY(src.exists());
672 QVERIFY(src.permissions() & exeFlags);
673 QFileInfo dst("copied_" + src.fileName());
674 QVERIFY(qinstall(src.filePath(), dst.filePath(), true));
675 QVERIFY(dst.exists());
676 QCOMPARE(src.size(), dst.size());
677 QVERIFY(dst.permissions() & readFlags);
678 QVERIFY(dst.permissions() & writeFlags);
679 QVERIFY(dst.permissions() & exeFlags);
680 test_compiler.clearCommandOutput();
681 }
682
683 // install a read-only file
684 {
685 QFile srcfile("foo.cpp");
686 QVERIFY(srcfile.setPermissions(srcfile.permissions() & ~writeFlags));
687 QFileInfo src(srcfile);
688 QFileInfo dst("bar.cpp");
689 QVERIFY(qinstall(src.filePath(), dst.filePath()));
690 QVERIFY(dst.exists());
691 QCOMPARE(src.size(), dst.size());
692 QVERIFY(dst.permissions() & readFlags);
693 QVERIFY(dst.permissions() & writeFlags);
694 QVERIFY(!(dst.permissions() & exeFlags));
695 test_compiler.clearCommandOutput();
696 }
697
698 // install a directory
699 {
700 QDir src = testDataDir;
701 src.cd(dirName: "project");
702 QDir dst("narf");
703 QVERIFY(qinstall(src.absolutePath(), dst.absolutePath()));
704 QCOMPARE(src.entryList(QDir::Files, QDir::Name), dst.entryList(QDir::Files, QDir::Name));
705 test_compiler.clearCommandOutput();
706 }
707
708 // install a directory with a read-only file
709 {
710 QDir src("narf");
711 QFile srcfile(src.filePath(fileName: "main.cpp"));
712 QVERIFY(srcfile.setPermissions(srcfile.permissions() & ~writeFlags));
713 QDir dst("zort");
714 QVERIFY(qinstall(src.absolutePath(), dst.absolutePath()));
715 QCOMPARE(src.entryList(QDir::Files, QDir::Name), dst.entryList(QDir::Files, QDir::Name));
716 }
717}
718
719void tst_qmake::resources()
720{
721 QString workDir = base_path + "/testdata/resources";
722 QVERIFY(test_compiler.qmake(workDir, "resources"));
723
724 {
725 QFile qrcFile(workDir + '/' + DIR_INFIX "qmake_pro_file.qrc");
726 QVERIFY2(qrcFile.exists(), qPrintable(qrcFile.fileName()));
727 QVERIFY(qrcFile.open(QFile::ReadOnly));
728 QByteArray qrcXml = qrcFile.readAll();
729 QVERIFY(qrcXml.contains("alias=\"resources.pro\""));
730 QVERIFY(qrcXml.contains("prefix=\"/prefix\""));
731 }
732
733 {
734 QFile qrcFile(workDir + '/' + DIR_INFIX "qmake_subdir.qrc");
735 QVERIFY(qrcFile.exists());
736 QVERIFY(qrcFile.open(QFile::ReadOnly));
737 QByteArray qrcXml = qrcFile.readAll();
738 QVERIFY(qrcXml.contains("alias=\"file.txt\""));
739 }
740
741 {
742 QFile qrcFile(workDir + '/' + DIR_INFIX "qmake_qmake_immediate.qrc");
743 QVERIFY(qrcFile.exists());
744 QVERIFY(qrcFile.open(QFile::ReadOnly));
745 QByteArray qrcXml = qrcFile.readAll();
746 QVERIFY(qrcXml.contains("alias=\"main.cpp\""));
747 }
748
749 QVERIFY(test_compiler.make(workDir));
750}
751
752void tst_qmake::conflictingTargets()
753{
754 QString workDir = base_path + "/testdata/conflicting_targets";
755 QVERIFY(test_compiler.qmake(workDir, "conflicting_targets"));
756 const QRegularExpression rex("Targets of builds '([^']+)' and '([^']+)' conflict");
757 auto match = rex.match(subject: test_compiler.commandOutput());
758 QVERIFY(match.hasMatch());
759 QStringList builds = { match.captured(nth: 1), match.captured(nth: 2) };
760 std::sort(first: builds.begin(), last: builds.end());
761 const QStringList expectedBuilds{"Debug", "Release"};
762 QCOMPARE(builds, expectedBuilds);
763}
764
765QTEST_MAIN(tst_qmake)
766#include "tst_qmake.moc"
767

source code of qtbase/tests/auto/tools/qmake/tst_qmake.cpp