3#define BOOST_TEST_MODULE testCircularDependencyFaultyFlags
9#include <boost/test/included/unit_test.hpp>
29 using ctk::VariableGroup::VariableGroup;
34 using ctk::VariableGroup::VariableGroup;
42 const std::string& name,
const std::string& description)
71 ctk::ReadAnyGroup rag({
a,
b,
inputGroup.circularInput1});
74 auto id = rag.readAny();
83 assert((
id ==
a.getId() ||
id ==
b.getId()) ||
id ==
inputGroup.circularInput1.getId() ||
91 if(
id ==
a.getId() ||
id ==
b.getId()) {
148 template<
typename APP_TYPE>
179 BOOST_CHECK(
aOut1.dataValidity() == validity);
180 BOOST_CHECK(
bOut1.dataValidity() == validity);
181 BOOST_CHECK(
cOut1.dataValidity() == validity);
182 BOOST_CHECK(
dOut1.dataValidity() == validity);
183 BOOST_CHECK(
aIn2.dataValidity() == validity);
184 BOOST_CHECK(
bIn2.dataValidity() == validity);
185 BOOST_CHECK(
cIn2.dataValidity() == validity);
186 BOOST_CHECK(
dIn2.dataValidity() == validity);
246 a.setDataValidity(ctk::DataValidity::faulty);
249 test.stepApplication();
252 checkAllDataValidity(ctk::DataValidity::faulty);
257 test.stepApplication();
260 checkAllDataValidity(ctk::DataValidity::faulty);
263 a.setDataValidity(ctk::DataValidity::ok);
265 test.stepApplication();
269 BOOST_CHECK(app.a.inputGroup.circularInput1.dataValidity() == ctk::DataValidity::faulty);
270 BOOST_CHECK(app.a.circularInput2.dataValidity() == ctk::DataValidity::faulty);
272 BOOST_CHECK(aOut1.dataValidity() == ctk::DataValidity::ok);
273 BOOST_CHECK(bOut1.dataValidity() == ctk::DataValidity::ok);
274 BOOST_CHECK(bIn2.dataValidity() == ctk::DataValidity::ok);
275 BOOST_CHECK(cIn2.dataValidity() == ctk::DataValidity::ok);
277 BOOST_CHECK(cOut1.dataValidity() == ctk::DataValidity::faulty);
278 BOOST_CHECK(dOut1.dataValidity() == ctk::DataValidity::faulty);
279 BOOST_CHECK(aIn2.dataValidity() == ctk::DataValidity::faulty);
280 BOOST_CHECK(dIn2.dataValidity() == ctk::DataValidity::faulty);
281 BOOST_CHECK(circleResult.dataValidity() == ctk::DataValidity::faulty);
285 test.stepApplication();
288 checkAllDataValidity(ctk::DataValidity::ok);
296 a.setDataValidity(ctk::DataValidity::faulty);
299 test.stepApplication();
301 b.setDataValidity(ctk::DataValidity::faulty);
304 test.stepApplication();
308 checkAllDataValidity(ctk::DataValidity::faulty);
310 a.setDataValidity(ctk::DataValidity::ok);
313 test.stepApplication();
317 checkAllDataValidity(ctk::DataValidity::faulty);
319 b.setDataValidity(ctk::DataValidity::ok);
322 test.stepApplication();
325 checkAllDataValidity(ctk::DataValidity::ok);
333 app.a.circularOutput1.setDataValidity(ctk::DataValidity::faulty);
335 test.stepApplication();
340 BOOST_CHECK(aOut1.dataValidity() == ctk::DataValidity::faulty);
341 BOOST_CHECK(bOut1.dataValidity() == ctk::DataValidity::faulty);
342 BOOST_CHECK(bIn2.dataValidity() == ctk::DataValidity::ok);
343 BOOST_CHECK(cIn2.dataValidity() == ctk::DataValidity::faulty);
345 BOOST_CHECK(cOut1.dataValidity() == ctk::DataValidity::ok);
346 BOOST_CHECK(dOut1.dataValidity() == ctk::DataValidity::ok);
347 BOOST_CHECK(aIn2.dataValidity() == ctk::DataValidity::ok);
348 BOOST_CHECK(dIn2.dataValidity() == ctk::DataValidity::ok);
349 BOOST_CHECK(circleResult.dataValidity() == ctk::DataValidity::ok);
352 test.stepApplication();
358 BOOST_CHECK(aOut1.dataValidity() == ctk::DataValidity::faulty);
359 BOOST_CHECK(bOut1.dataValidity() == ctk::DataValidity::faulty);
360 BOOST_CHECK(bIn2.dataValidity() == ctk::DataValidity::ok);
361 BOOST_CHECK(cIn2.dataValidity() == ctk::DataValidity::faulty);
363 BOOST_CHECK(cOut1.dataValidity() == ctk::DataValidity::faulty);
364 BOOST_CHECK(dOut1.dataValidity() == ctk::DataValidity::faulty);
365 BOOST_CHECK(aIn2.dataValidity() == ctk::DataValidity::faulty);
366 BOOST_CHECK(dIn2.dataValidity() == ctk::DataValidity::faulty);
367 BOOST_CHECK(circleResult.dataValidity() == ctk::DataValidity::faulty);
372 test.stepApplication();
375 checkAllDataValidity(ctk::DataValidity::faulty);
378 app.a.circularOutput1.setDataValidity(ctk::DataValidity::ok);
380 test.stepApplication();
384 BOOST_CHECK(aOut1.dataValidity() == ctk::DataValidity::ok);
385 BOOST_CHECK(bOut1.dataValidity() == ctk::DataValidity::ok);
386 BOOST_CHECK(bIn2.dataValidity() == ctk::DataValidity::ok);
387 BOOST_CHECK(cIn2.dataValidity() == ctk::DataValidity::ok);
389 BOOST_CHECK(cOut1.dataValidity() == ctk::DataValidity::faulty);
390 BOOST_CHECK(dOut1.dataValidity() == ctk::DataValidity::faulty);
391 BOOST_CHECK(aIn2.dataValidity() == ctk::DataValidity::faulty);
392 BOOST_CHECK(dIn2.dataValidity() == ctk::DataValidity::faulty);
393 BOOST_CHECK(circleResult.dataValidity() == ctk::DataValidity::faulty);
396 test.stepApplication();
399 checkAllDataValidity(ctk::DataValidity::ok);
407 a.setDataValidity(ctk::DataValidity::faulty);
410 test.stepApplication();
413 cTrigger.setDataValidity(ctk::DataValidity::faulty);
415 test.stepApplication();
419 checkAllDataValidity(ctk::DataValidity::faulty);
421 a.setDataValidity(ctk::DataValidity::ok);
424 test.stepApplication();
428 checkAllDataValidity(ctk::DataValidity::faulty);
431 cTrigger.setDataValidity(ctk::DataValidity::ok);
433 test.stepApplication();
438 BOOST_CHECK(aOut1.dataValidity() == ctk::DataValidity::faulty);
439 BOOST_CHECK(bOut1.dataValidity() == ctk::DataValidity::faulty);
440 BOOST_CHECK(bIn2.dataValidity() == ctk::DataValidity::faulty);
441 BOOST_CHECK(cIn2.dataValidity() == ctk::DataValidity::faulty);
443 BOOST_CHECK(cOut1.dataValidity() == ctk::DataValidity::ok);
444 BOOST_CHECK(dOut1.dataValidity() == ctk::DataValidity::ok);
445 BOOST_CHECK(aIn2.dataValidity() == ctk::DataValidity::ok);
446 BOOST_CHECK(dIn2.dataValidity() == ctk::DataValidity::ok);
447 BOOST_CHECK(circleResult.dataValidity() == ctk::DataValidity::ok);
451 test.stepApplication();
453 checkAllDataValidity(ctk::DataValidity::ok);
470 using ApplicationModule::ApplicationModule;
480 using TestModuleBase2::TestModuleBase2;
486 using ctk::VariableGroup::VariableGroup;
488 } outputGroup{
this,
"../BB",
""};
495 using TestModuleBase2::TestModuleBase2;
500 using ctk::VariableGroup::VariableGroup;
502 } outputGroup{
this,
"../CC",
""};
505 using ctk::VariableGroup::VariableGroup;
507 } outputGroup2{
this,
"../EE",
""};
511 using TestModuleBase2::TestModuleBase2;
516 using ctk::VariableGroup::VariableGroup;
518 } outputGroup{
this,
"../AA",
""};
522 using TestModuleBase2::TestModuleBase2;
527 using ctk::VariableGroup::VariableGroup;
529 } outputGroup{
this,
"../DD",
""};
532 using ctk::VariableGroup::VariableGroup;
534 } outputGroup2{
this,
"../FF",
""};
538 using TestModuleBase2::TestModuleBase2;
544 using ctk::VariableGroup::VariableGroup;
546 } outputGroup{
this,
"../AA",
""};
550 using TestModuleBase2::TestModuleBase2;
555 using ctk::VariableGroup::VariableGroup;
557 } outputGroup{
this,
"../DD",
""};
561 using TestModuleBase2::TestModuleBase2;
566 using ctk::VariableGroup::VariableGroup;
568 } outputGroup{
this,
"../HH",
""};
575 using TestModuleBase2::TestModuleBase2;
580 using ctk::VariableGroup::VariableGroup;
582 } outputGroup{
this,
"../GG",
""};
601 return Application::_circularDependencyNetworks;
650 BOOST_CHECK_EQUAL(circularNetworks.size(), 2);
652 const auto&
id = networkIter.first;
653 auto& network = networkIter.second;
655 if(network.size() == 6) {
656 std::list<ctk::EntityOwner*> modules = {&app.
aa, &app.
bb, &app.
cc, &app.
dd, &app.
ee, &app.
ff};
657 for(
auto* module : modules) {
659 BOOST_CHECK(std::count(network.begin(), network.end(), module) == 1);
661 BOOST_CHECK_EQUAL(module->getCircularNetworkHash(),
id);
664 else if(network.size() == 2) {
665 std::list<ctk::EntityOwner*> modules = {&app.
gg, &app.
hh};
666 for(
auto* module : modules) {
667 BOOST_CHECK(std::count(network.begin(), network.end(), module) == 1);
668 BOOST_CHECK_EQUAL(module->getCircularNetworkHash(),
id);
672 BOOST_CHECK_MESSAGE(
false,
"Network with wrong number of modules detected: " + std::to_string(network.size()));
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
ApplicationModule()=default
Default constructor: Allows late initialisation of modules (e.g.
void readAll(bool includeReturnChannels=false)
Read all readable variables in the group.
void writeAll(bool includeReturnChannels=false)
Just call write() on all writable variables in the group.
bool write(ChimeraTK::VersionNumber versionNumber)=delete
Helper class to facilitate tests of applications based on ApplicationCore.
ChimeraTK::ScalarRegisterAccessor< T > getScalar(const ChimeraTK::RegisterPath &name) const
Obtain a scalar process variable from the application, which is published to the control system.
void runApplication() const
Start the application in testable mode.
Class describing a node of a variable network.
bool isCircularInput() const
Returns true if a circular dependency has been detected and the node is a consumer.
InvalidityTracer application module.
BOOST_FIXTURE_TEST_CASE(OneInvalidVariable, CircularAppTestFixcture< TestApplication1 >)
Tests Technical specification: data validity propagation
BOOST_AUTO_TEST_CASE(TestCircularInputDetection)
Tests Technical specification: data validity propagation
Convenience class for output scalar accessors (always UpdateMode::push)
ctk::ScalarPushInput< int > fromEE
ctk::ScalarPushInput< int > fromDD
void prepare() override
Prepare the execution of the module.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarOutput< int > fromAA
ctk::ScalarOutput< int > fromBB
ctk::ScalarOutput< int > fromBB
ctk::ScalarPushInput< int > fromAA
ctk::ScalarOutput< int > fromCC
ctk::ScalarOutput< int > fromCC
ctk::ScalarPushInput< int > fromBB
ctk::ScalarRegisterAccessor< int > a
ctk::ScalarRegisterAccessor< int > dOut1
ctk::ScalarRegisterAccessor< int > circleResult
ctk::ScalarRegisterAccessor< int > aOut1
ctk::ScalarRegisterAccessor< int > cOut1
ctk::ScalarRegisterAccessor< int > dIn2
CircularAppTestFixcture()
ctk::ScalarRegisterAccessor< int > cTrigger
ctk::ScalarRegisterAccessor< int > bOut1
void checkAllDataValidity(ctk::DataValidity validity)
ctk::ScalarRegisterAccessor< int > bIn2
ctk::ScalarRegisterAccessor< int > cIn2
ctk::ScalarRegisterAccessor< int > b
ctk::ScalarRegisterAccessor< int > aIn2
ctk::ScalarPushInput< int > fromCC
ctk::ScalarPushInput< int > fromFF
ctk::ScalarOutput< int > fromDD
ctk::ScalarOutput< int > fromEE
ctk::ScalarPushInput< int > fromBB
ctk::ScalarPushInput< int > fromCC
ctk::ScalarOutput< int > fromFF
ctk::ScalarPushInput< int > fromHH
ctk::ScalarOutput< int > fromGG
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
void prepare() override
Prepare the execution of the module.
ctk::ScalarPushInput< int > fromGG
ctk::ScalarOutput< int > fromHH
ModuleA has two additional inputs to get invalidity flags. It is reading all inputs with ReadAny.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarPushInput< int > a
ctk::ScalarOutput< int > circleResult
void prepare() override
Prepare the execution of the module.
ctk::ScalarPushInput< int > b
ModuleC has a trigger together with a readAll.; (it's a trigger for the circle because there is alway...
ctk::ScalarPushInput< int > trigger
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Involve the DeviceModule. Here are some variables from a test device.
ctk::ScalarPollInput< int > i3
ctk::ScalarPollInput< int > i1
ctk::ScalarOutput< int > o1
~TestApplication1() override
~TestApplication2() override
std::map< size_t, std::list< EntityOwner * > > getCircularDependencyNetworks()
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarPushInput< int > fromCS
The base module has the inputs and outputs for the circular dependency.
ctk::ScalarOutput< int > circularOutput1
ctk::ScalarPushInput< int > circularInput1
TestModuleBase(const std::string &inputName, const std::string &outputName, ctk::ModuleGroup *owner, const std::string &name, const std::string &description)
ctk::ScalarOutput< int > circularOutput2
ctk::ScalarPushInput< int > circularInput2
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...