diff --git a/src/MaterialComboDelegate_test.cpp b/src/MaterialComboDelegate_test.cpp index 005996696..333d9e4d7 100644 --- a/src/MaterialComboDelegate_test.cpp +++ b/src/MaterialComboDelegate_test.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "MaterialComboDelegate.h" #include "Manager.h" @@ -186,3 +187,40 @@ TEST_F(MaterialComboDelegateTest, MaterialColumnWithoutSubEntityProducesEmptySty EXPECT_TRUE(option.text.isEmpty()); } + +TEST_F(MaterialComboDelegateTest, SetEditorDataForMaterialColumnWithoutSubEntityDoesNotBreakSelection) +{ + MaterialComboDelegate delegate; + QWidget parentWidget; + QStyleOptionViewItem option; + QStandardItemModel model(1, 3); + QModelIndex index = model.index(0, 2); + + QWidget* editor = delegate.createEditor(&parentWidget, option, index); + auto* comboBox = qobject_cast(editor); + ASSERT_NE(comboBox, nullptr); + ASSERT_GT(comboBox->count(), 0); + + comboBox->setCurrentIndex(0); + const QString previousText = comboBox->currentText(); + delegate.setEditorData(editor, index); + + // For non-editable QComboBox, setting an absent text may preserve current selection. + EXPECT_TRUE(comboBox->currentText().isEmpty() || comboBox->currentText() == previousText); + + delete editor; +} + +TEST_F(MaterialComboDelegateTest, CommitAndCloseEditorWithoutSenderDoesNotEmitSignals) +{ + MaterialComboDelegate delegate; + QSignalSpy commitSpy(&delegate, &QAbstractItemDelegate::commitData); + QSignalSpy closeSpy(&delegate, &QAbstractItemDelegate::closeEditor); + ASSERT_TRUE(commitSpy.isValid()); + ASSERT_TRUE(closeSpy.isValid()); + + ASSERT_TRUE(QMetaObject::invokeMethod(&delegate, "commitAndCloseEditor", Qt::DirectConnection)); + + EXPECT_EQ(commitSpy.count(), 0); + EXPECT_EQ(closeSpy.count(), 0); +} diff --git a/src/SelectionSet_test.cpp b/src/SelectionSet_test.cpp index 87ec0d0e0..4372e0d18 100644 --- a/src/SelectionSet_test.cpp +++ b/src/SelectionSet_test.cpp @@ -819,5 +819,48 @@ TEST_F(SelectionSetTests, RemoveNonExistentEntityAndSubEntityReturnFalse) Manager::getSingleton()->destroySceneNode(node); } +TEST_F(SelectionSetTests, SingletonKillAndRecreateProducesValidInstance) +{ + SelectionSet* first = SelectionSet::getSingleton(); + ASSERT_NE(first, nullptr); + + SelectionSet::kill(); + + SelectionSet* second = SelectionSet::getSingleton(); + ASSERT_NE(second, nullptr); +} + +TEST_F(SelectionSetTests, GetResolvedEntitiesWithEmptySelectionReturnsEmptyList) +{ + SelectionSet* selectionSet = SelectionSet::getSingleton(); + selectionSet->clear(); + + const QList resolved = selectionSet->getResolvedEntities(); + EXPECT_TRUE(resolved.isEmpty()); +} + +TEST_F(SelectionSetTests, GetSelectionCenterWithMultipleNodesAveragesPositions) +{ + SelectionSet* selectionSet = SelectionSet::getSingleton(); + selectionSet->clear(); + + Ogre::SceneNode* node1 = Manager::getSingleton()->addSceneNode("center_nodes_1"); + Ogre::SceneNode* node2 = Manager::getSingleton()->addSceneNode("center_nodes_2"); + ASSERT_NE(node1, nullptr); + ASSERT_NE(node2, nullptr); + + node1->setPosition(1.0f, 2.0f, 3.0f); + node2->setPosition(5.0f, 6.0f, 7.0f); + selectionSet->append(node1); + selectionSet->append(node2); + + const Ogre::Vector3 center = selectionSet->getSelectionCenter(); + EXPECT_EQ(center, Ogre::Vector3(3.0f, 4.0f, 5.0f)); + + selectionSet->clear(); + Manager::getSingleton()->destroySceneNode(node1); + Manager::getSingleton()->destroySceneNode(node2); +} + // NOTE: GetSelectionCenterWithSubEntity and all subsequent tests were removed // because they crash in CI (PrimitiveObject::createCube requires GL context).