diff options
Diffstat (limited to 'tests')
54 files changed, 1157 insertions, 53 deletions
diff --git a/tests/auto/api/testdata/project-editing/existingfile1.txt b/tests/auto/api/testdata/project-editing/existingfile1.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/existingfile1.txt diff --git a/tests/auto/api/testdata/project-editing/existingfile2.txt b/tests/auto/api/testdata/project-editing/existingfile2.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/existingfile2.txt diff --git a/tests/auto/api/testdata/project-editing/existingfile3.txt b/tests/auto/api/testdata/project-editing/existingfile3.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/existingfile3.txt diff --git a/tests/auto/api/testdata/project-editing/file.cpp b/tests/auto/api/testdata/project-editing/file.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/file.cpp diff --git a/tests/auto/api/testdata/project-editing/file.h b/tests/auto/api/testdata/project-editing/file.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/file.h diff --git a/tests/auto/api/testdata/project-editing/main.cpp b/tests/auto/api/testdata/project-editing/main.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/main.cpp diff --git a/tests/auto/api/testdata/project-editing/newfile1.txt b/tests/auto/api/testdata/project-editing/newfile1.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/newfile1.txt diff --git a/tests/auto/api/testdata/project-editing/newfile2.txt b/tests/auto/api/testdata/project-editing/newfile2.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/newfile2.txt diff --git a/tests/auto/api/testdata/project-editing/newfile3.txt b/tests/auto/api/testdata/project-editing/newfile3.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/newfile3.txt diff --git a/tests/auto/api/testdata/project-editing/newfile4.txt b/tests/auto/api/testdata/project-editing/newfile4.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/newfile4.txt diff --git a/tests/auto/api/testdata/project-editing/project.qbs b/tests/auto/api/testdata/project-editing/project.qbs new file mode 100644 index 000000000..9190f846c --- /dev/null +++ b/tests/auto/api/testdata/project-editing/project.qbs @@ -0,0 +1,31 @@ +import qbs + +CppApplication { + Group { + name: "Existing Group 1" + files: ["existingfile1.txt"] + } + property string aFile: "existingfile2.txt" + Group { + name: "Existing Group 2" + files: product.aFile + } + Group { + name: "Existing Group 3" + files: { + var file = "existingfile3.txt"; + return file; + } + } + Group { + name: "Existing Group 4" + prefix: "subdir/" + files: [] + } + Group { + name: "Existing Group 5" + prefix: "blubb" + files: [] + } + files: "main.cpp" +} diff --git a/tests/auto/api/testdata/project-editing/subdir/file.txt b/tests/auto/api/testdata/project-editing/subdir/file.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/project-editing/subdir/file.txt diff --git a/tests/auto/api/testdata/references/invalid1.qbs b/tests/auto/api/testdata/references/invalid1.qbs new file mode 100644 index 000000000..4bbb26d3a --- /dev/null +++ b/tests/auto/api/testdata/references/invalid1.qbs @@ -0,0 +1,5 @@ +import qbs + +Project { + references: "subdir-with-no-project" +}
\ No newline at end of file diff --git a/tests/auto/api/testdata/references/invalid2.qbs b/tests/auto/api/testdata/references/invalid2.qbs new file mode 100644 index 000000000..1946e2221 --- /dev/null +++ b/tests/auto/api/testdata/references/invalid2.qbs @@ -0,0 +1,5 @@ +import qbs + +Project { + references: "subdir-with-multiple-projects" +}
\ No newline at end of file diff --git a/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject1.qbs b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject1.qbs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject1.qbs diff --git a/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject2.qbs b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject2.qbs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject2.qbs diff --git a/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject3.qbs b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject3.qbs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject3.qbs diff --git a/tests/auto/api/testdata/references/subdir-with-no-project/test.txt b/tests/auto/api/testdata/references/subdir-with-no-project/test.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-no-project/test.txt diff --git a/tests/auto/api/testdata/references/subdir-with-one-project/p.qbs b/tests/auto/api/testdata/references/subdir-with-one-project/p.qbs new file mode 100644 index 000000000..7d453a671 --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-one-project/p.qbs @@ -0,0 +1,3 @@ +import qbs + +Project { } diff --git a/tests/auto/api/testdata/references/subdir-with-one-project/test.txt b/tests/auto/api/testdata/references/subdir-with-one-project/test.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/references/subdir-with-one-project/test.txt diff --git a/tests/auto/api/testdata/references/valid.qbs b/tests/auto/api/testdata/references/valid.qbs new file mode 100644 index 000000000..43d728a4d --- /dev/null +++ b/tests/auto/api/testdata/references/valid.qbs @@ -0,0 +1,5 @@ +import qbs + +Project { + references: "subdir-with-one-project" +} diff --git a/tests/auto/api/testdata/source-file-in-build-dir/file.cpp b/tests/auto/api/testdata/source-file-in-build-dir/file.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/source-file-in-build-dir/file.cpp diff --git a/tests/auto/api/testdata/source-file-in-build-dir/project.qbs b/tests/auto/api/testdata/source-file-in-build-dir/project.qbs new file mode 100644 index 000000000..47ae50a93 --- /dev/null +++ b/tests/auto/api/testdata/source-file-in-build-dir/project.qbs @@ -0,0 +1,5 @@ +import qbs + +CppApplication { + files: "**/*.cpp" +} diff --git a/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/moc_blubb.cpp b/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/moc_blubb.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/moc_blubb.cpp diff --git a/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/qt-debug.bg b/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/qt-debug.bg new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/source-file-in-build-dir/qt-debug/qt-debug.bg diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index c784f6a86..7536f4302 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -29,13 +29,15 @@ #include "tst_api.h" -#include "../../src/app/shared/qbssettings.h" +#include "../../../src/app/shared/qbssettings.h" #include <api/jobs.h> #include <api/project.h> #include <api/projectdata.h> #include <logging/ilogsink.h> +#include <tools/fileinfo.h> #include <tools/hostosinfo.h> +#include <tools/buildoptions.h> #include <tools/installoptions.h> #include <tools/preferences.h> #include <tools/setupprojectparameters.h> @@ -43,7 +45,9 @@ #include <QCoreApplication> #include <QDir> #include <QEventLoop> +#include <QFileInfo> #include <QScopedPointer> +#include <QStringList> #include <QTest> class LogSink: public qbs::ILogSink @@ -54,7 +58,22 @@ class LogSink: public qbs::ILogSink void doPrintMessage(qbs::LoggerLevel, const QString &, const QString &) { } }; -TestApi::TestApi() : m_logSink(new LogSink) +class BuildDescriptionReveiver : public QObject +{ + Q_OBJECT +public: + QString descriptions; + +private slots: + void handleDescription(const QString &, const QString &description) { + descriptions += description; + } +}; + +TestApi::TestApi() + : m_logSink(new LogSink) + , m_sourceDataDir(QDir::cleanPath(SRCDIR "/testdata")) + , m_workingDataDir(QCoreApplication::applicationDirPath() + "/../tests/auto/api/testWorkDir") { } @@ -63,6 +82,14 @@ TestApi::~TestApi() delete m_logSink; } +void TestApi::initTestCase() +{ + QString errorMessage; + qbs::Internal::removeDirectoryWithContents(m_workingDataDir, &errorMessage); + QVERIFY2(qbs::Internal::copyFileRecursion(m_sourceDataDir, + m_workingDataDir, false, &errorMessage), qPrintable(errorMessage)); +} + static void waitForFinished(qbs::AbstractJob *job) { QEventLoop loop; @@ -70,11 +97,240 @@ static void waitForFinished(qbs::AbstractJob *job) loop.exec(); } + +void printProjectData(const qbs::ProjectData &project) +{ + foreach (const qbs::ProductData &p, project.products()) { + qDebug(" Product '%s' at %s", qPrintable(p.name()), qPrintable(p.location().toString())); + foreach (const qbs::GroupData &g, p.groups()) { + qDebug(" Group '%s' at %s", qPrintable(g.name()), qPrintable(g.location().toString())); + qDebug(" Files: %s", qPrintable(g.filePaths().join(QLatin1String(", ")))); + } + } +} + +qbs::GroupData findGroup(const qbs::ProductData &product, const QString &name) +{ + foreach (const qbs::GroupData &g, product.groups()) { + if (g.name() == name) + return g; + } + return qbs::GroupData(); +} + +void TestApi::changeContent() +{ + qbs::SetupProjectParameters setupParams = defaultSetupParameters(); + setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + + "/project-editing/project.qbs")); + QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, + m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + qbs::Project project = job->project(); + qbs::ProjectData projectData = project.projectData(); + QCOMPARE(projectData.allProducts().count(), 1); + qbs::ProductData product = projectData.allProducts().first(); + QCOMPARE(product.groups().count(), 6); + + // Error handling: Invalid product. + qbs::ErrorInfo errorInfo = project.addGroup(qbs::ProductData(), "blubb"); + QVERIFY(errorInfo.hasError()); + QVERIFY(errorInfo.toString().contains("invalid")); + + // Error handling: Empty group name. + errorInfo = project.addGroup(product, QString()); + QVERIFY(errorInfo.hasError()); + QVERIFY(errorInfo.toString().contains("empty")); + + errorInfo = project.addGroup(product, "New Group 1"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + errorInfo = project.addGroup(product, "New Group 2"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Error handling: Group already inserted. + errorInfo = project.addGroup(product, "New Group 1"); + QVERIFY(errorInfo.hasError()); + QVERIFY(errorInfo.toString().contains("already")); + + // Error handling: Add list of files with double entries. + errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "file.cpp" + << "file.cpp"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("more than once"), qPrintable(errorInfo.toString())); + + // Add files to empty array literal. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + QCOMPARE(product.groups().count(), 8); + qbs::GroupData group = findGroup(product, "New Group 1"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "file.h" << "file.cpp"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Error handling: Add the same file again. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + QCOMPARE(product.groups().count(), 8); + group = findGroup(product, "New Group 1"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "file.cpp"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("already"), qPrintable(errorInfo.toString())); + + // Remove one of the newly added files again. + errorInfo = project.removeFiles(product, group, QStringList("file.h")); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Error handling: Try to remove the same file again. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + QCOMPARE(product.groups().count(), 8); + group = findGroup(product, "New Group 1"); + QVERIFY(group.isValid()); + errorInfo = project.removeFiles(product, group, QStringList() << "file.h"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("not known"), qPrintable(errorInfo.toString())); + + // Error handling: Try to remove a file from a complex list. + group = findGroup(product, "Existing Group 2"); + QVERIFY(group.isValid()); + errorInfo = project.removeFiles(product, group, QStringList() << "existingfile2.txt"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); + + // Remove file from product's 'files' binding. + errorInfo = project.removeFiles(product, qbs::GroupData(), QStringList("main.cpp")); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Add file to non-empty array literal. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 1"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Add files to list represented as a single string. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "newfile2.txt"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Add files to list represented as an identifier. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 2"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "newfile3.txt"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Add files to list represented as a block of code (not yet implemented). + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 3"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "newfile4.txt"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); + + // Add file to group with directory prefix. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 4"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "file.txt"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Error handling: Add file to group with non-directory prefix. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 5"); + QVERIFY(group.isValid()); + errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("prefix"), qPrintable(errorInfo.toString())); + + // Remove group. + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + product = projectData.products().first(); + group = findGroup(product, "Existing Group 5"); + QVERIFY(group.isValid()); + errorInfo = project.removeGroup(product, group); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + projectData = project.projectData(); + QVERIFY(projectData.products().count() == 1); + QCOMPARE(projectData.products().first().groups().count(), 7); + + // Error handling: Try to remove the same group again. + errorInfo = project.removeGroup(product, group); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("does not exist"), qPrintable(errorInfo.toString())); + + // Check whether building will take the added and removed cpp files into account. + // This must not be moved below the re-resolving test!!! + qbs::BuildOptions buildOptions; + buildOptions.setDryRun(true); + BuildDescriptionReveiver rcvr; + QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(buildOptions, this)); + connect(buildJob.data(), SIGNAL(reportCommandDescription(QString, QString)), &rcvr, + SLOT(handleDescription(QString,QString))); + waitForFinished(buildJob.data()); + QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); + QVERIFY(rcvr.descriptions.contains("compiling file.cpp")); + QVERIFY(!rcvr.descriptions.contains("compiling main.cpp")); + + // Now check whether the data updates were done correctly. + projectData = project.projectData(); + job.reset(qbs::Project::setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + project = job->project(); + const qbs::ProjectData newProjectData = project.projectData(); + const bool projectDataMatches = newProjectData == projectData; + if (!projectDataMatches) { + qDebug("This is the assumed project:"); + printProjectData(projectData); + qDebug("This is the actual project:"); + printProjectData(newProjectData); + } + QVERIFY(projectDataMatches); // Will fail if e.g. code locations don't match. + + // Now try building again and check if the newly resolved product behaves the same way. + buildJob.reset(project.buildAllProducts(buildOptions, this)); + connect(buildJob.data(), SIGNAL(reportCommandDescription(QString, QString)), &rcvr, + SLOT(handleDescription(QString,QString))); + waitForFinished(buildJob.data()); + QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); + QVERIFY(rcvr.descriptions.contains("compiling file.cpp")); + QVERIFY(!rcvr.descriptions.contains("compiling main.cpp")); + + // Error handling: Try to change the project during a build. + buildJob.reset(project.buildAllProducts(buildOptions, this)); + errorInfo = project.addGroup(newProjectData.products().first(), "blubb"); + QVERIFY(errorInfo.hasError()); + QVERIFY2(errorInfo.toString().contains("in process"), qPrintable(errorInfo.toString())); + waitForFinished(buildJob.data()); + errorInfo = project.addGroup(newProjectData.products().first(), "blubb"); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); +} + void TestApi::disabledInstallGroup() { qbs::SetupProjectParameters setupParams = defaultSetupParameters(); - setupParams.setProjectFilePath(QDir::cleanPath(QLatin1String(SRCDIR "/testdata" - "/disabled_install_group/project.qbs"))); + setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + + "/disabled_install_group/project.qbs")); QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, m_logSink, 0)); waitForFinished(job.data()); @@ -95,8 +351,8 @@ void TestApi::disabledInstallGroup() void TestApi::fileTagsFilterOverride() { qbs::SetupProjectParameters setupParams = defaultSetupParameters(); - setupParams.setProjectFilePath(QDir::cleanPath(QLatin1String(SRCDIR "/testdata" - "/filetagsfilter_override/project.qbs"))); + setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + + "/filetagsfilter_override/project.qbs")); QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, m_logSink, 0)); waitForFinished(job.data()); @@ -180,7 +436,7 @@ void TestApi::nonexistingProjectPropertyFromProduct() { qbs::SetupProjectParameters setupParams = defaultSetupParameters(); const QString projectDir - = QDir::cleanPath(QLatin1String(SRCDIR "/testdata/nonexistingprojectproperties")); + = QDir::cleanPath(m_workingDataDir + "/nonexistingprojectproperties"); const QString topLevelProjectFile = projectDir + QLatin1String("/invalidaccessfromproduct.qbs"); setupParams.setProjectFilePath(topLevelProjectFile); QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, @@ -195,8 +451,7 @@ void TestApi::nonexistingProjectPropertyFromProduct() void TestApi::nonexistingProjectPropertyFromCommandLine() { qbs::SetupProjectParameters setupParams = defaultSetupParameters(); - const QString projectDir - = QDir::cleanPath(QLatin1String(SRCDIR "/testdata/nonexistingprojectproperties")); + const QString projectDir = QDir::cleanPath(m_workingDataDir + "/nonexistingprojectproperties"); const QString topLevelProjectFile = projectDir + QLatin1String("/project.qbs"); setupParams.setProjectFilePath(topLevelProjectFile); QVariantMap projectProperties; @@ -220,14 +475,65 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters() const const QString qbsRootPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/../")); SettingsPtr settings = qbsSettings(); - setupParams.setSearchPaths(qbs::Preferences(settings.data()).searchPaths(qbsRootPath)); - setupParams.setPluginPaths(qbs::Preferences(settings.data()).pluginPaths(qbsRootPath)); + const QString profileName = QLatin1String("qbs_autotests"); + const qbs::Preferences prefs(settings.data(), profileName); + setupParams.setSearchPaths(prefs.searchPaths(qbsRootPath)); + setupParams.setPluginPaths(prefs.pluginPaths(qbsRootPath)); QVariantMap buildConfig; - buildConfig.insert(QLatin1String("qbs.profile"), QLatin1String("qbs_autotests")); + buildConfig.insert(QLatin1String("qbs.profile"), profileName); buildConfig.insert(QLatin1String("qbs.buildVariant"), QLatin1String("debug")); setupParams.setBuildConfiguration(buildConfig); setupParams.expandBuildConfiguration(settings.data()); return setupParams; } +void TestApi::references() +{ + qbs::SetupProjectParameters setupParams = defaultSetupParameters(); + const QString projectDir = QDir::cleanPath(m_workingDataDir + "/references"); + setupParams.setProjectFilePath(projectDir + QLatin1String("/invalid1.qbs")); + QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, + m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY(job->error().hasError()); + QString errorString = job->error().toString(); + QVERIFY2(errorString.contains("does not contain"), qPrintable(errorString)); + + setupParams.setProjectFilePath(projectDir + QLatin1String("/invalid2.qbs")); + job.reset(qbs::Project::setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY(job->error().hasError()); + errorString = job->error().toString(); + QVERIFY2(errorString.contains("contains more than one"), qPrintable(errorString)); + + setupParams.setProjectFilePath(projectDir + QLatin1String("/valid.qbs")); + job.reset(qbs::Project::setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + const qbs::ProjectData topLevelProject = job->project().projectData(); + QCOMPARE(topLevelProject.subProjects().count(), 1); + const QString subProjectFileName + = QFileInfo(topLevelProject.subProjects().first().location().fileName()).fileName(); + QCOMPARE(subProjectFileName, QString("p.qbs")); +} + +void TestApi::sourceFileInBuildDir() +{ + qbs::SetupProjectParameters setupParams = defaultSetupParameters(); + const QString projectDir = QDir::cleanPath(m_workingDataDir + "/source-file-in-build-dir"); + setupParams.setProjectFilePath(projectDir + QLatin1String("/project.qbs")); + QScopedPointer<qbs::SetupProjectJob> job(qbs::Project::setupProject(setupParams, + m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + const qbs::ProjectData projectData = job->project().projectData(); + QCOMPARE(projectData.allProducts().count(), 1); + const qbs::ProductData product = projectData.allProducts().first(); + QCOMPARE(product.groups().count(), 1); + const qbs::GroupData group = product.groups().first(); + QCOMPARE(group.allFilePaths().count(), 1); +} + QTEST_MAIN(TestApi) + +#include "tst_api.moc" diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index f0a7d6aeb..4f2ce62f9 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -32,10 +32,9 @@ #include <QObject> -namespace qbs { -class ILogSink; -class SetupProjectParameters; -} +namespace qbs { class SetupProjectParameters; } + +class LogSink; class TestApi : public QObject { @@ -46,17 +45,24 @@ public: ~TestApi(); private slots: + void initTestCase(); + + void changeContent(); void disabledInstallGroup(); void fileTagsFilterOverride(); void installableFiles(); void listBuildSystemFiles(); void nonexistingProjectPropertyFromProduct(); void nonexistingProjectPropertyFromCommandLine(); + void references(); + void sourceFileInBuildDir(); private: qbs::SetupProjectParameters defaultSetupParameters() const; - qbs::ILogSink * const m_logSink; + LogSink * const m_logSink; + const QString m_sourceDataDir; + const QString m_workingDataDir; }; #endif // Include guard. diff --git a/tests/auto/auto.pri b/tests/auto/auto.pri index 79330e3ad..979efe8ad 100644 --- a/tests/auto/auto.pri +++ b/tests/auto/auto.pri @@ -8,4 +8,4 @@ CONFIG += depend_includepath testcase console CONFIG -= app_bundle target.CONFIG += no_default_install -include(../../src/lib/use.pri) +include(../../src/lib/corelib/use_corelib.pri) diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/after/numbers.l b/tests/auto/blackbox/testdata/dynamicRuleOutputs/after/numbers.l new file mode 100644 index 000000000..b29f8798f --- /dev/null +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/after/numbers.l @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Build Suite. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +/* scanner for integer and float numbers */ + +%option noyywrap + +%{ +/* need this for the call to atof() below */ +#include <math.h> +%} + +DIGIT [0-9] + +%% + +{DIGIT}+ { + printf("integer: %s (%d)\n", yytext, atoi(yytext)); + } + +{DIGIT}+"."{DIGIT}* { + printf("float: %s (%g)\n", yytext, atof(yytext)); + } + +"{"[\^{}}\n]*"}" /* eat up one-line comments */ + +[ \t\n]+ /* eat up whitespace */ + +. printf("Unexpected character: %s\n", yytext); + +%% + +int main(int argc, char **argv) +{ + if (argc > 1) + yyin = fopen(argv[1], "r"); + else + yyin = stdin; + + yylex(); + return 0; +} + diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js new file mode 100644 index 000000000..232e8338f --- /dev/null +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Build Suite. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +// needs import qbs.TextFile + +function readFlexOptions(filePath) +{ + function splitOptions(str) + { + var options = []; + var opt = ""; + var inquote = false; + for (var i = 0; i < str.length; ++i) { + if (str[i] === '"') { + opt += '"'; + inquote = !inquote; + } else if (str[i] === ' ' && !inquote) { + options.push(opt); + opt = ""; + } else { + opt += str[i]; + } + } + if (opt.length) + options.push(opt); + return options; + } + + function unquote(str) + { + var l = str.length; + if (l > 2 && str[0] === '"' && str[l - 1] === '"') + return str.substr(1, l - 2); + return str; + } + + function parseOptionLine(result, str) + { + var options = splitOptions(str); + var re = /^(outfile|header-file)=(.*)$/; + var reres; + for (var k in options) { + re.lastIndex = 0; + reres = re.exec(options[k]); + if (reres === null) + continue; + result[reres[1]] = unquote(reres[2]); + } + } + + var tf = new TextFile(input.fileName); + var line; + var optrex = /^%option\s+(.*$)/; + var res; + var options = {}; + while (!tf.atEof()) { + line = tf.readLine(); + if (line === "%%") + break; + optrex.lastIndex = 0; + res = optrex.exec(line); + if (res === null) + continue; + parseOptionLine(options, res[1]); + } + tf.close(); + return options; +} + diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs new file mode 100644 index 000000000..b822e852e --- /dev/null +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Build Suite. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +import qbs 1.0 +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "flexoptionsreader.js" as FlexOptionsReader + +Project { + Product { + name: "genlexer" + type: "application" + Depends { name: "cpp" } + Group { + files: ["numbers.l"] + fileTags: ["flex"] + } + property bool isFlexAvailable: File.exists("/usr/bin/flex") // ### replace with PathProbe + Rule { + inputs: ["flex"] + outputFileTags: ["c", "hpp"] + outputArtifacts: { + var options = FlexOptionsReader.readFlexOptions(input.fileName); + var sourceFileName = options["outfile"] || "lex.yy.c"; + var headerFileName = options["header-file"]; + var result = [{ + filePath: "GeneratedFiles/" + product.name + "/" + sourceFileName, + fileTags: ["c"] + }]; + if (headerFileName) { + result.push({ + filePath: "GeneratedFiles/" + product.name + "/" + headerFileName, + fileTags: ["hpp"] + }); + } + return result; + } + prepare: { + var cmd; + if (product.isFlexAvailable) { + // flex is available. Let's call it. + cmd = new Command("flex", [input.fileName]); + cmd.workingDirectory = product.buildDirectory + "/GeneratedFiles/" + product.name; + } else { + // No flex available here, generate some C source and header. + cmd = new JavaScriptCommand(); + cmd.sourceFileName = outputs["c"][0].fileName; + cmd.headerFileName = outputs["hpp"] ? outputs["hpp"][0].fileName : ""; + cmd.sourceCode = function() { + var fsrc = new TextFile(sourceFileName, TextFile.WriteOnly); + if (headerFileName) { + fsrc.write("#include \"" + FileInfo.fileName(headerFileName) + + "\"\n\n"); + var fhdr = new TextFile(headerFileName, TextFile.WriteOnly); + fhdr.write("// a rather empty header file\n"); + fhdr.close(); + } + fsrc.write("int main() { return 0; }\n"); + fsrc.close(); + }; + } + cmd.description = "flexing " + FileInfo.fileName(input.fileName); + return cmd; + } + } + } +} + diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/numbers.l b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/numbers.l new file mode 100644 index 000000000..19f503562 --- /dev/null +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/numbers.l @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Build Suite. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +/* scanner for integer and float numbers */ + +%option noyywrap +%option outfile="numberscanner.c" header-file="numberscanner.h" + +%{ +/* need this for the call to atof() below */ +#include <math.h> +%} + +DIGIT [0-9] + +%% + +{DIGIT}+ { + printf("integer: %s (%d)\n", yytext, atoi(yytext)); + } + +{DIGIT}+"."{DIGIT}* { + printf("float: %s (%g)\n", yytext, atof(yytext)); + } + +"{"[\^{}}\n]*"}" /* eat up one-line comments */ + +[ \t\n]+ /* eat up whitespace */ + +. printf("Unexpected character: %s\n", yytext); + +%% + +int main(int argc, char **argv) +{ + if (argc > 1) + yyin = fopen(argv[1], "r"); + else + yyin = stdin; + + yylex(); + return 0; +} + diff --git a/tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs b/tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs new file mode 100644 index 000000000..32f7f7292 --- /dev/null +++ b/tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs @@ -0,0 +1,13 @@ +import qbs + +CppApplication { + condition: qbs.targetOS.contains("darwin") + type: ["application"] + files: ["main.m"] + cpp.frameworks: ["Foundation"] + cpp.infoPlist: { + return { + "QBS": "org.qt-project.qbs.testdata.embedInfoPlist" + }; + } +} diff --git a/tests/auto/blackbox/testdata/embedInfoPlist/main.m b/tests/auto/blackbox/testdata/embedInfoPlist/main.m new file mode 100644 index 000000000..b3f362223 --- /dev/null +++ b/tests/auto/blackbox/testdata/embedInfoPlist/main.m @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +int main() +{ + NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary]; + BOOL success = [[infoPlist objectForKey:@"QBS"] isEqualToString:@"org.qt-project.qbs.testdata.embedInfoPlist"]; + fprintf(success ? stdout : stderr, "%s\n", [[infoPlist description] UTF8String]); + return success ? 0 : 1; +} diff --git a/tests/auto/blackbox/testdata/explicitlyDependsOn/project.qbs b/tests/auto/blackbox/testdata/explicitlyDependsOn/project.qbs index ab98740c6..12ae1bd7e 100644 --- a/tests/auto/blackbox/testdata/explicitlyDependsOn/project.qbs +++ b/tests/auto/blackbox/testdata/explicitlyDependsOn/project.qbs @@ -5,7 +5,7 @@ Product { type: "mytype" files: "dependency.txt" FileTagger { - pattern: "*.txt" + patterns: "*.txt" fileTags: ["txt"] } Transformer { diff --git a/tests/auto/blackbox/testdata/jsextensions/file.qbs b/tests/auto/blackbox/testdata/jsextensions/file.qbs index 123665f60..f6b8ebf79 100644 --- a/tests/auto/blackbox/testdata/jsextensions/file.qbs +++ b/tests/auto/blackbox/testdata/jsextensions/file.qbs @@ -7,6 +7,10 @@ Product { var original = new TextFile("original.txt", TextFile.WriteOnly); original.close(); File.copy("original.txt", "copy.txt"); + var origTimestamp = File.lastModified("original.txt"); + var copyTimestamp = File.lastModified("copy.txt"); + if (origTimestamp > copyTimestamp) + throw new Error("Older file has newer timestamp."); File.remove("original.txt"); var copy = new TextFile("copy.txt", TextFile.WriteOnly); copy.writeLine(File.exists("original.txt")); diff --git a/tests/auto/blackbox/testdata/jsextensions/propertylist.qbs b/tests/auto/blackbox/testdata/jsextensions/propertylist.qbs new file mode 100644 index 000000000..94a1e1b31 --- /dev/null +++ b/tests/auto/blackbox/testdata/jsextensions/propertylist.qbs @@ -0,0 +1,38 @@ +import qbs +import qbs.Process +import qbs.PropertyList +import qbs.TextFile + +Product { + type: { + var obj = { + "Array": ["ListItem1", "ListItem2", "ListItem3"], + "Integer": 1, + "Boolean": true, + "String": "otherString" + }; + + var infoplist = new TextFile("test.xml", TextFile.WriteOnly); + infoplist.write(JSON.stringify(obj)); + infoplist.close(); + + var process = new Process(); + process.exec("plutil", ["-convert", "xml1", "test.xml"]); + process.close(); + + var xmlfile = new TextFile("test.xml", TextFile.ReadOnly); + var propertyList = new PropertyList(); + propertyList.read(xmlfile.readAll()); + xmlfile.close(); + + var jsontextfile = new TextFile("test.json", TextFile.WriteOnly); + jsontextfile.write(propertyList.toJSON()); + jsontextfile.close(); + + process = new Process(); + process.exec("plutil", ["-convert", "json", "test.xml"]); + process.close(); + + return "Pineapple Steve"; + } +} diff --git a/tests/auto/blackbox/testdata/nsis/hello.bat b/tests/auto/blackbox/testdata/nsis/hello.bat new file mode 100755 index 000000000..3af583cd8 --- /dev/null +++ b/tests/auto/blackbox/testdata/nsis/hello.bat @@ -0,0 +1 @@ +echo Hello world! diff --git a/tests/auto/blackbox/testdata/nsis/hello.nsi b/tests/auto/blackbox/testdata/nsis/hello.nsi new file mode 100755 index 000000000..70b73056a --- /dev/null +++ b/tests/auto/blackbox/testdata/nsis/hello.nsi @@ -0,0 +1,19 @@ +SetCompressor zlib + +!ifdef Win64 + Name "Qbs Hello - ${qbs.architecture} (64-bit)" +!else + Name "Qbs Hello - ${qbs.architecture} (32-bit)" +!endif + +OutFile "you-should-not-see-a-file-with-this-name.exe" +InstallDir "$DESKTOP\Qbs Hello" +RequestExecutionLevel user + +Page directory +Page instfiles + +Section "" + SetOutPath "$INSTDIR" + File "${batchFile}" +SectionEnd diff --git a/tests/auto/blackbox/testdata/nsis/hello.qbs b/tests/auto/blackbox/testdata/nsis/hello.qbs new file mode 100755 index 000000000..b7f3da505 --- /dev/null +++ b/tests/auto/blackbox/testdata/nsis/hello.qbs @@ -0,0 +1,10 @@ +import qbs + +NSISSetup { + condition: qbs.targetOS.contains("windows") + name: "Qbs Hello" + targetName: "qbs-hello-" + qbs.architecture + files: ["hello.nsi", "hello.bat"] + nsis.defines: ["batchFile=hello.bat"] + nsis.compressor: "lzma-solid" +} diff --git a/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs index ef14d3f47..e1ab9bddc 100644 --- a/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs +++ b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs @@ -3,7 +3,7 @@ import qbs.File Module { FileTagger { - pattern: "*.in" + patterns: ["*.in"] fileTags: "test-input" } diff --git a/tests/auto/blackbox/testdata/propertyChanges/project.qbs b/tests/auto/blackbox/testdata/propertyChanges/project.qbs index 9bccb5d06..0cba4f630 100644 --- a/tests/auto/blackbox/testdata/propertyChanges/project.qbs +++ b/tests/auto/blackbox/testdata/propertyChanges/project.qbs @@ -3,6 +3,7 @@ import qbs.TextFile Project { property var projectDefines: ["blubb2"] + property string fileContentSuffix: "suffix 1" CppApplication { name: qbs.enableDebugCode ? "product 1.debug" : "product 1.release" cpp.defines: ["blubb1"] @@ -16,7 +17,7 @@ Project { } CppApplication { name: "product 3" - cpp.defines: qbs.getenv("QBS_BLACKBOX_DEFINE") + cpp.defines: qbs.getEnv("QBS_BLACKBOX_DEFINE") files: "source3.cpp" } DynamicLibrary { @@ -27,6 +28,17 @@ Project { Product { name: "generated text file" + property string fileContentPrefix: "prefix 1" + + Transformer { + Artifact { fileName: "nothing" } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { print(product.fileContentPrefix); } + return cmd; + } + } Transformer { Artifact { fileName: "generated.txt" } @@ -37,7 +49,8 @@ Project { cmd.sourceCode = function() { file = new TextFile(output.fileName, TextFile.WriteOnly); file.truncate(); - file.write("contents 1"); + file.write(product.fileContentPrefix + "contents 1" + + project.fileContentSuffix); file.close(); } return cmd; diff --git a/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/narfzort.qbs b/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/narfzort.qbs index 45d4b748d..75bebf74d 100644 --- a/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/narfzort.qbs +++ b/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/narfzort.qbs @@ -5,7 +5,7 @@ import qbs.TextFile Module { property bool buildZort: true FileTagger { - pattern: "*.narf" + patterns: "*.narf" fileTags: ["narf"] } Rule { diff --git a/tests/auto/blackbox/testdata/soft-dependency/main.cpp b/tests/auto/blackbox/testdata/soft-dependency/main.cpp new file mode 100644 index 000000000..5f3248c7f --- /dev/null +++ b/tests/auto/blackbox/testdata/soft-dependency/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + thisShouldNotLink(); +} diff --git a/tests/auto/blackbox/testdata/soft-dependency/project.qbs b/tests/auto/blackbox/testdata/soft-dependency/project.qbs new file mode 100644 index 000000000..bbf37fda8 --- /dev/null +++ b/tests/auto/blackbox/testdata/soft-dependency/project.qbs @@ -0,0 +1,14 @@ +import qbs + +Application { + Depends { + name: "nosuchmodule" + required: false + } + Depends { + name: "cpp" + condition: nosuchmodule.present + } + + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/subprojects/toplevelproject.qbs b/tests/auto/blackbox/testdata/subprojects/toplevelproject.qbs index 84a2a211f..f167ccabc 100644 --- a/tests/auto/blackbox/testdata/subprojects/toplevelproject.qbs +++ b/tests/auto/blackbox/testdata/subprojects/toplevelproject.qbs @@ -2,7 +2,7 @@ import qbs Project { name: "top level project" - references: ["subproject2/subproject2.qbs"] + references: ["subproject2"] Project { condition: true diff --git a/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js b/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js index d5c40cde1..5174f8ce7 100644 --- a/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js +++ b/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js @@ -1,6 +1,6 @@ function fileList() { return []; } -function filesFromEnv(qbs) { return qbs.getenv("QBS_TEST_PULL_IN_FILE_VIA_ENV") ? ["environmentChange.cpp"] : []; } +function filesFromEnv(qbs) { return qbs.getEnv("QBS_TEST_PULL_IN_FILE_VIA_ENV") ? ["environmentChange.cpp"] : []; } function filesFromFs(qbs) { return File.exists(path + "/fileExists.cpp") ? ["fileExists.cpp"] : []; } diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index f6f68d849..08cf15a9b 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -71,7 +71,16 @@ TestBlackbox::TestBlackbox() int TestBlackbox::runQbs(const QbsRunParameters ¶ms) { - QStringList args = params.arguments; + QStringList args; + if (!params.command.isEmpty()) + args << params.command; + if ((QStringList() << QLatin1String("") << QLatin1String("build") << QLatin1String("clean") + << QLatin1String("install") << QLatin1String("resolve") << QLatin1String("run") + << QLatin1String("shell") << QLatin1String("status") << QLatin1String("update-timestamps")) + .contains(params.command)) { + args.append(QStringList(QLatin1String("-d")) << QLatin1String(".")); + } + args << params.arguments; if (params.useProfile) args.append(QLatin1String("profile:") + buildProfileName); QString cmdLine = qbsExecutableFilePath; @@ -273,7 +282,7 @@ void TestBlackbox::build_project_dry_run() QDir::setCurrent(testDataDir + projectSubDir); rmDirR(buildDir); - QCOMPARE(runQbs(QbsRunParameters("-n")), 0); + QCOMPARE(runQbs(QbsRunParameters(QStringList("-n"))), 0); const QStringList &buildDirContents = QDir(buildDir).entryList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); QVERIFY2(buildDirContents.isEmpty(), qPrintable(buildDirContents.join(" "))); @@ -359,7 +368,7 @@ void TestBlackbox::resolve_project_dry_run() QDir::setCurrent(testDataDir + projectSubDir); rmDirR(buildDir); - QCOMPARE(runQbs(QbsRunParameters(QStringList("resolve") << "-n")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("resolve"), QStringList("-n"))), 0); QVERIFY2(!QFile::exists(productFileName), qPrintable(productFileName)); QVERIFY2(!QFile::exists(buildGraphPath), qPrintable(buildGraphPath)); } @@ -408,7 +417,7 @@ void TestBlackbox::clean() QCOMPARE(runQbs(), 0); QVERIFY(QFile(appObjectFilePath).exists()); QVERIFY(QFile(appExeFilePath).exists()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("clean") << "--all-artifacts")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), QStringList("--all-artifacts"))), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(!QFile(depObjectFilePath).exists()); @@ -420,7 +429,8 @@ void TestBlackbox::clean() QCOMPARE(runQbs(), 0); QVERIFY(QFile(appObjectFilePath).exists()); QVERIFY(QFile(appExeFilePath).exists()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("clean") << "--all-artifacts" << "-n")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), + QStringList("--all-artifacts") << "-n")), 0); QVERIFY(QFile(appObjectFilePath).exists()); QVERIFY(QFile(appExeFilePath).exists()); QVERIFY(QFile(depObjectFilePath).exists()); @@ -434,7 +444,8 @@ void TestBlackbox::clean() QVERIFY(QFile(appExeFilePath).exists()); QVERIFY(QFile(depObjectFilePath).exists()); QVERIFY(QFile(depLibFilePath).exists()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("clean") << "--all-artifacts" << "-p" << "dep")), + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), + QStringList("--all-artifacts") << "-p" << "dep")), 0); QVERIFY(QFile(appObjectFilePath).exists()); QVERIFY(QFile(appExeFilePath).exists()); @@ -449,7 +460,8 @@ void TestBlackbox::clean() QVERIFY(QFile(appExeFilePath).exists()); QVERIFY(QFile(depObjectFilePath).exists()); QVERIFY(QFile(depLibFilePath).exists()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("clean") << "--all-artifacts" << "-p" << "app")), + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), + QStringList("--all-artifacts") << "-p" << "app")), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); @@ -545,6 +557,12 @@ void TestBlackbox::renameTargetArtifact() QCOMPARE(m_qbsStdout.count("linking"), 2); } +void TestBlackbox::softDependency() +{ + QDir::setCurrent(testDataDir + "/soft-dependency"); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::subProjects() { QDir::setCurrent(testDataDir + "/subprojects"); @@ -957,7 +975,7 @@ void TestBlackbox::wildcardRenaming() QCOMPARE(runQbs(QbsRunParameters("install")), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/pioniere.txt").exists()); QFile::rename(QDir::currentPath() + "/pioniere.txt", QDir::currentPath() + "/fdj.txt"); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install") << "--remove-first")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--remove-first"))), 0); QVERIFY(!QFileInfo(defaultInstallRoot + "/pioniere.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/fdj.txt").exists()); } @@ -970,7 +988,7 @@ void TestBlackbox::recursiveRenaming() QVERIFY(QFileInfo(defaultInstallRoot + "/dir/subdir/blubb.txt").exists()); waitForNewTimestamp(); QVERIFY(QFile::rename(QDir::currentPath() + "/dir/wasser.txt", QDir::currentPath() + "/dir/wein.txt")); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install") << "--remove-first")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--remove-first"))), 0); QVERIFY(!QFileInfo(defaultInstallRoot + "/dir/wasser.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/wein.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/subdir/blubb.txt").exists()); @@ -1096,7 +1114,7 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("Making output from input")); QFile generatedFile(buildDir + QLatin1String("/generated.txt")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); - QCOMPARE(generatedFile.readAll(), QByteArray("contents 1")); + QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 1suffix 1")); generatedFile.close(); // Incremental build with no changes. @@ -1238,7 +1256,45 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("Making output from input")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); - QCOMPARE(generatedFile.readAll(), QByteArray("contents 2")); + QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 2suffix 1")); + generatedFile.close(); + + // Incremental build, product property used in JavaScript command changed. + waitForNewTimestamp(); + QVERIFY(projectFile.open(QIODevice::ReadWrite)); + contents = projectFile.readAll(); + contents.replace("prefix 1", "prefix 2"); + projectFile.resize(0); + projectFile.write(contents); + projectFile.close(); + QCOMPARE(runQbs(params), 0); + QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); + QVERIFY(m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); + QVERIFY(generatedFile.open(QIODevice::ReadOnly)); + QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 1")); + generatedFile.close(); + + // Incremental build, project property used in JavaScript command changed. + waitForNewTimestamp(); + QVERIFY(projectFile.open(QIODevice::ReadWrite)); + contents = projectFile.readAll(); + contents.replace("suffix 1", "suffix 2"); + projectFile.resize(0); + projectFile.write(contents); + projectFile.close(); + QCOMPARE(runQbs(params), 0); + QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); + QVERIFY(m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); + QVERIFY(generatedFile.open(QIODevice::ReadOnly)); + QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 2")); generatedFile.close(); // Incremental build, prepare script of a rule in a module changed. @@ -1312,6 +1368,59 @@ void TestBlackbox::dynamicLibs() QCOMPARE(runQbs(), 0); } +void TestBlackbox::dynamicRuleOutputs() +{ + SKIP_TEST("QBS-370"); + const QString testDir = testDataDir + "/dynamicRuleOutputs"; + QDir::setCurrent(testDir); + if (QFile::exists("work")) + rmDirR("work"); + QDir().mkdir("work"); + ccp("before", "work"); + QDir::setCurrent(testDir + "/work"); + QCOMPARE(runQbs(), 0); + + const QString appFile = buildDir + "/genlexer" + QTC_HOST_EXE_SUFFIX; + const QString headerFile1 = buildDir + "/GeneratedFiles/genlexer/numberscanner.h"; + const QString sourceFile1 = buildDir + "/GeneratedFiles/genlexer/numberscanner.c"; + const QString sourceFile2 = buildDir + "/GeneratedFiles/genlexer/lex.yy.c"; + + // Check build #1: source and header file name are specified in numbers.l + QVERIFY(QFile::exists(appFile)); + QVERIFY(QFile::exists(headerFile1)); + QVERIFY(QFile::exists(sourceFile1)); + QVERIFY(!QFile::exists(sourceFile2)); + + QDateTime appFileTimeStamp1 = QFileInfo(appFile).lastModified(); + waitForNewTimestamp(); + QFile::remove("numbers.l"); + QFile::copy("../after/numbers.l", "numbers.l"); + touch("numbers.l"); + QCOMPARE(runQbs(), 0); + + // Check build #2: no file names are specified in numbers.l + // flex will default to lex.yy.c without header file. + QDateTime appFileTimeStamp2 = QFileInfo(appFile).lastModified(); + QVERIFY(appFileTimeStamp1 < appFileTimeStamp2); + QVERIFY(!QFile::exists(headerFile1)); + QVERIFY(!QFile::exists(sourceFile1)); + QVERIFY(QFile::exists(sourceFile2)); + + waitForNewTimestamp(); + QFile::remove("numbers.l"); + QFile::copy("../before/numbers.l", "numbers.l"); + touch("numbers.l"); + QCOMPARE(runQbs(), 0); + + // Check build #3: source and header file name are specified in numbers.l + QDateTime appFileTimeStamp3 = QFileInfo(appFile).lastModified(); + QVERIFY(appFileTimeStamp2 < appFileTimeStamp3); + QVERIFY(QFile::exists(appFile)); + QVERIFY(QFile::exists(headerFile1)); + QVERIFY(QFile::exists(sourceFile1)); + QVERIFY(!QFile::exists(sourceFile2)); +} + void TestBlackbox::explicitlyDependsOn() { QDir::setCurrent(testDataDir + "/explicitlyDependsOn"); @@ -1414,6 +1523,23 @@ void TestBlackbox::jsExtensionsProcess() QCOMPARE(lines.at(6).trimmed().constData(), "false"); } +void TestBlackbox::jsExtensionsPropertyList() +{ + if (!HostOsInfo::isOsxHost()) + SKIP_TEST("temporarily only applies on OS X"); + + QDir::setCurrent(testDataDir + "/jsextensions"); + QbsRunParameters params(QStringList() << "-nf" << "propertylist.qbs"); + QCOMPARE(runQbs(params), 0); + QFile file1("test.json"); + QVERIFY(file1.exists()); + QVERIFY(file1.open(QIODevice::ReadOnly)); + QFile file2("test.xml"); + QVERIFY(file2.exists()); + QVERIFY(file2.open(QIODevice::ReadOnly)); + QCOMPARE(file1.readAll(), file2.readAll()); +} + void TestBlackbox::jsExtensionsTextFile() { QDir::setCurrent(testDataDir + "/jsextensions"); @@ -1451,7 +1577,7 @@ void TestBlackbox::properQuoting() { QDir::setCurrent(testDataDir + "/proper quoting"); QCOMPARE(runQbs(), 0); - QbsRunParameters params(QStringList() << "run" << "-qp" << "Hello World"); + QbsRunParameters params(QLatin1String("run"), QStringList() << "-q" << "-p" << "Hello World"); params.expectFailure = true; // Because the exit code is non-zero. QCOMPARE(runQbs(params), 156); const char * const expectedOutput = "whitespaceless\ncontains space\ncontains\ttab\n" @@ -1473,7 +1599,7 @@ void TestBlackbox::installedApp() QVERIFY(QFile::exists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp")))); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install") << "--install-root" + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--install-root") << (testDataDir + "/installed-app"))), 0); QVERIFY(QFile::exists(testDataDir + HostOsInfo::appendExecutableSuffix("/installed-app/usr/bin/installedApp"))); @@ -1482,7 +1608,7 @@ void TestBlackbox::installedApp() QVERIFY(addedFile.open(QIODevice::WriteOnly)); addedFile.close(); QVERIFY(addedFile.exists()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install") << "--remove-first")), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--remove-first"))), 0); QVERIFY(QFile::exists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp")))); QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/src/main.cpp"))); @@ -1497,7 +1623,7 @@ void TestBlackbox::installedApp() projectFile.resize(0); projectFile.write(content); QVERIFY(projectFile.flush()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install"))), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); QVERIFY(QFile::exists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/local/bin/installedApp")))); QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/local/src/main.cpp"))); @@ -1508,7 +1634,7 @@ void TestBlackbox::installedApp() projectFile.resize(0); projectFile.write(content); QVERIFY(projectFile.flush()); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install"))), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); QVERIFY(QFile::exists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/local/custom/installedApp")))); @@ -1518,12 +1644,13 @@ void TestBlackbox::installedApp() projectFile.resize(0); projectFile.write(content); projectFile.close(); - QCOMPARE(runQbs(QbsRunParameters(QStringList("install"))), 0); + QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/local/source/main.cpp"))); rmDirR(buildDir); QbsRunParameters params; - params.arguments << "install" << "--no-build"; + params.command = "install"; + params.arguments << "--no-build"; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("No build graph")); @@ -1531,7 +1658,7 @@ void TestBlackbox::installedApp() void TestBlackbox::toolLookup() { - QbsRunParameters params(QStringList("detect-toolchains") << "--help"); + QbsRunParameters params(QLatin1String("detect-toolchains"), QStringList("--help")); params.useProfile = false; QCOMPARE(runQbs(params), 0); } @@ -1603,4 +1730,60 @@ void TestBlackbox::testAssembly() QCOMPARE((bool)m_qbsStdout.contains("creating libtestc.a"), haveGcc); } +void TestBlackbox::testNsis() +{ + QStringList regKeys; + regKeys << QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS") + << QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS"); + + QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") + .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + + foreach (const QString &key, regKeys) { + QSettings settings(key, QSettings::NativeFormat); + QString str = settings.value(QLatin1String(".")).toString(); + if (!str.isEmpty()) + paths.prepend(str); + } + + bool haveMakeNsis = false; + foreach (const QString &path, paths) { + if (QFile::exists(QDir::fromNativeSeparators(path) + + HostOsInfo::appendExecutableSuffix(QLatin1String("/makensis")))) { + haveMakeNsis = true; + break; + } + } + + if (!haveMakeNsis) { + SKIP_TEST("makensis is not installed"); + return; + } + + SettingsPtr settings = qbsSettings(); + Profile profile(buildProfileName, settings.data()); + bool targetIsWindows = profile.value("qbs.targetOS").toStringList().contains("windows"); + QDir::setCurrent(testDataDir + "/nsis"); + QVERIFY(runQbs() == 0); + QCOMPARE((bool)m_qbsStdout.contains("compiling hello.nsi"), targetIsWindows); + QCOMPARE((bool)m_qbsStdout.contains("SetCompressor ignored due to previous call with the /FINAL switch"), targetIsWindows); + QVERIFY(!QFile::exists(defaultInstallRoot + "/you-should-not-see-a-file-with-this-name.exe")); +} + +void TestBlackbox::testEmbedInfoPlist() +{ + if (!HostOsInfo::isOsxHost()) + SKIP_TEST("only applies on OS X"); + + QDir::setCurrent(testDataDir + QLatin1String("/embedInfoPlist")); + + QbsRunParameters params; + params.command = QLatin1String("run"); + QCOMPARE(runQbs(params), 0); + + params.arguments = QStringList(QLatin1String("cpp.embedInfoPlist:false")); + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); +} + QTEST_MAIN(TestBlackbox) diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index ab789374a..79b03e21d 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -45,12 +45,14 @@ public: init(); } - QbsRunParameters(const QStringList &args) : arguments(args) + QbsRunParameters(const QString &cmd, const QStringList &args = QStringList()) + : command(cmd), arguments(args) { init(); } - QbsRunParameters(const QString &arg) : arguments(arg) + QbsRunParameters(const QStringList &args) + : arguments(args) { init(); } @@ -62,6 +64,7 @@ public: environment = QProcessEnvironment::systemEnvironment(); } + QString command; QStringList arguments; QProcessEnvironment environment; bool expectFailure; @@ -104,11 +107,13 @@ private slots: void duplicateProductNames(); void duplicateProductNames_data(); void dynamicLibs(); + void dynamicRuleOutputs(); void explicitlyDependsOn(); void fileDependencies(); void jsExtensionsFile(); void jsExtensionsFileInfo(); void jsExtensionsProcess(); + void jsExtensionsPropertyList(); void jsExtensionsTextFile(); void inheritQbsSearchPaths(); void objC(); @@ -125,6 +130,7 @@ private slots: void rc(); void renameProduct(); void renameTargetArtifact(); + void softDependency(); void subProjects(); void track_qrc(); void track_qobject_change(); @@ -153,6 +159,8 @@ private slots: void checkProjectFilePath(); void missingProfile(); void testAssembly(); + void testNsis(); + void testEmbedInfoPlist(); private: QByteArray m_qbsStderr; diff --git a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp index 79a6b4661..63287ce23 100644 --- a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp +++ b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp @@ -151,20 +151,18 @@ private slots: QVERIFY(projectFile.open()); const QStringList fileArgs = QStringList() << "-f" << projectFile.fileName(); CommandLineParser parser; - QVERIFY(!parser.parseCommandLine(QStringList() << "-x" << fileArgs, settings.data())); // Unknown short option. - QVERIFY(!parser.parseCommandLine(QStringList() << "--xyz" << fileArgs, settings.data())); // Unknown long option. - QVERIFY(!parser.parseCommandLine(QStringList() << "-vjv" << fileArgs, settings.data())); // Invalid position. - QVERIFY(!parser.parseCommandLine(QStringList() << "-j" << fileArgs, settings.data())); // Missing argument. + QVERIFY(!parser.parseCommandLine(QStringList() << fileArgs << "-x", settings.data())); // Unknown short option. + QVERIFY(!parser.parseCommandLine(QStringList() << fileArgs << "--xyz", settings.data())); // Unknown long option. + QVERIFY(!parser.parseCommandLine(QStringList() << fileArgs << "-vjv", settings.data())); // Invalid position. + QVERIFY(!parser.parseCommandLine(QStringList() << fileArgs << "-j", settings.data())); // Missing argument. QVERIFY(!parser.parseCommandLine(QStringList() << "-j" << "0" << fileArgs, settings.data())); // Wrong argument. - QVERIFY(!parser.parseCommandLine(QStringList() << "--products" << fileArgs, + QVERIFY(!parser.parseCommandLine(QStringList() << fileArgs << "--products", settings.data())); // Missing argument. QVERIFY(!parser.parseCommandLine(QStringList() << "--changed-files" << "," << fileArgs, settings.data())); // Wrong argument. QVERIFY(!parser.parseCommandLine(QStringList() << "--log-level" << "blubb" << fileArgs, settings.data())); // Wrong argument. - QVERIFY(!parser.parseCommandLine(QStringList("properties") << fileArgs << "--force", - settings.data())); // Invalid option for command. } void testProjectFileLookup() diff --git a/tests/manual/WiXInstallers/ExampleScript.bat b/tests/manual/WiXInstallers/ExampleScript.bat new file mode 100644 index 000000000..3af583cd8 --- /dev/null +++ b/tests/manual/WiXInstallers/ExampleScript.bat @@ -0,0 +1 @@ +echo Hello world! diff --git a/tests/manual/WiXInstallers/QbsBootstrapper.wxs b/tests/manual/WiXInstallers/QbsBootstrapper.wxs new file mode 100755 index 000000000..272f6af5b --- /dev/null +++ b/tests/manual/WiXInstallers/QbsBootstrapper.wxs @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Bundle Name="QbsBootstrapper" Version="1.0.0.0" Manufacturer="Qt Project" UpgradeCode="7b05b159-c9ce-477c-9fb5-7fce3cd50396"> + <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" /> + + <Chain> + <MsiPackage SourceFile="$(var.msiName)" /> + </Chain> + </Bundle> +</Wix> diff --git a/tests/manual/WiXInstallers/QbsSetup.wxs b/tests/manual/WiXInstallers/QbsSetup.wxs new file mode 100755 index 000000000..8f97ff667 --- /dev/null +++ b/tests/manual/WiXInstallers/QbsSetup.wxs @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Product Id="*" Name="QbsSetup" Language="1033" Version="1.0.0.0" Manufacturer="Qt Project" UpgradeCode="f60f643e-b002-44d5-b3f4-edafd078314c"> + <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" /> + + <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> + <MediaTemplate /> + + <Feature Id="ProductFeature" Title="QbsSetup" Level="1"> + <ComponentGroupRef Id="ProductComponents" /> + </Feature> + </Product> + + <Fragment> + <Directory Id="TARGETDIR" Name="SourceDir"> + <?ifdef Win64 ?> + <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?> + <?else ?> + <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?> + <?endif ?> + <Directory Id="$(var.PlatformProgramFilesFolder)"> + <Directory Id="INSTALLFOLDER" Name="QbsSetup" /> + </Directory> + </Directory> + </Fragment> + + <Fragment> + <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> + <Component Id="ProductComponent"> + <File Source="$(var.project.path)/$(var.scriptName)" /> + </Component> + </ComponentGroup> + </Fragment> +</Wix> diff --git a/tests/manual/WiXInstallers/WiXInstallers.qbs b/tests/manual/WiXInstallers/WiXInstallers.qbs new file mode 100644 index 000000000..59cdf7f4c --- /dev/null +++ b/tests/manual/WiXInstallers/WiXInstallers.qbs @@ -0,0 +1,18 @@ +import qbs + +Project { + WindowsInstallerPackage { + name: "QbsSetup" + targetName: "qbs-" + qbs.architecture + files: ["QbsSetup.wxs", "ExampleScript.bat"] + wix.defines: ["scriptName=ExampleScript.bat"] + } + + BurnSetupPackage { + Depends { name: "QbsSetup" } + name: "QbsBootstrapper" + targetName: "qbs-setup-" + qbs.architecture + files: ["QbsBootstrapper.wxs"] + wix.defines: ["msiName=qbs-" + qbs.architecture + ".msi"] + } +} |