aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/blackbox/tst_blackbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/blackbox/tst_blackbox.cpp')
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp644
1 files changed, 644 insertions, 0 deletions
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index a2e8238c9..3a90d8ccb 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -43,6 +43,7 @@
#include <tools/version.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
@@ -53,6 +54,7 @@
#include <QtCore/qtemporarydir.h>
#include <QtCore/qtemporaryfile.h>
+#include <algorithm>
#include <functional>
#include <regex>
#include <utility>
@@ -5308,6 +5310,648 @@ void TestBlackbox::qbsConfig()
}
}
+static QJsonObject getNextSessionPacket(QProcess &session, QByteArray &data)
+{
+ int totalSize = -1;
+ QElapsedTimer timer;
+ timer.start();
+ QByteArray msg;
+ while (totalSize == -1 || msg.size() < totalSize) {
+ if (data.isEmpty())
+ session.waitForReadyRead(1000);
+ if (timer.elapsed() >= 10000)
+ return QJsonObject();
+ data += session.readAllStandardOutput();
+ if (totalSize == -1) {
+ static const QByteArray magicString = "qbsmsg:";
+ const int magicStringOffset = data.indexOf(magicString);
+ if (magicStringOffset == -1)
+ continue;
+ const int sizeOffset = magicStringOffset + magicString.length();
+ const int newlineOffset = data.indexOf('\n', sizeOffset);
+ if (newlineOffset == -1)
+ continue;
+ const QByteArray sizeString = data.mid(sizeOffset, newlineOffset - sizeOffset);
+ bool isNumber;
+ const int size = sizeString.toInt(&isNumber);
+ if (!isNumber || size <= 0)
+ return QJsonObject();
+ data = data.mid(newlineOffset + 1);
+ totalSize = size;
+ }
+ const int bytesToTake = std::min(totalSize - msg.size(), data.size());
+ msg += data.left(bytesToTake);
+ data = data.mid(bytesToTake);
+ }
+ return QJsonDocument::fromJson(QByteArray::fromBase64(msg)).object();
+}
+
+void TestBlackbox::qbsSession()
+{
+ QDir::setCurrent(testDataDir + "/qbs-session");
+ QProcess sessionProc;
+ sessionProc.start(qbsExecutableFilePath, QStringList("session"));
+
+ // Uncomment for debugging.
+ /*
+ connect(&sessionProc, &QProcess::readyReadStandardError, [&sessionProc] {
+ qDebug() << "stderr:" << sessionProc.readAllStandardError();
+ });
+ */
+
+ QVERIFY(sessionProc.waitForStarted());
+
+ const auto sendPacket = [&sessionProc](const QJsonObject &message) {
+ const QByteArray data = QJsonDocument(message).toJson().toBase64();
+ sessionProc.write("qbsmsg:");
+ sessionProc.write(QByteArray::number(data.length()));
+ sessionProc.write("\n");
+ sessionProc.write(data);
+ };
+
+ static const auto envToJson = [](const QProcessEnvironment &env) {
+ QJsonObject envObj;
+ const QStringList keys = env.keys();
+ for (const QString &key : keys)
+ envObj.insert(key, env.value(key));
+ return envObj;
+ };
+
+ static const auto envFromJson = [](const QJsonValue &v) {
+ const QJsonObject obj = v.toObject();
+ QProcessEnvironment env;
+ for (auto it = obj.begin(); it != obj.end(); ++it)
+ env.insert(it.key(), it.value().toString());
+ return env;
+ };
+
+ QByteArray incomingData;
+
+ // Wait for and verify hello packet.
+ QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type"), "hello");
+ QCOMPARE(receivedMessage.value("api-level").toInt(), 1);
+ QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 1);
+
+ // Resolve & verify structure
+ QJsonObject resolveMessage;
+ resolveMessage.insert("type", "resolve-project");
+ resolveMessage.insert("top-level-profile", profileName());
+ resolveMessage.insert("configuration-name", "my-config");
+ resolveMessage.insert("project-file-path", QDir::currentPath() + "/qbs-session.qbs");
+ resolveMessage.insert("build-root", QDir::currentPath());
+ resolveMessage.insert("settings-directory", settings()->baseDirectory());
+ QJsonObject overriddenValues;
+ overriddenValues.insert("products.theLib.cpp.cxxLanguageVersion", "c++17");
+ resolveMessage.insert("overridden-properties", overriddenValues);
+ resolveMessage.insert("environment", envToJson(QProcessEnvironment::systemEnvironment()));
+ resolveMessage.insert("data-mode", "only-if-changed");
+ resolveMessage.insert("log-time", true);
+ resolveMessage.insert("module-properties",
+ QJsonArray::fromStringList({"cpp.cxxLanguageVersion"}));
+ sendPacket(resolveMessage);
+ bool receivedLogData = false;
+ bool receivedStartedSignal = false;
+ bool receivedProgressData = false;
+ bool receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-resolved") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("name").toString(), "qbs-session");
+ const QJsonArray products = projectData.value("products").toArray();
+ QCOMPARE(products.size(), 2);
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("name").toString();
+ QVERIFY(!productName.isEmpty());
+ QVERIFY2(product.value("is-enabled").toBool(), qPrintable(productName));
+ bool theLib = false;
+ bool theApp = false;
+ if (productName == "theLib")
+ theLib = true;
+ else if (productName == "theApp")
+ theApp = true;
+ QVERIFY2(theLib || theApp, qPrintable(productName));
+ const QJsonArray groups = product.value("groups").toArray();
+ if (theLib)
+ QVERIFY(groups.size() >= 3);
+ else
+ QVERIFY(!groups.isEmpty());
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QJsonArray sourceArtifacts
+ = group.value("source-artifacts").toArray();
+ const auto findArtifact = [&sourceArtifacts](const QString fileName) {
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QJsonObject artifact = v.toObject();
+ if (QFileInfo(artifact.value("file-path").toString()).fileName()
+ == fileName) {
+ return artifact;
+ }
+ }
+ return QJsonObject();
+ };
+ const QString groupName = group.value("name").toString();
+ const auto getCxxLanguageVersion = [&group, &product] {
+ QJsonObject moduleProperties = group.value("module-properties").toObject();
+ if (moduleProperties.isEmpty())
+ moduleProperties = product.value("module-properties").toObject();
+ return moduleProperties.toVariantMap().value("cpp.cxxLanguageVersion")
+ .toStringList();
+ };
+ if (groupName == "sources") {
+ const QJsonObject artifact = findArtifact("lib.cpp");
+ QVERIFY2(!artifact.isEmpty(), "lib.cpp");
+ QCOMPARE(getCxxLanguageVersion(), {"c++17"});
+ } else if (groupName == "headers") {
+ const QJsonObject artifact = findArtifact("lib.h");
+ QVERIFY2(!artifact.isEmpty(), "lib.h");
+ } else if (groupName == "theApp") {
+ const QJsonObject artifact = findArtifact("main.cpp");
+ QVERIFY2(!artifact.isEmpty(), "main.cpp");
+ QCOMPARE(getCxxLanguageVersion(), {"c++14"});
+ }
+ }
+ }
+ break;
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+
+ // First build: No install, log time, default command description.
+ QJsonObject buildRequest;
+ buildRequest.insert("type", "build-project");
+ buildRequest.insert("log-time", true);
+ buildRequest.insert("install", false);
+ buildRequest.insert("data-mode", "only-if-changed");
+ sendPacket(buildRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ bool receivedCommandDescription = false;
+ bool receivedProcessResult = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("name").toString(), "qbs-session");
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType == "command-description") {
+ if (receivedMessage.value("message").toString().contains("compiling main.cpp"))
+ receivedCommandDescription = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY(receivedCommandDescription);
+ QVERIFY(receivedProcessResult);
+ const QString &exeFilePath = QDir::currentPath() + '/'
+ + relativeExecutableFilePath("theApp", "my-config");
+ QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath));
+ const QString defaultInstallRoot = QDir::currentPath() + '/'
+ + relativeBuildDir("my-config") + "/install-root";
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+
+ // Clean.
+ QJsonObject cleanRequest;
+ cleanRequest.insert("type", "clean-project");
+ cleanRequest.insert("settings-dir", settings()->baseDirectory());
+ cleanRequest.insert("log-time", true);
+ sendPacket(cleanRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-cleaned") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY2(!regularFileExists(exeFilePath), qPrintable(exeFilePath));
+
+ // Second build: Do not log the time, show command lines.
+ buildRequest.insert("log-time", false);
+ buildRequest.insert("command-echo-mode", "command-line");
+ sendPacket(buildRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ receivedCommandDescription = false;
+ receivedProcessResult = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QVERIFY(projectData.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType == "command-description") {
+ if (receivedMessage.value("message").toString().contains(
+ QDir::separator() + QString("main.cpp"))) {
+ receivedCommandDescription = true;
+ }
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(!receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY(receivedCommandDescription);
+ QVERIFY(receivedProcessResult);
+ QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath));
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+
+ // Install.
+ QJsonObject installRequest;
+ installRequest.insert("type", "install-project");
+ installRequest.insert("log-time", true);
+ const QString customInstallRoot = QDir::currentPath() + "/my-install-root";
+ QVERIFY2(!QFile::exists(customInstallRoot), qPrintable(customInstallRoot));
+ installRequest.insert("install-root", customInstallRoot);
+ sendPacket(installRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "install-done") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+ QVERIFY2(directoryExists(customInstallRoot), qPrintable(customInstallRoot));
+
+ // Retrieve modified environment.
+ QJsonObject getRunEnvRequest;
+ getRunEnvRequest.insert("type", "get-run-environment");
+ getRunEnvRequest.insert("product", "theApp");
+ const QProcessEnvironment inEnv = QProcessEnvironment::systemEnvironment();
+ QVERIFY(!inEnv.contains("MY_MODULE"));
+ getRunEnvRequest.insert("base-environment", envToJson(inEnv));
+ sendPacket(getRunEnvRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("run-environment"));
+ QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QProcessEnvironment outEnv = envFromJson(receivedMessage.value("full-environment"));
+ QVERIFY(outEnv.keys().size() > inEnv.keys().size());
+ QCOMPARE(outEnv.value("MY_MODULE"), QString("1"));
+
+ // Add two files to library and re-build.
+ QJsonObject addFilesRequest;
+ addFilesRequest.insert("type", "add-files");
+ addFilesRequest.insert("product", "theLib");
+ addFilesRequest.insert("group", "sources");
+ addFilesRequest.insert("files",
+ QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp",
+ QDir::currentPath() + "/file2.cpp"}));
+ sendPacket(addFilesRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("files-added"));
+ error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QJsonArray products = projectData.value("products").toArray();
+ bool file1 = false;
+ bool file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
+ }
+ }
+ QVERIFY(file1);
+ QVERIFY(file2);
+ receivedReply = false;
+ receivedProcessResult = false;
+ bool compiledFile1 = false;
+ bool compiledFile2 = false;
+ bool compiledMain = false;
+ bool compiledLib = false;
+ buildRequest.remove("command-echo-mode");
+ sendPacket(buildRequest);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "command-description") {
+ const QString msg = receivedMessage.value("message").toString();
+ if (msg.contains("compiling file1.cpp"))
+ compiledFile1 = true;
+ else if (msg.contains("compiling file2.cpp"))
+ compiledFile2 = true;
+ else if (msg.contains("compiling main.cpp"))
+ compiledMain = true;
+ else if (msg.contains("compiling lib.cpp"))
+ compiledLib = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(!receivedProcessResult);
+ QVERIFY(compiledFile1);
+ QVERIFY(compiledFile2);
+ QVERIFY(!compiledLib);
+ QVERIFY(!compiledMain);
+
+ // Remove one of the newly added files again and re-build.
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("file1.cpp");
+ touch("file2.cpp");
+ touch("main.cpp");
+ QJsonObject removeFilesRequest;
+ removeFilesRequest.insert("type", "remove-files");
+ removeFilesRequest.insert("product", "theLib");
+ removeFilesRequest.insert("group", "sources");
+ removeFilesRequest.insert("files",
+ QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp"}));
+ sendPacket(removeFilesRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("files-removed"));
+ error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ projectData = receivedMessage.value("project-data").toObject();
+ products = projectData.value("products").toArray();
+ file1 = false;
+ file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
+ }
+ }
+ QVERIFY(!file1);
+ QVERIFY(file2);
+ receivedReply = false;
+ receivedProcessResult = false;
+ compiledFile1 = false;
+ compiledFile2 = false;
+ compiledMain = false;
+ compiledLib = false;
+ sendPacket(buildRequest);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "command-description") {
+ const QString msg = receivedMessage.value("message").toString();
+ if (msg.contains("compiling file1.cpp"))
+ compiledFile1 = true;
+ else if (msg.contains("compiling file2.cpp"))
+ compiledFile2 = true;
+ else if (msg.contains("compiling main.cpp"))
+ compiledMain = true;
+ else if (msg.contains("compiling lib.cpp"))
+ compiledLib = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedProcessResult);
+ QVERIFY(!compiledFile1);
+ QVERIFY(compiledFile2);
+ QVERIFY(!compiledLib);
+ QVERIFY(compiledMain);
+
+ // Get generated files.
+ QJsonObject genFilesRequestPerFile;
+ genFilesRequestPerFile.insert("source-file", QDir::currentPath() + "/main.cpp");
+ genFilesRequestPerFile.insert("tags", QJsonArray{QJsonValue("obj")});
+ QJsonObject genFilesRequestPerProduct;
+ genFilesRequestPerProduct.insert("full-display-name", "theApp");
+ genFilesRequestPerProduct.insert("requests", QJsonArray({genFilesRequestPerFile}));
+ QJsonObject genFilesRequest;
+ genFilesRequest.insert("type", "get-generated-files-for-sources");
+ genFilesRequest.insert("products", QJsonArray({genFilesRequestPerProduct}));
+ sendPacket(genFilesRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("generated-files-for-sources"));
+ const QJsonArray products = receivedMessage.value("products").toArray();
+ QCOMPARE(products.size(), 1);
+ const QJsonArray results = products.first().toObject().value("results").toArray();
+ QCOMPARE(results.size(), 1);
+ const QJsonObject result = results.first().toObject();
+ QCOMPARE(result.value("source-file"), QDir::currentPath() + "/main.cpp");
+ const QJsonArray generatedFiles = result.value("generated-files").toArray();
+ QCOMPARE(generatedFiles.count(), 1);
+ QCOMPARE(QFileInfo(generatedFiles.first().toString()).fileName(),
+ objectFileName("main.cpp", profileName()));
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ // Release project.
+ const QJsonObject releaseRequest{qMakePair(QString("type"), QJsonValue("release-project"))};
+ sendPacket(releaseRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("project-released"));
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ // Get build graph info.
+ QJsonObject loadProjectMessage;
+ loadProjectMessage.insert("type", "resolve-project");
+ loadProjectMessage.insert("configuration-name", "my-config");
+ loadProjectMessage.insert("build-root", QDir::currentPath());
+ loadProjectMessage.insert("settings-dir", settings()->baseDirectory());
+ loadProjectMessage.insert("restore-behavior", "restore-only");
+ loadProjectMessage.insert("data-mode", "only-if-changed");
+ sendPacket(loadProjectMessage);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ if (receivedMessage.value("type") != "project-resolved")
+ continue;
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QString bgFilePath = QDir::currentPath() + '/'
+ + relativeBuildGraphFilePath("my-config");
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("build-graph-file-path").toString(), bgFilePath);
+ QCOMPARE(projectData.value("overridden-properties"), overriddenValues);
+ }
+ QVERIFY(receivedReply);
+
+ // Send unknown request.
+ const QJsonObject unknownRequest({qMakePair(QString("type"), QJsonValue("blubb"))});
+ sendPacket(unknownRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("protocol-error"));
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ QJsonObject quitRequest;
+ quitRequest.insert("type", "quit");
+ sendPacket(quitRequest);
+ QVERIFY(sessionProc.waitForFinished(3000));
+}
+
void TestBlackbox::radAfterIncompleteBuild_data()
{
QTest::addColumn<QString>("projectFileName");