diff --git a/tests/src/App/CMakeLists.txt b/tests/src/App/CMakeLists.txt index 6718941efc..82fc35397c 100644 --- a/tests/src/App/CMakeLists.txt +++ b/tests/src/App/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ComplexGeoData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Document.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/DocumentObject.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Expression.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionParser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ElementMap.cpp diff --git a/tests/src/App/DocumentObject.cpp b/tests/src/App/DocumentObject.cpp new file mode 100644 index 0000000000..5b1b23cbe3 --- /dev/null +++ b/tests/src/App/DocumentObject.cpp @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "gtest/gtest.h" +#include + +#include + +#include +#include +#include +#include +#include + +using namespace App; + +// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) + +class DocumentObjectTest: public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + } + + void SetUp() override + { + _docName = App::GetApplication().getUniqueDocumentName("test"); + _doc = App::GetApplication().newDocument(_docName.c_str(), "testUser"); + } + + void TearDown() override + { + App::GetApplication().closeDocument(_docName.c_str()); + } + + // NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes) + std::string _docName {}; + App::Document* _doc {}; + // NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes) +}; + + +TEST_F(DocumentObjectTest, getSubObjectList) +{ + // Arrange + + // The name of a Part::Box added to the document + auto boxName {_doc->addObject("Part::Box")->getNameInDocument()}; + // The name of a Part::Cylinder added to the document + auto cylName {_doc->addObject("Part::Cylinder")->getNameInDocument()}; + // The an App::Part added to the document + auto part {_doc->addObject("App::Part")}; + // The name of the App::Part added to the document + auto partName {part->getNameInDocument()}; + // The name of the object used as argument for the calls of DocumentObject::getSubObjectList() + auto subName {std::string()}; + + // a vector of int used as argument for the call of DocumentObject::getSubObjectList() with + // argument flatten not set (or set to false) + auto sizesNoFlatten {std::vector()}; + // a vector of int used as argument for the call of DocumentObject::getSubObjectList() with + // argument flatten set to true + auto sizesFlatten {std::vector()}; + // An helper string used to compose the argument of some calls of + // Base::Interpreter().runString() + auto cmd {std::string()}; + + // Performing a fusion to create an object that will be searched with the calls of + // DocumentObject::getSubObjectList() + Base::Interpreter().runString("from BOPTools import BOPFeatures"); + Base::Interpreter().runString("bp = BOPFeatures.BOPFeatures(App.activeDocument())"); + cmd = "bp.make_multi_fuse([\""; + cmd += boxName; + cmd += "\", \""; + cmd += cylName; + cmd += "\", ])"; + Base::Interpreter().runString(cmd.c_str()); + Base::Interpreter().runString("App.ActiveDocument.recompute()"); + // The name of the fusion object + auto fuseName {_doc->getObject("Fusion")->getNameInDocument()}; + + // Defining the name of the object that will be searched with the calls of + // DocumentObject::getSubObjectList() + subName = fuseName; + subName += "."; + subName += boxName; + subName += ".Edge1"; + + // Adding the fusion to the App::Part object to test the differences between calling + // DocumentObject::getSubObjectList() with the flatten argument set to false or set to true + cmd = "App.ActiveDocument.getObject(\""; + cmd += partName; + cmd += "\").addObject(App.ActiveDocument.getObject(\""; + cmd += fuseName; + cmd += "\"))"; + Base::Interpreter().runString(cmd.c_str()); + Base::Interpreter().runString("App.ActiveDocument.recompute()"); + + // A vector of DocumentObjects used to store the result of the call to + // DocumentObject::getSubObjectList() without the subname parameter + auto docSubObjsNoSubName {std::vector()}; + // A vector of DocumentObjects used to store the result of the call to + // DocumentObject::getSubObjectList() with only the subname parameter + auto docSubObjsWithSubName {std::vector()}; + // A vector of DocumentObjects used to store the result of the call to + // DocumentObject::getSubObjectList() with the parameters subname and subsizes + auto docSubObjsWithSubSizes {std::vector()}; + // A vector of DocumentObjects used to store the result of the call to + // DocumentObject::getSubObjectList() with the flatten parameter set to true + auto docSubObjsFlatten {std::vector()}; + + // Act + docSubObjsNoSubName = part->getSubObjectList(nullptr); + docSubObjsWithSubName = part->getSubObjectList(subName.c_str()); + docSubObjsWithSubSizes = part->getSubObjectList(subName.c_str(), &sizesNoFlatten); + docSubObjsFlatten = part->getSubObjectList(subName.c_str(), &sizesFlatten, true); + + // Assert + + // If DocumentObject::getSubObjectList() is called without giving the subname argument it + // returns a vector with only one entry, corresponding to the object that called the method + EXPECT_EQ(docSubObjsNoSubName.size(), 1); + EXPECT_EQ(docSubObjsNoSubName[0]->getID(), _doc->getObject(partName)->getID()); + + // If DocumentObject::getSubObjectList() is called with the subname argument it returns a vector + // with one entry for each sub object in the subname plus one entry with the object that called + // the method + EXPECT_EQ(docSubObjsWithSubName.size(), 3); + EXPECT_EQ(docSubObjsWithSubName[0]->getID(), _doc->getObject(partName)->getID()); + EXPECT_EQ(docSubObjsWithSubName[1]->getID(), _doc->getObject(fuseName)->getID()); + EXPECT_EQ(docSubObjsWithSubName[2]->getID(), _doc->getObject(boxName)->getID()); + + // If DocumentObject::getSubObjectList() is called with the subsizes argument it returns the + // same vector of the previous case and the subsizes argument stores the positions in the + // subname string corresponding to start of the sub objects names + EXPECT_EQ(docSubObjsWithSubSizes.size(), 3); + EXPECT_EQ(docSubObjsWithSubSizes[0]->getID(), _doc->getObject(partName)->getID()); + EXPECT_EQ(docSubObjsWithSubSizes[1]->getID(), _doc->getObject(fuseName)->getID()); + EXPECT_EQ(docSubObjsWithSubSizes[2]->getID(), _doc->getObject(boxName)->getID()); + EXPECT_EQ(sizesNoFlatten.size(), 3); + EXPECT_EQ(sizesNoFlatten[0], 0); + EXPECT_EQ(sizesNoFlatten[1], 7); + EXPECT_EQ(sizesNoFlatten[2], 17); + + // If DocumentObject::getSubObjectList() is called with the flatten argument set to true it + // returns a vector with all the sub objects in the subname that don't belong to the same + // App::GeoFeatureGroupExtension object, plus one entry with the object that called the method + EXPECT_EQ(docSubObjsFlatten.size(), 2); + EXPECT_EQ(docSubObjsFlatten[0]->getID(), _doc->getObject(partName)->getID()); + EXPECT_EQ(docSubObjsFlatten[1]->getID(), _doc->getObject(boxName)->getID()); + EXPECT_EQ(sizesFlatten.size(), 2); + EXPECT_EQ(sizesFlatten[0], 0); + EXPECT_EQ(sizesFlatten[1], 17); +} + +// NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)