diff --git a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp index 1f8429d1224..61e2cdf2e72 100644 --- a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp @@ -90,25 +90,22 @@ class STLExporter_test : public BaseSimulationTest { } } - void checkBasicBehavior(const std::string& filename, std::vector pathes){ + void checkBasicBehavior(const std::string& filename, std::vector pathes) + { dataPath = pathes ; EXPECT_MSG_NOEMIT(Error, Warning) ; - std::stringstream scene1; - scene1 << - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("testscene", scene1.str().c_str()); - - ASSERT_NE(root.get(), nullptr) << scene1.str() ; - root->init(sofa::core::execparams::defaultInstance()) ; + + const Node::SPtr root = sofa::simpleapi::createRootNode(sofa::simulation::getSimulation(), "root", {{"gravity", "0 0 0"}}); + sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"position", "0 1 2 3 4 5 6 7 8 9"}}); + sofa::simpleapi::createObject(root, "MeshOBJLoader", {{"name", "loader"}, {"filename", "mesh/liver-smooth.obj"}}); + const Node::SPtr visualNode = sofa::simpleapi::createChild(root, "Visual"); + sofa::simpleapi::createObject(visualNode, "VisualModel", {{"src", "@../loader"}}); + sofa::simpleapi::createObject(visualNode, "STLExporter", {{"name", "exporter1"}, {"filename", filename}, {"exportAtBegin", "true"}}); + + ASSERT_NE(root.get(), nullptr); + sofa::simulation::node::initRoot(root.get()); // SimulationInitDoneEvent is used to trigger exportAtBegin SimulationInitDoneEvent endInit; @@ -119,32 +116,27 @@ class STLExporter_test : public BaseSimulationTest { for(auto& pathToCheck : pathes) { - EXPECT_TRUE( FileSystem::exists(pathToCheck) ) << "Problem with '" << pathToCheck << "'"<< std::endl - << "================= scene dump ===========================" - << scene1.str() ; + EXPECT_TRUE( FileSystem::exists(pathToCheck) ); } } - void checkSimulationWriteEachNbStep(const std::string& filename, std::vector pathes, unsigned int numstep){ + void checkSimulationWriteEachNbStep(const std::string& filename, std::vector pathes, unsigned int numstep) + { dataPath = pathes ; EXPECT_MSG_NOEMIT(Error, Warning) ; - std::stringstream scene1; - scene1 << - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("testscene", scene1.str().c_str()); + + const Node::SPtr root = sofa::simpleapi::createRootNode(sofa::simulation::getSimulation(), "root", {{"gravity", "0 0 0"}}); + sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"position", "0 1 2 3 4 5 6 7 8 9"}}); + sofa::simpleapi::createObject(root, "MeshOBJLoader", {{"name", "loader"}, {"filename", "mesh/liver-smooth.obj"}}); + const Node::SPtr visualNode = sofa::simpleapi::createChild(root, "Visual"); + sofa::simpleapi::createObject(visualNode, "VisualModel", {{"src", "@../loader"}}); + sofa::simpleapi::createObject(visualNode, "STLExporter", {{"name", "exporterA"}, {"filename", filename}, {"exportEveryNumberOfSteps", "5"}}); ASSERT_NE(root.get(), nullptr) ; - root->init(sofa::core::execparams::defaultInstance()) ; + sofa::simulation::node::initRoot(root.get()); for(unsigned int i=0;i +void checkAlreadyContains(Node& self, LinkType& link, Component* obj) +{ + if constexpr (!LinkType::IsMultiLink) + { + if (link != obj && link != nullptr) + { + static const auto componentClassName = Component::GetClass()->className; + msg_warning(&self) << "Trying to add a " << componentClassName << " ('" + << obj->getName() << "' [" << obj->getClassName() << "] " << obj << ")" + << " into the Node '" << self.getPathName() + << "', whereas it already contains one ('" << link->getName() << "' [" << link->getClassName() << "] " << link.get() << ")." + << " Only one " << componentClassName << " is permitted in a Node. The previous " + << componentClassName << " is replaced and the behavior is undefined."; + } + } +} + #define NODE_DEFINE_SEQUENCE_ACCESSOR( CLASSNAME, FUNCTIONNAME, SEQUENCENAME ) \ - void Node::add##FUNCTIONNAME( CLASSNAME* obj ) { SEQUENCENAME.add(obj); } \ + void Node::add##FUNCTIONNAME( CLASSNAME* obj ) { checkAlreadyContains(*this, SEQUENCENAME, obj); SEQUENCENAME.add(obj); } \ void Node::remove##FUNCTIONNAME( CLASSNAME* obj ) { SEQUENCENAME.remove(obj); } NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::behavior::BaseAnimationLoop, AnimationLoop, animationManager ) diff --git a/Sofa/framework/Simulation/Graph/test/Node_test.cpp b/Sofa/framework/Simulation/Graph/test/Node_test.cpp index bb07c4221c1..edb453be83e 100644 --- a/Sofa/framework/Simulation/Graph/test/Node_test.cpp +++ b/Sofa/framework/Simulation/Graph/test/Node_test.cpp @@ -19,6 +19,8 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ +#include +#include #include using sofa::testing::BaseSimulationTest ; @@ -33,6 +35,9 @@ namespace sofa TEST( Node_test, getPathName) { + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + /* create trivial DAG : * * A @@ -90,6 +95,9 @@ TEST(Node_test, addObjectAtFront) TEST(Node_test, addObjectPreventingSharedContext) { + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + const sofa::core::sptr root = sofa::simpleapi::createNode("root"); const BaseObject::SPtr A = core::objectmodel::New("A"); @@ -177,6 +185,53 @@ TEST(Node_test, getObjectsStdUnorderedSet) EXPECT_NE(objects.find(B.get()), objects.end()); } +class CounterVisitor : public simulation::MechanicalVisitor +{ +public: + using MechanicalVisitor::MechanicalVisitor; + + Result fwdMechanicalState(simulation::Node* node, sofa::core::behavior::BaseMechanicalState* state) override + { + SOFA_UNUSED(node); + SOFA_UNUSED(state); + m_counter++; + return Result::RESULT_CONTINUE; + } + + Result fwdMappedMechanicalState(simulation::Node* node, sofa::core::behavior::BaseMechanicalState* state) override + { + SOFA_UNUSED(node); + SOFA_UNUSED(state); + ++m_counter; + return Result::RESULT_CONTINUE; + } + + std::size_t m_counter = 0; +}; + +TEST(Node_test, twoMechanicalStatesInTheSameNode) +{ + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + + const sofa::core::sptr root = sofa::simpleapi::createNode("root"); + + const auto plugins = testing::makeScopedPlugin({Sofa.Component.StateContainer}); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"template", "Vec3"}, {"name", "A"}}); + + EXPECT_MSG_EMIT(Warning); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"template", "Vec3"}, {"name", "B"}}); + + //the last added state is the one in Node + EXPECT_EQ(root->mechanicalState->getName(), "B"); + + CounterVisitor visitor(core::MechanicalParams::defaultInstance()); + root->executeVisitor(&visitor); + + //only one of the two added states is visited + EXPECT_EQ(visitor.m_counter, 1); +} + }// namespace sofa diff --git a/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp b/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp index 53507e22024..8fad0b75081 100644 --- a/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp +++ b/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp @@ -223,10 +223,9 @@ struct Scene_test: public NumericTest root = simulation::getSimulation()->createNewGraph("root"); root->addObject(core::objectmodel::New >()); - typename UniformMass3::SPtr uniformMass = core::objectmodel::New(); + typename UniformMass3::SPtr uniformMass = core::objectmodel::New>(); uniformMass->d_totalMass.setValue(1.0); root->addObject(uniformMass); - root->addObject(core::objectmodel::New >()); const simulation::Node::SPtr child = simulation::getSimulation()->createNewNode("child"); root->addChild(child);