2022-05-10 10:06:48 +00:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2024-02-02 13:36:10 +00:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2020-11-26 16:31:50 +00:00
|
|
|
#include <QTest>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#include "testcompiler.h"
|
|
|
|
|
2019-03-12 08:03:13 +00:00
|
|
|
#include <QDir>
|
|
|
|
#include <QDirIterator>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QObject>
|
2019-07-31 11:53:24 +00:00
|
|
|
#include <QRegularExpression>
|
2012-10-05 08:12:08 +00:00
|
|
|
#include <QStandardPaths>
|
2019-03-12 08:03:13 +00:00
|
|
|
#include <QTemporaryDir>
|
2020-11-26 16:31:50 +00:00
|
|
|
#include <QLibraryInfo>
|
|
|
|
#include <QProcessEnvironment>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
class tst_qmake : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
2019-03-12 08:03:13 +00:00
|
|
|
public:
|
|
|
|
tst_qmake();
|
|
|
|
|
2015-12-03 15:59:30 +00:00
|
|
|
private slots:
|
2011-04-27 10:05:43 +00:00
|
|
|
void initTestCase();
|
2019-03-12 08:03:13 +00:00
|
|
|
void cleanupTestCase();
|
2011-04-27 10:05:43 +00:00
|
|
|
void cleanup();
|
|
|
|
void simple_app();
|
|
|
|
void simple_app_shadowbuild();
|
|
|
|
void simple_app_shadowbuild2();
|
2019-03-12 09:53:35 +00:00
|
|
|
void simple_app_versioned();
|
2011-04-27 10:05:43 +00:00
|
|
|
void simple_lib();
|
|
|
|
void simple_dll();
|
|
|
|
void subdirs();
|
2011-05-12 07:45:55 +00:00
|
|
|
void subdir_via_pro_file_extra_target();
|
2011-04-27 10:05:43 +00:00
|
|
|
void duplicateLibraryEntries();
|
|
|
|
void export_across_file_boundaries();
|
|
|
|
void include_dir();
|
2012-09-06 11:51:37 +00:00
|
|
|
void include_pwd();
|
2011-04-27 10:05:43 +00:00
|
|
|
void install_files();
|
|
|
|
void install_depends();
|
|
|
|
void quotedfilenames();
|
|
|
|
void prompt();
|
|
|
|
void one_space();
|
|
|
|
void findMocs();
|
|
|
|
void findDeps();
|
2015-11-25 10:57:36 +00:00
|
|
|
void rawString();
|
2019-08-02 11:18:46 +00:00
|
|
|
#if defined(Q_OS_DARWIN)
|
2011-04-27 10:05:43 +00:00
|
|
|
void bundle_spaces();
|
Fail builds on Apple platforms with invalid Info.plist
Information property lists (Info.plist) files are part of application
bundles on Apple platforms and contain basic information about the
application, such as the name of the application's executable.
The Info.plist file can have multiple formats, such as binary or XML.
Makefiles generated by qmake convert Info.plist files to XML by default,
so that variables in the Info.plist can be substituted with values
defined by qmake, such as the name of the application's executable. This
is important if users use external tools such as Xcode for modifying the
Info.plist file, which may save it in binary format. To convert the
formats, the plutil tool shipped with macOS (or the Xcode command-line
tools) is used. The Unix tool sed is then used to actually substitute
variables.
If the Info.plist file is invalid, e.g., due to an invalid tag name, the
plutil invocation fails. However, the converted plist is piped into sed
for variable substitution. The plutil command will simply write an error
message to standard out and return with a non-zero exit code. Due to the
pipe chain, make will not fail and the error message will end up in the
Info.plist in the built application bundle. The application bundle is
then invalid as well, as vital information such as the name of the
executable of the application is missing.
The change ensures that the pipe chain fails, if plutil exits with a
non-zero exit code.
The issue was introduced with my solution for QTBUG-45357. Beforehand,
Info.plists and mistakes therein were simply copied into the application
bundle.
[ChangeLog][qmake] Fail builds on Apple platforms if the Info.plist is
invalid instead of generating corrupt application bundles.
Pick-to: 6.5 6.9 6.10
Change-Id: Ibdb2a18e9bbf35a654af8534aa61188f8389c55a
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2025-06-26 15:37:27 +00:00
|
|
|
void invalid_info_plist();
|
2019-08-02 11:18:46 +00:00
|
|
|
#elif defined(Q_OS_WIN)
|
|
|
|
void windowsResources();
|
2011-04-27 10:05:43 +00:00
|
|
|
#endif
|
|
|
|
void substitutes();
|
2012-08-10 15:21:30 +00:00
|
|
|
void project();
|
2012-10-25 08:55:00 +00:00
|
|
|
void proFileCache();
|
2019-08-06 07:53:54 +00:00
|
|
|
void qinstall();
|
2015-04-17 13:08:21 +00:00
|
|
|
void resources();
|
2019-07-31 11:53:24 +00:00
|
|
|
void conflictingTargets();
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
TestCompiler test_compiler;
|
2019-03-12 08:03:13 +00:00
|
|
|
QTemporaryDir tempWorkDir;
|
2011-04-27 10:05:43 +00:00
|
|
|
QString base_path;
|
2019-03-12 08:03:13 +00:00
|
|
|
const QString origCurrentDirPath;
|
2011-04-27 10:05:43 +00:00
|
|
|
};
|
|
|
|
|
2019-03-12 08:03:13 +00:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:34:50 +00:00
|
|
|
void tst_qmake::initTestCase()
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2024-06-16 12:51:03 +00:00
|
|
|
#if defined(Q_OS_APPLE)
|
|
|
|
if (QProcess::execute("xcode-select", { "-p" }) != 0)
|
|
|
|
QSKIP("Xcode or Xcode command line tools not installed");
|
|
|
|
#endif
|
|
|
|
|
2019-03-12 08:03:13 +00:00
|
|
|
QVERIFY2(tempWorkDir.isValid(), qPrintable(tempWorkDir.errorString()));
|
2020-09-04 07:45:26 +00:00
|
|
|
QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
|
2012-08-13 13:42:01 +00:00
|
|
|
QString cmd = QString("%1/qmake").arg(binpath);
|
2020-10-23 13:41:13 +00:00
|
|
|
|
|
|
|
// If Qt is cross-compiled with CMake, we might also cross-compile qmake for the device.
|
|
|
|
// In this case we don't want to use the cross-compiled qmake, but rather the host qmake
|
|
|
|
// shell wrapper (if it's available).
|
|
|
|
const QString hostQmake = QString("%1/host-qmake").arg(binpath);
|
|
|
|
if (QFile::exists(hostQmake)) {
|
|
|
|
cmd = hostQmake;
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#ifdef Q_CC_MSVC
|
2012-10-05 08:12:08 +00:00
|
|
|
const QString jom = QStandardPaths::findExecutable(QLatin1String("jom.exe"));
|
|
|
|
if (jom.isEmpty()) {
|
|
|
|
test_compiler.setBaseCommands( QLatin1String("nmake"), cmd );
|
|
|
|
} else {
|
|
|
|
test_compiler.setBaseCommands( jom, cmd );
|
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
#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
|
2019-03-12 08:03:13 +00:00
|
|
|
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.");
|
Port from container.count()/length() to size()
This is semantic patch using ClangTidyTransformator:
auto QtContainerClass = expr(hasType(namedDecl(hasAnyName(<classes>)))).bind(o)
makeRule(cxxMemberCallExpr(on(QtContainerClass),
callee(cxxMethodDecl(hasAnyName({"count", "length"),
parameterCountIs(0))))),
changeTo(cat(access(o, cat("size"), "()"))),
cat("use 'size()' instead of 'count()/length()'"))
a.k.a qt-port-to-std-compatible-api with config Scope: 'Container'.
<classes> are:
// sequential:
"QByteArray",
"QList",
"QQueue",
"QStack",
"QString",
"QVarLengthArray",
"QVector",
// associative:
"QHash",
"QMultiHash",
"QMap",
"QMultiMap",
"QSet",
// Qt has no QMultiSet
Change-Id: Ibe8837be96e8d30d1846881ecd65180c1bc459af
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2022-09-30 12:09:04 +00:00
|
|
|
testDataPath.chop(subProgram.size() - testDataSubDir.size());
|
2019-03-12 08:03:13 +00:00
|
|
|
|
|
|
|
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);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_qmake::cleanup()
|
|
|
|
{
|
2012-02-23 14:35:04 +00:00
|
|
|
test_compiler.resetArguments();
|
2012-02-23 14:39:23 +00:00
|
|
|
test_compiler.resetEnvironment();
|
2011-04-27 10:05:43 +00:00
|
|
|
test_compiler.clearCommandOutput();
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_qmake::simple_app()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/simple_app";
|
2014-11-18 13:57:21 +00:00
|
|
|
QString destDir = workDir + "/dest dir";
|
2019-03-12 09:53:35 +00:00
|
|
|
QString installDir = workDir + "/dist";
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2019-03-12 09:53:35 +00:00
|
|
|
QVERIFY( test_compiler.qmake( workDir, "simple_app", QString() ));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.make( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
|
2019-03-12 09:53:35 +00:00
|
|
|
|
|
|
|
QVERIFY(test_compiler.make(workDir, "install"));
|
|
|
|
QVERIFY(test_compiler.exists(installDir, "simple app", Exe, "1.0.0"));
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
|
2011-04-27 10:05:43 +00:00
|
|
|
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";
|
2014-11-18 13:57:21 +00:00
|
|
|
QString destDir = buildDir + "/dest dir";
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
|
|
|
|
QVERIFY( test_compiler.make( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
|
2011-04-27 10:05:43 +00:00
|
|
|
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";
|
2014-11-18 13:57:21 +00:00
|
|
|
QString destDir = buildDir + "/dest dir";
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QVERIFY( test_compiler.qmake( workDir, "simple_app", buildDir ));
|
|
|
|
QVERIFY( test_compiler.make( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" ));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should still exist after a make clean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( buildDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( !test_compiler.exists( destDir, "simple app", Exe, "1.0.0" )); // Should not exist after a make distclean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.removeMakefile( buildDir ) );
|
|
|
|
}
|
|
|
|
|
2019-03-12 09:53:35 +00:00
|
|
|
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));
|
2019-03-12 10:59:58 +00:00
|
|
|
if (checkPdb)
|
2019-03-12 09:53:35 +00:00
|
|
|
QVERIFY(!QFile::exists(pdbFilePath));
|
|
|
|
QVERIFY(test_compiler.removeMakefile(buildDir));
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
void tst_qmake::simple_dll()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/simple_dll";
|
2014-11-18 13:57:21 +00:00
|
|
|
QString destDir = workDir + "/dest dir";
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QDir D;
|
|
|
|
D.remove( workDir + "/Makefile");
|
|
|
|
QVERIFY( test_compiler.qmake( workDir, "simple_dll" ));
|
|
|
|
QVERIFY( test_compiler.make( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" ));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should still exist after a make clean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( !test_compiler.exists( destDir, "simple dll", Dll, "1.0.0" )); // Should not exist after a make distclean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.removeMakefile( workDir ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_qmake::simple_lib()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/simple_lib";
|
2014-11-18 13:57:21 +00:00
|
|
|
QString destDir = workDir + "/dest dir";
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QDir D;
|
|
|
|
D.remove( workDir + "/Makefile");
|
|
|
|
QVERIFY( test_compiler.qmake( workDir, "simple_lib" ));
|
|
|
|
QVERIFY( test_compiler.make( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" ));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should still exist after a make clean
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( workDir ));
|
2014-11-18 13:57:21 +00:00
|
|
|
QVERIFY( !test_compiler.exists( destDir, "simple lib", Lib, "1.0.0" )); // Should not exist after a make distclean
|
2011-04-27 10:05:43 +00:00
|
|
|
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 ));
|
2019-03-12 08:03:13 +00:00
|
|
|
QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
|
|
|
|
QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeClean( workDir ));
|
|
|
|
// Should still exist after a make clean
|
2019-03-12 08:03:13 +00:00
|
|
|
QVERIFY( test_compiler.exists(workDir + "/simple_app/dest dir", "simple app", Exe));
|
|
|
|
QVERIFY( test_compiler.exists(workDir + "/simple_dll/dest dir", "simple dll", Dll));
|
2011-04-27 10:05:43 +00:00
|
|
|
// 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 ) );
|
|
|
|
}
|
|
|
|
|
2011-05-12 07:45:55 +00:00
|
|
|
void tst_qmake::subdir_via_pro_file_extra_target()
|
|
|
|
{
|
2020-01-13 12:56:04 +00:00
|
|
|
if (QProcessEnvironment::systemEnvironment().contains(QStringLiteral("QT_TEST_RUNNING_IN_CTEST")))
|
|
|
|
QSKIP("This test does not run properly when invoked from CTest.");
|
|
|
|
|
2011-05-12 07:45:55 +00:00
|
|
|
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" ));
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
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()
|
|
|
|
{
|
2013-06-21 19:53:03 +00:00
|
|
|
#ifdef QT_NO_WIDGETS
|
|
|
|
QSKIP("This test depends on QtWidgets");
|
|
|
|
#else
|
2011-04-27 10:05:43 +00:00
|
|
|
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 ));
|
2013-06-21 19:53:03 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2012-09-06 11:51:37 +00:00
|
|
|
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 ));
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
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" ));
|
2017-02-24 15:22:53 +00:00
|
|
|
QCOMPARE(QFileInfo(workDir + "/test.txt").lastModified(), QFileInfo(workDir + "/dist/test.txt").lastModified());
|
2011-04-27 10:05:43 +00:00
|
|
|
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;
|
2019-06-27 13:48:30 +00:00
|
|
|
qmake.setProcessChannelMode(QProcess::MergedChannels);
|
2011-04-27 10:05:43 +00:00
|
|
|
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) );
|
|
|
|
}
|
|
|
|
|
2015-11-25 10:57:36 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
struct TempFile
|
|
|
|
: QFile
|
|
|
|
{
|
|
|
|
TempFile(QString filename)
|
|
|
|
: QFile(filename)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~TempFile()
|
|
|
|
{
|
|
|
|
if (this->exists())
|
|
|
|
this->remove();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-08-02 11:18:46 +00:00
|
|
|
#if defined(Q_OS_DARWIN)
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
void tst_qmake::bundle_spaces()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/bundle-spaces";
|
|
|
|
|
2012-02-23 14:35:04 +00:00
|
|
|
// We set up alternate arguments here, to make sure we're testing Mac
|
2011-04-27 10:05:43 +00:00
|
|
|
// Bundles and since this might be the wrong output we rely on dry-running
|
|
|
|
// make (-n).
|
|
|
|
|
2014-11-27 13:12:52 +00:00
|
|
|
test_compiler.setArguments(QStringList() << "-n",
|
|
|
|
QStringList() << "-spec" << "macx-clang");
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-02-23 14:35:04 +00:00
|
|
|
QVERIFY( test_compiler.qmake(workDir, "bundle-spaces") );
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
TempFile non_existing_file(workDir + "/non-existing file");
|
|
|
|
QVERIFY( !non_existing_file.exists() );
|
|
|
|
|
|
|
|
// Make fails: no rule to make "non-existing file"
|
2012-02-23 14:38:30 +00:00
|
|
|
QVERIFY( test_compiler.make(workDir, QString(), true) );
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QVERIFY( non_existing_file.open(QIODevice::WriteOnly) );
|
|
|
|
QVERIFY( non_existing_file.exists() );
|
|
|
|
|
|
|
|
// Aha!
|
2012-02-23 14:35:04 +00:00
|
|
|
QVERIFY( test_compiler.make(workDir) );
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
QVERIFY( non_existing_file.remove() );
|
|
|
|
QVERIFY( !non_existing_file.exists() );
|
2012-02-23 14:35:04 +00:00
|
|
|
QVERIFY( test_compiler.removeMakefile(workDir) );
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
Fail builds on Apple platforms with invalid Info.plist
Information property lists (Info.plist) files are part of application
bundles on Apple platforms and contain basic information about the
application, such as the name of the application's executable.
The Info.plist file can have multiple formats, such as binary or XML.
Makefiles generated by qmake convert Info.plist files to XML by default,
so that variables in the Info.plist can be substituted with values
defined by qmake, such as the name of the application's executable. This
is important if users use external tools such as Xcode for modifying the
Info.plist file, which may save it in binary format. To convert the
formats, the plutil tool shipped with macOS (or the Xcode command-line
tools) is used. The Unix tool sed is then used to actually substitute
variables.
If the Info.plist file is invalid, e.g., due to an invalid tag name, the
plutil invocation fails. However, the converted plist is piped into sed
for variable substitution. The plutil command will simply write an error
message to standard out and return with a non-zero exit code. Due to the
pipe chain, make will not fail and the error message will end up in the
Info.plist in the built application bundle. The application bundle is
then invalid as well, as vital information such as the name of the
executable of the application is missing.
The change ensures that the pipe chain fails, if plutil exits with a
non-zero exit code.
The issue was introduced with my solution for QTBUG-45357. Beforehand,
Info.plists and mistakes therein were simply copied into the application
bundle.
[ChangeLog][qmake] Fail builds on Apple platforms if the Info.plist is
invalid instead of generating corrupt application bundles.
Pick-to: 6.5 6.9 6.10
Change-Id: Ibdb2a18e9bbf35a654af8534aa61188f8389c55a
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2025-06-26 15:37:27 +00:00
|
|
|
|
|
|
|
void tst_qmake::invalid_info_plist()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/invalid-info-plist";
|
|
|
|
|
|
|
|
// We set up alternate arguments here, to make sure we're testing Mac
|
|
|
|
// Bundles. We need to actually run make to check whether the failing
|
|
|
|
// plutil invocation breaks the build.
|
|
|
|
|
|
|
|
test_compiler.setArguments(QStringList(),
|
|
|
|
QStringList() << "-spec" << "macx-clang");
|
|
|
|
|
|
|
|
QVERIFY( test_compiler.qmake(workDir, "invalid-info-plist") );
|
|
|
|
|
|
|
|
// Make fails: plutil fails to parse the Info.plist file
|
|
|
|
QVERIFY( test_compiler.make(workDir, QString(), true) );
|
|
|
|
}
|
2019-08-02 11:18:46 +00:00
|
|
|
|
|
|
|
#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)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
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, "" ));
|
2012-02-11 09:42:03 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QVERIFY( test_compiler.makeDistClean( buildDir ));
|
|
|
|
}
|
|
|
|
|
2012-08-10 15:21:30 +00:00
|
|
|
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" ));
|
|
|
|
}
|
|
|
|
|
2012-10-25 08:55:00 +00:00
|
|
|
void tst_qmake::proFileCache()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/pro_file_cache";
|
|
|
|
QVERIFY( test_compiler.qmake( workDir, "pro_file_cache" ));
|
|
|
|
}
|
|
|
|
|
2019-08-06 07:53:54 +00:00
|
|
|
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
|
|
|
|
{
|
2021-01-25 10:12:37 +00:00
|
|
|
const QString mocFilePath = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath)
|
2019-08-06 07:53:54 +00:00
|
|
|
+ "/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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-17 13:08:21 +00:00
|
|
|
void tst_qmake::resources()
|
|
|
|
{
|
|
|
|
QString workDir = base_path + "/testdata/resources";
|
|
|
|
QVERIFY(test_compiler.qmake(workDir, "resources"));
|
|
|
|
|
|
|
|
{
|
2020-06-25 18:45:55 +00:00
|
|
|
QFile qrcFile(workDir + '/' + "qmake_pro_file.qrc");
|
2019-03-12 08:03:13 +00:00
|
|
|
QVERIFY2(qrcFile.exists(), qPrintable(qrcFile.fileName()));
|
2015-04-17 13:08:21 +00:00
|
|
|
QVERIFY(qrcFile.open(QFile::ReadOnly));
|
|
|
|
QByteArray qrcXml = qrcFile.readAll();
|
|
|
|
QVERIFY(qrcXml.contains("alias=\"resources.pro\""));
|
|
|
|
QVERIFY(qrcXml.contains("prefix=\"/prefix\""));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-06-25 18:45:55 +00:00
|
|
|
QFile qrcFile(workDir + '/' + "qmake_subdir.qrc");
|
2015-04-17 13:08:21 +00:00
|
|
|
QVERIFY(qrcFile.exists());
|
|
|
|
QVERIFY(qrcFile.open(QFile::ReadOnly));
|
|
|
|
QByteArray qrcXml = qrcFile.readAll();
|
|
|
|
QVERIFY(qrcXml.contains("alias=\"file.txt\""));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-06-25 18:45:55 +00:00
|
|
|
QFile qrcFile(workDir + '/' + "qmake_qmake_immediate.qrc");
|
2015-04-17 13:08:21 +00:00
|
|
|
QVERIFY(qrcFile.exists());
|
|
|
|
QVERIFY(qrcFile.open(QFile::ReadOnly));
|
|
|
|
QByteArray qrcXml = qrcFile.readAll();
|
|
|
|
QVERIFY(qrcXml.contains("alias=\"main.cpp\""));
|
|
|
|
}
|
|
|
|
|
|
|
|
QVERIFY(test_compiler.make(workDir));
|
|
|
|
}
|
|
|
|
|
2019-07-31 11:53:24 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QTEST_MAIN(tst_qmake)
|
|
|
|
#include "tst_qmake.moc"
|