diff options
Diffstat (limited to 'tests/auto/api/tst_api.cpp')
-rw-r--r-- | tests/auto/api/tst_api.cpp | 159 |
1 files changed, 89 insertions, 70 deletions
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index 200239081..3816eca2b 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -362,7 +362,10 @@ void TestApi::buildProject() + QLatin1String(".qbs"); qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); removeBuildDir(params); - qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath); + ProcessResultReceiver resultReceiver; + qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, nullptr, &resultReceiver); + if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); VERIFY_NO_ERROR(errorInfo); QVERIFY(regularFileExists(relativeBuildGraphFilePath())); if (!productFileName.isEmpty()) { @@ -483,9 +486,14 @@ void TestApi::buildSingleFile() m_logSink->setLogLevel(qbs::LoggerMaxLevel); std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts(options)); BuildDescriptionReceiver receiver; + ProcessResultReceiver resultReceiver; + connect(buildJob.get(), &qbs::BuildJob::reportProcessResult, + &resultReceiver, &ProcessResultReceiver::handleProcessResult); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, &receiver, &BuildDescriptionReceiver::handleDescription); waitForFinished(buildJob.get()); + if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QCOMPARE(receiver.descriptions.count("compiling"), 2); QCOMPARE(receiver.descriptions.count("precompiling"), 1); @@ -920,16 +928,12 @@ void TestApi::dependencyOnMultiplexedType() } else { QVERIFY(p.name() == "p2"); ++p2Count; - - // FIXME: This is an odd effect of our current algorithm: We collect the products - // matching the requested type and add Depends items with their names ("p1" in - // this case). Later, the algorithm checking for compatibility regarding the - // multiplexing axes picks the aggregate. However, the aggregate does not have - // a matching type... It's not entirely clear what the real expected - // result should be here. - QCOMPARE(p.dependencies().size(), 2); + QVERIFY(p.dependencies().contains("dep")); } } + QCOMPARE(depCount, 1); + QCOMPARE(p1Count, 3); + QCOMPARE(p2Count, 1); std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); @@ -1002,7 +1006,7 @@ void TestApi::errorInSetupRunEnvironment() qbs::ErrorInfo error; const QProcessEnvironment env = runEnv.runEnvironment(&error); QVERIFY(error.hasError()); - QVERIFY(error.toString().contains("trallala")); + QVERIFY2(error.toString().contains("trallala"), qPrintable(error.toString())); } catch (const qbs::ErrorInfo &) { exceptionCaught = true; } @@ -1021,10 +1025,11 @@ void TestApi::excludedInputs() waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(job->error().toString())); QVERIFY(project.isValid()); - QCOMPARE(project.projectData().products().size(), 2); + const qbs::ProjectData projectData = project.projectData(); + QCOMPARE(projectData.products().size(), 2); qbs::ProductData depProduct; qbs::ProductData pProduct; - for (const qbs::ProductData &p : project.projectData().products()) { + for (const qbs::ProductData &p : projectData.products()) { if (p.name() == "dep") depProduct = p; else if (p.name() == "p") @@ -1283,7 +1288,7 @@ void TestApi::fallbackGcc() QVERIFY(project.isValid()); QList<qbs::ProductData> products = project.allProducts(); QCOMPARE(products.size(), 2); - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "unixProfile") { qbs::PropertyMap moduleProps = p.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), @@ -1417,6 +1422,9 @@ void TestApi::infiniteLoopBuilding_data() QTest::addColumn<QString>("projectDirName"); QTest::newRow("JS Command") << QString("infinite-loop-js"); QTest::newRow("Process Command") << QString("infinite-loop-process"); + QTest::newRow("Scanner (scan property)") << QString("infinite-loop-scanning-scan"); + QTest::newRow("Scanner (searchPaths property)") + << QString("infinite-loop-scanning-searchpaths"); } void TestApi::infiniteLoopResolving() @@ -1545,27 +1553,30 @@ void TestApi::linkDynamicAndStaticLibs() BuildDescriptionReceiver bdr; qbs::BuildOptions options; options.setEchoMode(qbs::CommandEchoModeCommandLine); + m_logSink->output.clear(); const qbs::ErrorInfo errorInfo = doBuildProject("link-dynamiclibs-staticlibs", &bdr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); + const bool isGcc = m_logSink->output.contains("is gcc: true"); + const bool isNotGcc = m_logSink->output.contains("is gcc: false"); + if (isNotGcc) + QSKIP("The remainder of this test applies only to GCC"); + QVERIFY(isGcc); + // The dependent static libs should not appear in the link command for the executable. - const SettingsPtr s = settings(); - const qbs::Profile buildProfile(profileName(), s.get()); - if (profileToolchain(buildProfile).contains("gcc")) { - static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); - QString appLinkCmd; - for (const QString &line : qAsConst(bdr.descriptionLines)) { - const auto ln = line.toStdString(); - if (std::regex_search(ln, appLinkCmdRex)) { - appLinkCmd = line; - break; - } + static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); + QString appLinkCmd; + for (const QString &line : std::as_const(bdr.descriptionLines)) { + const auto ln = line.toStdString(); + if (std::regex_search(ln, appLinkCmdRex)) { + appLinkCmd = line; + break; } - QVERIFY(!appLinkCmd.isEmpty()); - QVERIFY(!appLinkCmd.contains("static1")); - QVERIFY(!appLinkCmd.contains("static2")); } + QVERIFY(!appLinkCmd.isEmpty()); + QVERIFY(!appLinkCmd.contains("static1")); + QVERIFY(!appLinkCmd.contains("static2")); } void TestApi::linkStaticAndDynamicLibs() @@ -1580,31 +1591,32 @@ void TestApi::linkStaticAndDynamicLibs() const bool isNormalUnix = m_logSink->output.contains("is normal unix: yes"); const bool isNotNormalUnix = m_logSink->output.contains("is normal unix: no"); QVERIFY2(isNormalUnix != isNotNormalUnix, qPrintable(m_logSink->output)); + const bool isGcc = m_logSink->output.contains("is gcc: true"); + const bool isNotGcc = m_logSink->output.contains("is gcc: false"); + if (isNotGcc) + QSKIP("The remainder of this test applies only to GCC"); + QVERIFY(isGcc); // The dependencies libdynamic1.so and libstatic2.a must not appear in the link command for the // executable. The -rpath-link line for libdynamic1.so must be there. - const SettingsPtr s = settings(); - const qbs::Profile buildProfile(profileName(), s.get()); - if (profileToolchain(buildProfile).contains("gcc")) { - static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); - QString appLinkCmd; - for (const QString &line : qAsConst(bdr.descriptionLines)) { - const auto ln = line.toStdString(); - if (std::regex_search(ln, appLinkCmdRex)) { - appLinkCmd = line; - break; - } - } - QVERIFY(!appLinkCmd.isEmpty()); - if (isNormalUnix) { - const std::regex rpathLinkRex("-rpath-link=\\S*/" - + relativeProductBuildDir("dynamic2").toStdString()); - const auto ln = appLinkCmd.toStdString(); - QVERIFY(std::regex_search(ln, rpathLinkRex)); + static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); + QString appLinkCmd; + for (const QString &line : std::as_const(bdr.descriptionLines)) { + const auto ln = line.toStdString(); + if (std::regex_search(ln, appLinkCmdRex)) { + appLinkCmd = line; + break; } - QVERIFY(!appLinkCmd.contains("libstatic2.a")); - QVERIFY(!appLinkCmd.contains("libdynamic2.so")); } + QVERIFY(!appLinkCmd.isEmpty()); + if (isNormalUnix) { + const std::regex rpathLinkRex("-rpath-link=\\S*/" + + relativeProductBuildDir("dynamic2").toStdString()); + const auto ln = appLinkCmd.toStdString(); + QVERIFY(std::regex_search(ln, rpathLinkRex)); + } + QVERIFY(!appLinkCmd.contains("libstatic2.a")); + QVERIFY(!appLinkCmd.contains("libdynamic2.so")); } void TestApi::listBuildSystemFiles() @@ -1652,7 +1664,7 @@ void TestApi::localProfiles() qbs::ProductData libClang; qbs::ProductData appDebug; qbs::ProductData appRelease; - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.name() == "lib") { if (p.profile() == "mingwProfile") libMingw = p; @@ -1722,7 +1734,7 @@ void TestApi::localProfiles() products = project.allProducts(); QCOMPARE(products.size(), 4); int clangProfiles = 0; - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "clangProfile") { ++clangProfiles; moduleProps = p.moduleProperties(); @@ -1818,7 +1830,8 @@ void TestApi::multiArch() QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QCOMPARE(project.profile(), profileName()); - const QList<qbs::ProductData> &products = project.projectData().products(); + const qbs::ProjectData projectData = project.projectData(); + const QList<qbs::ProductData> &products = projectData.products(); QCOMPARE(products.size(), 3); QList<qbs::ProductData> hostProducts; QList<qbs::ProductData> targetProducts; @@ -1877,26 +1890,23 @@ void TestApi::multiArch() QFile p2ArtifactInstalled(installRoot + "/host/host-tool.output"); QVERIFY2(p2ArtifactInstalled.exists(), qPrintable(p2ArtifactInstalled.fileName())); - // Error check: Try to build for the same profile twice. + // Specifying the same profile twice should not result in an attempt to multiplex. overriddenValues.insert("project.targetProfile", hostProfile.name()); setupParams.setOverriddenValues(overriddenValues); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); - QVERIFY(setupJob->error().hasError()); - QVERIFY2(setupJob->error().toString().contains("Duplicate entry 'host' in qbs.profiles."), - qPrintable(setupJob->error().toString())); + QVERIFY(!setupJob->error().hasError()); + QCOMPARE(int(setupJob->project().projectData().products().size()), 2); - // Error check: Try to build for the same profile twice, this time attaching - // the properties via the product name. + // The same, but this time attaching the properties via the product name. overriddenValues.remove(QStringLiteral("project.targetProfile")); overriddenValues.insert("products.p1.myProfiles", targetProfile.name() + ',' + targetProfile.name()); setupParams.setOverriddenValues(overriddenValues); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); - QVERIFY(setupJob->error().hasError()); - QVERIFY2(setupJob->error().toString().contains("Duplicate entry 'target' in qbs.profiles."), - qPrintable(setupJob->error().toString())); + QVERIFY(!setupJob->error().hasError()); + QCOMPARE(int(setupJob->project().projectData().products().size()), 2); } struct ProductDataSelector @@ -1915,7 +1925,8 @@ struct ProductDataSelector bool qbsPropertiesMatch(const qbs::ProductData &p) const { for (auto it = qbsProperties.begin(); it != qbsProperties.end(); ++it) { - if (it.value() != p.moduleProperties().getModuleProperty("qbs", it.key())) + if (!qbs::qVariantsEqual( + it.value(), p.moduleProperties().getModuleProperty("qbs", it.key()))) return false; } return true; @@ -2210,7 +2221,7 @@ void TestApi::newPatternMatch() void TestApi::nonexistingProjectPropertyFromProduct() { qbs::SetupProjectParameters setupParams - = defaultSetupParameters("nonexistingprojectproperties"); + = defaultSetupParameters("nonexistingprojectproperties/invalidaccessfromproduct.qbs"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); @@ -2519,6 +2530,7 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &proje setupParams.setLibexecPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH))); setupParams.setTopLevelProfile(profileName()); + setupParams.setMaxJobCount(2); setupParams.setConfigurationName(QStringLiteral("default")); setupParams.setSettingsDirectory(settings()->baseDirectory()); return setupParams; @@ -2703,12 +2715,15 @@ void TestApi::restoredWarnings() waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 2); + QCOMPARE(toSet(m_logSink->warnings).size(), 5); const auto beforeErrors = m_logSink->warnings; for (const qbs::ErrorInfo &e : beforeErrors) { const QString msg = e.toString(); QVERIFY2(msg.contains("Superfluous version") - || msg.contains("Property 'blubb' is not declared"), + || msg.contains("Property 'blubb' is not declared") + || msg.contains("this one comes from a thread") + || msg.contains("Product 'theOtherProduct' had errors and was disabled") + || msg.contains("Product 'theProduct' had errors and was disabled"), qPrintable(msg)); } m_logSink->warnings.clear(); @@ -2718,25 +2733,29 @@ void TestApi::restoredWarnings() waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 2); + QCOMPARE(toSet(m_logSink->warnings).size(), 5); m_logSink->warnings.clear(); // Re-resolving with changes: Errors come from the re-resolving, stored ones must be suppressed. QVariantMap overridenValues; - overridenValues.insert("products.theProduct.moreFiles", true); + overridenValues.insert("products.aThirdProduct.moreFiles", true); setupParams.setOverriddenValues(overridenValues); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 3); // One more for the additional group + QCOMPARE(toSet(m_logSink->warnings).size(), 6); // One more for the additional group const auto afterErrors = m_logSink->warnings; for (const qbs::ErrorInfo &e : afterErrors) { const QString msg = e.toString(); - QVERIFY2(msg.contains("Superfluous version") - || msg.contains("Property 'blubb' is not declared") - || msg.contains("blubb.cpp' does not exist"), - qPrintable(msg)); + QVERIFY2( + msg.contains("Superfluous version") || msg.contains("Property 'blubb' is not declared") + || msg.contains("blubb.txt' does not exist") + || msg.contains("this one comes from a thread") + || msg.contains("Product 'theOtherProduct' had errors and was disabled") + || msg.contains("Product 'theThirdProduct' had errors and was disabled") + || msg.contains("Product 'theProduct' had errors and was disabled"), + qPrintable(msg)); } m_logSink->warnings.clear(); } |