summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2020-09-29 13:51:13 (GMT)
committerKitware Robot <kwrobot@kitware.com>2020-09-29 13:51:22 (GMT)
commitaf048185b1b4c20ddda2998e448c81449b803944 (patch)
tree622ad3408eefc424c832c269c75ca0ef80268f21
parent39677de5e209445c8cbc5957c1e79088d5d2a03a (diff)
parent85f5009d2786349a6576d19bf6b605f825775b44 (diff)
downloadCMake-af048185b1b4c20ddda2998e448c81449b803944.zip
CMake-af048185b1b4c20ddda2998e448c81449b803944.tar.gz
CMake-af048185b1b4c20ddda2998e448c81449b803944.tar.bz2
Merge topic 'cmake-gui-environment'
85f5009d27 CMake GUI: Add environment editor d6c051c126 Tests: Add some basic configure tests for the CMake GUI 7cd95d9996 Tests: Add CatchShow helper for CMake GUI tests Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !5270
-rw-r--r--Help/release/dev/cmake-gui-environment.rst4
-rw-r--r--Source/QtDialog/CMakeLists.txt4
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx17
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h1
-rw-r--r--Source/QtDialog/CMakeSetupDialog.ui76
-rw-r--r--Source/QtDialog/EnvironmentDialog.cxx194
-rw-r--r--Source/QtDialog/EnvironmentDialog.h59
-rw-r--r--Source/QtDialog/EnvironmentDialog.ui130
-rw-r--r--Source/QtDialog/QCMake.cxx87
-rw-r--r--Source/QtDialog/QCMake.h8
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cmake9
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cxx104
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.h5
-rw-r--r--Tests/CMakeGUI/CMakeLists.txt29
-rw-r--r--Tests/CMakeGUI/CatchShow.cxx25
-rw-r--r--Tests/CMakeGUI/CatchShow.h41
-rw-r--r--Tests/CMakeGUI/CatchShowTest.cxx49
-rw-r--r--Tests/CMakeGUI/CatchShowTest.h15
-rw-r--r--Tests/CMakeGUI/EnvironmentDialogTest.cxx142
-rw-r--r--Tests/CMakeGUI/EnvironmentDialogTest.h15
-rw-r--r--Tests/CMakeGUI/environment/CMakeLists.txt.in18
-rw-r--r--Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in5
-rw-r--r--Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in4
23 files changed, 1002 insertions, 39 deletions
diff --git a/Help/release/dev/cmake-gui-environment.rst b/Help/release/dev/cmake-gui-environment.rst
new file mode 100644
index 0000000..1c8485e
--- /dev/null
+++ b/Help/release/dev/cmake-gui-environment.rst
@@ -0,0 +1,4 @@
+cmake-gui-environment
+---------------------
+
+* The :manual:`CMake GUI <cmake-gui(1)>` now has an environment variable editor.
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 0ec012c..5fd0e89 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -84,6 +84,8 @@ set(SRCS
CMakeSetupDialog.cxx
CMakeSetupDialog.h
Compilers.h
+ EnvironmentDialog.cxx
+ EnvironmentDialog.h
FirstConfigure.cxx
FirstConfigure.h
QCMake.cxx
@@ -102,6 +104,7 @@ qt5_wrap_ui(UI_SRCS
Compilers.ui
CrossCompiler.ui
AddCacheEntry.ui
+ EnvironmentDialog.ui
RegexExplorer.ui
WarningMessagesDialog.ui
)
@@ -109,6 +112,7 @@ qt5_wrap_cpp(MOC_SRCS
AddCacheEntry.h
Compilers.h
CMakeSetupDialog.h
+ EnvironmentDialog.h
FirstConfigure.h
QCMake.h
QCMakeCacheView.h
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index f6bde8f..a904b94 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -16,6 +16,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
+#include <QProcessEnvironment>
#include <QProgressBar>
#include <QSettings>
#include <QShortcut>
@@ -35,6 +36,7 @@
#include "cmVersion.h"
#include "AddCacheEntry.h"
+#include "EnvironmentDialog.h"
#include "FirstConfigure.h"
#include "RegexExplorer.h"
#include "WarningMessagesDialog.h"
@@ -292,6 +294,9 @@ void CMakeSetupDialog::initialize()
QObject::connect(this->AddEntry, &QToolButton::clicked, this,
&CMakeSetupDialog::addCacheEntry);
+ QObject::connect(this->Environment, &QToolButton::clicked, this,
+ &CMakeSetupDialog::editEnvironment);
+
QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
this->CMakeThread->cmakeInstance(),
&QCMake::setWarnUninitializedMode);
@@ -742,6 +747,7 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->ConfigureAction->setEnabled(enabled);
this->AddEntry->setEnabled(enabled);
this->RemoveEntry->setEnabled(false); // let selection re-enable it
+ this->Environment->setEnabled(enabled);
}
bool CMakeSetupDialog::setupFirstConfigure()
@@ -1075,6 +1081,17 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
}
}
+void CMakeSetupDialog::editEnvironment()
+{
+ EnvironmentDialog dialog(this->CMakeThread->cmakeInstance()->environment(),
+ this);
+ if (dialog.exec() == QDialog::Accepted) {
+ QMetaObject::invokeMethod(
+ this->CMakeThread->cmakeInstance(), "setEnvironment",
+ Q_ARG(QProcessEnvironment, dialog.environment()));
+ }
+}
+
void CMakeSetupDialog::addCacheEntry()
{
QDialog dialog(this);
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
index eba0b1e..d752ef2 100644
--- a/Source/QtDialog/CMakeSetupDialog.h
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -65,6 +65,7 @@ protected slots:
void setCacheModified();
void removeSelectedCacheEntries();
void selectionChanged();
+ void editEnvironment();
void addCacheEntry();
void startSearch();
void setDebugOutput(bool);
diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui
index dc22a29..5feee91 100644
--- a/Source/QtDialog/CMakeSetupDialog.ui
+++ b/Source/QtDialog/CMakeSetupDialog.ui
@@ -11,7 +11,16 @@
</rect>
</property>
<layout class="QGridLayout">
- <property name="margin">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
@@ -19,7 +28,16 @@
</property>
<item row="0" column="0">
<layout class="QGridLayout">
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
@@ -90,7 +108,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -98,7 +125,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -191,6 +227,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QPushButton" name="Environment">
+ <property name="text">
+ <string>E&amp;nvironment...</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -224,7 +267,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -241,13 +293,13 @@
</property>
</widget>
</item>
- <item>
- <widget class="QPushButton" name="OpenProjectButton">
- <property name="text">
- <string>Open &amp;Project</string>
- </property>
- </widget>
- </item>
+ <item>
+ <widget class="QPushButton" name="OpenProjectButton">
+ <property name="text">
+ <string>Open &amp;Project</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QLabel" name="Generator">
<property name="text">
diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx
new file mode 100644
index 0000000..846456c
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.cxx
@@ -0,0 +1,194 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "EnvironmentDialog.h"
+
+#include <QDialogButtonBox>
+#include <QGridLayout>
+#include <QItemSelectionModel>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QStandardItem>
+
+EnvironmentItemModel::EnvironmentItemModel(
+ const QProcessEnvironment& environment, QObject* parent)
+ : QStandardItemModel(parent)
+{
+ this->clear();
+ for (auto const& key : environment.keys()) {
+ auto value = environment.value(key);
+ this->appendVariable(key, value);
+ }
+}
+
+QProcessEnvironment EnvironmentItemModel::environment() const
+{
+ QProcessEnvironment env;
+ for (int i = 0; i < this->rowCount(); ++i) {
+ auto name = this->data(this->index(i, 0), Qt::DisplayRole).toString();
+ auto value = this->data(this->index(i, 1), Qt::DisplayRole).toString();
+ env.insert(name, value);
+ }
+ return env;
+}
+
+void EnvironmentItemModel::clear()
+{
+ this->QStandardItemModel::clear();
+
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+QModelIndex EnvironmentItemModel::buddy(const QModelIndex& index) const
+{
+ if (index.column() == 0) {
+ return this->index(index.row(), index.column() + 1, index.parent());
+ }
+ return index;
+}
+
+void EnvironmentItemModel::appendVariable(const QString& key,
+ const QString& value)
+{
+ this->insertVariable(this->rowCount(), key, value);
+}
+
+void EnvironmentItemModel::insertVariable(int row, const QString& key,
+ const QString& value)
+{
+ for (int i = 0; i < this->rowCount(); ++i) {
+ if (this->data(this->index(i, 0), Qt::DisplayRole) == key) {
+ this->setData(this->index(i, 1), value, Qt::DisplayRole);
+ return;
+ }
+ }
+
+ auto* keyItem = new QStandardItem(key);
+ auto* valueItem = new QStandardItem(value);
+ this->insertRow(row, { keyItem, valueItem });
+}
+
+EnvironmentSearchFilter::EnvironmentSearchFilter(QObject* parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+bool EnvironmentSearchFilter::filterAcceptsRow(int row,
+ const QModelIndex& parent) const
+{
+ auto* model = this->sourceModel();
+ auto key =
+ model->data(model->index(row, 0, parent), Qt::DisplayRole).toString();
+ return key.contains(this->filterRegExp());
+}
+
+EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
+ QWidget* parent)
+ : QDialog(parent)
+{
+ this->setupUi(this);
+
+ this->RemoveEntry->setEnabled(false);
+
+ this->m_model = new EnvironmentItemModel(environment, this);
+ this->m_filter = new EnvironmentSearchFilter(this);
+ this->m_filter->setSourceModel(this->m_model);
+ this->Environment->setModel(this->m_filter);
+
+ this->Environment->setUniformRowHeights(true);
+ this->Environment->setRootIsDecorated(false);
+ this->Environment->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ this->Environment->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ QObject::connect(this->AddEntry, &QToolButton::clicked, this,
+ &EnvironmentDialog::addEntry);
+ QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
+ &EnvironmentDialog::removeSelectedEntries);
+ QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
+ &EnvironmentSearchFilter::setFilterFixedString);
+ QObject::connect(this->Environment->selectionModel(),
+ &QItemSelectionModel::selectionChanged, this,
+ &EnvironmentDialog::selectionChanged);
+}
+
+QProcessEnvironment EnvironmentDialog::environment() const
+{
+ return this->m_model->environment();
+}
+
+void EnvironmentDialog::addEntry()
+{
+ // Build the dialog manually because it's simple enough
+ QDialog dialog(this);
+ dialog.setWindowTitle("Add Environment Variable");
+
+ auto* layout = new QGridLayout;
+ dialog.setLayout(layout);
+
+ auto* nameLabel = new QLabel;
+ nameLabel->setText("Name:");
+ layout->addWidget(nameLabel, 0, 0);
+
+ auto* nameEdit = new QLineEdit;
+ nameEdit->setObjectName("name");
+ layout->addWidget(nameEdit, 0, 1);
+
+ auto* valueLabel = new QLabel;
+ valueLabel->setText("Value:");
+ layout->addWidget(valueLabel, 1, 0);
+
+ auto* valueEdit = new QLineEdit;
+ valueEdit->setObjectName("value");
+ layout->addWidget(valueEdit, 1, 1);
+
+ auto* buttons = new QDialogButtonBox;
+ buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ QObject::connect(
+ buttons, &QDialogButtonBox::accepted, &dialog,
+ [this, &dialog, nameEdit]() {
+ auto text = nameEdit->text();
+ if (text.isEmpty()) {
+ QMessageBox::critical(&dialog, "Error", "Name must be non-empty.");
+ return;
+ }
+
+ auto* model = this->Environment->model();
+ for (int i = 0; i < model->rowCount(); ++i) {
+ if (model->data(model->index(i, 0), Qt::DisplayRole) == text) {
+ QMessageBox::critical(
+ &dialog, "Error",
+ tr("Environment variable \"%1\" already exists.").arg(text));
+ return;
+ }
+ }
+
+ dialog.accept();
+ });
+ QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::reject);
+ layout->addWidget(buttons, 2, 0, 1, 2);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ this->m_model->insertVariable(0, nameEdit->text(), valueEdit->text());
+ }
+}
+
+void EnvironmentDialog::removeSelectedEntries()
+{
+ QModelIndexList idxs = this->Environment->selectionModel()->selectedRows();
+ QList<QPersistentModelIndex> pidxs;
+ foreach (QModelIndex const& i, idxs) {
+ pidxs.append(i);
+ }
+ foreach (QPersistentModelIndex const& pi, pidxs) {
+ this->Environment->model()->removeRow(pi.row(), pi.parent());
+ }
+}
+
+void EnvironmentDialog::selectionChanged()
+{
+ auto selected = this->Environment->selectionModel()->selectedRows();
+ this->RemoveEntry->setEnabled(!selected.isEmpty());
+}
diff --git a/Source/QtDialog/EnvironmentDialog.h b/Source/QtDialog/EnvironmentDialog.h
new file mode 100644
index 0000000..6aae798
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.h
@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <QDialog>
+#include <QObject>
+#include <QProcessEnvironment>
+#include <QSortFilterProxyModel>
+#include <QStandardItemModel>
+
+#include "ui_EnvironmentDialog.h"
+
+class EnvironmentItemModel : public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ EnvironmentItemModel(const QProcessEnvironment& environment,
+ QObject* parent = nullptr);
+
+ QProcessEnvironment environment() const;
+ void clear();
+
+ QModelIndex buddy(const QModelIndex& index) const override;
+
+public slots:
+ void appendVariable(const QString& key, const QString& value);
+ void insertVariable(int row, const QString& key, const QString& value);
+};
+
+class EnvironmentSearchFilter : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ EnvironmentSearchFilter(QObject* parent = nullptr);
+
+protected:
+ bool filterAcceptsRow(int row, const QModelIndex& parent) const override;
+};
+
+class EnvironmentDialog
+ : public QDialog
+ , public Ui::EnvironmentDialog
+{
+ Q_OBJECT
+public:
+ EnvironmentDialog(const QProcessEnvironment& environment,
+ QWidget* parent = nullptr);
+
+ QProcessEnvironment environment() const;
+
+protected slots:
+ void addEntry();
+ void removeSelectedEntries();
+ void selectionChanged();
+
+private:
+ EnvironmentItemModel* m_model;
+ EnvironmentSearchFilter* m_filter;
+};
diff --git a/Source/QtDialog/EnvironmentDialog.ui b/Source/QtDialog/EnvironmentDialog.ui
new file mode 100644
index 0000000..dea7624
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EnvironmentDialog</class>
+ <widget class="QDialog" name="EnvironmentDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Environment Editor</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>S&amp;earch:</string>
+ </property>
+ <property name="buddy">
+ <cstring>Search</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="Search"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>12</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="AddEntry">
+ <property name="text">
+ <string>&amp;Add Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="RemoveEntry">
+ <property name="text">
+ <string>&amp;Remove Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="Environment"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="CMakeSetup.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>EnvironmentDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>EnvironmentDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 6090256..974c545 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -19,10 +19,12 @@
QCMake::QCMake(QObject* p)
: QObject(p)
+ , Environment(QProcessEnvironment::systemEnvironment())
{
this->WarnUninitializedMode = false;
qRegisterMetaType<QCMakeProperty>();
qRegisterMetaType<QCMakePropertyList>();
+ qRegisterMetaType<QProcessEnvironment>();
cmSystemTools::DisableRunCommandOutput();
cmSystemTools::SetRunCommandHideConsole(true);
@@ -151,34 +153,46 @@ void QCMake::setToolset(const QString& toolset)
}
}
+void QCMake::setEnvironment(const QProcessEnvironment& environment)
+{
+ this->Environment = environment;
+}
+
void QCMake::configure()
{
+ int err;
+ {
+ cmSystemTools::SaveRestoreEnvironment restoreEnv;
+ this->setUpEnvironment();
+
#ifdef Q_OS_WIN
- UINT lastErrorMode = SetErrorMode(0);
+ UINT lastErrorMode = SetErrorMode(0);
#endif
- this->CMakeInstance->SetHomeDirectory(
- this->SourceDirectory.toLocal8Bit().data());
- this->CMakeInstance->SetHomeOutputDirectory(
- this->BinaryDirectory.toLocal8Bit().data());
- this->CMakeInstance->SetGlobalGenerator(
- this->CMakeInstance->CreateGlobalGenerator(
- this->Generator.toLocal8Bit().data()));
- this->CMakeInstance->SetGeneratorPlatform(
- this->Platform.toLocal8Bit().data());
- this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data());
- this->CMakeInstance->LoadCache();
- this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
- this->CMakeInstance->PreLoadCMakeFiles();
-
- InterruptFlag = 0;
- cmSystemTools::ResetErrorOccuredFlag();
-
- int err = this->CMakeInstance->Configure();
+ this->CMakeInstance->SetHomeDirectory(
+ this->SourceDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetHomeOutputDirectory(
+ this->BinaryDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetGlobalGenerator(
+ this->CMakeInstance->CreateGlobalGenerator(
+ this->Generator.toLocal8Bit().data()));
+ this->CMakeInstance->SetGeneratorPlatform(
+ this->Platform.toLocal8Bit().data());
+ this->CMakeInstance->SetGeneratorToolset(
+ this->Toolset.toLocal8Bit().data());
+ this->CMakeInstance->LoadCache();
+ this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
+ this->CMakeInstance->PreLoadCMakeFiles();
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ err = this->CMakeInstance->Configure();
#ifdef Q_OS_WIN
- SetErrorMode(lastErrorMode);
+ SetErrorMode(lastErrorMode);
#endif
+ }
emit this->propertiesChanged(this->properties());
emit this->configureDone(err);
@@ -186,18 +200,24 @@ void QCMake::configure()
void QCMake::generate()
{
+ int err;
+ {
+ cmSystemTools::SaveRestoreEnvironment restoreEnv;
+ this->setUpEnvironment();
+
#ifdef Q_OS_WIN
- UINT lastErrorMode = SetErrorMode(0);
+ UINT lastErrorMode = SetErrorMode(0);
#endif
- InterruptFlag = 0;
- cmSystemTools::ResetErrorOccuredFlag();
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
- int err = this->CMakeInstance->Generate();
+ err = this->CMakeInstance->Generate();
#ifdef Q_OS_WIN
- SetErrorMode(lastErrorMode);
+ SetErrorMode(lastErrorMode);
#endif
+ }
emit this->generateDone(err);
checkOpenPossible();
@@ -373,6 +393,18 @@ void QCMake::stderrCallback(std::string const& msg)
QCoreApplication::processEvents();
}
+void QCMake::setUpEnvironment() const
+{
+ auto env = QProcessEnvironment::systemEnvironment();
+ for (auto const& key : env.keys()) {
+ cmSystemTools::UnsetEnv(key.toLocal8Bit().data());
+ }
+
+ for (auto const& var : this->Environment.toStringList()) {
+ cmSystemTools::PutEnv(var.toLocal8Bit().data());
+ }
+}
+
QString QCMake::binaryDirectory() const
{
return this->BinaryDirectory;
@@ -388,6 +420,11 @@ QString QCMake::generator() const
return this->Generator;
}
+QProcessEnvironment QCMake::environment() const
+{
+ return this->Environment;
+}
+
std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
{
return AvailableGenerators;
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index e87660b..f569951 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -18,6 +18,7 @@
#include <QList>
#include <QMetaType>
#include <QObject>
+#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QVariant>
@@ -55,6 +56,7 @@ using QCMakePropertyList = QList<QCMakeProperty>;
// allow QVariant to be a property or list of properties
Q_DECLARE_METATYPE(QCMakeProperty)
Q_DECLARE_METATYPE(QCMakePropertyList)
+Q_DECLARE_METATYPE(QProcessEnvironment)
/// Qt API for CMake library.
/// Wrapper like class allows for easier integration with
@@ -78,6 +80,8 @@ public slots:
void setPlatform(const QString& platform);
/// set the desired generator to use
void setToolset(const QString& toolset);
+ /// set the configure and generate environment
+ void setEnvironment(const QProcessEnvironment& environment);
/// do the configure step
void configure();
/// generate the files
@@ -125,6 +129,8 @@ public:
QString sourceDirectory() const;
/// get the current generator
QString generator() const;
+ /// get the configure and generate environment
+ QProcessEnvironment environment() const;
/// get the available generators
std::vector<cmake::GeneratorInfo> const& availableGenerators() const;
/// get whether to do debug output
@@ -170,6 +176,7 @@ protected:
void messageCallback(std::string const& msg, const char* title);
void stdoutCallback(std::string const& msg);
void stderrCallback(std::string const& msg);
+ void setUpEnvironment() const;
bool WarnUninitializedMode;
QString SourceDirectory;
@@ -180,4 +187,5 @@ protected:
std::vector<cmake::GeneratorInfo> AvailableGenerators;
QString CMakeExecutable;
QAtomicInt InterruptFlag;
+ QProcessEnvironment Environment;
};
diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake
index 3d8c27e..b60ec35 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cmake
+++ b/Tests/CMakeGUI/CMakeGUITest.cmake
@@ -109,3 +109,12 @@ run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists
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)
diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx
index a7a5d17..80ea08d 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cxx
+++ b/Tests/CMakeGUI/CMakeGUITest.cxx
@@ -2,8 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "CMakeGUITest.h"
+#include "QCMake.h"
#include <QApplication>
#include <QEventLoop>
+#include <QMessageBox>
#include <QSettings>
#include <QString>
#include <QStringList>
@@ -13,6 +15,9 @@
#include "CMakeSetupDialog.h"
+#include "CatchShow.h"
+#include "FirstConfigure.h"
+
namespace {
void loopSleep(int msecs = 100)
{
@@ -28,6 +33,44 @@ CMakeGUITest::CMakeGUITest(CMakeSetupDialog* window, QObject* parent)
{
}
+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);
@@ -68,6 +111,67 @@ void CMakeGUITest::sourceBinaryArgs_data()
<< 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 SetupDefaultQSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);
diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h
index 55a885b..891cf62 100644
--- a/Tests/CMakeGUI/CMakeGUITest.h
+++ b/Tests/CMakeGUI/CMakeGUITest.h
@@ -15,7 +15,12 @@ public:
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();
};
diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt
index 2a2ee1a..c6bc88a 100644
--- a/Tests/CMakeGUI/CMakeLists.txt
+++ b/Tests/CMakeGUI/CMakeLists.txt
@@ -10,13 +10,24 @@ include_directories(
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 Qt5::Core Qt5::Test Qt5::Widgets)
+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}
@@ -35,11 +46,25 @@ function(add_cmake_gui_lib_test name)
${_t_MOC_SOURCES}
)
add_executable(${name} ${_t_SOURCES} ${MOC_SRCS})
- target_link_libraries(${name} CMakeGUILib Qt5::Core Qt5::Test Qt5::Widgets)
+ 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
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/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/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")