| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "CMakeGUITest.h" | |
| #include <QApplication> | |
| #include <QEventLoop> | |
| #include <QFile> | |
| #include <QJsonArray> | |
| #include <QJsonDocument> | |
| #include <QJsonObject> | |
| #include <QMessageBox> | |
| #include <QSettings> | |
| #include <QString> | |
| #include <QStringList> | |
| #include <QTimer> | |
| #include <QtGlobal> | |
| #include <QtTest> | |
| #include "CMakeSetupDialog.h" | |
| #include "CatchShow.h" | |
| #include "FirstConfigure.h" | |
| #include "QCMake.h" | |
| using WindowSetupHelper = std::function<void(CMakeSetupDialog*)>; | |
| Q_DECLARE_METATYPE(WindowSetupHelper) | |
| namespace { | |
| void loopSleep(int msecs = 500) | |
| { | |
| QEventLoop loop; | |
| QTimer::singleShot(msecs, &loop, &QEventLoop::quit); | |
| loop.exec(); | |
| } | |
| } | |
| CMakeGUITest::CMakeGUITest(CMakeSetupDialog* window, QObject* parent) | |
| : QObject(parent) | |
| , m_window(window) | |
| { | |
| } | |
| void CMakeGUITest::tryConfigure(int expectedResult, int timeout) | |
| { | |
| auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); | |
| bool done = false; | |
| CatchShow catchConfigure; | |
| catchConfigure.setCallback<FirstConfigure>([&done](FirstConfigure* dialog) { | |
| if (done) { | |
| return; | |
| } | |
| done = true; | |
| dialog->findChild<StartCompilerSetup*>()->setCurrentGenerator( | |
| CMAKE_GENERATOR); | |
| dialog->accept(); | |
| }); | |
| CatchShow catchMessages; | |
| catchMessages.setCallback<QMessageBox>([](QMessageBox* box) { | |
| if (box->text().contains("Build directory does not exist")) { | |
| box->accept(); | |
| } | |
| if (box->text().contains("Error in configuration process")) { | |
| box->accept(); | |
| } | |
| }); | |
| QSignalSpy configureDoneSpy(cmake, &QCMake::configureDone); | |
| QVERIFY(configureDoneSpy.isValid()); | |
| QMetaObject::invokeMethod( | |
| this->m_window, [this]() { this->m_window->ConfigureButton->click(); }, | |
| Qt::QueuedConnection); | |
| QVERIFY(configureDoneSpy.wait(timeout)); | |
| QList<QVariant> configureDoneSignalArguments = configureDoneSpy.takeFirst(); | |
| QCOMPARE(configureDoneSignalArguments.at(0).toInt(), expectedResult); | |
| } | |
| void CMakeGUITest::tryGenerate(int expectedResult, int timeout) | |
| { | |
| auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); | |
| CatchShow catchMessages; | |
| catchMessages.setCallback<QMessageBox>([](QMessageBox* box) { | |
| if (box->text().contains("Error in generation process")) { | |
| box->accept(); | |
| } | |
| }); | |
| QSignalSpy generateDoneSpy(cmake, &QCMake::generateDone); | |
| QVERIFY(generateDoneSpy.isValid()); | |
| QMetaObject::invokeMethod( | |
| this->m_window, [this]() { this->m_window->GenerateButton->click(); }, | |
| Qt::QueuedConnection); | |
| QVERIFY(generateDoneSpy.wait(timeout)); | |
| QList<QVariant> generateDoneSignalArguments = generateDoneSpy.takeFirst(); | |
| QCOMPARE(generateDoneSignalArguments.at(0).toInt(), expectedResult); | |
| } | |
| void CMakeGUITest::sourceBinaryArgs() | |
| { | |
| QFETCH(QString, sourceDir); | |
| QFETCH(QString, binaryDir); | |
| // Wait a bit for everything to update | |
| loopSleep(); | |
| QCOMPARE(this->m_window->SourceDirectory->text(), sourceDir); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), binaryDir); | |
| } | |
| void CMakeGUITest::sourceBinaryArgs_data() | |
| { | |
| QTest::addColumn<QString>("sourceDir"); | |
| QTest::addColumn<QString>("binaryDir"); | |
| QTest::newRow("sourceAndBinaryDir") | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceAndBinaryDir/src" | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceAndBinaryDir/build"; | |
| QTest::newRow("sourceAndBinaryDirRelative") << CMakeGUITest_BINARY_DIR | |
| "/sourceBinaryArgs-sourceAndBinaryDirRelative/src" | |
| << CMakeGUITest_BINARY_DIR | |
| "/sourceBinaryArgs-sourceAndBinaryDirRelative/build"; | |
| QTest::newRow("sourceDir") | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceDir/src" | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceDir"; | |
| QTest::newRow("binaryDir") | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-binaryDir/src" | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-binaryDir/build"; | |
| QTest::newRow("noExist") << "" | |
| << ""; | |
| QTest::newRow("noExistConfig") | |
| << "" | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfig/oldbuild"; | |
| QTest::newRow("noExistConfigExists") | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfigExists/src" | |
| << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfigExists/build"; | |
| } | |
| void CMakeGUITest::simpleConfigure() | |
| { | |
| QFETCH(QString, sourceDir); | |
| QFETCH(QString, binaryDir); | |
| QFETCH(int, expectedResult); | |
| this->m_window->SourceDirectory->setText(sourceDir); | |
| this->m_window->BinaryDirectory->setCurrentText(binaryDir); | |
| // Wait a bit for everything to update | |
| loopSleep(); | |
| this->tryConfigure(expectedResult, 1000); | |
| } | |
| void CMakeGUITest::simpleConfigure_data() | |
| { | |
| QTest::addColumn<QString>("sourceDir"); | |
| QTest::addColumn<QString>("binaryDir"); | |
| QTest::addColumn<int>("expectedResult"); | |
| QTest::newRow("success") << CMakeGUITest_BINARY_DIR | |
| "/simpleConfigure-success/src" | |
| << CMakeGUITest_BINARY_DIR | |
| "/simpleConfigure-success/build" | |
| << 0; | |
| QTest::newRow("fail") << CMakeGUITest_BINARY_DIR "/simpleConfigure-fail/src" | |
| << CMakeGUITest_BINARY_DIR | |
| "/simpleConfigure-fail/build" | |
| << -1; | |
| } | |
| void CMakeGUITest::instrumentation() | |
| { | |
| this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR | |
| "/instrumentation/src"); | |
| this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR | |
| "/instrumentation/build"); | |
| // Wait a bit for everything to update | |
| loopSleep(); | |
| this->tryConfigure(); | |
| this->tryConfigure(); | |
| this->tryGenerate(); | |
| } | |
| void CMakeGUITest::environment() | |
| { | |
| auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); | |
| this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR | |
| "/environment/src"); | |
| this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR | |
| "/environment/build"); | |
| // We are already testing EnvironmentDialog, so just trust that it's | |
| // connected correctly and modify the environment directly. | |
| auto env = cmake->environment(); | |
| env.insert("ADDED_VARIABLE", "Added variable"); | |
| env.insert("CHANGED_VARIABLE", "Changed variable"); | |
| env.remove("REMOVED_VARIABLE"); | |
| cmake->setEnvironment(env); | |
| // Wait a bit for everything to update | |
| loopSleep(); | |
| this->tryConfigure(); | |
| auto penv = QProcessEnvironment::systemEnvironment(); | |
| QVERIFY(!penv.contains("ADDED_VARIABLE")); | |
| QCOMPARE(penv.value("KEPT_VARIABLE"), "Kept variable"); | |
| QCOMPARE(penv.value("CHANGED_VARIABLE"), "This variable will be changed"); | |
| QCOMPARE(penv.value("REMOVED_VARIABLE"), "Removed variable"); | |
| } | |
| void CMakeGUITest::presetArg() | |
| { | |
| QFETCH(WindowSetupHelper, setupFunction); | |
| QFETCH(QString, presetName); | |
| QFETCH(QString, sourceDir); | |
| QFETCH(QString, binaryDir); | |
| QFETCH(QCMakePropertyList, properties); | |
| if (setupFunction) { | |
| setupFunction(this->m_window); | |
| } | |
| // Wait a bit for everything to update | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), presetName); | |
| QCOMPARE(this->m_window->SourceDirectory->text(), sourceDir); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), binaryDir); | |
| auto actualProperties = | |
| this->m_window->CacheValues->cacheModel()->properties(); | |
| QCOMPARE(actualProperties.size(), properties.size()); | |
| for (int i = 0; i < actualProperties.size(); ++i) { | |
| // operator==() only compares Key, we need to compare Value and Type too | |
| QCOMPARE(actualProperties[i].Key, properties[i].Key); | |
| QCOMPARE(actualProperties[i].Value, properties[i].Value); | |
| QCOMPARE(actualProperties[i].Type, properties[i].Type); | |
| } | |
| } | |
| namespace { | |
| QCMakePropertyList makePresetProperties(QString const& name) | |
| { | |
| return QCMakePropertyList{ | |
| QCMakeProperty{ | |
| /*Key=*/"FALSE_VARIABLE", | |
| /*Value=*/false, | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::BOOL, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"FILEPATH_VARIABLE", | |
| /*Value=*/ | |
| QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src/CMakeLists.txt") | |
| .arg(name), | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::FILEPATH, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"ON_VARIABLE", | |
| /*Value=*/true, | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::BOOL, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"PATH_VARIABLE", | |
| /*Value=*/ | |
| QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src").arg(name), | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::PATH, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"SOURCE_DIR_NAME_VARIABLE", | |
| /*Value=*/"src", | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::STRING, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"STRING_VARIABLE", | |
| /*Value=*/"String value", | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::STRING, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"UNINITIALIZED_VARIABLE", | |
| /*Value=*/"Uninitialized value", | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::STRING, | |
| /*Advanced=*/false, | |
| }, | |
| }; | |
| } | |
| } | |
| void CMakeGUITest::presetArg_data() | |
| { | |
| QTest::addColumn<WindowSetupHelper>("setupFunction"); | |
| QTest::addColumn<QString>("presetName"); | |
| QTest::addColumn<QString>("sourceDir"); | |
| QTest::addColumn<QString>("binaryDir"); | |
| QTest::addColumn<QCMakePropertyList>("properties"); | |
| QTest::newRow("preset") << WindowSetupHelper{} << "ninja" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-preset/src" | |
| << CMakeGUITest_BINARY_DIR | |
| "/presetArg-preset/src/build" | |
| << makePresetProperties("presetArg-preset"); | |
| QTest::newRow("presetBinary") | |
| << WindowSetupHelper{} << "ninja" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/src" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/build" | |
| << makePresetProperties("presetArg-presetBinary"); | |
| QTest::newRow("presetBinaryChange") | |
| << WindowSetupHelper{ [](CMakeSetupDialog* window) { | |
| loopSleep(); | |
| window->Preset->setPresetName("ninja2"); | |
| } } | |
| << "ninja2" << CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src/build" | |
| << makePresetProperties("presetArg-presetBinaryChange"); | |
| QTest::newRow("noPresetBinaryChange") | |
| << WindowSetupHelper{ [](CMakeSetupDialog* window) { | |
| loopSleep(); | |
| window->Preset->setPresetName("ninja"); | |
| } } | |
| << "ninja" << CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src/build" | |
| << makePresetProperties("presetArg-noPresetBinaryChange"); | |
| QTest::newRow("presetConfigExists") | |
| << WindowSetupHelper{} << "ninja" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src/build" | |
| << makePresetProperties("presetArg-presetConfigExists"); | |
| QCMakePropertyList installDirProperties{ | |
| QCMakeProperty{ | |
| /*Key=*/"CMAKE_INSTALL_PREFIX", | |
| /*Value=*/ | |
| QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR | |
| "/presetArg-installDir/src/install"), | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::PATH, | |
| /*Advanced=*/false, | |
| }, | |
| QCMakeProperty{ | |
| /*Key=*/"CMAKE_TOOLCHAIN_FILE", | |
| /*Value=*/ | |
| QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR | |
| "/presetArg-installDir/src/toolchain.cmake"), | |
| /*Strings=*/{}, | |
| /*Help=*/"", | |
| /*Type=*/QCMakeProperty::FILEPATH, | |
| /*Advanced=*/false, | |
| }, | |
| }; | |
| QTest::newRow("installDir") | |
| << WindowSetupHelper{} << "installDir" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-installDir/src" | |
| << CMakeGUITest_BINARY_DIR "/presetArg-installDir/src/build" | |
| << installDirProperties; | |
| QTest::newRow("noExist") << WindowSetupHelper{} << QString{} | |
| << CMakeGUITest_BINARY_DIR "/presetArg-noExist/src" | |
| << "" << QCMakePropertyList{}; | |
| } | |
| namespace { | |
| void writePresets(QString const& buildDir, QStringList const& names) | |
| { | |
| QJsonArray presets{ | |
| QJsonObject{ | |
| { "name", "base" }, | |
| { "generator", "Ninja" }, | |
| { "binaryDir", | |
| QString::fromLocal8Bit("${sourceDir}/%1/${presetName}") | |
| .arg(buildDir) }, | |
| { "hidden", true }, | |
| }, | |
| }; | |
| for (auto const& name : names) { | |
| presets.append(QJsonObject{ | |
| { "name", name }, | |
| { "inherits", QJsonArray{ "base" } }, | |
| }); | |
| } | |
| QJsonDocument doc{ QJsonObject{ | |
| { "version", 1 }, | |
| { "configurePresets", presets }, | |
| } }; | |
| QFile presetsFile(CMakeGUITest_BINARY_DIR | |
| "/changingPresets/src/CMakePresets.json"); | |
| bool open = presetsFile.open(QIODevice::WriteOnly); | |
| Q_ASSERT(open); | |
| presetsFile.write(doc.toJson()); | |
| } | |
| } | |
| void CMakeGUITest::changingPresets() | |
| { | |
| QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src"); | |
| this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR | |
| "/changingPresets/src"); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), QString{}); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 0); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), ""); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), false); | |
| writePresets("build1", { "preset" }); | |
| this->m_window->ReloadPresetsButton->click(); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), QString{}); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), ""); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| this->m_window->Preset->setPresetName("preset"); | |
| this->m_window->ReloadPresetsButton->click(); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), "preset"); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| writePresets("build2", { "preset2", "preset" }); | |
| this->m_window->ReloadPresetsButton->click(); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), "preset"); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 2); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| writePresets("build3", { "preset2" }); | |
| this->m_window->ReloadPresetsButton->click(); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), QString{}); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| this->m_window->Preset->setPresetName("preset2"); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), "preset2"); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src2"); | |
| QFile::copy(CMakeGUITest_BINARY_DIR "/changingPresets/src/CMakePresets.json", | |
| CMakeGUITest_BINARY_DIR | |
| "/changingPresets/src2/CMakePresets.json"); | |
| this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR | |
| "/changingPresets/src2"); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), QString{}); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| this->m_window->Preset->setPresetName("preset2"); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), "preset2"); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 1); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), true); | |
| QFile(CMakeGUITest_BINARY_DIR "/changingPresets/src2/CMakePresets.json") | |
| .remove(); | |
| this->m_window->ReloadPresetsButton->click(); | |
| loopSleep(); | |
| QCOMPARE(this->m_window->Preset->presetName(), QString{}); | |
| QCOMPARE(this->m_window->Preset->presets().size(), 0); | |
| QCOMPARE(this->m_window->BinaryDirectory->currentText(), | |
| CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2"); | |
| QCOMPARE(this->m_window->Preset->isEnabled(), false); | |
| } | |
| namespace { | |
| QString modelValue(QCMakeCacheModel* model, QString const& key) | |
| { | |
| for (auto const& prop : model->properties()) { | |
| if (prop.Key == key) { | |
| return prop.Value.toString(); | |
| } | |
| } | |
| return QString{}; | |
| } | |
| QString readCacheValue(QString const& buildDir, QString const& key) | |
| { | |
| QFile cache(buildDir + "/CMakeCache.txt"); | |
| if (!cache.open(QIODevice::ReadOnly | QIODevice::Text)) { | |
| return QString{}; | |
| } | |
| QString const prefix = key + ":"; | |
| while (!cache.atEnd()) { | |
| QString const line = QString::fromLocal8Bit(cache.readLine()).trimmed(); | |
| if (line.startsWith(prefix)) { | |
| int const eq = line.indexOf('='); | |
| if (eq >= 0) { | |
| return line.mid(eq + 1); | |
| } | |
| } | |
| } | |
| return QString{}; | |
| } | |
| } | |
| void CMakeGUITest::presetApplyOrdering() | |
| { | |
| QFETCH(QString, scenario); | |
| QFETCH(QString, buildDir); | |
| QFETCH(QString, expectedValue); | |
| auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); | |
| // Let the initial cache load from the preconfigured build settle. | |
| loopSleep(); | |
| QSignalSpy configureDoneSpy(cmake, &QCMake::configureDone); | |
| QVERIFY(configureDoneSpy.isValid()); | |
| // Select and configure in one main-thread run, with no yield between, to | |
| // hit the race. | |
| this->m_window->Preset->setPresetName("raceA"); | |
| if (scenario == "replace" || scenario == "replaceCycle") { | |
| this->m_window->Preset->setPresetName("raceB"); | |
| } | |
| if (scenario == "replaceCycle") { | |
| this->m_window->Preset->setPresetName("raceA"); | |
| } | |
| // Dependent actions must be off the instant the request is submitted. | |
| QVERIFY(!this->m_window->ConfigureButton->isEnabled()); | |
| QVERIFY(!this->m_window->GenerateButton->isEnabled()); | |
| // Activating while a preset applies must not configure with the stale model. | |
| this->m_window->ConfigureButton->click(); | |
| QCOMPARE(configureDoneSpy.count(), 0); | |
| // Gate lifts only once the accepted completion has installed the model. | |
| QTRY_VERIFY(this->m_window->ConfigureButton->isEnabled()); | |
| // The click during the pending window did nothing. | |
| QCOMPARE(configureDoneSpy.count(), 0); | |
| // Model holds the winning preset, not the preconfigured value. | |
| QCOMPARE(modelValue(this->m_window->CacheValues->cacheModel(), "RACE_VALUE"), | |
| expectedValue); | |
| // A real configure writes that value through to the cache. | |
| this->tryConfigure(); | |
| QCOMPARE(readCacheValue(buildDir, "RACE_VALUE"), expectedValue); | |
| } | |
| void CMakeGUITest::presetApplyOrdering_data() | |
| { | |
| QTest::addColumn<QString>("scenario"); | |
| QTest::addColumn<QString>("buildDir"); | |
| QTest::addColumn<QString>("expectedValue"); | |
| QTest::newRow("apply") << "apply" | |
| << CMakeGUITest_BINARY_DIR | |
| "/presetApplyOrdering-apply/build" | |
| << "presetA"; | |
| QTest::newRow("replace") << "replace" | |
| << CMakeGUITest_BINARY_DIR | |
| "/presetApplyOrdering-replace/build" | |
| << "presetB"; | |
| QTest::newRow("replaceCycle") | |
| << "replaceCycle" | |
| << CMakeGUITest_BINARY_DIR "/presetApplyOrdering-replaceCycle/build" | |
| << "presetA"; | |
| } | |
| void CMakeGUITest::presetApplyStartup() | |
| { | |
| QFETCH(QString, requestedPreset); | |
| QFETCH(bool, available); | |
| // The deferred gate must have the actions off at startup, before presets | |
| // load. Deterministic: pending was set on the main thread before the event | |
| // loop processed any worker result. | |
| QVERIFY(!this->m_window->ConfigureButton->isEnabled()); | |
| QVERIFY(!this->m_window->GenerateButton->isEnabled()); | |
| // Gate lifts once presets resolve, applied or not. | |
| QTRY_VERIFY(this->m_window->ConfigureButton->isEnabled()); | |
| QVERIFY(this->m_window->GenerateButton->isEnabled()); | |
| if (available) { | |
| QCOMPARE(this->m_window->Preset->presetName(), requestedPreset); | |
| QCOMPARE( | |
| modelValue(this->m_window->CacheValues->cacheModel(), "RACE_VALUE"), | |
| QString("presetA")); | |
| } else { | |
| QVERIFY(this->m_window->Preset->presetName() != requestedPreset); | |
| } | |
| } | |
| void CMakeGUITest::presetApplyStartup_data() | |
| { | |
| QTest::addColumn<QString>("requestedPreset"); | |
| QTest::addColumn<bool>("available"); | |
| QTest::newRow("available") << "raceA" << true; | |
| QTest::newRow("unavailable") << "doesNotExist" << false; | |
| } | |
| void SetupDefaultQSettings() | |
| { | |
| QSettings::setDefaultFormat(QSettings::IniFormat); | |
| QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, | |
| QString::fromLocal8Bit(qgetenv("CMake_GUI_CONFIG_DIR"))); | |
| } | |
| int CMakeGUIExec(CMakeSetupDialog* window) | |
| { | |
| auto nameArray = qgetenv("CMake_GUI_TEST_NAME"); | |
| auto name = QString::fromLocal8Bit(nameArray); | |
| if (name.isEmpty()) { | |
| return QApplication::exec(); | |
| } | |
| QStringList args{ "CMakeGUITest", name }; | |
| CMakeGUITest obj(window); | |
| return QTest::qExec(&obj, args); | |
| } |