qt5base-lts/tests/auto/tools/qmake/tst_qmake.cpp
Joerg Bornemann af61b5ca5c CMake: Fix tst_qmake::resources() on Windows
This test calls qmake on a project that generates a .qrc file. On
Windows, where debug_and_release is on by default, the generated qrc
file ends up in a "debug" or "release" subdirectory. On other
platforms the file is generated directly in the build dir.

To guess the right location, the preprocessor defines RELEASE_BUILD
and DEBUG_BUILD were passed to tst_qmake.cpp by the test's .pro file.
While the mapping from debug_and_release was fine for the .pro file,
it was commented out in the automatically converted CMakeLists.txt.

Instead of trying to fix the condition, we're going the easier route
that's used in all other .pro files of tst_qmake: make sure that
debug_and_release doesn't get in the way. In other tests this is done
by setting
    DESTDIR = ./
which doesn't work for the generated qrc file. That's why we simply do
    CONFIG -= debug_and_release
to make sure that everything is generated directly in the build dir.

Change-Id: I557ac4e21d7b385004d369fae8a3f727d76d4d88
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
2020-06-26 21:24:50 +02:00

762 lines
28 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include "testcompiler.h"
#include <QDir>
#include <QDirIterator>
#include <QObject>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QTemporaryDir>
class tst_qmake : public QObject
{
Q_OBJECT
public:
tst_qmake();
private slots:
void initTestCase();
void cleanupTestCase();
void cleanup();
void simple_app();
void simple_app_shadowbuild();
void simple_app_shadowbuild2();
void simple_app_versioned();
void simple_lib();
void simple_dll();
void subdirs();
void subdir_via_pro_file_extra_target();
void duplicateLibraryEntries();
void export_across_file_boundaries();
void include_dir();
void include_pwd();
void install_files();
void install_depends();
void quotedfilenames();
void prompt();
void one_space();
void findMocs();
void findDeps();
void rawString();
#if defined(Q_OS_DARWIN)
void bundle_spaces();
#elif defined(Q_OS_WIN)
void windowsResources();
#endif
void substitutes();
void project();
void proFileCache();
void qinstall();
void resources();
void conflictingTargets();
private:
TestCompiler test_compiler;
QTemporaryDir tempWorkDir;
QString base_path;
const QString origCurrentDirPath;
};
tst_qmake::tst_qmake()
: tempWorkDir(QDir::tempPath() + "/tst_qmake"),
origCurrentDirPath(QDir::currentPath())
{
}
static void copyDir(const QString &sourceDirPath, const QString &targetDirPath)
{
QDir currentDir;
QDirIterator dit(sourceDirPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
while (dit.hasNext()) {
dit.next();
const QString targetPath = targetDirPath + QLatin1Char('/') + dit.fileName();
currentDir.mkpath(targetPath);
copyDir(dit.filePath(), targetPath);
}
QDirIterator fit(sourceDirPath, QDir::Files | QDir::Hidden);
while (fit.hasNext()) {
fit.next();
const QString targetPath = targetDirPath + QLatin1Char('/') + fit.fileName();
QFile::remove(targetPath); // allowed to fail
QFile src(fit.filePath());
QVERIFY2(src.copy(targetPath), qPrintable(src.errorString()));
}
}
void tst_qmake::initTestCase()
{
QVERIFY2(tempWorkDir.isValid(), qPrintable(tempWorkDir.errorString()));
QString binpath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
QString cmd = QString("%1/qmake").arg(binpath);
#ifdef Q_CC_MSVC
const QString jom = QStandardPaths::findExecutable(QLatin1String("jom.exe"));
if (jom.isEmpty()) {
test_compiler.setBaseCommands( QLatin1String("nmake"), cmd );
} else {
test_compiler.setBaseCommands( jom, cmd );
}
#elif defined(Q_CC_MINGW)
test_compiler.setBaseCommands( "mingw32-make", cmd );
#elif defined(Q_OS_WIN) && defined(Q_CC_GNU)
test_compiler.setBaseCommands( "mmmake", cmd );
#else
test_compiler.setBaseCommands( "make", cmd );
#endif
const QString testDataSubDir = QStringLiteral("testdata");
const QString subProgram = testDataSubDir + QLatin1String("/simple_app/main.cpp");
QString testDataPath = QFINDTESTDATA(subProgram);
if (!testDataPath.endsWith(subProgram))
QFAIL("Cannot find test data directory.");
testDataPath.chop(subProgram.length() - testDataSubDir.length());
QString userWorkDir = qgetenv("TST_QMAKE_BUILD_DIR");
if (userWorkDir.isEmpty()) {
base_path = tempWorkDir.path();
} else {
if (!QFile::exists(userWorkDir)) {
QFAIL(qUtf8Printable(QStringLiteral("TST_QMAKE_BUILD_DIR %1 does not exist.")
.arg(userWorkDir)));
}
base_path = userWorkDir;
}
copyDir(testDataPath, base_path + QLatin1Char('/') + testDataSubDir);
}
void tst_qmake::cleanupTestCase()
{
// On Windows, ~QTemporaryDir fails to remove the directory if we're still in there.
QDir::setCurrent(origCurrentDirPath);
}
void tst_qmake::cleanup()
{
test_compiler.resetArguments();
test_compiler.resetEnvironment();
test_compiler.clearCommandOutput();
}
void tst_qmake::simple_app()
{
QString workDir = base_path + "/testdata/simple_app";
QString destDir = workDir + "/dest dir";
QString installDir = workDir + "/dist";
QVERIFY( test_compiler.qmake( workDir, "simple_app", QString() ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
QVERIFY(test_compiler.make(workDir, "install"));
QVERIFY(test_compiler.exists(installDir, "simple app", Exe, "1.0.0"));
QVERIFY( test_compiler.makeClean( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( workDir ) );
}
void tst_qmake::simple_app_shadowbuild()
{
QString workDir = base_path + "/testdata/simple_app";
QString buildDir = base_path + "/testdata/simple_app_build";
QString destDir = buildDir + "/dest dir";
QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
QVERIFY( test_compiler.make( buildDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
QVERIFY( test_compiler.makeClean( buildDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( buildDir ));
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( buildDir ) );
}
void tst_qmake::simple_app_shadowbuild2()
{
QString workDir = base_path + "/testdata/simple_app";
QString buildDir = base_path + "/testdata/simple_app/build";
QString destDir = buildDir + "/dest dir";
QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
QVERIFY( test_compiler.make( buildDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
QVERIFY( test_compiler.makeClean( buildDir ));
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( buildDir ));
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( buildDir ) );
}
void tst_qmake::simple_app_versioned()
{
QString workDir = base_path + "/testdata/simple_app";
QString buildDir = base_path + "/testdata/simple_app_versioned_build";
QString destDir = buildDir + "/dest dir";
QString installDir = buildDir + "/dist";
QString version = "4.5.6";
QVERIFY(test_compiler.qmake(workDir, "simple_app", buildDir, QStringList{ "VERSION=" + version }));
QString qmakeOutput = test_compiler.commandOutput();
QVERIFY(test_compiler.make(buildDir));
QVERIFY(test_compiler.exists(destDir, "simple app", Exe, version));
QString pdbFilePath;
bool checkPdb = qmakeOutput.contains("Project MESSAGE: check for pdb, please");
if (checkPdb) {
QString targetBase = QFileInfo(TestCompiler::targetName(Exe, "simple app", version))
.completeBaseName();
pdbFilePath = destDir + '/' + targetBase + ".pdb";
QVERIFY2(QFile::exists(pdbFilePath), qPrintable(pdbFilePath));
QVERIFY(test_compiler.make(buildDir, "install"));
QString installedPdbFilePath = installDir + '/' + targetBase + ".pdb";
QVERIFY2(QFile::exists(installedPdbFilePath), qPrintable(installedPdbFilePath));
}
QVERIFY(test_compiler.makeClean(buildDir));
QVERIFY(test_compiler.exists(destDir, "simple app", Exe, version));
QVERIFY(test_compiler.makeDistClean(buildDir));
QVERIFY(!test_compiler.exists(destDir, "simple app", Exe, version));
if (checkPdb)
QVERIFY(!QFile::exists(pdbFilePath));
QVERIFY(test_compiler.removeMakefile(buildDir));
}
void tst_qmake::simple_dll()
{
QString workDir = base_path + "/testdata/simple_dll";
QString destDir = workDir + "/dest dir";
QDir D;
D.remove( workDir + "/Makefile");
QVERIFY( test_compiler.qmake( workDir, "simple_dll" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" ));
QVERIFY( test_compiler.makeClean( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( !test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( workDir ) );
}
void tst_qmake::simple_lib()
{
QString workDir = base_path + "/testdata/simple_lib";
QString destDir = workDir + "/dest dir";
QDir D;
D.remove( workDir + "/Makefile");
QVERIFY( test_compiler.qmake( workDir, "simple_lib" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" ));
QVERIFY( test_compiler.makeClean( workDir ));
QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( !test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( workDir ) );
}
void tst_qmake::subdirs()
{
QString workDir = base_path + "/testdata/subdirs";
QDir D;
D.remove( workDir + "/simple_app/Makefile");
D.remove( workDir + "/simple_dll/Makefile");
QVERIFY( test_compiler.qmake( workDir, "subdirs" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
QVERIFY( test_compiler.makeClean( workDir ));
// Should still exist after a make clean
QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
// Since subdirs templates do not have a make dist clean, we should clean up ourselves
// properly
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( test_compiler.removeMakefile( workDir ) );
}
void tst_qmake::subdir_via_pro_file_extra_target()
{
if (QProcessEnvironment::systemEnvironment().contains(QStringLiteral("QT_TEST_RUNNING_IN_CTEST")))
QSKIP("This test does not run properly when invoked from CTest.");
QString workDir = base_path + "/testdata/subdir_via_pro_file_extra_target";
QDir D;
D.remove( workDir + "/Makefile");
D.remove( workDir + "/Makefile.subdir");
D.remove( workDir + "/simple/Makefile");
D.remove( workDir + "/simple/Makefile.subdir");
QVERIFY( test_compiler.qmake( workDir, "subdir_via_pro_file_extra_target" ));
QVERIFY( test_compiler.make( workDir, "extratarget" ));
}
void tst_qmake::duplicateLibraryEntries()
{
QVERIFY(true);
/* TODO: this test does not work as the problem it tests doesn't happen
until after the parsing of the pro-file and thus has to be tested
by parsing the Makefile. This is not doable with the current
testcompiler framework and has as such been put on hold.
QString workDir = base_path + "/testdata/duplicateLibraryEntries";
QVERIFY(test_compiler.qmake(workDir, "duplicateLibraryEntries")); */
}
void tst_qmake::export_across_file_boundaries()
{
// This relies on features so we need to set the QMAKEFEATURES environment variable
test_compiler.addToEnvironment("QMAKEFEATURES=.");
QString workDir = base_path + "/testdata/export_across_file_boundaries";
QVERIFY( test_compiler.qmake( workDir, "foo" ));
}
void tst_qmake::include_dir()
{
#ifdef QT_NO_WIDGETS
QSKIP("This test depends on QtWidgets");
#else
QString workDir = base_path + "/testdata/include_dir";
QVERIFY( test_compiler.qmake( workDir, "foo" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.makeDistClean( workDir ));
QString buildDir = base_path + "/testdata/include_dir_build";
QVERIFY( test_compiler.qmake( workDir, "foo", buildDir ));
QVERIFY( test_compiler.make( buildDir ));
QVERIFY( test_compiler.exists( buildDir, "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.makeDistClean( buildDir ));
#endif
}
void tst_qmake::include_pwd()
{
QString workDir = base_path + "/testdata/include_pwd";
QVERIFY( test_compiler.qmake( workDir, "include_pwd" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.makeDistClean( workDir ));
}
void tst_qmake::install_files()
{
QString workDir = base_path + "/testdata/shadow_files";
QVERIFY( test_compiler.qmake( workDir, "foo" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.make( workDir, "install" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "test.txt", Plain, "1.0.0" ));
QCOMPARE(QFileInfo(workDir + "/test.txt").lastModified(), QFileInfo(workDir + "/dist/test.txt").lastModified());
QVERIFY( test_compiler.make( workDir, "uninstall" ));
QVERIFY( test_compiler.makeDistClean( workDir ));
QString buildDir = base_path + "/testdata/shadow_files_build";
QVERIFY( test_compiler.qmake( workDir, "foo", buildDir ));
QVERIFY( test_compiler.make( buildDir ));
QVERIFY( test_compiler.exists( buildDir, "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.make( buildDir, "install" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "test.txt", Plain, "1.0.0" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "foo.bar", Plain, "1.0.0" ));
QVERIFY( test_compiler.make( buildDir, "uninstall" ));
QVERIFY( test_compiler.makeDistClean( buildDir ));
}
void tst_qmake::install_depends()
{
QString workDir = base_path + "/testdata/install_depends";
QVERIFY( test_compiler.qmake( workDir, "foo" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.make( workDir, "install" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "foo", Exe, "1.0.0" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "test1", Plain, "1.0.0" ));
QVERIFY( test_compiler.exists( workDir + "/dist", "test2", Plain, "1.0.0" ));
QVERIFY( test_compiler.make( workDir, "uninstall" ));
QVERIFY( test_compiler.makeDistClean( workDir ));
}
void tst_qmake::quotedfilenames()
{
QString workDir = base_path + "/testdata/quotedfilenames";
QVERIFY( test_compiler.qmake( workDir, "quotedfilenames" ));
QVERIFY( test_compiler.makeClean( workDir ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "quotedfilenames", Exe, "1.0.0" ));
}
void tst_qmake::prompt()
{
#if 0
QProcess qmake;
qmake.setProcessChannelMode(QProcess::MergedChannels);
qmake.setWorkingDirectory(QLatin1String("testdata/prompt"));
qmake.start(QLatin1String("qmake CONFIG-=debug_and_release CONFIG-=debug CONFIG+=release"),
QIODevice::Text | QIODevice::ReadWrite);
QVERIFY(qmake.waitForStarted(20000));
QByteArray read = qmake.readAll();
qDebug() << read;
QCOMPARE(read, QByteArray("Project PROMPT: Prompteroo? "));
qmake.write("promptetiprompt\n");
QVERIFY(qmake.waitForFinished(20000));
#endif
}
void tst_qmake::one_space()
{
QString workDir = base_path + "/testdata/one_space";
QVERIFY( test_compiler.qmake( workDir, "one_space" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "one space", Exe, "1.0.0" ));
QVERIFY( test_compiler.makeClean( workDir ));
QVERIFY( test_compiler.exists( workDir, "one space", Exe, "1.0.0" )); // Should still exist after a make clean
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( !test_compiler.exists( workDir, "one space", Exe, "1.0.0" )); // Should not exist after a make distclean
QVERIFY( test_compiler.removeMakefile( workDir ) );
}
void tst_qmake::findMocs()
{
QString workDir = base_path + "/testdata/findMocs";
QVERIFY( test_compiler.qmake(workDir, "findMocs") );
QVERIFY( test_compiler.make(workDir) );
QVERIFY( test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeClean(workDir) );
QVERIFY( test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeDistClean(workDir ) );
QVERIFY( !test_compiler.exists(workDir, "findMocs", Exe, "1.0.0" ) );
QVERIFY( test_compiler.removeMakefile(workDir) );
}
void tst_qmake::findDeps()
{
QString workDir = base_path + "/testdata/findDeps";
QVERIFY( test_compiler.qmake(workDir, "findDeps") );
QVERIFY( test_compiler.make(workDir) );
QVERIFY( test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeClean(workDir) );
QVERIFY( test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeDistClean(workDir ) );
QVERIFY( !test_compiler.exists(workDir, "findDeps", Exe, "1.0.0" ) );
QVERIFY( test_compiler.removeMakefile(workDir) );
}
void tst_qmake::rawString()
{
#ifdef Q_COMPILER_RAW_STRINGS
QString workDir = base_path + "/testdata/rawString";
QVERIFY( test_compiler.qmake(workDir, "rawString") );
QVERIFY( test_compiler.make(workDir) );
QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeClean(workDir) );
QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
QVERIFY( test_compiler.makeDistClean(workDir ) );
QVERIFY( !test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) );
QVERIFY( test_compiler.removeMakefile(workDir) );
#else
QSKIP("Test for C++11 raw strings depends on compiler support for them");
#endif
}
struct TempFile
: QFile
{
TempFile(QString filename)
: QFile(filename)
{
}
~TempFile()
{
if (this->exists())
this->remove();
}
};
#if defined(Q_OS_DARWIN)
void tst_qmake::bundle_spaces()
{
QString workDir = base_path + "/testdata/bundle-spaces";
// We set up alternate arguments here, to make sure we're testing Mac
// Bundles and since this might be the wrong output we rely on dry-running
// make (-n).
test_compiler.setArguments(QStringList() << "-n",
QStringList() << "-spec" << "macx-clang");
QVERIFY( test_compiler.qmake(workDir, "bundle-spaces") );
TempFile non_existing_file(workDir + "/non-existing file");
QVERIFY( !non_existing_file.exists() );
// Make fails: no rule to make "non-existing file"
QVERIFY( test_compiler.make(workDir, QString(), true) );
QVERIFY( non_existing_file.open(QIODevice::WriteOnly) );
QVERIFY( non_existing_file.exists() );
// Aha!
QVERIFY( test_compiler.make(workDir) );
// Cleanup
QVERIFY( non_existing_file.remove() );
QVERIFY( !non_existing_file.exists() );
QVERIFY( test_compiler.removeMakefile(workDir) );
}
#elif defined(Q_OS_WIN) // defined(Q_OS_DARWIN)
void tst_qmake::windowsResources()
{
QString workDir = base_path + "/testdata/windows_resources";
QVERIFY(test_compiler.qmake(workDir, "windows_resources"));
QVERIFY(test_compiler.make(workDir));
// Another "make" must not rebuild the .res file
test_compiler.clearCommandOutput();
QVERIFY(test_compiler.make(workDir));
QVERIFY(!test_compiler.commandOutput().contains("windows_resources.rc"));
test_compiler.clearCommandOutput();
// Wait a second to make sure we get a new timestamp in the touch below
QTest::qWait(1000);
// Touch the deepest include of the .rc file
QVERIFY(test_compiler.runCommand("cmd", QStringList{"/c",
"echo.>>" + QDir::toNativeSeparators(workDir + "/version.inc")}));
// The next "make" must rebuild the .res file
QVERIFY(test_compiler.make(workDir));
QVERIFY(test_compiler.commandOutput().contains("windows_resources.rc"));
}
#endif // defined(Q_OS_WIN)
void tst_qmake::substitutes()
{
QString workDir = base_path + "/testdata/substitutes";
QVERIFY( test_compiler.qmake( workDir, "test" ));
QVERIFY( test_compiler.exists( workDir, "test", Plain, "" ));
QVERIFY( test_compiler.exists( workDir, "sub/test2", Plain, "" ));
QVERIFY( test_compiler.exists( workDir, "sub/indirect_test.txt", Plain, "" ));
QVERIFY( test_compiler.makeDistClean( workDir ));
QString buildDir = base_path + "/testdata/substitutes_build";
QVERIFY( test_compiler.qmake( workDir, "test", buildDir ));
QVERIFY( test_compiler.exists( buildDir, "test", Plain, "" ));
QVERIFY( test_compiler.exists( buildDir, "sub/test2", Plain, "" ));
QVERIFY( test_compiler.exists( buildDir, "sub/indirect_test.txt", Plain, "" ));
QFile copySource(workDir + "/copy.txt");
QFile copyDestination(buildDir + "/copy_test.txt");
QVERIFY(copySource.open(QFile::ReadOnly));
QVERIFY(copyDestination.open(QFile::ReadOnly));
QCOMPARE(copySource.readAll(), copyDestination.readAll());
QVERIFY( test_compiler.makeDistClean( buildDir ));
}
void tst_qmake::project()
{
QString workDir = base_path + "/testdata/project";
QVERIFY( test_compiler.qmakeProject( workDir, "project" ));
QVERIFY( test_compiler.exists( workDir, "project.pro", Plain, "" ));
QVERIFY( test_compiler.qmake( workDir, "project" ));
QVERIFY( test_compiler.exists( workDir, "Makefile", Plain, "" ));
QVERIFY( test_compiler.make( workDir ));
QVERIFY( test_compiler.exists( workDir, "project", Exe, "" ));
QVERIFY( test_compiler.makeDistClean( workDir ));
QVERIFY( test_compiler.removeProject( workDir, "project" ));
}
void tst_qmake::proFileCache()
{
QString workDir = base_path + "/testdata/pro_file_cache";
QVERIFY( test_compiler.qmake( workDir, "pro_file_cache" ));
}
void tst_qmake::qinstall()
{
const QString testName = "qinstall";
QDir testDataDir = base_path + "/testdata";
if (testDataDir.exists(testName))
testDataDir.rmdir(testName);
QVERIFY(testDataDir.mkdir(testName));
const QString workDir = testDataDir.filePath(testName);
auto qinstall = [&](const QString &src, const QString &dst, bool executable = false) {
QStringList args = {"-install", "qinstall"};
if (executable)
args << "-exe";
args << src << dst;
return test_compiler.qmake(workDir, args);
};
const QFileDevice::Permissions readFlags
= QFileDevice::ReadOwner | QFileDevice::ReadUser
| QFileDevice::ReadGroup | QFileDevice::ReadOther;
const QFileDevice::Permissions writeFlags
= QFileDevice::WriteOwner | QFileDevice::WriteUser
| QFileDevice::WriteGroup | QFileDevice::WriteOther;
const QFileDevice::Permissions exeFlags
= QFileDevice::ExeOwner | QFileDevice::ExeUser
| QFileDevice::ExeGroup | QFileDevice::ExeOther;
// install a regular file
{
QFileInfo src(testDataDir.filePath("project/main.cpp"));
QFileInfo dst("foo.cpp");
QVERIFY(qinstall(src.filePath(), dst.filePath()));
QVERIFY(dst.exists());
QCOMPARE(src.size(), dst.size());
QVERIFY(dst.permissions() & readFlags);
QVERIFY(dst.permissions() & writeFlags);
QVERIFY(!(dst.permissions() & exeFlags));
test_compiler.clearCommandOutput();
}
// install an executable file
{
const QString mocFilePath = QLibraryInfo::location(QLibraryInfo::BinariesPath)
+ "/moc"
#ifdef Q_OS_WIN
+ ".exe"
#endif
;
QFileInfo src(mocFilePath);
QVERIFY(src.exists());
QVERIFY(src.permissions() & exeFlags);
QFileInfo dst("copied_" + src.fileName());
QVERIFY(qinstall(src.filePath(), dst.filePath(), true));
QVERIFY(dst.exists());
QCOMPARE(src.size(), dst.size());
QVERIFY(dst.permissions() & readFlags);
QVERIFY(dst.permissions() & writeFlags);
QVERIFY(dst.permissions() & exeFlags);
test_compiler.clearCommandOutput();
}
// install a read-only file
{
QFile srcfile("foo.cpp");
QVERIFY(srcfile.setPermissions(srcfile.permissions() & ~writeFlags));
QFileInfo src(srcfile);
QFileInfo dst("bar.cpp");
QVERIFY(qinstall(src.filePath(), dst.filePath()));
QVERIFY(dst.exists());
QCOMPARE(src.size(), dst.size());
QVERIFY(dst.permissions() & readFlags);
QVERIFY(dst.permissions() & writeFlags);
QVERIFY(!(dst.permissions() & exeFlags));
test_compiler.clearCommandOutput();
}
// install a directory
{
QDir src = testDataDir;
src.cd("project");
QDir dst("narf");
QVERIFY(qinstall(src.absolutePath(), dst.absolutePath()));
QCOMPARE(src.entryList(QDir::Files, QDir::Name), dst.entryList(QDir::Files, QDir::Name));
test_compiler.clearCommandOutput();
}
// install a directory with a read-only file
{
QDir src("narf");
QFile srcfile(src.filePath("main.cpp"));
QVERIFY(srcfile.setPermissions(srcfile.permissions() & ~writeFlags));
QDir dst("zort");
QVERIFY(qinstall(src.absolutePath(), dst.absolutePath()));
QCOMPARE(src.entryList(QDir::Files, QDir::Name), dst.entryList(QDir::Files, QDir::Name));
}
}
void tst_qmake::resources()
{
QString workDir = base_path + "/testdata/resources";
QVERIFY(test_compiler.qmake(workDir, "resources"));
{
QFile qrcFile(workDir + '/' + "qmake_pro_file.qrc");
QVERIFY2(qrcFile.exists(), qPrintable(qrcFile.fileName()));
QVERIFY(qrcFile.open(QFile::ReadOnly));
QByteArray qrcXml = qrcFile.readAll();
QVERIFY(qrcXml.contains("alias=\"resources.pro\""));
QVERIFY(qrcXml.contains("prefix=\"/prefix\""));
}
{
QFile qrcFile(workDir + '/' + "qmake_subdir.qrc");
QVERIFY(qrcFile.exists());
QVERIFY(qrcFile.open(QFile::ReadOnly));
QByteArray qrcXml = qrcFile.readAll();
QVERIFY(qrcXml.contains("alias=\"file.txt\""));
}
{
QFile qrcFile(workDir + '/' + "qmake_qmake_immediate.qrc");
QVERIFY(qrcFile.exists());
QVERIFY(qrcFile.open(QFile::ReadOnly));
QByteArray qrcXml = qrcFile.readAll();
QVERIFY(qrcXml.contains("alias=\"main.cpp\""));
}
QVERIFY(test_compiler.make(workDir));
}
void tst_qmake::conflictingTargets()
{
QString workDir = base_path + "/testdata/conflicting_targets";
QVERIFY(test_compiler.qmake(workDir, "conflicting_targets"));
const QRegularExpression rex("Targets of builds '([^']+)' and '([^']+)' conflict");
auto match = rex.match(test_compiler.commandOutput());
QVERIFY(match.hasMatch());
QStringList builds = { match.captured(1), match.captured(2) };
std::sort(builds.begin(), builds.end());
const QStringList expectedBuilds{"Debug", "Release"};
QCOMPARE(builds, expectedBuilds);
}
QTEST_MAIN(tst_qmake)
#include "tst_qmake.moc"