aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2020-06-18 19:46:01 +0200
committerTim Jenssen <tim.jenssen@qt.io>2020-06-30 10:28:07 +0000
commit1e6807c680924f39c071a5d5db4a3881adb14c19 (patch)
tree5b48ff6d75678e13e6422952a8ae5aed9f0916f8 /tests
parent009c2745e27a9b1e9bc3886f159c271fb491c7d4 (diff)
QmlDesigner: Add listmodeleditor
Task-number: QDS-2294 Change-Id: I66cae3a0d4265ab112eaf6b04e3a5972d185ff43 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/unit/unittest/google-using-declarations.h2
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp21
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h8
-rw-r--r--tests/unit/unittest/gtest-qt-printing.cpp16
-rw-r--r--tests/unit/unittest/gtest-qt-printing.h4
-rw-r--r--tests/unit/unittest/listmodeleditor-test.cpp911
-rw-r--r--tests/unit/unittest/mocklistmodeleditorview.h59
-rw-r--r--tests/unit/unittest/unittest.pro6
8 files changed, 1020 insertions, 7 deletions
diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h
index 1a92ff3388..de52483403 100644
--- a/tests/unit/unittest/google-using-declarations.h
+++ b/tests/unit/unittest/google-using-declarations.h
@@ -65,6 +65,8 @@ using testing::Property;
using testing::Return;
using testing::ReturnRef;
using testing::SafeMatcherCast;
+using testing::SaveArg;
+using testing::SaveArgPointee;
using testing::Sequence;
using testing::SizeIs;
using testing::StrEq;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 326058d7a9..20e44154d9 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -47,6 +47,7 @@
#include <filepathview.h>
#include <filestatus.h>
#include <includesearchpath.h>
+#include <modelnode.h>
#include <nativefilepath.h>
#include <pchpaths.h>
#include <pchtask.h>
@@ -68,6 +69,7 @@
#include <tooltipinfo.h>
#include <usedmacro.h>
#include <utils/link.h>
+#include <variantproperty.h>
#include <sqlite3ext.h>
@@ -1449,6 +1451,25 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag) {
} // namespace Internal
} // namespace ClangTools
+namespace QmlDesigner {
+
+std::ostream &operator<<(std::ostream &out, const ModelNode &node)
+{
+ if (!node.isValid())
+ return out << "(invalid)";
+
+ return out << "(" << node.id() << ")";
+}
+std::ostream &operator<<(std::ostream &out, const VariantProperty &property)
+{
+ if (!property.isValid())
+ return out << "(invalid)";
+
+ return out << "(" << property.parentModelNode() << ", " << property.name() << ", "
+ << property.value() << ")";
+}
+} // namespace QmlDesigner
+
void setFilePathCache(ClangBackEnd::FilePathCaching *cache)
{
filePathCache = cache;
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index e0cb55315f..565479be03 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -350,4 +350,12 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag);
} // namespace Internal
} // namespace CppTools
+namespace QmlDesigner {
+class ModelNode;
+class VariantProperty;
+
+std::ostream &operator<<(std::ostream &out, const ModelNode &node);
+std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
+} // namespace QmlDesigner
+
void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache);
diff --git a/tests/unit/unittest/gtest-qt-printing.cpp b/tests/unit/unittest/gtest-qt-printing.cpp
index cd97883b16..c097fd0b4c 100644
--- a/tests/unit/unittest/gtest-qt-printing.cpp
+++ b/tests/unit/unittest/gtest-qt-printing.cpp
@@ -59,9 +59,11 @@ std::ostream &operator<<(std::ostream &out, const QVariant &variant)
QString output;
QDebug debug(&output);
- debug << variant;
+ debug.noquote().nospace() << variant;
- return out << output;
+ QByteArray utf8Text = output.toUtf8();
+
+ return out.write(utf8Text.data(), utf8Text.size());
}
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format)
@@ -88,4 +90,14 @@ void PrintTo(const QString &text, std::ostream *os)
*os << text;
}
+void PrintTo(const QVariant &variant, std::ostream *os)
+{
+ *os << variant;
+}
+
+void PrintTo(const QByteArray &text, std::ostream *os)
+{
+ *os << text;
+}
+
QT_END_NAMESPACE
diff --git a/tests/unit/unittest/gtest-qt-printing.h b/tests/unit/unittest/gtest-qt-printing.h
index 424762273b..ebaeb2c785 100644
--- a/tests/unit/unittest/gtest-qt-printing.h
+++ b/tests/unit/unittest/gtest-qt-printing.h
@@ -35,10 +35,12 @@ class QVariant;
class QString;
class QTextCharFormat;
-std::ostream &operator<<(std::ostream &out, const QVariant &variant);
+std::ostream &operator<<(std::ostream &out, const QVariant &QVariant);
std::ostream &operator<<(std::ostream &out, const QString &text);
std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray);
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format);
void PrintTo(const QString &text, std::ostream *os);
+void PrintTo(const QVariant &variant, std::ostream *os);
+void PrintTo(const QByteArray &text, std::ostream *os);
QT_END_NAMESPACE
diff --git a/tests/unit/unittest/listmodeleditor-test.cpp b/tests/unit/unittest/listmodeleditor-test.cpp
index 7a876890c5..ca0913f865 100644
--- a/tests/unit/unittest/listmodeleditor-test.cpp
+++ b/tests/unit/unittest/listmodeleditor-test.cpp
@@ -27,21 +27,926 @@
#include "googletest.h"
+#include "mocklistmodeleditorview.h"
+
#include <qmldesigner/components/listmodeleditor/listmodeleditormodel.h>
-#include <qmldesigner/components/listmodeleditor/listmodeleditorview.h>
+#include <qmldesigner/designercore/include/abstractview.h>
#include <qmldesigner/designercore/include/model.h>
+#include <qmldesigner/designercore/include/nodelistproperty.h>
+#include <qmldesigner/designercore/include/variantproperty.h>
namespace {
+using QmlDesigner::AbstractProperty;
+using QmlDesigner::AbstractView;
+using QmlDesigner::ModelNode;
+
+MATCHER_P2(HasItem,
+ name,
+ value,
+ std::string(negation ? "hasn't " : "has ") + "(" + name + ", " + value + ")")
+{
+ QStandardItem *item = arg;
+
+ return item->data(Qt::UserRole).toString() == name && item->data(Qt::UserRole).toDouble() == value;
+}
+
+MATCHER(IsInvalid, std::string(negation ? "isn't null" : "is null"))
+{
+ return !arg.isValid();
+}
+
+MATCHER_P3(IsVariantProperty,
+ node,
+ name,
+ value,
+ std::string(negation ? "isn't " : "is ") + "(" + name + ", " + PrintToString(value) + ")")
+{
+ const QmlDesigner::VariantProperty &property = arg;
+
+ return property.parentModelNode() == node && property.name() == name && property.value() == value;
+}
+
+MATCHER_P2(IsVariantProperty,
+ name,
+ value,
+ std::string(negation ? "isn't " : "is ") + "(" + name + ", " + PrintToString(value) + ")")
+{
+ const QmlDesigner::VariantProperty &property = arg;
+
+ return property.name() == name && property.value() == value;
+}
+
+MATCHER_P2(IsAbstractProperty, node, name, std::string(negation ? "isn't " : "is ") + "(" + name + ")")
+{
+ const QmlDesigner::AbstractProperty &property = arg;
+
+ return property.parentModelNode() == node && property.name() == name;
+}
+
class ListModelEditor : public testing::Test
{
public:
- ListModelEditor() { designerModel->attachView(&view); }
+ ListModelEditor()
+ {
+ designerModel->attachView(&mockView);
+
+ emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
+
+ listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
+ mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
+ element1 = createElement({{"name", "foo"}, {"value", 1}, {"value2", 42}});
+ element2 = createElement({{"value", 4}, {"name", "bar"}, {"image", "pic.png"}});
+ element3 = createElement({{"image", "pic.png"}, {"name", "poo"}, {"value", 111}});
+ }
+
+ using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
+
+ ModelNode createElement(std::initializer_list<Entry> entries)
+ {
+ auto element = mockView.createModelNode("QtQml.Models/ListElement", 2, 15);
+ listModelNode.defaultNodeListProperty().reparentHere(element);
+
+ for (const auto &entry : entries) {
+ element.variantProperty(entry.first).setValue(entry.second);
+ }
+
+ return element;
+ }
+
+ QList<QString> headerLabels(const QmlDesigner::ListModelEditorModel &model) const
+ {
+ QList<QString> labels;
+ labels.reserve(model.columnCount());
+
+ for (int i = 0; i < model.columnCount(); ++i)
+ labels.push_back(model.headerData(i, Qt::Horizontal).toString());
+
+ return labels;
+ }
+
+ QList<QList<QVariant>> displayValues() const
+ {
+ QList<QList<QVariant>> rows;
+
+ for (int rowIndex = 0; rowIndex < model.rowCount(); ++rowIndex) {
+ QList<QVariant> row;
+
+ for (int columnIndex = 0; columnIndex < model.columnCount(); ++columnIndex)
+ row.push_back(model.data(model.index(rowIndex, columnIndex), Qt::DisplayRole));
+
+ rows.push_back(row);
+ }
+
+ return rows;
+ }
+
+ QList<QList<QColor>> backgroundColors() const
+ {
+ QList<QList<QColor>> rows;
+
+ for (int rowIndex = 0; rowIndex < model.rowCount(); ++rowIndex) {
+ QList<QColor> row;
+
+ for (int columnIndex = 0; columnIndex < model.columnCount(); ++columnIndex)
+ row.push_back(
+ model.data(model.index(rowIndex, columnIndex), Qt::BackgroundColorRole)
+ .value<QColor>());
+
+ rows.push_back(row);
+ }
+
+ return rows;
+ }
+
+ QList<QList<QmlDesigner::VariantProperty>> properties() const
+ {
+ QList<QList<QmlDesigner::VariantProperty>> properties;
+ properties.reserve(10);
+
+ auto nodes = listModelNode.defaultNodeListProperty().toModelNodeList();
+
+ for (const ModelNode &node : nodes)
+ properties.push_back(node.variantProperties());
+
+ return properties;
+ }
protected:
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
- QmlDesigner::ListModelEditorView view;
+ NiceMock<MockListModelEditorView> mockView;
QmlDesigner::ListModelEditorModel model;
+ ModelNode listModelNode;
+ ModelNode emptyListModelNode;
+ ModelNode element1;
+ ModelNode element2;
+ ModelNode element3;
};
+TEST_F(ListModelEditor, CreatePropertyNameSet)
+{
+ model.setListModel(listModelNode);
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, CreatePropertyNameSetForEmptyList)
+{
+ model.setListModel(emptyListModelNode);
+
+ ASSERT_THAT(model.propertyNames(), IsEmpty());
+}
+
+TEST_F(ListModelEditor, HorizontalLabels)
+{
+ model.setListModel(listModelNode);
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, HorizontalLabelsForEmptyList)
+{
+ model.setListModel(emptyListModelNode);
+
+ ASSERT_THAT(headerLabels(model), IsEmpty());
+}
+
+TEST_F(ListModelEditor, DisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, ChangeValueChangesDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(0, 1, "hello");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "hello", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, EditValueCallVariantPropertiesChanged)
+{
+ model.setListModel(listModelNode);
+
+ EXPECT_CALL(mockView,
+ variantPropertiesChanged(ElementsAre(IsVariantProperty(element1, "name", "hello")),
+ Eq(AbstractView::NoAdditionalChanges)));
+
+ model.setValue(0, 1, "hello");
+}
+
+TEST_F(ListModelEditor, ChangeDisplayValueCallsVariantPropertiesChanged)
+{
+ model.setListModel(listModelNode);
+
+ EXPECT_CALL(mockView,
+ variantPropertiesChanged(ElementsAre(IsVariantProperty(element1, "name", "hello")),
+ Eq(AbstractView::NoAdditionalChanges)))
+ .Times(0);
+
+ model.setValue(0, 1, "hello", Qt::DisplayRole);
+}
+
+TEST_F(ListModelEditor, AddRowAddedInvalidRow)
+{
+ model.setListModel(listModelNode);
+
+ model.addRow();
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid()),
+ ElementsAre(IsInvalid(), IsInvalid(), IsInvalid(), IsInvalid())));
+}
+
+TEST_F(ListModelEditor, AddRowCreatesNewModelNodeAndReparents)
+{
+ model.setListModel(listModelNode);
+
+ EXPECT_CALL(mockView, nodeCreated(Property(&ModelNode::type, Eq("QtQml.Models.ListElement"))));
+ EXPECT_CALL(mockView,
+ nodeReparented(Property(&ModelNode::type, Eq("QtQml.Models.ListElement")),
+ Property(&AbstractProperty::parentModelNode, Eq(listModelNode)),
+ _,
+ _));
+
+ model.addRow();
+}
+
+TEST_F(ListModelEditor, ChangeAddedRowPropery)
+{
+ model.setListModel(listModelNode);
+ model.addRow();
+
+ model.setValue(3, 2, 22);
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid()),
+ ElementsAre(IsInvalid(), IsInvalid(), 22, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, ChangeAddedRowProperyCallsVariantPropertiesChanged)
+{
+ model.setListModel(listModelNode);
+ ModelNode element4;
+ ON_CALL(mockView, nodeReparented(_, _, _, _)).WillByDefault(SaveArg<0>(&element4));
+ model.addRow();
+
+ EXPECT_CALL(mockView,
+ variantPropertiesChanged(ElementsAre(IsVariantProperty(element4, "value", 22)),
+ Eq(AbstractView::PropertiesAdded)));
+
+ model.setValue(3, 2, 22);
+}
+
+TEST_F(ListModelEditor, AddColumnInsertsPropertyName)
+{
+ model.setListModel(listModelNode);
+
+ model.addColumn("other");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "other", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, AddColumnInsertsPropertyNameToEmptyModel)
+{
+ model.setListModel(emptyListModelNode);
+
+ model.addColumn("foo");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("foo"));
+}
+
+TEST_F(ListModelEditor, AddTwiceColumnInsertsPropertyNameToEmptyModel)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("foo");
+
+ model.addColumn("foo2");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("foo", "foo2"));
+}
+
+TEST_F(ListModelEditor, AddSameColumnInsertsPropertyName)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("foo");
+
+ model.addColumn("foo");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("foo"));
+}
+
+TEST_F(ListModelEditor, AddColumnInsertsHeaderLabel)
+{
+ model.setListModel(listModelNode);
+
+ model.addColumn("other");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "other", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, AddColumnInsertsHeaderLabelToEmptyModel)
+{
+ model.setListModel(emptyListModelNode);
+
+ model.addColumn("foo");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("foo"));
+}
+
+TEST_F(ListModelEditor, AddTwiceColumnInsertsHeaderLabelToEmptyModel)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("foo");
+
+ model.addColumn("foo2");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("foo", "foo2"));
+}
+
+TEST_F(ListModelEditor, AddSameColumnInsertsHeaderLabel)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("foo");
+
+ model.addColumn("foo");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("foo"));
+}
+
+TEST_F(ListModelEditor, AddColumnInsertsDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.addColumn("other");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", IsInvalid(), 1, 42),
+ ElementsAre("pic.png", "bar", IsInvalid(), 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", IsInvalid(), 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, ChangeAddColumnPropertyDisplayValue)
+{
+ model.setListModel(listModelNode);
+ model.addColumn("other");
+
+ model.setValue(1, 2, 22);
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", IsInvalid(), 1, 42),
+ ElementsAre("pic.png", "bar", 22, 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", IsInvalid(), 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, ChangeAddColumnPropertyCallsVariantPropertiesChanged)
+{
+ model.setListModel(listModelNode);
+ model.addColumn("other");
+
+ EXPECT_CALL(mockView,
+ variantPropertiesChanged(ElementsAre(IsVariantProperty(element2, "other", 434)), _));
+
+ model.setValue(1, 2, 434);
+}
+
+TEST_F(ListModelEditor, RemoveColumnRemovesDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.removeColumn(2);
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 42),
+ ElementsAre("pic.png", "bar", IsInvalid()),
+ ElementsAre("pic.png", "poo", IsInvalid())));
+}
+
+TEST_F(ListModelEditor, RemoveColumnRemovesProperties)
+{
+ model.setListModel(listModelNode);
+
+ EXPECT_CALL(mockView, propertiesRemoved(ElementsAre(IsAbstractProperty(element2, "image"))));
+ EXPECT_CALL(mockView, propertiesRemoved(ElementsAre(IsAbstractProperty(element3, "image"))));
+
+ model.removeColumn(0);
+}
+
+TEST_F(ListModelEditor, RemoveColumnRemovesPropertyName)
+{
+ model.setListModel(listModelNode);
+
+ model.removeColumn(1);
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, RemoveRowRemovesDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.removeRow(1);
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "poo", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, RemoveRowRemovesElementInListModel)
+{
+ model.setListModel(listModelNode);
+
+ EXPECT_CALL(mockView, nodeRemoved(Eq(element2), _, _));
+
+ model.removeRow(1);
+}
+
+TEST_F(ListModelEditor, ConvertStringFloatToFloat)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "25.5");
+
+ ASSERT_THAT(element2.variantProperty("name").value().value<double>(), 25.5);
+ ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::Double);
+}
+
+TEST_F(ListModelEditor, ConvertStringIntegerToDouble)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "25");
+
+ ASSERT_THAT(element2.variantProperty("name").value().value<double>(), 25);
+ ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::Double);
+}
+
+TEST_F(ListModelEditor, DontConvertStringToNumber)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "hello");
+
+ ASSERT_THAT(element2.variantProperty("name").value().value<QString>(), "hello");
+ ASSERT_THAT(element2.variantProperty("name").value().type(), QVariant::String);
+}
+
+TEST_F(ListModelEditor, EmptyStringsRemovesProperty)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "");
+
+ ASSERT_THAT(element2.variantProperty("name").value().value<QString>(), Eq(""));
+}
+
+TEST_F(ListModelEditor, InvalidVariantRemovesProperty)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, QVariant());
+
+ ASSERT_FALSE(element2.hasProperty("name"));
+}
+
+TEST_F(ListModelEditor, DispayValueIsChangedToDouble)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "25.5");
+
+ ASSERT_THAT(displayValues()[1][1].type(), QVariant::Double);
+}
+
+TEST_F(ListModelEditor, StringDispayValueIsNotChanged)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, "25.5a");
+
+ ASSERT_THAT(displayValues()[1][1].type(), QVariant::String);
+}
+
+TEST_F(ListModelEditor, SetInvalidToDarkYellowBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ ASSERT_THAT(
+ backgroundColors(),
+ ElementsAre(
+ ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, SettingValueChangesBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(0, 0, "foo");
+
+ ASSERT_THAT(
+ backgroundColors(),
+ ElementsAre(
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, SettingValueChangesByDisplayRoleBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(0, 0, "foo", Qt::DisplayRole);
+
+ ASSERT_THAT(
+ backgroundColors(),
+ ElementsAre(
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, ResettingValueChangesBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, QVariant{});
+
+ ASSERT_THAT(
+ backgroundColors(),
+ ElementsAre(
+ ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
+ ElementsAre(Not(Qt::darkYellow), Qt::darkYellow, Not(Qt::darkYellow), Qt::darkYellow),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, ResettingValueChangesByDisplayRoleBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(1, 1, QVariant{}, Qt::DisplayRole);
+
+ ASSERT_THAT(
+ backgroundColors(),
+ ElementsAre(
+ ElementsAre(Qt::darkYellow, Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow)),
+ ElementsAre(Not(Qt::darkYellow), Qt::darkYellow, Not(Qt::darkYellow), Qt::darkYellow),
+ ElementsAre(Not(Qt::darkYellow), Not(Qt::darkYellow), Not(Qt::darkYellow), Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, SettingNullValueChangesBackgroundColor)
+{
+ model.setListModel(listModelNode);
+
+ model.setValue(0, 0, 0);
+
+ ASSERT_THAT(backgroundColors(),
+ ElementsAre(ElementsAre(_, _, _, _),
+ ElementsAre(_, _, _, Qt::darkYellow),
+ ElementsAre(_, _, _, Qt::darkYellow)));
+}
+
+TEST_F(ListModelEditor, DontRenamePropertyIfColumnNameExists)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "value2");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExists)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "value2");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExistsDoesNotChangeDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "value2");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, DontRenameColumnIfColumnNameExistsDoesNotChangeProperties)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "value2");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("name", "bar"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("name", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RenamePropertyButDontChangeOrder)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "mood");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "mood", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, RenameColumnButDontChangeOrder)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "mood");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("image", "mood", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, RenameColumnButDontChangeOrderDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "mood");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
+ ElementsAre("pic.png", "bar", 4, IsInvalid()),
+ ElementsAre("pic.png", "poo", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, RenameColumnButDontChangeOrderProperies)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "mood");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("mood", "bar"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("mood", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RemoveColumnAfterRenameColumn)
+{
+ model.setListModel(listModelNode);
+ model.renameColumn(1, "mood");
+
+ model.removeColumn(1);
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, ChangeValueAfterRenameColumn)
+{
+ model.setListModel(listModelNode);
+ model.renameColumn(1, "mood");
+
+ model.setValue(1, 1, "taaa");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("mood", "taaa"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("mood", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RemovePropertyAfterRenameColumn)
+{
+ model.setListModel(listModelNode);
+ model.renameColumn(1, "mood");
+
+ model.setValue(1, 1, {});
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("mood", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RenameToPrecedingProperty)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "alpha");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("alpha", "image", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, RenameToPrecedingColumn)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "alpha");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("alpha", "image", "value", "value2"));
+}
+
+TEST_F(ListModelEditor, RenameToPrecedingColumnDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "alpha");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre("foo", IsInvalid(), 1, 42),
+ ElementsAre("bar", "pic.png", 4, IsInvalid()),
+ ElementsAre("poo", "pic.png", 111, IsInvalid())));
+}
+
+TEST_F(ListModelEditor, RenameToPrecedingColumnProperties)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(1, "alpha");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("alpha", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("alpha", "bar"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("alpha", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RenameToFollowingProperty)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(2, "zoo");
+
+ ASSERT_THAT(model.propertyNames(), ElementsAre("image", "name", "value2", "zoo"));
+}
+
+TEST_F(ListModelEditor, RenameToFollowingColumn)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(2, "zoo");
+
+ ASSERT_THAT(headerLabels(model), ElementsAre("image", "name", "value2", "zoo"));
+}
+
+TEST_F(ListModelEditor, RenameToFollowingColumnDisplayValues)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(2, "zoo");
+
+ ASSERT_THAT(displayValues(),
+ ElementsAre(ElementsAre(IsInvalid(), "foo", 42, 1),
+ ElementsAre("pic.png", "bar", IsInvalid(), 4),
+ ElementsAre("pic.png", "poo", IsInvalid(), 111)));
+}
+
+TEST_F(ListModelEditor, RenameToFollowingColumnProperties)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(2, "zoo");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
+ IsVariantProperty("zoo", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("name", "bar"),
+ IsVariantProperty("zoo", 4)),
+ UnorderedElementsAre(IsVariantProperty("image", "pic.png"),
+ IsVariantProperty("name", "poo"),
+ IsVariantProperty("zoo", 111))));
+}
+
+TEST_F(ListModelEditor, RenamePropertiesWithInvalidValue)
+{
+ model.setListModel(listModelNode);
+
+ model.renameColumn(0, "mood");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
+ IsVariantProperty("name", "bar"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
+ IsVariantProperty("name", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, ChangeValueAfterRenamePropertiesWithInvalidValue)
+{
+ model.setListModel(listModelNode);
+ model.renameColumn(0, "mood");
+
+ model.setValue(0, 0, "haaa");
+
+ ASSERT_THAT(properties(),
+ ElementsAre(UnorderedElementsAre(IsVariantProperty("mood", "haaa"),
+ IsVariantProperty("name", "foo"),
+ IsVariantProperty("value", 1),
+ IsVariantProperty("value2", 42)),
+ UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
+ IsVariantProperty("name", "bar"),
+ IsVariantProperty("value", 4)),
+ UnorderedElementsAre(IsVariantProperty("mood", "pic.png"),
+ IsVariantProperty("name", "poo"),
+ IsVariantProperty("value", 111))));
+}
+
+TEST_F(ListModelEditor, RemoveLastRow)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("mood");
+ model.addRow();
+
+ model.removeRow(0);
+
+ ASSERT_THAT(displayValues(), IsEmpty());
+}
+
+TEST_F(ListModelEditor, RemoveLastColumn)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("mood");
+ model.addRow();
+
+ model.removeColumn(0);
+
+ ASSERT_THAT(displayValues(), ElementsAre(IsEmpty()));
+}
+
+TEST_F(ListModelEditor, RemoveLastEmptyColumn)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("mood");
+ model.addRow();
+ model.removeRow(0);
+
+ model.removeColumn(0);
+
+ ASSERT_THAT(displayValues(), IsEmpty());
+}
+
+TEST_F(ListModelEditor, RemoveLastEmptyRow)
+{
+ model.setListModel(emptyListModelNode);
+ model.addColumn("mood");
+ model.addRow();
+ model.removeColumn(0);
+
+ model.removeRow(0);
+
+ ASSERT_THAT(displayValues(), IsEmpty());
+}
+
} // namespace
diff --git a/tests/unit/unittest/mocklistmodeleditorview.h b/tests/unit/unittest/mocklistmodeleditorview.h
new file mode 100644
index 0000000000..6bec164f33
--- /dev/null
+++ b/tests/unit/unittest/mocklistmodeleditorview.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <googletest.h>
+
+#include <qmldesigner/designercore/include/abstractview.h>
+
+class MockListModelEditorView : public QmlDesigner::AbstractView
+{
+public:
+ MOCK_METHOD(void,
+ variantPropertiesChanged,
+ (const QList<QmlDesigner::VariantProperty> &propertyList,
+ PropertyChangeFlags propertyChange),
+ (override));
+ MOCK_METHOD(void, nodeCreated, (const QmlDesigner::ModelNode &createdNode), (override));
+ MOCK_METHOD(void,
+ nodeReparented,
+ (const QmlDesigner::ModelNode &node,
+ const QmlDesigner::NodeAbstractProperty &newPropertyParent,
+ const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
+ AbstractView::PropertyChangeFlags propertyChange),
+ (override));
+ MOCK_METHOD(void,
+ propertiesRemoved,
+ (const QList<QmlDesigner::AbstractProperty> &propertyList),
+ (override));
+
+ MOCK_METHOD(void,
+ nodeRemoved,
+ (const QmlDesigner::ModelNode &removedNode,
+ const QmlDesigner::NodeAbstractProperty &parentProperty,
+ AbstractView::PropertyChangeFlags propertyChange),
+ (override));
+};
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 2ccc0bdb54..3917237d0b 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -39,8 +39,11 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug
}
gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type
-msvc: QMAKE_CXXFLAGS += /bigobj /wd4267 /wd4141 /wd4146 /wd4624
+msvc{
+QMAKE_CXXFLAGS += /bigobj /wd4267 /wd4141 /wd4146 /wd4624
+QMAKE_LFLAGS += /INCREMENTAL
+}
# create fake CppTools.json for the mime type definitions
dependencyList = "\"Dependencies\" : []"
cpptoolsjson.input = $$PWD/../../../src/plugins/cpptools/CppTools.json.in
@@ -244,6 +247,7 @@ HEADERS += \
mockclangpathwatcher.h \
mockclangpathwatchernotifier.h \
mockfilesystem.h \
+ mocklistmodeleditorview.h \
mockpchcreator.h \
mockpchmanagerclient.h \
mockpchmanagernotifier.h \