diff options
Diffstat (limited to 'tests')
34 files changed, 721 insertions, 130 deletions
diff --git a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs index e2094576e..855528615 100644 --- a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs +++ b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs @@ -12,12 +12,7 @@ Project { type: "mytype" name: "caller" Depends { name: "infinite-loop" } - Group { - files: "dummy-input.txt" // Needed because of QBS-277 - fileTags: "schnurz" - } Rule { - inputs: "schnurz" usings: "application" Artifact { fileName: "dummy" diff --git a/tests/auto/api/testdata/is-runnable/project.qbs b/tests/auto/api/testdata/is-runnable/project.qbs new file mode 100644 index 000000000..02200fff2 --- /dev/null +++ b/tests/auto/api/testdata/is-runnable/project.qbs @@ -0,0 +1,10 @@ +import qbs + +Project { + CppApplication { + name: "app" + } + DynamicLibrary { + name: "lib" + } +} diff --git a/tests/auto/api/testdata/project-editing/project-with-no-files.qbs b/tests/auto/api/testdata/project-editing/project-with-no-files.qbs new file mode 100644 index 000000000..824ae6dcd --- /dev/null +++ b/tests/auto/api/testdata/project-editing/project-with-no-files.qbs @@ -0,0 +1,7 @@ +import qbs + +CppApplication { + Group { + files: "file.cpp" + } +} diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index 3b0fb1828..124665b1e 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -368,6 +368,36 @@ void TestApi::changeContent() waitForFinished(buildJob.data()); errorInfo = project.addGroup(newProjectData.products().first(), "blubb"); QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + + // Add a file to the top level of a product that does not have a "files" binding yet. + setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + + "/project-editing/project-with-no-files.qbs")); + job.reset(qbs::Project::setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + project = job->project(); + projectData = project.projectData(); + QCOMPARE(projectData.allProducts().count(), 1); + product = projectData.allProducts().first(); + errorInfo = project.addFiles(product, qbs::GroupData(), QStringList("main.cpp")); + QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); + projectData = project.projectData(); + rcvr.descriptions.clear(); + 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 main.cpp")); + job.reset(qbs::Project::setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + if (job->project().projectData() != projectData) { + printProjectData(projectData); + qDebug("\n====\n"); + printProjectData(job->project().projectData()); + } + QVERIFY(job->project().projectData() == projectData); } static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project project) @@ -425,7 +455,6 @@ void TestApi::fileTagsFilterOverride() QList<qbs::InstallableFile> installableFiles = project.installableFilesForProduct(product, qbs::InstallOptions()); QCOMPARE(installableFiles.count(), 1); - QEXPECT_FAIL(0, "QBS-424", Continue); QVERIFY(installableFiles.first().targetDirectory().contains("habicht")); } @@ -443,7 +472,7 @@ void TestApi::infiniteLoopBuilding() qbs::Project project = setupJob->project(); const QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions())); QTimer::singleShot(1000, buildJob.data(), SLOT(cancel())); - QVERIFY(waitForFinished(buildJob.data(), 30000)); + QVERIFY(waitForFinished(buildJob.data(), 300000)); } void TestApi::infiniteLoopBuilding_data() @@ -462,7 +491,7 @@ void TestApi::infiniteLoopResolving() QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project::setupProject(setupParams, m_logSink, 0)); QTimer::singleShot(1000, setupJob.data(), SLOT(cancel())); - QVERIFY(waitForFinished(setupJob.data(), 30000)); + QVERIFY(waitForFinished(setupJob.data(), 300000)); QVERIFY2(setupJob->error().toString().toLower().contains("cancel"), qPrintable(setupJob->error().toString())); } @@ -517,6 +546,27 @@ void TestApi::installableFiles() QCOMPARE(installableFiles.last().targetFilePath(), QLatin1String("/tmp/dir/file2.txt")); } +void TestApi::isRunnable() +{ + qbs::SetupProjectParameters setupParams = defaultSetupParameters(); + setupParams.setProjectFilePath(QDir::cleanPath(QLatin1String(SRCDIR "/testdata" + "/is-runnable/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(); + const QList<qbs::ProductData> products = project.projectData().products(); + QCOMPARE(products.count(), 2); + foreach (const qbs::ProductData &p, products) { + QVERIFY2(p.name() == "app" || p.name() == "lib", qPrintable(p.name())); + if (p.name() == "app") + QVERIFY(p.isRunnable()); + else + QVERIFY(!p.isRunnable()); + } +} + void TestApi::listBuildSystemFiles() { qbs::SetupProjectParameters setupParams = defaultSetupParameters(); @@ -582,11 +632,8 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters() const const qbs::Preferences prefs(settings.data(), profileName); setupParams.setSearchPaths(prefs.searchPaths(qbsRootPath)); setupParams.setPluginPaths(prefs.pluginPaths(qbsRootPath + QLatin1String("/lib"))); - QVariantMap buildConfig; - buildConfig.insert(QLatin1String("qbs.profile"), profileName); - buildConfig.insert(QLatin1String("qbs.buildVariant"), QLatin1String("debug")); - setupParams.setBuildConfiguration(buildConfig); - setupParams.expandBuildConfiguration(settings.data()); + setupParams.setTopLevelProfile(profileName); + setupParams.setBuildVariant(QLatin1String("debug")); return setupParams; } diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index 9aab60651..0ad65c5e5 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -55,6 +55,7 @@ private slots: void infiniteLoopBuilding_data(); void infiniteLoopResolving(); void installableFiles(); + void isRunnable(); void listBuildSystemFiles(); void nonexistingProjectPropertyFromProduct(); void nonexistingProjectPropertyFromCommandLine(); diff --git a/tests/auto/blackbox/testdata/appWithoutSources/a.c b/tests/auto/blackbox/testdata/appWithoutSources/a.c new file mode 100644 index 000000000..bf7759e11 --- /dev/null +++ b/tests/auto/blackbox/testdata/appWithoutSources/a.c @@ -0,0 +1 @@ +int foo() { return 42; } diff --git a/tests/auto/blackbox/testdata/appWithoutSources/b.c b/tests/auto/blackbox/testdata/appWithoutSources/b.c new file mode 100644 index 000000000..e3841fa32 --- /dev/null +++ b/tests/auto/blackbox/testdata/appWithoutSources/b.c @@ -0,0 +1,10 @@ +#include <stdio.h> + +int foo(); // defined in a.cpp + +int main() +{ + printf("The answer is %d.\n", foo()); + return 0; +} + diff --git a/tests/auto/blackbox/testdata/appWithoutSources/project.qbs b/tests/auto/blackbox/testdata/appWithoutSources/project.qbs new file mode 100644 index 000000000..dca195e29 --- /dev/null +++ b/tests/auto/blackbox/testdata/appWithoutSources/project.qbs @@ -0,0 +1,33 @@ +import qbs 1.0 + +Project { + StaticLibrary { + name: "a" + + Depends { name: "cpp" } + + files: [ + "a.c", + ] + } + + StaticLibrary { + name: "b" + + Depends { name: "a" } + Depends { name: "cpp" } + + files: [ + "b.c", + ] + } + + CppApplication { + name: "appWithoutSources" + type: ["application"] + cpp.entryPoint: "main" + + Depends { name: "a" } + Depends { name: "b" } + } +} diff --git a/tests/auto/blackbox/testdata/build-directories/project.qbs b/tests/auto/blackbox/testdata/build-directories/project.qbs new file mode 100644 index 000000000..cb83999e2 --- /dev/null +++ b/tests/auto/blackbox/testdata/build-directories/project.qbs @@ -0,0 +1,44 @@ +import qbs + +Project { + Product { + name: "p1" + type: "blubb1" + Transformer { + Artifact { + fileName: "dummy1.txt" + fileTags: product.type + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { + print(product.buildDirectory); + } + return cmd; + } + } + } + Product { + name: "p2" + type: "blubb2" + Depends { name: "p1" } + Rule { + usings: "blubb1" + Artifact { + fileName: "dummy2.txt" + fileTags: product.type + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { + print(product.buildDirectory); + print(project.buildDirectory); + print(project.sourceDirectory); + } + return cmd; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs index 61504573f..2c145682a 100644 --- a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs @@ -64,12 +64,12 @@ Project { var sourceFileName = options["outfile"] || "lex.yy.c"; var headerFileName = options["header-file"]; var result = [{ - filePath: "GeneratedFiles/" + product.name + "/" + sourceFileName, + filePath: "GeneratedFiles/" + sourceFileName, fileTags: ["c"] }]; if (headerFileName) { result.push({ - filePath: "GeneratedFiles/" + product.name + "/" + headerFileName, + filePath: "GeneratedFiles/" + headerFileName, fileTags: ["hpp"] }); } @@ -80,7 +80,7 @@ Project { if (product.isFlexAvailable) { // flex is available. Let's call it. cmd = new Command("flex", [input.filePath]); - cmd.workingDirectory = product.buildDirectory + "/GeneratedFiles/" + product.name; + cmd.workingDirectory = product.buildDirectory + "/GeneratedFiles"; } else { // No flex available here, generate some C source and header. cmd = new JavaScriptCommand(); diff --git a/tests/auto/blackbox/testdata/empty-filetag-list/dontcompilethis.cpp b/tests/auto/blackbox/testdata/empty-filetag-list/dontcompilethis.cpp new file mode 100644 index 000000000..bac3b631d --- /dev/null +++ b/tests/auto/blackbox/testdata/empty-filetag-list/dontcompilethis.cpp @@ -0,0 +1 @@ +This is not C++. diff --git a/tests/auto/blackbox/testdata/empty-filetag-list/project.qbs b/tests/auto/blackbox/testdata/empty-filetag-list/project.qbs new file mode 100644 index 000000000..294616124 --- /dev/null +++ b/tests/auto/blackbox/testdata/empty-filetag-list/project.qbs @@ -0,0 +1,8 @@ +import qbs + +CppApplication { + Group { + files: "dontcompilethis.cpp" + fileTags: [] + } +} diff --git a/tests/auto/blackbox/testdata/nodejs/hello.js b/tests/auto/blackbox/testdata/nodejs/hello.js new file mode 100644 index 000000000..43f1e2ffd --- /dev/null +++ b/tests/auto/blackbox/testdata/nodejs/hello.js @@ -0,0 +1,3 @@ +if (console) { + console.log("hello world"); +} diff --git a/tests/auto/blackbox/testdata/nodejs/hello.qbs b/tests/auto/blackbox/testdata/nodejs/hello.qbs new file mode 100644 index 000000000..e11b1a599 --- /dev/null +++ b/tests/auto/blackbox/testdata/nodejs/hello.qbs @@ -0,0 +1,7 @@ +import qbs + +NodeJSApplication { + nodejs.applicationFile: "hello.js" + name: "hello" + files: "hello.js" +} diff --git a/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/broken.cpp b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/broken.cpp new file mode 100644 index 000000000..57f89ed17 --- /dev/null +++ b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/broken.cpp @@ -0,0 +1 @@ +broken diff --git a/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/fine.cpp b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/fine.cpp new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/fine.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/project.qbs b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/project.qbs new file mode 100644 index 000000000..97f1e9897 --- /dev/null +++ b/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/project.qbs @@ -0,0 +1,5 @@ +import qbs + +CppApplication { + files: ["fine.cpp", "broken.cpp"] +} diff --git a/tests/auto/api/testdata/infinite-loop-process/dummy-input.txt b/tests/auto/blackbox/testdata/rad-after-incomplete-build/dummy.txt index e69de29bb..e69de29bb 100644 --- a/tests/auto/api/testdata/infinite-loop-process/dummy-input.txt +++ b/tests/auto/blackbox/testdata/rad-after-incomplete-build/dummy.txt diff --git a/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_rule.qbs b/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_rule.qbs new file mode 100644 index 000000000..8d36c6d11 --- /dev/null +++ b/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_rule.qbs @@ -0,0 +1,26 @@ +import qbs +import qbs.TextFile + +Product { + type: "custom" + Group { + files: "dummy.txt" + fileTags: "input" + } + Rule { + inputs: "input" + Artifact { + fileTags: "custom" + fileName: "oldfile" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "creating file"; + cmd.sourceCode = function() { + var f = new TextFile(output.filePath, TextFile.WriteOnly); + f.close(); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_transformer.qbs b/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_transformer.qbs new file mode 100644 index 000000000..a36bd108f --- /dev/null +++ b/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_transformer.qbs @@ -0,0 +1,21 @@ +import qbs +import qbs.TextFile + +Product { + type: "custom" + Transformer { + Artifact { + fileTags: "custom" + fileName: "oldfile" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "creating file"; + cmd.sourceCode = function() { + var f = new TextFile(output.filePath, TextFile.WriteOnly); + f.close(); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/simpleProbe/main.cpp b/tests/auto/blackbox/testdata/simpleProbe/main.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/simpleProbe/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/simpleProbe/simpleProbe.qbs b/tests/auto/blackbox/testdata/simpleProbe/simpleProbe.qbs new file mode 100644 index 000000000..b409c7cc6 --- /dev/null +++ b/tests/auto/blackbox/testdata/simpleProbe/simpleProbe.qbs @@ -0,0 +1,31 @@ +import qbs 1.0 +import qbs.Probes + +CppApplication { + Probe { + id: probe1 + property string someString + configure: { + someString = "one"; + found = true; + } + } + Probe { + id: probe2 + configure: { + found = false; + } + } + name: "MyApp" + type: { + if (!probe1.found) + throw "probe1 not found"; + if (probe2.found) + throw "probe2 unexpectedly found"; + if (probe1.someString !== "one") + throw "probe1.someString expected to be \"one\"." + return "application" + } + files: ["main.cpp"] +} + diff --git a/tests/auto/blackbox/testdata/typescript/animals.ts b/tests/auto/blackbox/testdata/typescript/animals.ts new file mode 100644 index 000000000..a33ae5c11 --- /dev/null +++ b/tests/auto/blackbox/testdata/typescript/animals.ts @@ -0,0 +1,21 @@ +export interface Mammal { + speak(): string; +} + +export class Cat implements Mammal { + public speak() { + return "Meow"; // a cat says meow + } +} + +export class Dog implements Mammal { + public speak() { + return "Woof"; // a dog says woof + } +} + +export class Human implements Mammal { + public speak() { + return "Hello"; + } +} diff --git a/tests/auto/blackbox/testdata/typescript/extra.js b/tests/auto/blackbox/testdata/typescript/extra.js new file mode 100644 index 000000000..5500e4688 --- /dev/null +++ b/tests/auto/blackbox/testdata/typescript/extra.js @@ -0,0 +1,3 @@ +if (console) { + console.log("This doesn't do anything useful!"); +} diff --git a/tests/auto/blackbox/testdata/typescript/foo.ts b/tests/auto/blackbox/testdata/typescript/foo.ts new file mode 100644 index 000000000..3554d317a --- /dev/null +++ b/tests/auto/blackbox/testdata/typescript/foo.ts @@ -0,0 +1,5 @@ +export class Greeter { + public getGreeting(): string { + return "guten Tag!"; + } +} diff --git a/tests/auto/blackbox/testdata/typescript/main.ts b/tests/auto/blackbox/testdata/typescript/main.ts new file mode 100644 index 000000000..c41eebea5 --- /dev/null +++ b/tests/auto/blackbox/testdata/typescript/main.ts @@ -0,0 +1,19 @@ +import Animals = require("animals"); +import Foo = require("foo"); + +function main() { + var mammals: Animals.Mammal[] = []; + mammals.push(new Animals.Human()); + mammals.push(new Animals.Dog()); + mammals.push(new Animals.Cat()); + + // Make everyone speak + for (var i = 0; i < mammals.length; ++i) { + console.log(mammals[i].speak()); + } + + var greeting: string = (new Foo.Greeter()).getGreeting(); + console.log(greeting); +} + +main(); diff --git a/tests/auto/blackbox/testdata/typescript/typescript.qbs b/tests/auto/blackbox/testdata/typescript/typescript.qbs new file mode 100644 index 000000000..8407d1203 --- /dev/null +++ b/tests/auto/blackbox/testdata/typescript/typescript.qbs @@ -0,0 +1,34 @@ +import qbs + +Project { + NodeJSApplication { + Depends { name: "typescript" } + Depends { name: "lib" } + + typescript.warningLevel: ["pedantic"] + typescript.generateDeclarations: true + typescript.moduleLoader: "commonjs" + nodejs.applicationFile: "main.ts" + + name: "animals" + + files: [ + "animals.ts", + "extra.js", + "main.ts" + ] + } + + Product { + Depends { name: "typescript" } + + typescript.generateDeclarations: true + typescript.moduleLoader: "commonjs" + + name: "lib" + + files: [ + "foo.ts" + ] + } +} diff --git a/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom1.in b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom1.in new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom1.in diff --git a/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom2.in b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom2.in new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom2.in diff --git a/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/project.qbs b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/project.qbs new file mode 100644 index 000000000..80644232e --- /dev/null +++ b/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/project.qbs @@ -0,0 +1,62 @@ +import qbs +import qbs.FileInfo +import qbs.TextFile + +Project { + Product { + name: "p1" + type: "custom" + Group { + files: "custom1.in" + fileTags: "custom.in" + } + } + Product { + name: "p2" + type: "custom" + Group { + files: "custom2.in" + fileTags: "custom.in" + } + } + + Rule { + inputs: "custom.in" + Artifact { + fileName: FileInfo.baseName(input.filePath) + ".out" + fileTags: "custom" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating " + output.fileName; + cmd.sourceCode = function() { + var f = new TextFile(output.filePath, TextFile.WriteOnly); + f.close(); + } + return cmd; + } + } + + Product { + name: "p3" + type: "custom-plus" + Depends { name: "p1" } + Depends { name: "p2" } + Rule { + usings: "custom" + Artifact { + fileName: FileInfo.fileName(input.filePath) + ".plus" + fileTags: "custom-plus" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating " + output.fileName; + cmd.sourceCode = function() { + var f = new TextFile(output.filePath, TextFile.WriteOnly); + f.close(); + } + return cmd; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs b/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs index 718901675..88f50733d 100644 --- a/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs +++ b/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs @@ -13,12 +13,12 @@ Project { name: "QbsBootstrapper" targetName: "qbs-setup-" + qbs.architecture files: ["QbsBootstrapper.wxs"] - wix.defines: ["msiName=qbs-" + qbs.architecture + ".msi"] + wix.defines: ["msiName=" + project.buildDirectory + "/QbsSetup/qbs-" + qbs.architecture + ".msi"] } WindowsInstallerPackage { name: "RegressionBuster9000" - files: ["QbsSetup.wxs", "Qt.wxs"] + files: ["QbsSetup.wxs", "Qt.wxs", "de.wxl"] wix.defines: ["scriptName=ExampleScript.bat"] wix.cultures: [] } diff --git a/tests/auto/blackbox/testdata/wix/de.wxl b/tests/auto/blackbox/testdata/wix/de.wxl new file mode 100644 index 000000000..75394cfdd --- /dev/null +++ b/tests/auto/blackbox/testdata/wix/de.wxl @@ -0,0 +1 @@ +<WixLocalization xmlns="http://schemas.microsoft.com/wix/2006/localization"/> diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 5838be604..148066009 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -48,6 +48,12 @@ using qbs::Internal::HostOsInfo; using qbs::Internal::removeDirectoryWithContents; using qbs::Profile; +static bool regularFileExists(const QString &filePath) +{ + const QFileInfo fi(filePath); + return fi.exists() && fi.isFile(); +} + static QString initQbsExecutableFilePath() { QString filePath = QCoreApplication::applicationDirPath() + QLatin1String("/qbs"); @@ -182,7 +188,7 @@ void TestBlackbox::sanitizeOutput(QByteArray *ba) void TestBlackbox::initTestCase() { - QVERIFY(QFile::exists(qbsExecutableFilePath)); + QVERIFY(regularFileExists(qbsExecutableFilePath)); SettingsPtr settings = qbsSettings(QString()); if (!settings->profiles().contains(buildProfileName)) @@ -268,49 +274,68 @@ void TestBlackbox::baseProperties() QCOMPARE(runQbs(), 0); } +void TestBlackbox::buildDirectories() +{ + const QString projectDir + = QDir::cleanPath(testDataDir + QLatin1String("/build-directories")); + const QString projectBuildDir = projectDir + '/' + buildDir; + QDir::setCurrent(projectDir); + QCOMPARE(runQbs(QStringList("-qq")), 0); + const QStringList outputLines + = QString::fromLocal8Bit(m_qbsStderr.trimmed()).split('\n', QString::SkipEmptyParts); + QCOMPARE(outputLines.count(), 4); + QCOMPARE(outputLines.at(0).trimmed(), projectDir + '/' + productBuildDir("p1")); + QCOMPARE(outputLines.at(1).trimmed(), projectDir + '/' + productBuildDir("p2")); + QCOMPARE(outputLines.at(2).trimmed(), projectBuildDir); + QCOMPARE(outputLines.at(3).trimmed(), projectDir); +} + void TestBlackbox::build_project_data() { QTest::addColumn<QString>("projectSubDir"); QTest::addColumn<QString>("productFileName"); QTest::newRow("BPs in Sources") << QString("buildproperties_source") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/HelloWorld")); + << executableFilePath("HelloWorld"); QTest::newRow("code generator") << QString("codegen") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/codegen")); + << executableFilePath("codegen"); QTest::newRow("link static libs") << QString("link_staticlib") - << QString(buildDir + QLatin1String("/") - + HostOsInfo::appendExecutableSuffix("HelloWorld")); + << executableFilePath("HelloWorld"); QTest::newRow("precompiled header") << QString("precompiledHeader") - << QString(buildDir + QLatin1String("/") - + HostOsInfo::appendExecutableSuffix("MyApp")); + << executableFilePath("MyApp"); QTest::newRow("lots of dots") << QString("lotsofdots") - << QString(buildDir + QLatin1String("/") - + HostOsInfo::appendExecutableSuffix("lots.of.dots")); + << executableFilePath("lots.of.dots"); QTest::newRow("Qt5 plugin") << QString("qt5plugin") - << QString(buildDir + QLatin1String("/") + HostOsInfo::dynamicLibraryName("echoplugin")); + << productBuildDir("echoplugin") + '/' + HostOsInfo::dynamicLibraryName("echoplugin"); QTest::newRow("Q_OBJECT in source") << QString("moc_cpp") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/moc_cpp")); + << executableFilePath("moc_cpp"); QTest::newRow("Q_OBJECT in header") << QString("moc_hpp") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/moc_hpp")); + << executableFilePath("moc_hpp"); QTest::newRow("Q_OBJECT in header, moc_XXX.cpp included") << QString("moc_hpp_included") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/moc_hpp_included")); + << executableFilePath("moc_hpp_included"); QTest::newRow("app and lib with same source file") << QString("lib_samesource") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/HelloWorldApp")); + << executableFilePath("HelloWorldApp"); QTest::newRow("source files with the same base name but different extensions") << QString("sameBaseName") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/basename")); + << executableFilePath("basename"); QTest::newRow("static library dependencies") << QString("staticLibDeps") - << QString(HostOsInfo::appendExecutableSuffix(buildDir + "/staticLibDeps")); + << executableFilePath("staticLibDeps"); + QTest::newRow("simple probes") + << QString("simpleProbe") + << executableFilePath("MyApp"); + QTest::newRow("application without sources") + << QString("appWithoutSources") + << executableFilePath("appWithoutSources"); } void TestBlackbox::build_project() @@ -324,13 +349,13 @@ void TestBlackbox::build_project() rmDirR(buildDir); QCOMPARE(runQbs(), 0); - QVERIFY2(QFile::exists(productFileName), qPrintable(productFileName)); - QVERIFY(QFile::exists(buildGraphPath)); + QVERIFY2(regularFileExists(productFileName), qPrintable(productFileName)); + QVERIFY(regularFileExists(buildGraphPath)); QVERIFY2(QFile::remove(productFileName), qPrintable(productFileName)); waitForNewTimestamp(); QCOMPARE(runQbs(QbsRunParameters(QStringList("--check-timestamps"))), 0); - QVERIFY2(QFile::exists(productFileName), qPrintable(productFileName)); - QVERIFY(QFile::exists(buildGraphPath)); + QVERIFY2(regularFileExists(productFileName), qPrintable(productFileName)); + QVERIFY(regularFileExists(buildGraphPath)); } void TestBlackbox::build_project_dry_run_data() @@ -396,7 +421,7 @@ void TestBlackbox::dependenciesProperty() { QDir::setCurrent(testDataDir + QLatin1String("/dependenciesProperty")); QCOMPARE(runQbs(), 0); - QFile depsFile(buildDir + QLatin1String("/product1.deps")); + QFile depsFile(productBuildDir("product1") + QLatin1String("/product1.deps")); QVERIFY(depsFile.open(QFile::ReadOnly)); QString deps = QString::fromLatin1(depsFile.readAll()); QVERIFY(!deps.isEmpty()); @@ -454,7 +479,7 @@ void TestBlackbox::resolve_project() QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); QVERIFY2(!QFile::exists(productFileName), qPrintable(productFileName)); - QVERIFY(QFile::exists(buildGraphPath)); + QVERIFY(regularFileExists(buildGraphPath)); } void TestBlackbox::resolve_project_dry_run_data() @@ -477,6 +502,15 @@ void TestBlackbox::resolve_project_dry_run() QVERIFY2(!QFile::exists(buildGraphPath), qPrintable(buildGraphPath)); } +void TestBlackbox::usingsAsSoleInputsNonMultiplexed() +{ + QDir::setCurrent(testDataDir + QLatin1String("/usings-as-sole-inputs-non-multiplexed")); + QCOMPARE(runQbs(), 0); + const QString p3BuildDir = productBuildDir("p3"); + QVERIFY(regularFileExists(p3BuildDir + "/custom1.out.plus")); + QVERIFY(regularFileExists(p3BuildDir + "/custom2.out.plus")); +} + static bool symlinkExists(const QString &linkFilePath) { return QFileInfo(linkFilePath).isSymLink(); @@ -484,10 +518,10 @@ static bool symlinkExists(const QString &linkFilePath) void TestBlackbox::clean() { - const QString appObjectFilePath = buildDir + "/.obj/app/main.cpp" + QTC_HOST_OBJECT_SUFFIX; - const QString appExeFilePath = buildDir + "/app" + QTC_HOST_EXE_SUFFIX; - const QString depObjectFilePath = buildDir + "/.obj/dep/dep.cpp" + QTC_HOST_OBJECT_SUFFIX; - const QString depLibBase = buildDir + '/' + QTC_HOST_DYNAMICLIB_PREFIX + "dep"; + const QString appObjectFilePath = productBuildDir("app") + "/.obj/main.cpp" + QTC_HOST_OBJECT_SUFFIX; + const QString appExeFilePath = executableFilePath("app"); + const QString depObjectFilePath = productBuildDir("dep") + "/.obj/dep.cpp" + QTC_HOST_OBJECT_SUFFIX; + const QString depLibBase = productBuildDir("dep") + '/' + QTC_HOST_DYNAMICLIB_PREFIX + "dep"; QString depLibFilePath; QStringList symlinks; if (qbs::Internal::HostOsInfo::isOsxHost()) { @@ -508,24 +542,24 @@ void TestBlackbox::clean() // Default behavior: Remove only temporaries. QCOMPARE(runQbs(), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); - QVERIFY(QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); + QVERIFY(regularFileExists(depObjectFilePath)); + QVERIFY(regularFileExists(depLibFilePath)); foreach (const QString &symLink, symlinks) - QVERIFY2(QFile(symLink).exists(), qPrintable(symLink)); + QVERIFY2(regularFileExists(symLink), qPrintable(symLink)); QCOMPARE(runQbs(QbsRunParameters("clean")), 0); QVERIFY(!QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); + QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(!QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(depLibFilePath)); foreach (const QString &symLink, symlinks) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); // Remove all. QCOMPARE(runQbs(), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), QStringList("--all-artifacts"))), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); @@ -536,28 +570,28 @@ void TestBlackbox::clean() // Dry run. QCOMPARE(runQbs(), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), QStringList("--all-artifacts") << "-n")), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); - QVERIFY(QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); + QVERIFY(regularFileExists(depObjectFilePath)); + QVERIFY(regularFileExists(depLibFilePath)); foreach (const QString &symLink, symlinks) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); // Product-wise, dependency only. QCOMPARE(runQbs(), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); - QVERIFY(QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); + QVERIFY(regularFileExists(depObjectFilePath)); + QVERIFY(regularFileExists(depLibFilePath)); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), QStringList("--all-artifacts") << "-p" << "dep")), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); foreach (const QString &symLink, symlinks) @@ -565,17 +599,17 @@ void TestBlackbox::clean() // Product-wise, dependent product only. QCOMPARE(runQbs(), 0); - QVERIFY(QFile(appObjectFilePath).exists()); - QVERIFY(QFile(appExeFilePath).exists()); - QVERIFY(QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(appObjectFilePath)); + QVERIFY(regularFileExists(appExeFilePath)); + QVERIFY(regularFileExists(depObjectFilePath)); + QVERIFY(regularFileExists(depLibFilePath)); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("clean"), QStringList("--all-artifacts") << "-p" << "app")), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); - QVERIFY(QFile(depObjectFilePath).exists()); - QVERIFY(QFile(depLibFilePath).exists()); + QVERIFY(regularFileExists(depObjectFilePath)); + QVERIFY(regularFileExists(depLibFilePath)); foreach (const QString &symLink, symlinks) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); } @@ -717,8 +751,8 @@ void TestBlackbox::track_qrc() { QDir::setCurrent(testDataDir + "/qrc"); QCOMPARE(runQbs(), 0); - const QString fileName = HostOsInfo::appendExecutableSuffix(buildDir + "/i"); - QVERIFY2(QFile(fileName).exists(), qPrintable(fileName)); + const QString fileName = executableFilePath("i"); + QVERIFY2(regularFileExists(fileName), qPrintable(fileName)); QDateTime dt = QFileInfo(fileName).lastModified(); QTest::qSleep(2020); { @@ -729,7 +763,7 @@ void TestBlackbox::track_qrc() f.close(); } QCOMPARE(runQbs(), 0); - QVERIFY(QFile(fileName).exists()); + QVERIFY(regularFileExists(fileName)); QVERIFY(dt < QFileInfo(fileName).lastModified()); } @@ -740,18 +774,18 @@ void TestBlackbox::track_qobject_change() QVERIFY(QFile("bla_qobject.h").copy("bla.h")); touch("bla.h"); QCOMPARE(runQbs(), 0); - const QString productFilePath = HostOsInfo::appendExecutableSuffix(buildDir + "/i"); - QVERIFY2(QFile(productFilePath).exists(), qPrintable(productFilePath)); + const QString productFilePath = executableFilePath("i"); + QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath)); QString moc_bla_objectFileName - = buildDir + "/.obj/i/GeneratedFiles/i/moc_bla.cpp" QTC_HOST_OBJECT_SUFFIX; - QVERIFY(QFile(moc_bla_objectFileName).exists()); + = buildDir + "/i/.obj/GeneratedFiles/moc_bla.cpp" QTC_HOST_OBJECT_SUFFIX; + QVERIFY2(regularFileExists(moc_bla_objectFileName), qPrintable(moc_bla_objectFileName)); QTest::qSleep(1000); QFile("bla.h").remove(); QVERIFY(QFile("bla_noqobject.h").copy("bla.h")); touch("bla.h"); QCOMPARE(runQbs(), 0); - QVERIFY(QFile(productFilePath).exists()); + QVERIFY(regularFileExists(productFilePath)); QVERIFY(!QFile(moc_bla_objectFileName).exists()); } @@ -767,7 +801,7 @@ void TestBlackbox::trackAddFile() QDir::setCurrent(testDataDir + "/trackAddFile/work"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); QCOMPARE(process.exitCode(), 0); @@ -783,7 +817,7 @@ void TestBlackbox::trackAddFile() touch("main.cpp"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY(process.waitForStarted()); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitCode(), 0); @@ -872,7 +906,7 @@ void TestBlackbox::trackRemoveFile() QDir::setCurrent(testDataDir + "/trackAddFile/work"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); QCOMPARE(process.exitCode(), 0); @@ -896,7 +930,7 @@ void TestBlackbox::trackRemoveFile() touch("project.qbs"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY(process.waitForStarted()); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitCode(), 0); @@ -909,7 +943,7 @@ void TestBlackbox::trackRemoveFile() QCOMPARE(unchangedObjectFileTime1, unchangedObjectFileTime2); // the object file for the removed cpp file should have vanished too - QCOMPARE(QFile::exists(buildDir + "/someapp/zort.cpp" QTC_HOST_OBJECT_SUFFIX), false); + QCOMPARE(regularFileExists(buildDir + "/someapp/zort.cpp" QTC_HOST_OBJECT_SUFFIX), false); } void TestBlackbox::trackAddFileTag() @@ -924,7 +958,7 @@ void TestBlackbox::trackAddFileTag() QDir::setCurrent(testDataDir + "/trackFileTags/work"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); QCOMPARE(process.exitCode(), 0); @@ -937,7 +971,7 @@ void TestBlackbox::trackAddFileTag() touch("project.qbs"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY(process.waitForStarted()); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitCode(), 0); @@ -958,12 +992,11 @@ void TestBlackbox::trackRemoveFileTag() QCOMPARE(runQbs(), 0); // check if the artifacts are here that will become stale in the 2nd step - QVERIFY2(QFile::exists(buildDir + "/.obj/someapp/main_foo.cpp" QTC_HOST_OBJECT_SUFFIX), - qPrintable(buildDir + "/.obj/someapp/main_foo.cpp" QTC_HOST_OBJECT_SUFFIX)); - QVERIFY2(QFile::exists(buildDir + "/main_foo.cpp"), qPrintable(buildDir + "/main_foo.cpp")); - QVERIFY2(QFile::exists(buildDir + "/main.foo"), qPrintable(buildDir + "/main.foo")); + QVERIFY(regularFileExists(buildDir + "/someapp/.obj/main_foo.cpp" QTC_HOST_OBJECT_SUFFIX)); + QVERIFY(regularFileExists(productBuildDir("someapp") + "/main_foo.cpp")); + QVERIFY(regularFileExists(productBuildDir("someapp") + "/main.foo")); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY(process.waitForStarted()); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitCode(), 0); @@ -976,7 +1009,7 @@ void TestBlackbox::trackRemoveFileTag() touch("project.qbs"); QCOMPARE(runQbs(), 0); - process.start(buildDir + "/someapp"); + process.start(executableFilePath("someapp")); QVERIFY(process.waitForStarted()); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitCode(), 0); @@ -984,9 +1017,9 @@ void TestBlackbox::trackRemoveFileTag() QCOMPARE(output.takeFirst().trimmed().constData(), "there's no foo here"); // check if stale artifacts have been removed - QCOMPARE(QFile::exists(buildDir + "/someapp/main_foo.cpp" QTC_HOST_OBJECT_SUFFIX), false); - QCOMPARE(QFile::exists(buildDir + "/someapp/main_foo.cpp"), false); - QCOMPARE(QFile::exists(buildDir + "/someapp/main.foo"), false); + QCOMPARE(regularFileExists(productBuildDir("someapp") + "/.obj/main_foo.cpp" QTC_HOST_OBJECT_SUFFIX), false); + QCOMPARE(regularFileExists(productBuildDir("someapp") + "/main_foo.cpp"), false); + QCOMPARE(regularFileExists(productBuildDir("someapp") + "/main.foo"), false); } void TestBlackbox::trackAddMocInclude() @@ -1117,10 +1150,10 @@ void TestBlackbox::ruleConditions() { QDir::setCurrent(testDataDir + "/ruleConditions"); QCOMPARE(runQbs(), 0); - QVERIFY(QFileInfo(buildDir + HostOsInfo::appendExecutableSuffix("/zorted")).exists()); - QVERIFY(QFileInfo(buildDir + HostOsInfo::appendExecutableSuffix("/unzorted")).exists()); - QVERIFY(QFileInfo(buildDir + "/zorted.foo.narf.zort").exists()); - QVERIFY(!QFileInfo(buildDir + "/unzorted.foo.narf.zort").exists()); + QVERIFY(QFileInfo(executableFilePath("zorted")).exists()); + QVERIFY(QFileInfo(executableFilePath("unzorted")).exists()); + QVERIFY(QFileInfo(productBuildDir("zorted") + "/zorted.foo.narf.zort").exists()); + QVERIFY(!QFileInfo(productBuildDir("unzorted") + "/unzorted.foo.narf.zort").exists()); } void TestBlackbox::ruleCycle() @@ -1184,8 +1217,7 @@ void TestBlackbox::overrideProjectProperties() << QLatin1String("project.someInt:156") << QLatin1String("project.someStringList:one") << QLatin1String("MyAppForYou.mainFile:main.cpp"))), 0); - QVERIFY(QFile::exists(buildDir + HostOsInfo::appendExecutableSuffix("/MyAppForYou"))); - + QVERIFY(regularFileExists(executableFilePath("MyAppForYou"))); QVERIFY(QFile::remove(buildGraphPath)); QbsRunParameters params; params.arguments << QLatin1String("-f") << QLatin1String("project_using_helper_lib.qbs"); @@ -1205,7 +1237,7 @@ void TestBlackbox::productProperties() QDir::setCurrent(testDataDir + "/productproperties"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << QLatin1String("-f") << QLatin1String("project.qbs"))), 0); - QVERIFY(QFile::exists(buildDir + HostOsInfo::appendExecutableSuffix("/blubb_user"))); + QVERIFY(regularFileExists(executableFilePath("blubb_user"))); } void TestBlackbox::propertyChanges() @@ -1223,7 +1255,7 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(m_qbsStdout.contains("Making output from input")); - QFile generatedFile(buildDir + QLatin1String("/generated.txt")); + QFile generatedFile(productBuildDir("generated text file") + "/generated.txt"); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 1suffix 1")); generatedFile.close(); @@ -1489,15 +1521,15 @@ void TestBlackbox::dynamicRuleOutputs() 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"; + const QString appFile = executableFilePath("genlexer"); + const QString headerFile1 = productBuildDir("genlexer") + "/GeneratedFiles/numberscanner.h"; + const QString sourceFile1 = productBuildDir("genlexer") + "/GeneratedFiles/numberscanner.c"; + const QString sourceFile2 = productBuildDir("genlexer") + "/GeneratedFiles/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(regularFileExists(appFile)); + QVERIFY(regularFileExists(headerFile1)); + QVERIFY(regularFileExists(sourceFile1)); QVERIFY(!QFile::exists(sourceFile2)); QDateTime appFileTimeStamp1 = QFileInfo(appFile).lastModified(); @@ -1513,7 +1545,7 @@ void TestBlackbox::dynamicRuleOutputs() QVERIFY(appFileTimeStamp1 < appFileTimeStamp2); QVERIFY(!QFile::exists(headerFile1)); QVERIFY(!QFile::exists(sourceFile1)); - QVERIFY(QFile::exists(sourceFile2)); + QVERIFY(regularFileExists(sourceFile2)); waitForNewTimestamp(); QFile::remove("numbers.l"); @@ -1524,12 +1556,18 @@ void TestBlackbox::dynamicRuleOutputs() // 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(regularFileExists(appFile)); + QVERIFY(regularFileExists(headerFile1)); + QVERIFY(regularFileExists(sourceFile1)); QVERIFY(!QFile::exists(sourceFile2)); } +void TestBlackbox::emptyFileTagList() +{ + QDir::setCurrent(testDataDir + "/empty-filetag-list"); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::erroneousFiles_data() { QTest::addColumn<QString>("errorMessage"); @@ -1572,8 +1610,8 @@ void TestBlackbox::fileDependencies() QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling narf.cpp")); QVERIFY(m_qbsStdout.contains("compiling zort.cpp")); - const QString productFileName = HostOsInfo::appendExecutableSuffix(buildDir + "/myapp"); - QVERIFY2(QFile::exists(productFileName), qPrintable(productFileName)); + const QString productFileName = executableFilePath("myapp"); + QVERIFY2(regularFileExists(productFileName), qPrintable(productFileName)); // Incremental build without changes. QCOMPARE(runQbs(), 0); @@ -1740,6 +1778,18 @@ void TestBlackbox::mocCppIncluded() QCOMPARE(runQbs(), 0); } +void TestBlackbox::nonBrokenFilesInBrokenProduct() +{ + QDir::setCurrent(testDataDir + "/non-broken-files-in-broken-product"); + QbsRunParameters params("-k"); + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + QVERIFY(m_qbsStdout.contains("fine.cpp")); + QVERIFY(runQbs(params) != 0); + QEXPECT_FAIL("", "QBS-635", Continue); + QVERIFY(!m_qbsStdout.contains("fine.cpp")); // The non-broken file must not be recompiled. +} + void TestBlackbox::objC() { QDir::setCurrent(testDataDir + "/objc"); @@ -1751,7 +1801,7 @@ void TestBlackbox::qmlDebugging() QDir::setCurrent(testDataDir + "/qml-debugging"); QCOMPARE(runQbs(), 0); QProcess nm; - nm.start("nm", QStringList(HostOsInfo::appendExecutableSuffix(buildDir + "/debuggable-app"))); + nm.start("nm", QStringList(executableFilePath("debuggable-app"))); if (nm.waitForStarted()) { // Let's ignore hosts without nm. QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString())); QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData()); @@ -1784,17 +1834,80 @@ void TestBlackbox::propertiesBlocks() QCOMPARE(runQbs(), 0); } +void TestBlackbox::radAfterIncompleteBuild_data() +{ + QTest::addColumn<QString>("projectFileName"); + QTest::newRow("Project with Rule") << "project_with_rule.qbs"; + QTest::newRow("Project with Transformer") << "project_with_transformer.qbs"; +} + +void TestBlackbox::radAfterIncompleteBuild() +{ + QDir::setCurrent(testDataDir + "/rad-after-incomplete-build"); + rmDirR(buildDir); + QFETCH(QString, projectFileName); + + // Step 1: Have a directory where a file used to be. + QbsRunParameters params(QStringList() << "-f" << projectFileName); + QCOMPARE(runQbs(params), 0); + waitForNewTimestamp(); + QFile projectFile(projectFileName); + QVERIFY(projectFile.open(QIODevice::ReadWrite)); + QByteArray content = projectFile.readAll(); + content.replace("oldfile", "oldfile/newfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + waitForNewTimestamp(); + content.replace("oldfile/newfile", "newfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + params.expectFailure = false; + QCOMPARE(runQbs(params), 0); + waitForNewTimestamp(); + content.replace("newfile", "oldfile/newfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + QCOMPARE(runQbs(params), 0); + + // Step 2: Have a file where a directory used to be. + waitForNewTimestamp(); + content.replace("oldfile/newfile", "oldfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + waitForNewTimestamp(); + content.replace("oldfile", "newfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + params.expectFailure = false; + QCOMPARE(runQbs(params), 0); + waitForNewTimestamp(); + content.replace("newfile", "oldfile"); + projectFile.resize(0); + projectFile.write(content); + projectFile.flush(); + QCOMPARE(runQbs(params), 0); +} + void TestBlackbox::installedApp() { QDir::setCurrent(testDataDir + "/installed_artifact"); QCOMPARE(runQbs(QbsRunParameters("install")), 0); - QVERIFY(QFile::exists(defaultInstallRoot + QVERIFY(regularFileExists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp")))); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--install-root") << (testDataDir + "/installed-app"))), 0); - QVERIFY(QFile::exists(testDataDir + QVERIFY(regularFileExists(testDataDir + HostOsInfo::appendExecutableSuffix("/installed-app/usr/bin/installedApp"))); QFile addedFile(defaultInstallRoot + QLatin1String("/blubb.txt")); @@ -1802,9 +1915,9 @@ void TestBlackbox::installedApp() addedFile.close(); QVERIFY(addedFile.exists()); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"), QStringList("--remove-first"))), 0); - QVERIFY(QFile::exists(defaultInstallRoot + QVERIFY(regularFileExists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp")))); - QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/src/main.cpp"))); + QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/src/main.cpp"))); QVERIFY(!addedFile.exists()); // Check whether changing install parameters on the product causes re-installation. @@ -1817,9 +1930,9 @@ void TestBlackbox::installedApp() projectFile.write(content); QVERIFY(projectFile.flush()); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); - QVERIFY(QFile::exists(defaultInstallRoot + QVERIFY(regularFileExists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/local/bin/installedApp")))); - QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/local/src/main.cpp"))); + QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/local/src/main.cpp"))); // Check whether changing install parameters on the artifact causes re-installation. content.replace("qbs.installDir: \"bin\"", "qbs.installDir: 'custom'"); @@ -1828,7 +1941,7 @@ void TestBlackbox::installedApp() projectFile.write(content); QVERIFY(projectFile.flush()); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); - QVERIFY(QFile::exists(defaultInstallRoot + QVERIFY(regularFileExists(defaultInstallRoot + HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/local/custom/installedApp")))); // Check whether changing install parameters on a source file causes re-installation. @@ -1838,7 +1951,7 @@ void TestBlackbox::installedApp() projectFile.write(content); projectFile.close(); QCOMPARE(runQbs(QbsRunParameters(QLatin1String("install"))), 0); - QVERIFY(QFile::exists(defaultInstallRoot + QLatin1String("/usr/local/source/main.cpp"))); + QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/local/source/main.cpp"))); rmDirR(buildDir); QbsRunParameters params; @@ -1941,7 +2054,7 @@ void TestBlackbox::testNsis() bool haveMakeNsis = false; foreach (const QString &path, paths) { - if (QFile::exists(QDir::fromNativeSeparators(path) + + if (regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QLatin1String("/makensis")))) { haveMakeNsis = true; break; @@ -2001,9 +2114,9 @@ static bool haveWiX() } foreach (const QString &path, paths) { - if (QFile::exists(QDir::fromNativeSeparators(path) + + if (regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QLatin1String("/candle"))) && - QFile::exists(QDir::fromNativeSeparators(path) + + regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QLatin1String("/light")))) { return true; } @@ -2034,8 +2147,77 @@ void TestBlackbox::testWiX() QVERIFY(m_qbsStdout.contains("compiling QbsBootstrapper.wxs")); QVERIFY(m_qbsStdout.contains("linking qbs-" + arch + ".msi")); QVERIFY(m_qbsStdout.contains("linking qbs-setup-" + arch + ".exe")); - QVERIFY(QFile::exists(buildDir + "/qbs-" + arch + ".msi")); - QVERIFY(QFile::exists(buildDir + "/qbs-setup-" + arch + ".exe")); + QVERIFY(regularFileExists(buildDir + "/QbsSetup/qbs-" + arch + ".msi")); + QVERIFY(regularFileExists(buildDir + "/QbsBootstrapper/qbs-setup-" + arch + ".exe")); +} + +static QString findExecutable(const QStringList &fileNames) +{ + const QStringList path = QString::fromLocal8Bit(qgetenv("PATH")) + .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + + foreach (const QString &fileName, fileNames) { + foreach (const QString &ppath, path) { + const QString fullPath = ppath + QLatin1Char('/') + fileName; + if (QFileInfo(fullPath).exists()) + return QDir::cleanPath(fullPath); + } + } + return QString(); +} + +static bool haveNodeJs() +{ + // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to a + // conflict with another package containing a binary named node + return !findExecutable(QStringList() + << QLatin1String("nodejs") + << QLatin1String("node")).isEmpty(); +} + +void TestBlackbox::testNodeJs() +{ + if (!haveNodeJs()) { + SKIP_TEST("Node.js is not installed"); + return; + } + + QDir::setCurrent(testDataDir + QLatin1String("/nodejs")); + + QbsRunParameters params; + params.command = QLatin1String("run"); + QCOMPARE(runQbs(params), 0); + QVERIFY((bool)m_qbsStdout.contains("hello world")); + QVERIFY(regularFileExists(buildDir + "/hello/hello.js")); +} + +void TestBlackbox::testTypeScript() +{ + if (!haveNodeJs()) { + SKIP_TEST("node.js is not installed"); + return; + } + + QDir::setCurrent(testDataDir + QLatin1String("/typescript")); + + QbsRunParameters params; + params.command = QLatin1String("run"); + params.arguments = QStringList() << "-p" << "animals"; + QCOMPARE(runQbs(params), 0); + + QVERIFY(regularFileExists(buildDir + "/animals/animals.js")); + QVERIFY(regularFileExists(buildDir + "/animals/extra.js")); + QVERIFY(regularFileExists(buildDir + "/animals/main.js")); +} + +QString TestBlackbox::productBuildDir(const QString &productName) const +{ + return buildDir + '/' + productName; +} + +QString TestBlackbox::executableFilePath(const QString &productName) const +{ + return productBuildDir(productName) + '/' + HostOsInfo::appendExecutableSuffix(productName); } QTEST_MAIN(TestBlackbox) diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index c236d4273..568d1c08e 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -100,6 +100,7 @@ private slots: void addedFilePersistent(); void addQObjectMacroToCppFile(); void baseProperties(); + void buildDirectories(); void build_project_data(); void build_project(); void build_project_dry_run_data(); @@ -114,6 +115,7 @@ private slots: void duplicateProductNames_data(); void dynamicLibs(); void dynamicRuleOutputs(); + void emptyFileTagList(); void erroneousFiles_data(); void erroneousFiles(); void explicitlyDependsOn(); @@ -125,15 +127,19 @@ private slots: void jsExtensionsTextFile(); void inheritQbsSearchPaths(); void mocCppIncluded(); + void nonBrokenFilesInBrokenProduct(); void objC(); void qmlDebugging(); void projectWithPropertiesItem(); void properQuoting(); void propertiesBlocks(); + void radAfterIncompleteBuild_data(); + void radAfterIncompleteBuild(); void resolve_project_data(); void resolve_project(); void resolve_project_dry_run_data(); void resolve_project_dry_run(); + void usingsAsSoleInputsNonMultiplexed(); void clean(); void exportSimple(); void exportWithRecursiveDepends(); @@ -173,8 +179,13 @@ private slots: void testNsis(); void testEmbedInfoPlist(); void testWiX(); + void testNodeJs(); + void testTypeScript(); private: + QString productBuildDir(const QString &productName) const; + QString executableFilePath(const QString &productName) const; + QByteArray m_qbsStderr; QByteArray m_qbsStdout; }; |