diff --git a/tests/src/App/CMakeLists.txt b/tests/src/App/CMakeLists.txt index 94afdcd0a9..d2b8d95226 100644 --- a/tests/src/App/CMakeLists.txt +++ b/tests/src/App/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(Tests_run PRIVATE MappedName.cpp Metadata.cpp ProjectFile.cpp + Property.h Property.cpp PropertyExpressionEngine.cpp StringHasher.cpp diff --git a/tests/src/App/Property.cpp b/tests/src/App/Property.cpp index 4589f5b8b9..04f3aa8e42 100644 --- a/tests/src/App/Property.cpp +++ b/tests/src/App/Property.cpp @@ -1,11 +1,46 @@ +/**************************************************************************** + * Copyright (c) 2024 Werner Mayer * + * Copyright (c) 2025 Pieter Hijma * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ + #include -#include "App/PropertyLinks.h" -#include #include #include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + #include +#include "Property.h" + TEST(PropertyLink, TestSetValues) { App::PropertyLinkSubList prop; @@ -50,3 +85,231 @@ TEST_F(PropertyFloatTest, testWriteRead) prop2.Restore(reader); EXPECT_DOUBLE_EQ(prop2.getValue(), value); } + +std::string RenameProperty::_docName; +App::Document* RenameProperty::_doc {nullptr}; + +// Tests whether we can rename a property +TEST_F(RenameProperty, renameProperty) +{ + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "NewName"); + + // Assert + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); +} + +// Tests whether we can rename a property from Python +TEST_F(RenameProperty, renamePropertyPython) +{ + // Act + Base::Interpreter().runString( + "App.ActiveDocument.getObject('VarSet').renameProperty('Variable', 'NewName')"); + + // Assert + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); +} + +// Tests whether we can rename a property in a chain +TEST_F(RenameProperty, renamePropertyChain) +{ + // Act 1 + bool isRenamed = varSet->renameDynamicProperty(prop, "Name1"); + + // Assert 1 + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "Name1"); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("Name1"), prop); + + // Act 2 + auto prop1 = freecad_cast(varSet->getDynamicPropertyByName("Name1")); + isRenamed = varSet->renameDynamicProperty(prop1, "Name2"); + + // Assert 2 + EXPECT_TRUE(isRenamed); + EXPECT_EQ(prop, prop1); + EXPECT_STREQ(varSet->getPropertyName(prop1), "Name2"); + EXPECT_EQ(varSet->getDynamicPropertyByName("Name1"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("Name2"), prop1); +} + +// Tests whether we can rename a static property +TEST_F(RenameProperty, renameStaticProperty) +{ + // Arrange + App::Property* prop = varSet->getPropertyByName("Label"); + + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "MyLabel"); + + // Assert + EXPECT_FALSE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "Label"); + EXPECT_EQ(varSet->getDynamicPropertyByName("MyLabel"), nullptr); +} + +// Tests whether we can rename a static property from Python +TEST_F(RenameProperty, renameStaticPropertyPython) +{ + // Arrange + App::Property* prop = varSet->getPropertyByName("Label"); + + // Act / Assert + EXPECT_THROW( + Base::Interpreter().runString( + "App.ActiveDocument.getObject('VarSet006').renameProperty('Label', 'NewName')"), + Base::Exception); + + // Assert + EXPECT_STREQ(varSet->getPropertyName(prop), "Label"); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), nullptr); +} + +// Tests whether we can rename a locked property +TEST_F(RenameProperty, renameLockedProperty) +{ + // Arrange + prop->setStatus(App::Property::LockDynamic, true); + + // Act / Assert + EXPECT_THROW(varSet->renameDynamicProperty(prop, "NewName"), Base::RuntimeError); + + // Assert + EXPECT_STREQ(varSet->getPropertyName(prop), "Variable"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), prop); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), nullptr); +} + +// Tests whether we can rename to a property that already exists +TEST_F(RenameProperty, renameToExistingProperty) +{ + // Arrange + App::Property* prop2 = + varSet->addDynamicProperty("App::PropertyInteger", "Variable2", "Variables"); + + // Act / Assert + EXPECT_THROW(varSet->renameDynamicProperty(prop2, "Variable"), Base::NameError); + + // Assert + EXPECT_STREQ(varSet->getPropertyName(prop), "Variable"); + EXPECT_STREQ(varSet->getPropertyName(prop2), "Variable2"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), prop); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable2"), prop2); +} + +// Tests whether we can rename to a property that is invalid +TEST_F(RenameProperty, renameToInvalidProperty) +{ + // Act / Assert + EXPECT_THROW(varSet->renameDynamicProperty(prop, "0Variable"), Base::NameError); + + // Assert + EXPECT_STREQ(varSet->getPropertyName(prop), "Variable"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), prop); + EXPECT_EQ(varSet->getDynamicPropertyByName("0Variable"), nullptr); +} + +// Tests whether we can rename a property that is used in an expression in the same container +TEST_F(RenameProperty, updateExpressionSameContainer) +{ + // Arrange + const auto* prop2 = freecad_cast( + varSet->addDynamicProperty("App::PropertyInteger", "Variable2", "Variables")); + + App::ObjectIdentifier path(*prop2); + std::shared_ptr expr(App::Expression::parse(varSet, "Variable")); + varSet->setExpression(path, expr); + varSet->ExpressionEngine.execute(); + + // Assert before the rename + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(prop2->getValue(), Value); + + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "NewName"); + varSet->ExpressionEngine.execute(); + + // Assert after the rename + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); + EXPECT_EQ(prop2->getValue(), Value); +} + +// Tests whether we can rename a property that is used in an expression in a different container +TEST_F(RenameProperty, updateExpressionDifferentContainer) +{ + // Arrange + auto* varSet2 = freecad_cast(_doc->addObject("App::VarSet", "VarSet2")); + const auto* prop2 = freecad_cast( + varSet2->addDynamicProperty("App::PropertyInteger", "Variable2", "Variables")); + + App::ObjectIdentifier path(*prop2); + std::shared_ptr expr(App::Expression::parse(varSet, "VarSet.Variable")); + varSet2->setExpression(path, expr); + varSet2->ExpressionEngine.execute(); + + // Assert before the rename + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(prop2->getValue(), Value); + + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "NewName"); + varSet2->ExpressionEngine.execute(); + + // Assert after the rename + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); + EXPECT_EQ(prop2->getValue(), Value); +} + +// Tests whether we can rename a property that is used in an expression in a different document +TEST_F(RenameProperty, updateExpressionDifferentDocument) +{ + // Arrange + std::string docName = App::GetApplication().getUniqueDocumentName("test2"); + App::Document* doc = App::GetApplication().newDocument(docName.c_str(), "testUser"); + + auto* varSet2 = freecad_cast(doc->addObject("App::VarSet", "VarSet2")); + const auto* prop2 = freecad_cast( + varSet2->addDynamicProperty("App::PropertyInteger", "Variable2", "Variables")); + + App::ObjectIdentifier path(*prop2); + std::shared_ptr expr(App::Expression::parse(varSet, "test#VarSet.Variable")); + _doc->saveAs("test.FCStd"); + doc->saveAs("test2.FCStd"); + varSet2->setExpression(path, expr); + varSet2->ExpressionEngine.execute(); + + // Assert before the rename + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(prop2->getValue(), Value); + + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "NewName"); + varSet2->ExpressionEngine.execute(); + + // Assert after the rename + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); + EXPECT_EQ(prop2->getValue(), Value); +} diff --git a/tests/src/App/Property.h b/tests/src/App/Property.h new file mode 100644 index 0000000000..0e83bc4348 --- /dev/null +++ b/tests/src/App/Property.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * Copyright (c) 2025 Pieter Hijma * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ +#ifndef TEST_PROPERTY_H +#define TEST_PROPERTY_H + +#include + +#include +#include +#include + +#include + +class RenameProperty: public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + _docName = App::GetApplication().getUniqueDocumentName("test"); + _doc = App::GetApplication().newDocument(_docName.c_str(), "testUser"); + } + + void SetUp() override + { + varSet = freecad_cast(_doc->addObject("App::VarSet", "VarSet")); + prop = freecad_cast( + varSet->addDynamicProperty("App::PropertyInteger", "Variable", "Variables")); + prop->setValue(Value); + } + + void TearDown() override + { + _doc->removeObject(varSet->getNameInDocument()); + } + + static void TearDownTestSuite() + { + App::GetApplication().closeDocument(_docName.c_str()); + } + + const long Value = 123; + App::VarSet* varSet {}; + App::PropertyInteger* prop {}; + + static std::string _docName; + static App::Document* _doc; +}; + +#endif