Skip to content

Commit

Permalink
Merge branch 'master' into topology_changes_fix
Browse files Browse the repository at this point in the history
  • Loading branch information
epernod committed Apr 11, 2019
2 parents 096e212 + 801cda5 commit 3aa9607
Show file tree
Hide file tree
Showing 21 changed files with 545 additions and 32 deletions.
1 change: 1 addition & 0 deletions SofaKernel/framework/framework_test/CMakeLists.txt
Expand Up @@ -9,6 +9,7 @@ set(SOURCE_FILES
core/objectmodel/BaseLink_test.cpp
core/objectmodel/BaseObjectDescription_test.cpp
core/objectmodel/DataFileName_test.cpp
core/objectmodel/DataCallback_test.cpp
core/DataEngine_test.cpp
defaulttype/MapMapSparseMatrixEigenUtils_test.cpp
defaulttype/MatTypes_test.cpp
Expand Down
@@ -0,0 +1,205 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture, development version *
* (c) 2006-2019 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program 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 Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#include <sofa/core/objectmodel/DataCallback.h>
using sofa::core::objectmodel::DataCallback;

#include <sofa/core/objectmodel/BaseObject.h>

#include <sofa/helper/testing/BaseTest.h>
using sofa::helper::testing::BaseTest ;


namespace sofa {


/// Test suite for data callbacks
struct DataCallback_test: public BaseTest
{
class TestObject : public sofa::core::objectmodel::BaseObject
{
public:
/// data attached to an object
Data<int> d_objdata1;
Data<int> d_objdata2;
DataCallback m_datacallback1;
DataCallback m_datacallback2;
DataCallback m_datacallbackAll;

void printData1()
{
msg_info("DataCallback_test") << "TestObject : Value of objdata1 changed : "
<< this->d_objdata1.getValue();
msg_warning("DataCallback_test") << "TestObject : Value of objdata2 did not changed : "
<< this->d_objdata2.getValue();
}
void printData2()
{
msg_advice("DataCallback_test") << "TestObject : Value of objdata2 changed : "
<< this->d_objdata2.getValue();
msg_error("DataCallback_test") << "TestObject : Value of objdata1 did not changed : "
<< this->d_objdata1.getValue();
}
void printDataAll()
{
msg_fatal("DataCallback_test") << "TestObject : Value of objdata1 or objdata2 changed : "
<< this->d_objdata1.getValue() << " | "
<< this->d_objdata2.getValue();
}

TestObject()
: sofa::core::objectmodel::BaseObject()
, d_objdata1(initData(&d_objdata1, 0, "objdata1", "objdata1"))
, d_objdata2(initData(&d_objdata2, 1, "objdata2", "objdata2"))
, m_datacallback1()
, m_datacallback2()
, m_datacallbackAll( )
{
m_datacallback1.addInput(&d_objdata1);
m_datacallback2.addInput(&d_objdata2);
m_datacallbackAll.addInputs({&d_objdata1, &d_objdata2});
}
};
};


TEST_F(DataCallback_test, testDataCallbackWithBind_1)
{
TestObject obj;
obj.m_datacallback1.addCallback(std::bind(&TestObject::printData1, &obj));

EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;

//callback is expected to print an info and a warning message
EXPECT_MSG_EMIT(Info) ;
EXPECT_MSG_EMIT(Warning) ;
obj.d_objdata1.setValue(123);
EXPECT_EQ( obj.d_objdata1.getValue(), 123 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;
}

TEST_F(DataCallback_test, testDataCallbackWithOldSyntax_1)
{
TestObject obj;
obj.m_datacallback1.addCallback([&obj](){obj.printData1();});

EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;

//callback is expected to print an info and a warning message
EXPECT_MSG_EMIT(Info) ;
EXPECT_MSG_EMIT(Warning) ;
obj.d_objdata1.setValue(123);
EXPECT_EQ( obj.d_objdata1.getValue(), 123 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;
}

TEST_F(DataCallback_test, testDataCallback_1)
{
TestObject obj;
obj.m_datacallback1.addCallback([&obj](){obj.printData1();});

EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;

/// callback is expected to print an info and a warning message
EXPECT_MSG_EMIT(Info) ;
EXPECT_MSG_EMIT(Warning) ;
obj.d_objdata1.setValue(123);
EXPECT_EQ( obj.d_objdata1.getValue(), 123 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;
}

TEST_F(DataCallback_test, testDataCallback_2)
{
TestObject obj;
obj.m_datacallback2.addCallback([&obj](){obj.printData2();});

EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;

//callback is expected to print an advice and an error message
EXPECT_MSG_EMIT(Advice) ;
EXPECT_MSG_EMIT(Error) ;
obj.d_objdata2.setValue(456);
EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 456 ) ;
}

/// In this test we show how we can use the Data &DataCallback without
/// any BaseObject.
TEST_F(DataCallback_test, testDataCallbackExample_1)
{
Data<int> a;
Data<int> b;
DataCallback cb;
cb.addInputs({&a,&b});

std::vector<int> results;

cb.addCallback([&a,&b, &results](){
msg_info("Example1") << a.getValue() << "+" << b.getValue() << "=" << a.getValue() + b.getValue();
results.push_back(a.getValue() + b.getValue());
});
cb.addCallback([&a,&b, &results](){
msg_info("Example1") << a.getValue() << "*" << b.getValue() << "=" << a.getValue() * b.getValue();
results.push_back(a.getValue() * b.getValue());
});

a.setValue(5);
EXPECT_EQ(results.size(), 2);
EXPECT_EQ(results[0], 5);
EXPECT_EQ(results[1], 0);

b.setValue(6);
EXPECT_EQ(results.size(), 4);
EXPECT_EQ(results[2], 11);
EXPECT_EQ(results[3], 30);

b.setValue(7);
EXPECT_EQ(results.size(), 6);
EXPECT_EQ(results[4], 12);
EXPECT_EQ(results[5], 35);
}


TEST_F(DataCallback_test, testDataCallback_All)
{
TestObject obj;
obj.m_datacallbackAll.addCallback([&obj](){obj.printDataAll();});

EXPECT_EQ( obj.d_objdata1.getValue(), 0 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;

//callback is expected to print a fatal message
EXPECT_MSG_EMIT(Fatal) ;
obj.d_objdata1.setValue(234);
EXPECT_EQ( obj.d_objdata1.getValue(), 234 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 1 ) ;
EXPECT_MSG_EMIT(Fatal) ; // how to expect an other (fatal) message ?
obj.d_objdata2.setValue(987);
EXPECT_EQ( obj.d_objdata1.getValue(), 234 ) ;
EXPECT_EQ( obj.d_objdata2.getValue(), 987 ) ;
}


}// namespace sofa
2 changes: 2 additions & 0 deletions SofaKernel/framework/sofa/core/CMakeLists.txt
Expand Up @@ -121,6 +121,7 @@ set(HEADER_FILES
objectmodel/ScriptEvent.h
objectmodel/SPtr.h
objectmodel/Tag.h
objectmodel/DataCallback.h
topology/BaseMeshTopology.h
topology/BaseTopology.h
topology/BaseTopologyData.h
Expand Down Expand Up @@ -212,6 +213,7 @@ set(SOURCE_FILES
objectmodel/Context.cpp
objectmodel/DDGNode.cpp
objectmodel/Data.cpp
objectmodel/DataCallback.cpp
objectmodel/DataFileName.cpp
objectmodel/DetachNodeEvent.cpp
objectmodel/Event.cpp
Expand Down
14 changes: 11 additions & 3 deletions SofaKernel/framework/sofa/core/objectmodel/BaseObject.cpp
Expand Up @@ -94,9 +94,17 @@ void BaseObject::parse( BaseObjectDescription* arg )
}
else
{
std::vector< std::string > attributeList;
arg->getAttributeList(attributeList);
setSrc(valueString, &attributeList);
if(valueString.size() == 1) // ignore '@' alone
{
msg_warning() << "'src=@' does nothing.";
}
else
{
std::vector< std::string > attributeList;
arg->getAttributeList(attributeList);
setSrc(valueString, &attributeList);
}

}
arg->removeAttribute("src");
}
Expand Down
5 changes: 5 additions & 0 deletions SofaKernel/framework/sofa/core/objectmodel/DDGNode.cpp
Expand Up @@ -107,6 +107,11 @@ void DDGNode::cleanDirty(const core::ExecParams* params)
}
}

void DDGNode::notifyEndEdit(const core::ExecParams* params)
{
for(DDGLinkIterator it=outputs.begin(params), itend=outputs.end(params); it != itend; ++it)
(*it)->notifyEndEdit(params);
}

void DDGNode::cleanDirtyOutputsOfInputs(const core::ExecParams* params)
{
Expand Down
3 changes: 3 additions & 0 deletions SofaKernel/framework/sofa/core/objectmodel/DDGNode.h
Expand Up @@ -178,6 +178,9 @@ class SOFA_CORE_API DDGNode
/// Set dirty flag to false
void cleanDirty(const core::ExecParams* params = nullptr);

/// Notify links that the DGNode has been modified
virtual void notifyEndEdit(const core::ExecParams* params = 0);

/// Utility method to call update if necessary. This method should be called before reading of writing the value of this node.
void updateIfDirty(const core::ExecParams* params = nullptr) const
{
Expand Down
1 change: 1 addition & 0 deletions SofaKernel/framework/sofa/core/objectmodel/Data.h
Expand Up @@ -448,6 +448,7 @@ class Data : public TData<T>
inline void endEdit(const core::ExecParams* params = nullptr)
{
m_values[DDGNode::currentAspect(params)].endEdit();
BaseData::notifyEndEdit(params);
}

/// @warning writeOnly (the Data is not updated before being set)
Expand Down
90 changes: 90 additions & 0 deletions SofaKernel/framework/sofa/core/objectmodel/DataCallback.cpp
@@ -0,0 +1,90 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture, development version *
* (c) 2006-2019 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program 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 Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#include <sofa/core/objectmodel/DataCallback.h>

namespace sofa
{

namespace core
{

namespace objectmodel
{

void DataCallback::addInputs(std::initializer_list<BaseData*> data)
{
for(BaseData* d : data)
{
addInput(d);
}
}

void DataCallback::addCallback(std::function<void(void)> f)
{
m_callbacks.push_back(f);
}

void DataCallback::notifyEndEdit(const core::ExecParams* params)
{
if (!m_updating)
{
m_updating = true;
for (auto& callback : m_callbacks)
callback();

sofa::core::objectmodel::DDGNode::notifyEndEdit(params);
m_updating = false;
}
else
{
msg_warning("DataCallback") << "A DataCallback seems to have a circular dependency, please fix it to remove this warning.";
}
}

const std::string& DataCallback::getName() const
{
static std::string s="";
return s;
}

sofa::core::objectmodel::Base* DataCallback::getOwner() const
{
return nullptr;
}

sofa::core::objectmodel::BaseData* DataCallback::getData() const
{
return nullptr;
}

void DataCallback::update()
{

}

} /// namespace objectmodel

} /// namespace core

} /// namespace sofa


0 comments on commit 3aa9607

Please sign in to comment.