4#define BOOST_TEST_MODULE testUserInputValidator
11#include <boost/mpl/list.hpp>
12#include <boost/test/included/unit_test.hpp>
16 using namespace boost::unit_test_framework;
24 using ctk::ApplicationModule::ApplicationModule;
39 ctk::TransferElementID change;
42 change = group.readAny();
52 using ModuleA::ModuleA;
70 using ctk::ApplicationModule::ApplicationModule;
83 ctk::TransferElementID change;
87 change = group.readAny();
96 using ctk::ApplicationModule::ApplicationModule;
110 ctk::TransferElementID change;
117 change = group.readAny();
127 std::cout <<
"testSingleVariable" << std::endl;
130 using ctk::Application::Application;
132 ModuleA moduleA{
this,
"ModuleA",
""};
138 auto modAin1 = test.
getScalar<
int>(
"/ModuleA/in1");
142 modAin1.setAndWrite(8);
144 BOOST_TEST(!modAin1.readLatest());
145 BOOST_TEST(app.moduleA.in1 == 8);
147 modAin1.setAndWrite(10);
149 BOOST_TEST(modAin1.readLatest());
150 BOOST_TEST(modAin1 == 8);
151 BOOST_TEST(app.moduleA.in1 == 8);
157 std::cout <<
"testFallback" << std::endl;
159 struct ModuleAmod :
public ModuleA {
160 using ModuleA::ModuleA;
161 void prepare()
override {
163 validator.setFallback(in1, 7);
168 using ctk::Application::Application;
170 ModuleAmod moduleA{
this,
"ModuleA",
""};
176 auto modAin1 = test.
getScalar<
int>(
"/ModuleA/in1");
182 BOOST_TEST(!modAin1.readLatest());
183 BOOST_TEST(app.moduleA.in1 == 7);
189 std::cout <<
"testMultipleVariablesDifferentChecks" << std::endl;
193 using ctk::Application::Application;
201 auto in1 = test.
getScalar<
int>(
"/ModuleA/in1");
202 auto in2 = test.
getScalar<
int>(
"/ModuleA/in2");
209 BOOST_TEST(!in1.readLatest());
210 BOOST_TEST(!in2.readLatest());
214 BOOST_TEST(in1.readLatest());
215 BOOST_TEST(in1 == 3);
216 BOOST_TEST(app.moduleA.in1 == 3);
217 BOOST_TEST(app.moduleA.in2 == 12);
221 BOOST_TEST(!in1.readLatest());
222 BOOST_TEST(app.moduleA.in1 == 9);
223 BOOST_TEST(app.moduleA.in2 == 12);
225 BOOST_TEST(!in2.readLatest());
229 BOOST_TEST(in2.readLatest());
230 BOOST_TEST(in2 == 12);
231 BOOST_TEST(app.moduleA.in1 == 9);
232 BOOST_TEST(app.moduleA.in2 == 12);
236 BOOST_TEST(!in2.readLatest());
237 BOOST_TEST(app.moduleA.in1 == 9);
238 BOOST_TEST(app.moduleA.in2 == 13);
240 BOOST_TEST(!in1.readLatest());
246 std::cout <<
"testMultipleVariablesSameCheck" << std::endl;
250 struct ModuleAmod :
public ModuleA {
251 using ModuleA::ModuleA;
255 void prepare()
override {
258 "in1 needs to be smaller than 10 and in2 needs to be bigger than 10", [&] {
return in1 < 10 && in2 > 10; },
264 using ctk::Application::Application;
266 ModuleAmod moduleA{
this,
"ModuleA",
""};
276 auto in1 = test.
getScalar<
int>(
"/ModuleA/in1");
277 auto in2 = test.
getScalar<
int>(
"/ModuleA/in2");
284 BOOST_TEST(!in1.readLatest());
285 BOOST_TEST(!in2.readLatest());
289 BOOST_TEST(in1.readLatest());
290 BOOST_TEST(in1 == 3);
291 BOOST_TEST(app.moduleA.in1 == 3);
292 BOOST_TEST(app.moduleA.in2 == 12);
296 BOOST_TEST(!in1.readLatest());
297 BOOST_TEST(app.moduleA.in1 == 9);
298 BOOST_TEST(app.moduleA.in2 == 12);
300 BOOST_TEST(!in2.readLatest());
304 BOOST_TEST(in2.readLatest());
305 BOOST_TEST(in2 == 12);
306 BOOST_TEST(app.moduleA.in1 == 9);
307 BOOST_TEST(app.moduleA.in2 == 12);
311 BOOST_TEST(!in2.readLatest());
312 BOOST_TEST(app.moduleA.in1 == 9);
313 BOOST_TEST(app.moduleA.in2 == 13);
315 BOOST_TEST(!in1.readLatest());
321 std::cout <<
"testMultipleChecksSameVariable" << std::endl;
324 struct ModuleAmod :
public ModuleA {
325 using ModuleA::ModuleA;
327 void prepare()
override {
329 validator.add(
"in1 needs to be greater than -5", [&] {
return in1 > -5; }, in1);
334 using ctk::Application::Application;
336 ModuleAmod moduleA{
this,
"ModuleA",
""};
342 auto in1 = test.
getScalar<
int>(
"/ModuleA/in1");
348 BOOST_TEST(!in1.readLatest());
352 BOOST_TEST(in1.readLatest());
353 BOOST_TEST(in1 == 3);
354 BOOST_TEST(app.moduleA.in1 == 3);
358 BOOST_TEST(!in1.readLatest());
359 BOOST_TEST(app.moduleA.in1 == 9);
363 BOOST_TEST(in1.readLatest());
364 BOOST_TEST(in1 == 9);
365 BOOST_TEST(app.moduleA.in1 == 9);
371 std::cout <<
"testSetErrorFunction" << std::endl;
375 using ctk::Application::Application;
383 std::string errorMessage;
385 app.moduleA.validator.setErrorFunction([&](
const std::string& msg) { errorMessage = msg; });
387 auto modAin1 = test.
getScalar<
int>(
"/ModuleA/in1");
388 auto modAin2 = test.
getScalar<
int>(
"/ModuleA/in2");
394 modAin1.setAndWrite(8);
396 BOOST_TEST(!modAin1.readLatest());
397 BOOST_TEST(app.moduleA.in1 == 8);
398 BOOST_TEST(errorMessage.empty());
400 modAin1.setAndWrite(10);
402 BOOST_TEST(modAin1.readLatest());
403 BOOST_TEST(modAin1 == 8);
404 BOOST_TEST(app.moduleA.in1 == 8);
405 BOOST_TEST(errorMessage == app.moduleA.in1ErrorMessage);
407 modAin2.setAndWrite(1);
409 BOOST_TEST(modAin2.readLatest());
410 BOOST_TEST(modAin2 == 20);
411 BOOST_TEST(app.moduleA.in2 == 20);
412 BOOST_TEST(errorMessage == app.moduleA.in2ErrorMessage);
418 std::cout <<
"testBackwardsPropagationSingleDownstream" << std::endl;
424 using ctk::Application::Application;
427 ModuleA downstream{
this,
"Downstream",
""};
433 auto upstrIn = test.
getScalar<
int>(
"/Upstream/in1");
434 auto downstrIn = test.
getScalar<
int>(
"/Downstream/in1");
441 downstrIn.readLatest();
442 BOOST_TEST(downstrIn == 6);
444 upstrIn.setAndWrite(30);
446 BOOST_TEST(upstrIn.readNonBlocking());
447 BOOST_TEST(upstrIn == 5);
448 BOOST_TEST(!downstrIn.readNonBlocking());
450 upstrIn.setAndWrite(12);
452 BOOST_TEST(upstrIn.readNonBlocking());
453 BOOST_TEST(upstrIn == 5);
454 BOOST_TEST(downstrIn.readLatest());
455 BOOST_TEST(downstrIn == 6);
461 std::cout <<
"testBackwardsPropagationTwoDownstream" << std::endl;
466 using ctk::Application::Application;
469 ModuleA downstream1{
this,
"Downstream1",
""};
470 ModuleA downstream2{
this,
"Downstream2",
""};
476 auto upstrIn = test.
getScalar<
int>(
"/Upstream/in1");
477 auto downstr1In = test.
getScalar<
int>(
"/Downstream1/in1");
478 auto downstr2In = test.
getScalar<
int>(
"/Downstream2/in1");
485 downstr1In.readLatest();
486 BOOST_TEST(downstr1In == 6);
487 downstr2In.readLatest();
488 BOOST_TEST(downstr2In == 7);
490 upstrIn.setAndWrite(30);
492 BOOST_TEST(upstrIn.readNonBlocking());
493 BOOST_TEST(upstrIn == 5);
494 BOOST_TEST(!downstr1In.readNonBlocking());
495 BOOST_TEST(!downstr2In.readNonBlocking());
497 upstrIn.setAndWrite(12);
499 BOOST_TEST(upstrIn.readNonBlocking());
500 BOOST_TEST(upstrIn == 5);
501 BOOST_TEST(downstr1In.readLatest());
502 BOOST_TEST(downstr1In == 6);
503 BOOST_TEST(downstr2In.readLatest());
504 BOOST_TEST(downstr2In == 7);
510 std::cout <<
"testFunnelThreadedFanOut" << std::endl;
515 using ctk::Application::Application;
517 ModuleA module1{
this,
"Module",
""};
518 ModuleA module2{
this,
"Module",
""};
524 auto in1 = test.
getScalar<
int>(
"/Module/in1");
532 BOOST_TEST(in1.readNonBlocking());
533 BOOST_TEST(in1 == 5);
534 BOOST_TEST(app.module1.in1 == 5);
535 BOOST_TEST(app.module2.in1 == 5);
541 std::cout <<
"testFunnelFeedingFanOut" << std::endl;
546 using ctk::Application::Application;
549 ModuleA module1{
this,
"Downstream",
""};
550 ModuleA module2{
this,
"Downstream",
""};
556 auto in1 = test.
getScalar<
int>(
"/Upstream/in1");
564 BOOST_TEST(in1.readNonBlocking());
565 BOOST_TEST(in1 == 5);
566 BOOST_TEST(app.module1.in1 == 6);
567 BOOST_TEST(app.module2.in1 == 6);
573 std::cout <<
"testDeepBackwardsPropagation" << std::endl;
578 using ctk::Application::Application;
582 ModuleA downstream{
this,
"Downstream",
""};
586 app.upstream.out1 = {&app.upstream,
"/Midstream/in1",
"",
"First validated input"};
590 auto upstrIn = test.
getScalar<
int>(
"/Upstream/in1");
591 auto midstreamIn = test.
getScalar<
int>(
"/Midstream/in1");
592 auto downstrIn = test.
getScalar<
int>(
"/Downstream/in1");
599 midstreamIn.readLatest();
600 downstrIn.readLatest();
601 BOOST_TEST(midstreamIn == 6);
602 BOOST_TEST(downstrIn == 7);
604 upstrIn.setAndWrite(12);
606 BOOST_TEST(midstreamIn.readNonBlocking());
607 BOOST_TEST(midstreamIn == 13);
608 BOOST_TEST(downstrIn.readNonBlocking());
609 BOOST_TEST(downstrIn == 14);
610 BOOST_TEST(downstrIn.readNonBlocking());
611 BOOST_TEST(downstrIn == 7);
612 BOOST_TEST(!downstrIn.readNonBlocking());
613 BOOST_TEST(midstreamIn.readNonBlocking());
614 BOOST_TEST(midstreamIn == 6);
615 BOOST_TEST(!midstreamIn.readNonBlocking());
616 BOOST_TEST(upstrIn.readNonBlocking());
617 BOOST_TEST(upstrIn == 5);
618 BOOST_TEST(!upstrIn.readNonBlocking());
625 upstrIn.setAndWrite(12);
626 upstrIn.setAndWrite(13);
628 BOOST_TEST(midstreamIn.readNonBlocking());
629 BOOST_TEST(midstreamIn == 13);
630 BOOST_TEST(downstrIn.readNonBlocking());
631 BOOST_TEST(downstrIn == 14);
633 BOOST_TEST(downstrIn.readLatest());
634 BOOST_TEST(downstrIn == 7);
635 BOOST_TEST(midstreamIn.readLatest());
636 BOOST_TEST(midstreamIn == 6);
637 BOOST_TEST(upstrIn.readLatest());
638 BOOST_TEST(upstrIn == 5);
643 upstrIn.setAndWrite(12);
644 upstrIn.setAndWrite(3);
664 BOOST_TEST(downstrIn.readLatest());
665 BOOST_TEST(midstreamIn.readLatest());
667 BOOST_TEST(upstrIn.readLatest());
668 BOOST_TEST(midstreamIn == 6);
669 BOOST_TEST(upstrIn == 5);
673 BOOST_ERROR(
"The wanted 'likely' scenario could not be observed, only the unwanted 'unlikely'.");
675 BOOST_TEST(!upstrIn.readLatest());
676 BOOST_TEST(downstrIn == 5);
677 BOOST_TEST(midstreamIn == 4);
678 BOOST_TEST(upstrIn == 3);
const std::string & getName() const
Get the name of the module instance.
ChimeraTK::ReadAnyGroup readAnyGroup()
Create a ChimeraTK::ReadAnyGroup for all readable variables in this Module.
void writeIfDifferent(UserType newValue, VersionNumber versionNumber, DataValidity validity)=delete
Helper class to facilitate tests of applications based on ApplicationCore.
void stepApplication(bool waitForDeviceInitialisation=true) const
Perform a "step" of the application.
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.
void setScalarDefault(const ChimeraTK::RegisterPath &name, const T &value)
Set default value for scalar process variable.
InvalidityTracer application module.
Convenience class for output scalar accessors with return channel ("read back") (always UpdateMode::p...