diff options
Diffstat (limited to 'Tests/CMakeGUI')
33 files changed, 1729 insertions, 0 deletions
diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake new file mode 100644 index 0000000..2c6baf3 --- /dev/null +++ b/Tests/CMakeGUI/CMakeGUITest.cmake @@ -0,0 +1,158 @@ +function(run_cmake_gui_test name) + if(DEFINED ENV{CMakeGUITest_TEST_FILTER} AND NOT name MATCHES "$ENV{CMakeGUITest_TEST_FILTER}") + return() + endif() + + set(_fail) + + cmake_parse_arguments(_rcgt + "DO_CONFIGURE" + "GENERATOR" + "ARGS;CONFIGURE_ARGS" + ${ARGN} + ) + + string(REPLACE ":" "-" _file_name "${name}") + set(_srcdir "${CMakeGUITest_SOURCE_DIR}/${_file_name}") + set(_workdir "${CMakeGUITest_BINARY_DIR}/${_file_name}") + + file(REMOVE_RECURSE "${_workdir}") + file(MAKE_DIRECTORY "${_workdir}") + + set(_ini_in "${_srcdir}/CMakeSetup.ini.in") + if(EXISTS "${_ini_in}") + configure_file("${_ini_in}" "${_workdir}/config/Kitware/CMakeSetup.ini" @ONLY) + endif() + set(_cmakelists_in "${_srcdir}/CMakeLists.txt.in") + if(EXISTS "${_cmakelists_in}") + configure_file("${_cmakelists_in}" "${_workdir}/src/CMakeLists.txt" @ONLY) + endif() + set(_cmakepresets_in "${_srcdir}/CMakePresets.json.in") + if(EXISTS "${_cmakepresets_in}") + configure_file("${_cmakepresets_in}" "${_workdir}/src/CMakePresets.json" @ONLY) + endif() + if(_rcgt_DO_CONFIGURE) + if(NOT _rcgt_GENERATOR) + set(_rcgt_GENERATOR "${CMakeGUITest_GENERATOR}") + endif() + execute_process( + COMMAND "${CMAKE_COMMAND}" + -S "${_workdir}/src" + -B "${_workdir}/build" + -G "${_rcgt_GENERATOR}" + ${_rcgt_CONFIGURE_ARGS} + RESULT_VARIABLE _result + OUTPUT_VARIABLE _output + ERROR_VARIABLE _error + ) + if(_result) + set(_fail 1) + string(REPLACE "\n" "\n " _formatted_output "${_output}") + string(REPLACE "\n" "\n " _formatted_error "${_error}") + message(SEND_ERROR + "Configuring ${_workdir}/src failed with exit code ${_result}, should be 0\n" + "stdout:\n ${_formatted_output}\n" + "stderr:\n ${_formatted_error}" + ) + endif() + endif() + + set(ENV{CMake_GUI_TEST_NAME} "${name}") + set(ENV{CMake_GUI_CONFIG_DIR} "${_workdir}/config") + execute_process( + COMMAND "${CMakeGUITest_COMMAND}" ${_rcgt_ARGS} + WORKING_DIRECTORY "${_workdir}" + RESULT_VARIABLE _result + OUTPUT_VARIABLE _output + ERROR_VARIABLE _error + ) + if(_result) + set(_fail 1) + string(REPLACE "\n" "\n " _formatted_output "${_output}") + string(REPLACE "\n" "\n " _formatted_error "${_error}") + message(SEND_ERROR "CMake GUI test ${name} failed with exit code ${_result}, should be 0\n" + "stdout:\n ${_formatted_output}\n" + "stderr:\n ${_formatted_error}" + ) + endif() + + if(NOT _fail) + message(STATUS "${name} -- passed") + endif() +endfunction() + +run_cmake_gui_test(sourceBinaryArgs:sourceAndBinaryDir + ARGS + -S "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceAndBinaryDir/src" + -B "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceAndBinaryDir/build" + ) +run_cmake_gui_test(sourceBinaryArgs:sourceAndBinaryDirRelative + ARGS + "-Ssrc" + "-Bbuild" + ) +run_cmake_gui_test(sourceBinaryArgs:sourceDir + ARGS + "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceDir/src" + ) +run_cmake_gui_test(sourceBinaryArgs:binaryDir + DO_CONFIGURE + ARGS + "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-binaryDir/build" + ) +run_cmake_gui_test(sourceBinaryArgs:noExist + ARGS + "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExist/noexist" + ) +run_cmake_gui_test(sourceBinaryArgs:noExistConfig + ARGS + "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExistConfig/noexist" + ) +run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists + DO_CONFIGURE + ARGS + "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExistConfigExists/noexist" + ) + +run_cmake_gui_test(simpleConfigure:success) +run_cmake_gui_test(simpleConfigure:fail) + +unset(ENV{ADDED_VARIABLE}) +set(ENV{KEPT_VARIABLE} "Kept variable") +set(ENV{CHANGED_VARIABLE} "This variable will be changed") +set(ENV{REMOVED_VARIABLE} "Removed variable") +run_cmake_gui_test(environment) + +run_cmake_gui_test(presetArg:preset + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-preset/src" + "--preset=ninja" + ) +run_cmake_gui_test(presetArg:presetBinary + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/src" + -B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/build" + "--preset=ninja" + ) +run_cmake_gui_test(presetArg:presetBinaryChange + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/src" + -B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/build" + "--preset=ninja" + ) +run_cmake_gui_test(presetArg:noPresetBinaryChange + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/src" + -B "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/build" + ) +run_cmake_gui_test(presetArg:presetConfigExists + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetConfigExists/src" + "--preset=ninja" + ) +run_cmake_gui_test(presetArg:noExist + ARGS + -S "${CMakeGUITest_BINARY_DIR}/presetArg-noExist/src" + "--preset=noExist" + ) +run_cmake_gui_test(changingPresets) diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx new file mode 100644 index 0000000..2b5d973 --- /dev/null +++ b/Tests/CMakeGUI/CMakeGUITest.cxx @@ -0,0 +1,449 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "CMakeGUITest.h" + +#include "QCMake.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" + +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)); + + QCOMPARE(configureDoneSpy, { { 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::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(const QString& 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=*/"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"); + QTest::newRow("noExist") << WindowSetupHelper{} << QString{} + << CMakeGUITest_BINARY_DIR "/presetArg-noExist/src" + << "" << QCMakePropertyList{}; +} + +namespace { +void writePresets(const QString& buildDir, const QStringList& 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" }); + loopSleep(1500); + 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"); + 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" }); + loopSleep(1500); + 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" }); + loopSleep(1500); + 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(); + loopSleep(1500); + 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); +} + +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); +} diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h new file mode 100644 index 0000000..e6293a4 --- /dev/null +++ b/Tests/CMakeGUI/CMakeGUITest.h @@ -0,0 +1,29 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QObject> + +class CMakeSetupDialog; + +class CMakeGUITest : public QObject +{ + Q_OBJECT +public: + CMakeGUITest(CMakeSetupDialog* window, QObject* parent = nullptr); + +private: + CMakeSetupDialog* m_window = nullptr; + + void tryConfigure(int expectedResult = 0, int timeout = 60000); + +private slots: + void sourceBinaryArgs(); + void sourceBinaryArgs_data(); + void simpleConfigure(); + void simpleConfigure_data(); + void environment(); + void presetArg(); + void presetArg_data(); + void changingPresets(); +}; diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt new file mode 100644 index 0000000..4e8609b --- /dev/null +++ b/Tests/CMakeGUI/CMakeLists.txt @@ -0,0 +1,95 @@ +include(CMakeParseArguments) + +find_package(Qt5Test REQUIRED) + +include_directories( + ${CMake_SOURCE_DIR}/Source + ${CMake_SOURCE_DIR}/Source/QtDialog + ${CMake_BINARY_DIR}/Source/QtDialog + ) + +set(MOC_SRCS) +qt5_wrap_cpp(MOC_SRCS + CatchShow.h + ) +add_library(CMakeGUITestLib STATIC ${MOC_SRCS} + CatchShow.cxx + CatchShow.h + ) +target_link_libraries(CMakeGUITestLib Qt5::Core Qt5::Gui Qt5::Widgets) + +set(MOC_SRCS) +qt5_wrap_cpp(MOC_SRCS + CMakeGUITest.h + ) +add_executable(CMakeGUITest CMakeGUITest.cxx ${MOC_SRCS}) +target_link_libraries(CMakeGUITest CMakeGUIMainLib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets) +target_compile_definitions(CMakeGUITest PRIVATE + "CMakeGUITest_SOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" + "CMakeGUITest_BINARY_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\"" + "CMAKE_GENERATOR=\"${CMAKE_GENERATOR}\"" + ) + +add_test(NAME CMakeGUI COMMAND ${CMAKE_CMAKE_COMMAND} + "-DCMakeGUITest_COMMAND=$<TARGET_FILE:CMakeGUITest>" + "-DCMakeGUITest_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + "-DCMakeGUITest_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "-DCMakeGUITest_GENERATOR=${CMAKE_GENERATOR}" + -P "${CMAKE_CURRENT_LIST_DIR}/CMakeGUITest.cmake" + ) + +function(add_cmake_gui_lib_test name) + cmake_parse_arguments(_t "" "" "SOURCES;MOC_SOURCES" ${ARGN}) + + set(MOC_SRCS) + qt5_wrap_cpp(MOC_SRCS + ${_t_MOC_SOURCES} + ) + add_executable(${name} ${_t_SOURCES} ${MOC_SRCS}) + target_link_libraries(${name} CMakeGUILib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets) + + add_test(NAME "CMakeGUILib.${name}" COMMAND ${name}) +endfunction() + +add_cmake_gui_lib_test(CatchShow + SOURCES + CatchShowTest.cxx + CatchShowTest.h + MOC_SOURCES + CatchShowTest.h + ) +add_cmake_gui_lib_test(EnvironmentDialog + SOURCES + EnvironmentDialogTest.cxx + EnvironmentDialogTest.h + MOC_SOURCES + EnvironmentDialogTest.h + ) +add_cmake_gui_lib_test(QCMakeCacheModel + SOURCES + QCMakeCacheModelTest.cxx + QCMakeCacheModelTest.h + MOC_SOURCES + QCMakeCacheModelTest.h + ) +add_cmake_gui_lib_test(QCMakePreset + SOURCES + QCMakePresetTest.cxx + QCMakePresetTest.h + MOC_SOURCES + QCMakePresetTest.h + ) +add_cmake_gui_lib_test(QCMakePresetItemModel + SOURCES + QCMakePresetItemModelTest.cxx + QCMakePresetItemModelTest.h + MOC_SOURCES + QCMakePresetItemModelTest.h + ) +add_cmake_gui_lib_test(QCMakePresetComboBox + SOURCES + QCMakePresetComboBoxTest.cxx + QCMakePresetComboBoxTest.h + MOC_SOURCES + QCMakePresetComboBoxTest.h + ) diff --git a/Tests/CMakeGUI/CatchShow.cxx b/Tests/CMakeGUI/CatchShow.cxx new file mode 100644 index 0000000..aee2d9d --- /dev/null +++ b/Tests/CMakeGUI/CatchShow.cxx @@ -0,0 +1,25 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "CatchShow.h" + +#include <QCoreApplication> + +CatchShow::CatchShow(QObject* parent) + : QObject(parent) +{ + QCoreApplication::instance()->installEventFilter(this); +} + +bool CatchShow::eventFilter(QObject* obj, QEvent* event) +{ + if (this->m_callback && event->type() == QEvent::Show) { + this->m_callback(obj); + } + + return this->QObject::eventFilter(obj, event); +} + +int CatchShow::count() const +{ + return this->m_count; +} diff --git a/Tests/CMakeGUI/CatchShow.h b/Tests/CMakeGUI/CatchShow.h new file mode 100644 index 0000000..0254c15 --- /dev/null +++ b/Tests/CMakeGUI/CatchShow.h @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <functional> +#include <memory> + +#include <QObject> +#include <QWidget> + +class CatchShow : public QObject +{ + Q_OBJECT +public: + CatchShow(QObject* parent = nullptr); + + template <typename T, typename F> + void setCallback(F&& func); + bool eventFilter(QObject* obj, QEvent* event) override; + int count() const; + +private: + std::function<void(QObject* obj)> m_callback; + int m_count = 0; +}; + +template <typename T, typename F> +void CatchShow::setCallback(F&& func) +{ + this->m_callback = [this, func](QObject* obj) { + auto* d = qobject_cast<T*>(obj); + if (d) { + QMetaObject::invokeMethod(obj, + [this, func, d]() { + ++this->m_count; + func(d); + }, + Qt::QueuedConnection); + } + }; +} diff --git a/Tests/CMakeGUI/CatchShowTest.cxx b/Tests/CMakeGUI/CatchShowTest.cxx new file mode 100644 index 0000000..acea8ea --- /dev/null +++ b/Tests/CMakeGUI/CatchShowTest.cxx @@ -0,0 +1,49 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "CatchShowTest.h" + +#include <QMessageBox> +#include <QtTest> + +#include "CatchShow.h" + +CatchShowTest::CatchShowTest(QObject* parent) + : QObject(parent) +{ +} + +void CatchShowTest::catchShow() +{ + bool have = false; + CatchShow catcher; + catcher.setCallback<QMessageBox>([&have](QMessageBox* box) { + have = true; + box->accept(); + }); + + QCOMPARE(catcher.count(), 0); + QCOMPARE(have, false); + + { + QDialog dialog; + dialog.show(); + QCOMPARE(catcher.count(), 0); + QCOMPARE(have, false); + } + + { + have = false; + QMessageBox::critical(nullptr, "Error", "This is an error"); + QCOMPARE(catcher.count(), 1); + QCOMPARE(have, true); + } + + { + have = false; + QMessageBox::information(nullptr, "Info", "This is information"); + QCOMPARE(catcher.count(), 2); + QCOMPARE(have, true); + } +} + +QTEST_MAIN(CatchShowTest) diff --git a/Tests/CMakeGUI/CatchShowTest.h b/Tests/CMakeGUI/CatchShowTest.h new file mode 100644 index 0000000..6da2163 --- /dev/null +++ b/Tests/CMakeGUI/CatchShowTest.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QObject> + +class CatchShowTest : public QObject +{ + Q_OBJECT +public: + CatchShowTest(QObject* parent = nullptr); + +private slots: + void catchShow(); +}; diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.cxx b/Tests/CMakeGUI/EnvironmentDialogTest.cxx new file mode 100644 index 0000000..9ec4996 --- /dev/null +++ b/Tests/CMakeGUI/EnvironmentDialogTest.cxx @@ -0,0 +1,142 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "EnvironmentDialogTest.h" + +#include <QDialogButtonBox> +#include <QMessageBox> +#include <QObject> +#include <QPushButton> +#include <QString> +#include <QtTest> + +#include "CatchShow.h" +#include "EnvironmentDialog.h" + +EnvironmentDialogTest::EnvironmentDialogTest(QObject* parent) + : QObject(parent) +{ +} + +void EnvironmentDialogTest::environmentDialog() +{ + CatchShow catcher; + catcher.setCallback<QMessageBox>([](QMessageBox* box) { box->accept(); }); + + QProcessEnvironment env; + env.insert("DELETED_VARIABLE_1", "Deleted variable 1"); + env.insert("DELETED_VARIABLE_2", "Deleted variable 2"); + env.insert("KEPT_VARIABLE", "Kept variable"); + env.insert("CHANGED_VARIABLE", "This will be changed"); + + EnvironmentDialog dialog(env); + + { + QStringList expected{ + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 0); + } + + { + CatchShow catcher2; + bool done = false; + catcher2.setCallback<QDialog>([&catcher, &done](QDialog* box) { + if (done) { + return; + } + done = true; + + auto name = box->findChild<QLineEdit*>("name"); + auto value = box->findChild<QLineEdit*>("value"); + auto acceptReject = box->findChild<QDialogButtonBox*>(); + + name->setText(""); + value->setText(""); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 1); + + name->setText("KEPT_VARIABLE"); + value->setText(""); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 2); + + name->setText("ADDED_VARIABLE"); + value->setText("Added variable"); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 2); + }); + dialog.AddEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 2); + QVERIFY(done); + } + + { + CatchShow catcher2; + bool done = false; + catcher2.setCallback<QDialog>([&done](QDialog* box) { + if (done) { + return; + } + done = true; + + auto name = box->findChild<QLineEdit*>("name"); + auto value = box->findChild<QLineEdit*>("value"); + auto acceptReject = box->findChild<QDialogButtonBox*>(); + + name->setText("DISCARDED_VARIABLE"); + value->setText("Discarded variable"); + acceptReject->button(QDialogButtonBox::Cancel)->click(); + }); + dialog.AddEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 2); + QVERIFY(done); + } + + { + auto* model = dialog.Environment->model(); + auto* selectionModel = dialog.Environment->selectionModel(); + for (int i = 0; i < model->rowCount(); ++i) { + auto index1 = model->index(i, 0); + auto index2 = model->buddy(index1); + auto name = model->data(index1, Qt::DisplayRole).toString(); + if (name == "DELETED_VARIABLE_1" || name == "DELETED_VARIABLE_2") { + selectionModel->select(index1, QItemSelectionModel::Select); + selectionModel->select(index2, QItemSelectionModel::Select); + } else if (name == "CHANGED_VARIABLE") { + model->setData(index2, "Changed variable", Qt::DisplayRole); + } + } + dialog.RemoveEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=Changed variable", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + } +} + +QTEST_MAIN(EnvironmentDialogTest) diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.h b/Tests/CMakeGUI/EnvironmentDialogTest.h new file mode 100644 index 0000000..bcba2c5 --- /dev/null +++ b/Tests/CMakeGUI/EnvironmentDialogTest.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QObject> + +class EnvironmentDialogTest : public QObject +{ + Q_OBJECT +public: + EnvironmentDialogTest(QObject* parent = nullptr); + +private slots: + void environmentDialog(); +}; diff --git a/Tests/CMakeGUI/QCMakeCacheModelTest.cxx b/Tests/CMakeGUI/QCMakeCacheModelTest.cxx new file mode 100644 index 0000000..f9bc6ae --- /dev/null +++ b/Tests/CMakeGUI/QCMakeCacheModelTest.cxx @@ -0,0 +1,108 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "QCMakeCacheModelTest.h" + +#include <algorithm> +#include <iostream> + +#include "QCMakeCacheView.h" +#include <QtTest> + +namespace { +QCMakeProperty makeProperty( + const QString& name, const QString& value, + QCMakeProperty::PropertyType type = QCMakeProperty::STRING, + bool advanced = false) +{ + return QCMakeProperty{ + /*Key=*/name, + /*Value=*/value, + /*Strings=*/{}, + /*Help=*/"", + /*Type=*/type, + /*Advanced=*/advanced, + }; +} +} + +void QCMakeCacheModelTest::setNewProperties() +{ + QFETCH(QCMakePropertyList, oldList); + QFETCH(QCMakePropertyList, newList); + QFETCH(QVector<QString>, names); + QFETCH(QVector<QString>, values); + QFETCH(QVector<QVariant>, background); + + QCMakeCacheModel model; + model.setViewType(QCMakeCacheModel::FlatView); + model.setProperties(oldList); + model.setProperties(newList); + + auto rows = model.rowCount(); + QVector<QString> actualNames(rows); + QVector<QString> actualValues(rows); + QVector<QVariant> actualBackground1(rows); + QVector<QVariant> actualBackground2(rows); + for (int i = 0; i < rows; ++i) { + auto idx1 = model.index(i, 0); + auto idx2 = model.index(i, 1); + + auto name = model.data(idx1, Qt::DisplayRole); + QVERIFY(name.canConvert<QString>()); + actualNames[i] = name.value<QString>(); + + auto value = model.data(idx2, Qt::DisplayRole); + QVERIFY(name.canConvert<QString>()); + actualValues[i] = value.value<QString>(); + + actualBackground1[i] = model.data(idx1, Qt::BackgroundRole); + actualBackground2[i] = model.data(idx2, Qt::BackgroundRole); + } + + QCOMPARE(actualNames, names); + QCOMPARE(actualValues, values); + QCOMPARE(actualBackground1, background); + QCOMPARE(actualBackground2, background); +} + +void QCMakeCacheModelTest::setNewProperties_data() +{ + QTest::addColumn<QCMakePropertyList>("oldList"); + QTest::addColumn<QCMakePropertyList>("newList"); + QTest::addColumn<QVector<QString>>("names"); + QTest::addColumn<QVector<QString>>("values"); + QTest::addColumn<QVector<QVariant>>("background"); + + QTest::newRow("empty") << QCMakePropertyList{} << QCMakePropertyList{} + << QVector<QString>{} << QVector<QString>{} + << QVector<QVariant>{}; + QTest::newRow("noNew") << QCMakePropertyList{ makeProperty("VARIABLE_1", + "Value 1") } + << QCMakePropertyList{} << QVector<QString>{} + << QVector<QString>{} << QVector<QVariant>{}; + QTest::newRow("allNew") + << QCMakePropertyList{} + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") } + << QVector<QString>{ "VARIABLE_1" } << QVector<QString>{ "Value 1" } + << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } } }; + QTest::newRow("mixed") + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") } + << QCMakePropertyList{ makeProperty("VARIABLE_2", "Value 2") } + << QVector<QString>{ "VARIABLE_2" } << QVector<QString>{ "Value 2" } + << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } } }; + QTest::newRow("overridden") + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") } + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Overridden value") } + << QVector<QString>{ "VARIABLE_1" } + << QVector<QString>{ "Overridden value" } + << QVector<QVariant>{ QVariant{} }; + QTest::newRow("overriddenMixed") + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") } + << QCMakePropertyList{ makeProperty("VARIABLE_1", "Overridden value"), + makeProperty("VARIABLE_2", "Value 2") } + << QVector<QString>{ "VARIABLE_2", "VARIABLE_1" } + << QVector<QString>{ "Value 2", "Overridden value" } + << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } }, QVariant{} }; +} + +QTEST_MAIN(QCMakeCacheModelTest) diff --git a/Tests/CMakeGUI/QCMakeCacheModelTest.h b/Tests/CMakeGUI/QCMakeCacheModelTest.h new file mode 100644 index 0000000..e88db94 --- /dev/null +++ b/Tests/CMakeGUI/QCMakeCacheModelTest.h @@ -0,0 +1,14 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "QCMakeCacheView.h" +#include <QObject> + +class QCMakeCacheModelTest : public QObject +{ + Q_OBJECT +private slots: + void setNewProperties(); + void setNewProperties_data(); +}; diff --git a/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx new file mode 100644 index 0000000..a95d008 --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx @@ -0,0 +1,82 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "QCMakePresetComboBoxTest.h" + +#include <QtTest> + +void QCMakePresetComboBoxTest::changePresets() +{ + QCMakePresetComboBox box; + QSignalSpy presetChanged(&box, &QCMakePresetComboBox::presetChanged); + + QCOMPARE(presetChanged.size(), 0); + + box.setPresets({}); + QCOMPARE(presetChanged.size(), 0); + + box.setPresetName(QString{}); + QCOMPARE(presetChanged.size(), 0); + + box.setPresets({ + { + /*name=*/"preset", + /*description=*/"", + /*description=*/"", + /*generator=*/"Ninja", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/true, + }, + }); + QCOMPARE(presetChanged.size(), 0); + + box.setPresetName(QString{}); + QCOMPARE(presetChanged.size(), 0); + + box.setPresetName("noexist"); + QCOMPARE(presetChanged.size(), 0); + + box.setPresetName("preset"); + QCOMPARE(presetChanged.size(), 1); + QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" }); + + box.setPresets({ + { + /*name=*/"preset", + /*description=*/"", + /*description=*/"", + /*generator=*/"Ninja Multi-Config", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/true, + }, + }); + QCOMPARE(presetChanged.size(), 1); + + box.setPresetName("noexist"); + QCOMPARE(presetChanged.size(), 2); + QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} }); + + box.setPresetName("preset"); + QCOMPARE(presetChanged.size(), 3); + QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" }); + + box.blockSignals(true); + box.setPresetName(QString{}); + box.blockSignals(false); + QCOMPARE(presetChanged.size(), 3); + + box.setPresetName("preset"); + QCOMPARE(presetChanged.size(), 4); + QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" }); + + box.setPresets({}); + QCOMPARE(presetChanged.size(), 5); + QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} }); +} + +QTEST_MAIN(QCMakePresetComboBoxTest) diff --git a/Tests/CMakeGUI/QCMakePresetComboBoxTest.h b/Tests/CMakeGUI/QCMakePresetComboBoxTest.h new file mode 100644 index 0000000..433adbb --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetComboBoxTest.h @@ -0,0 +1,13 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "QCMakePresetComboBox.h" +#include <QObject> + +class QCMakePresetComboBoxTest : public QObject +{ + Q_OBJECT +private slots: + void changePresets(); +}; diff --git a/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx new file mode 100644 index 0000000..97dbb30 --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx @@ -0,0 +1,166 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "QCMakePresetItemModelTest.h" + +#include <utility> + +#include "QCMakePreset.h" +#include "QCMakePresetItemModel.h" +#include <QHash> +#include <QMetaType> +#include <QSignalSpy> +#include <QVariant> +#include <QVector> +#include <QtTest> + +using QItemDataHash = QHash<Qt::ItemDataRole, QVariant>; + +void QCMakePresetItemModelTest::initTestCase() +{ + QMetaType::registerComparators<QCMakePreset>(); +} + +void QCMakePresetItemModelTest::initTestCase_data() +{ + QTest::addColumn<QVector<QCMakePreset>>("presets"); + QTest::addColumn<QVector<QItemDataHash>>("data"); + + QVector<QCMakePreset> presets{ + QCMakePreset{ + /*name=*/"no-description", + /*description=*/"", + /*description=*/"", + /*generator=*/"", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/true, + }, + QCMakePreset{ + /*name=*/"short-description", + /*description=*/"Short Description", + /*description=*/"", + /*generator=*/"", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/true, + }, + QCMakePreset{ + /*name=*/"long-description", + /*description=*/"", + /*description=*/"Long Description", + /*generator=*/"", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/true, + }, + QCMakePreset{ + /*name=*/"disabled", + /*description=*/"", + /*description=*/"", + /*generator=*/"", + /*architecture=*/"", + /*setArchitecture=*/true, + /*toolset=*/"", + /*setToolset=*/true, + /*enabled=*/false, + }, + }; + QVector<QItemDataHash> data{ + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "" }, + { Qt::DisplayRole, "no-description" }, + { Qt::ToolTipRole, "" }, + { Qt::UserRole, QVariant::fromValue(presets[0]) }, + { Qt::FontRole, QFont{} }, + }, + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "" }, + { Qt::DisplayRole, "Short Description" }, + { Qt::ToolTipRole, "" }, + { Qt::UserRole, QVariant::fromValue(presets[1]) }, + { Qt::FontRole, QFont{} }, + }, + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "" }, + { Qt::DisplayRole, "long-description" }, + { Qt::ToolTipRole, "Long Description" }, + { Qt::UserRole, QVariant::fromValue(presets[2]) }, + { Qt::FontRole, QFont{} }, + }, + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "" }, + { Qt::DisplayRole, "disabled" }, + { Qt::ToolTipRole, "" }, + { Qt::UserRole, QVariant::fromValue(presets[3]) }, + { Qt::FontRole, QFont{} }, + }, + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "separator" }, + { Qt::DisplayRole, QVariant{} }, + { Qt::ToolTipRole, QVariant{} }, + { Qt::UserRole, QVariant{} }, + { Qt::FontRole, QFont{} }, + }, + QItemDataHash{ + { Qt::AccessibleDescriptionRole, "" }, + { Qt::DisplayRole, "<custom>" }, + { Qt::ToolTipRole, "Specify all settings manually" }, + { Qt::UserRole, QVariant{} }, + { Qt::FontRole, + []() { + QFont f; + f.setItalic(true); + return f; + }() }, + }, + }; + QTest::newRow("many") << presets << data; + QTest::newRow("none") << QVector<QCMakePreset>{} + << QVector<QItemDataHash>{ data.last() }; +} + +void QCMakePresetItemModelTest::data() +{ + QFETCH_GLOBAL(QVector<QCMakePreset>, presets); + QFETCH_GLOBAL(QVector<QItemDataHash>, data); + QFETCH(Qt::ItemDataRole, role); + + QCMakePresetItemModel model; + QSignalSpy spy1(&model, &QCMakePresetItemModel::modelAboutToBeReset); + QSignalSpy spy2(&model, &QCMakePresetItemModel::modelReset); + model.setPresets(presets); + QCOMPARE(spy1.size(), 1); + QCOMPARE(spy2.size(), 1); + + QVector<QVariant> expectedData(data.size()); + for (int i = 0; i < data.size(); ++i) { + expectedData[i] = data[i][role]; + } + + auto rows = model.rowCount(); + QVector<QVariant> actualData(rows); + for (int i = 0; i < rows; ++i) { + actualData[i] = model.data(model.index(i, 0), role); + } + + QCOMPARE(actualData, expectedData); +} + +void QCMakePresetItemModelTest::data_data() +{ + QTest::addColumn<Qt::ItemDataRole>("role"); + + QTest::newRow("accessible") << Qt::AccessibleDescriptionRole; + QTest::newRow("display") << Qt::DisplayRole; + QTest::newRow("tooltip") << Qt::ToolTipRole; + QTest::newRow("user") << Qt::UserRole; + QTest::newRow("font") << Qt::FontRole; +} + +QTEST_MAIN(QCMakePresetItemModelTest) diff --git a/Tests/CMakeGUI/QCMakePresetItemModelTest.h b/Tests/CMakeGUI/QCMakePresetItemModelTest.h new file mode 100644 index 0000000..ff6efae --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetItemModelTest.h @@ -0,0 +1,17 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "QCMakePresetItemModel.h" +#include <QObject> + +class QCMakePresetItemModelTest : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void initTestCase_data(); + + void data(); + void data_data(); +}; diff --git a/Tests/CMakeGUI/QCMakePresetTest.cxx b/Tests/CMakeGUI/QCMakePresetTest.cxx new file mode 100644 index 0000000..2081055 --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetTest.cxx @@ -0,0 +1,85 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "QCMakePresetTest.h" + +#include <utility> + +#include "QCMakePreset.h" +#include <QtTest> + +namespace { +QCMakePreset makePreset() +{ + return QCMakePreset{ + /*name=*/"name", + /*displayName=*/"displayName", + /*description=*/"description", + /*generator=*/"generator", + /*architecture=*/"architecture", + /*setArchitecture=*/true, + /*toolset=*/"toolset", + /*setToolset=*/true, + /*enabled=*/true, + }; +} + +template <typename T, typename U> +QCMakePreset makePreset(T QCMakePreset::*field, U&& value) +{ + auto preset = makePreset(); + preset.*field = std::forward<U>(value); + return preset; +} +} + +void QCMakePresetTest::equality() +{ + QFETCH(QCMakePreset, rhs); + QFETCH(bool, equal); + QFETCH(bool, lt); + QFETCH(bool, gt); + + auto lhs = makePreset(); + QVERIFY((lhs == rhs) == equal); + QVERIFY((lhs != rhs) == !equal); + QVERIFY((lhs < rhs) == lt); + QVERIFY((lhs >= rhs) == !lt); + QVERIFY((lhs > rhs) == gt); + QVERIFY((lhs <= rhs) == !gt); +} + +void QCMakePresetTest::equality_data() +{ + QTest::addColumn<QCMakePreset>("rhs"); + QTest::addColumn<bool>("equal"); + QTest::addColumn<bool>("lt"); + QTest::addColumn<bool>("gt"); + + QTest::newRow("equal") << makePreset() << true << false << false; + QTest::newRow("name") << makePreset(&QCMakePreset::name, "other-name") + << false << true << false; + QTest::newRow("displayName") + << makePreset(&QCMakePreset::displayName, "other-displayName") << false + << true << false; + QTest::newRow("description") + << makePreset(&QCMakePreset::description, "other-description") << false + << true << false; + QTest::newRow("generator") + << makePreset(&QCMakePreset::generator, "other-generator") << false << true + << false; + QTest::newRow("architecture") + << makePreset(&QCMakePreset::architecture, "other-architecture") << false + << true << false; + QTest::newRow("setArchitecture") + << makePreset(&QCMakePreset::setArchitecture, false) << false << false + << true; + QTest::newRow("toolset") << makePreset(&QCMakePreset::toolset, + "other-toolset") + << false << false << true; + QTest::newRow("setToolset") + << makePreset(&QCMakePreset::setToolset, false) << false << false << true; + QTest::newRow("enabled") << makePreset(&QCMakePreset::enabled, false) + << false << false << true; +} + +QTEST_MAIN(QCMakePresetTest) diff --git a/Tests/CMakeGUI/QCMakePresetTest.h b/Tests/CMakeGUI/QCMakePresetTest.h new file mode 100644 index 0000000..5eac88d --- /dev/null +++ b/Tests/CMakeGUI/QCMakePresetTest.h @@ -0,0 +1,14 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "QCMakePreset.h" +#include <QObject> + +class QCMakePresetTest : public QObject +{ + Q_OBJECT +private slots: + void equality(); + void equality_data(); +}; diff --git a/Tests/CMakeGUI/environment/CMakeLists.txt.in b/Tests/CMakeGUI/environment/CMakeLists.txt.in new file mode 100644 index 0000000..1eeeb85 --- /dev/null +++ b/Tests/CMakeGUI/environment/CMakeLists.txt.in @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.18) +project(environment NONE) + +if(NOT "$ENV{KEPT_VARIABLE}" STREQUAL "Kept variable") + message(SEND_ERROR "KEPT_VARIABLE is \"$ENV{KEPT_VARIABLE}\", should be \"Kept variable\"") +endif() + +if(NOT "$ENV{ADDED_VARIABLE}" STREQUAL "Added variable") + message(SEND_ERROR "ADDED_VARIABLE is \"$ENV{ADDED_VARIABLE}\", should be \"Added variable\"") +endif() + +if(NOT "$ENV{CHANGED_VARIABLE}" STREQUAL "Changed variable") + message(SEND_ERROR "CHANGED_VARIABLE is \"$ENV{CHANGED_VARIABLE}\", should be \"Changed variable\"") +endif() + +if(DEFINED ENV{REMOVED_VARIABLE}) + message(SEND_ERROR "REMOVED_VARIABLE should not be defined") +endif() diff --git a/Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in new file mode 100644 index 0000000..d78d69d --- /dev/null +++ b/Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in @@ -0,0 +1,33 @@ +{ + "version": 1, + "configurePresets": [ + { + "name": "ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "STRING_VARIABLE": { + "type": "STRING", + "value": "String value" + }, + "PATH_VARIABLE": { + "type": "PATH", + "value": "${sourceDir}" + }, + "FILEPATH_VARIABLE": { + "type": "FILEPATH", + "value": "${sourceDir}/CMakeLists.txt" + }, + "ON_VARIABLE": { + "type": "BOOL", + "value": "ON" + }, + "FALSE_VARIABLE": { + "type": "BOOL", + "value": "FALSE" + }, + "UNINITIALIZED_VARIABLE": "Uninitialized value" + } + } + ] +} diff --git a/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in new file mode 100644 index 0000000..d78d69d --- /dev/null +++ b/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in @@ -0,0 +1,33 @@ +{ + "version": 1, + "configurePresets": [ + { + "name": "ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "STRING_VARIABLE": { + "type": "STRING", + "value": "String value" + }, + "PATH_VARIABLE": { + "type": "PATH", + "value": "${sourceDir}" + }, + "FILEPATH_VARIABLE": { + "type": "FILEPATH", + "value": "${sourceDir}/CMakeLists.txt" + }, + "ON_VARIABLE": { + "type": "BOOL", + "value": "ON" + }, + "FALSE_VARIABLE": { + "type": "BOOL", + "value": "FALSE" + }, + "UNINITIALIZED_VARIABLE": "Uninitialized value" + } + } + ] +} diff --git a/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in new file mode 100644 index 0000000..d78d69d --- /dev/null +++ b/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in @@ -0,0 +1,33 @@ +{ + "version": 1, + "configurePresets": [ + { + "name": "ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "STRING_VARIABLE": { + "type": "STRING", + "value": "String value" + }, + "PATH_VARIABLE": { + "type": "PATH", + "value": "${sourceDir}" + }, + "FILEPATH_VARIABLE": { + "type": "FILEPATH", + "value": "${sourceDir}/CMakeLists.txt" + }, + "ON_VARIABLE": { + "type": "BOOL", + "value": "ON" + }, + "FALSE_VARIABLE": { + "type": "BOOL", + "value": "FALSE" + }, + "UNINITIALIZED_VARIABLE": "Uninitialized value" + } + } + ] +} diff --git a/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in new file mode 100644 index 0000000..6fe20d6 --- /dev/null +++ b/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in @@ -0,0 +1,39 @@ +{ + "version": 1, + "configurePresets": [ + { + "name": "ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "STRING_VARIABLE": { + "type": "STRING", + "value": "String value" + }, + "PATH_VARIABLE": { + "type": "PATH", + "value": "${sourceDir}" + }, + "FILEPATH_VARIABLE": { + "type": "FILEPATH", + "value": "${sourceDir}/CMakeLists.txt" + }, + "ON_VARIABLE": { + "type": "BOOL", + "value": "ON" + }, + "FALSE_VARIABLE": { + "type": "BOOL", + "value": "FALSE" + }, + "UNINITIALIZED_VARIABLE": "Uninitialized value" + } + }, + { + "name": "ninja2", + "inherits": [ + "ninja" + ] + } + ] +} diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in new file mode 100644 index 0000000..2ae4a57 --- /dev/null +++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.18) +project(sourceBinaryArgs-sourceDir NONE) diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in new file mode 100644 index 0000000..d78d69d --- /dev/null +++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in @@ -0,0 +1,33 @@ +{ + "version": 1, + "configurePresets": [ + { + "name": "ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "STRING_VARIABLE": { + "type": "STRING", + "value": "String value" + }, + "PATH_VARIABLE": { + "type": "PATH", + "value": "${sourceDir}" + }, + "FILEPATH_VARIABLE": { + "type": "FILEPATH", + "value": "${sourceDir}/CMakeLists.txt" + }, + "ON_VARIABLE": { + "type": "BOOL", + "value": "ON" + }, + "FALSE_VARIABLE": { + "type": "BOOL", + "value": "FALSE" + }, + "UNINITIALIZED_VARIABLE": "Uninitialized value" + } + } + ] +} diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in new file mode 100644 index 0000000..a5d0c71 --- /dev/null +++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in @@ -0,0 +1,2 @@ +[Settings] +StartPath\WhereBuild0=@CMake_BINARY_DIR@ diff --git a/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in new file mode 100644 index 0000000..dc55064 --- /dev/null +++ b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.18) +project(simpleConfigure-fail NONE) + +message(STATUS "This is a failed configure") +message(FATAL_ERROR "Error") diff --git a/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in new file mode 100644 index 0000000..fc42c00 --- /dev/null +++ b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.18) +project(simpleConfigure-success NONE) + +message(STATUS "This is a successful configure") diff --git a/Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in new file mode 100644 index 0000000..2ae4a57 --- /dev/null +++ b/Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.18) +project(sourceBinaryArgs-sourceDir NONE) diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in new file mode 100644 index 0000000..db49eea --- /dev/null +++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in @@ -0,0 +1,2 @@ +[Settings] +StartPath\WhereBuild0=@CMakeGUITest_BINARY_DIR@/sourceBinaryArgs-noExistConfig/oldbuild diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in new file mode 100644 index 0000000..2ae4a57 --- /dev/null +++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.18) +project(sourceBinaryArgs-sourceDir NONE) diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in new file mode 100644 index 0000000..4ffd917 --- /dev/null +++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in @@ -0,0 +1,2 @@ +[Settings] +StartPath\WhereBuild0=@CMakeGUITest_BINARY_DIR@/sourceBinaryArgs-noExistConfigExists/build diff --git a/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in new file mode 100644 index 0000000..2ae4a57 --- /dev/null +++ b/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.18) +project(sourceBinaryArgs-sourceDir NONE) |