API
 
Loading...
Searching...
No Matches
indiCompRules_test.cpp
Go to the documentation of this file.
1/** \file indiCompRules_test.cpp
2 * \brief Catch2 tests for stateRuleEngine comparison-rule helpers.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup stateRuleEngine_files
6 */
7
8#include "../../../tests/testXWC.hpp"
9
10#include "../indiCompRules.hpp"
11
12namespace libXWCTest
13{
14
15/** \addtogroup stateRuleEngine_unit_test
16 * \brief Additional unit tests for the stateRuleEngine application.
17 *
18 * \ingroup application_unit_test
19 */
20
21/// Namespace for `stateRuleEngine` unit tests.
22/** \ingroup stateRuleEngine_unit_test
23 */
24namespace stateRuleEngineTest
25{
26
27SCENARIO( "basic INDI Property Element-value rules", "[stateRuleEngine::rules]" )
28{
29 // clang-format off
30 #ifdef STATERULEENGINE_TEST_DOXYGEN_REF
35 #endif
36 // clang-format on
37
38 GIVEN( "string comparison" )
39 {
40 pcf::IndiProperty prop1( pcf::IndiProperty::Text );
41 prop1.setDevice( "ruleTest" );
42 prop1.setName( "prop1" );
43 prop1.setPerm( pcf::IndiProperty::ReadWrite );
44 prop1.setState( pcf::IndiProperty::Idle );
45 prop1.add( pcf::IndiElement( "current" ) );
46 prop1["current"] = "test";
47 prop1.add( pcf::IndiElement( "target" ) );
48 prop1["target"] = "tset";
49
50 txtValRule rule1;
51
52 rule1.property( &prop1 );
53 rule1.element( "current" );
54
55 WHEN( "string should be equal and is" )
56 {
58 rule1.target( "test" );
59
60 REQUIRE( rule1.value() == true );
61 }
62
63 WHEN( "string should be equal and is not" )
64 {
66 rule1.target( "tset" );
67
68 REQUIRE( rule1.value() == false );
69 }
70
71 WHEN( "string should be not equal and is not equal" )
72 {
74 rule1.target( "tset" );
75
76 REQUIRE( rule1.value() == true );
77 }
78
79 WHEN( "string should be not equal and is equal" )
80 {
82 rule1.target( "test" );
83
84 REQUIRE( rule1.value() == false );
85 }
86 }
87
88 GIVEN( "float comparison" )
89 {
90 pcf::IndiProperty prop1( pcf::IndiProperty::Number );
91 prop1.setDevice( "ruleTest" );
92 prop1.setName( "prop1" );
93 prop1.setPerm( pcf::IndiProperty::ReadWrite );
94 prop1.setState( pcf::IndiProperty::Idle );
95 prop1.add( pcf::IndiElement( "current" ) );
96 prop1["current"].setValue( 2.314159 );
97 prop1.add( pcf::IndiElement( "target" ) );
98 prop1["target"].setValue( 1.567202 );
99
100 numValRule rule1;
101
102 rule1.property( &prop1 );
103 rule1.element( "current" );
104
105 WHEN( "float should be equal and is" )
106 {
108 rule1.target( 2.314159 );
109 REQUIRE( rule1.value() == true );
110 }
111
112 WHEN( "float should be equal and aren't" )
113 {
115 rule1.target( 3.314159 );
116 REQUIRE( rule1.value() == false );
117 }
118
119 WHEN( "float should be equal and aren't within tol" )
120 {
122 rule1.target( 2.314158 );
123
124 REQUIRE( rule1.value() == false );
125 }
126
127 WHEN( "float should be equal and are within tol" )
128 {
130 rule1.target( 2.314158 );
131 rule1.tol( 1e-4 );
132
133 REQUIRE( rule1.value() == true );
134 }
135
136 WHEN( "float should be less than and is" )
137 {
139 rule1.target( 4.67892 );
140 REQUIRE( rule1.value() == true );
141 }
142
143 WHEN( "float should be less than but is not" )
144 {
146 rule1.target( 1.67892 );
147 REQUIRE( rule1.value() == false );
148 }
149
150 WHEN( "float should be greater than and is" )
151 {
153 rule1.target( 1.2 );
154 REQUIRE( rule1.value() == true );
155 }
156
157 WHEN( "float should be greater than but is not" )
158 {
160 rule1.target( 7.9 );
161 REQUIRE( rule1.value() == false );
162 }
163
164 WHEN( "float should be less-or-equal than and is less than" )
165 {
167 rule1.target( 4.67892 );
168 REQUIRE( rule1.value() == true );
169 }
170
171 WHEN( "float should be less-or-equal than and is equal" )
172 {
174 rule1.target( 2.314159 );
175 REQUIRE( rule1.value() == true );
176 }
177
178 WHEN( "float should be less-or-equal than but is not" )
179 {
181 rule1.target( 0.789 );
182 REQUIRE( rule1.value() == false );
183 }
184
185 WHEN( "float should be greater-or-equal than and is greater than" )
186 {
188 rule1.target( 2.05 );
189 REQUIRE( rule1.value() == true );
190 }
191
192 WHEN( "float should be greater-or-equal than and is equal" )
193 {
195 rule1.target( 2.314159 );
196 REQUIRE( rule1.value() == true );
197 }
198
199 WHEN( "float should be greater-or-equal than but is not" )
200 {
202 rule1.target( 3.789 );
203 REQUIRE( rule1.value() == false );
204 }
205 }
206
207 GIVEN( "switch comparison" )
208 {
209 pcf::IndiProperty prop1( pcf::IndiProperty::Switch );
210 prop1.setDevice( "ruleTest" );
211 prop1.setName( "prop1" );
212 prop1.setPerm( pcf::IndiProperty::ReadWrite );
213 prop1.setState( pcf::IndiProperty::Idle );
214 prop1.add( pcf::IndiElement( "toggle" ) );
215
216 swValRule rule1;
217
218 rule1.property( &prop1 );
219 rule1.element( "toggle" );
220
221 WHEN( "switch is on and should be equal and is" )
222 {
223 prop1["toggle"].setSwitchState( pcf::IndiElement::On );
224 rule1.target( "On" );
226 REQUIRE( rule1.value() == true );
227 }
228
229 WHEN( "switch is on and should be equal but isn't" )
230 {
231 prop1["toggle"].setSwitchState( pcf::IndiElement::On );
232 rule1.target( "Off" );
234 REQUIRE( rule1.value() == false );
235 }
236
237 WHEN( "switch is on and should be not equal and is not" )
238 {
239 prop1["toggle"].setSwitchState( pcf::IndiElement::On );
240 rule1.target( "Off" );
242 REQUIRE( rule1.value() == true );
243 }
244
245 WHEN( "switch is on and should be not equal but is" )
246 {
247 prop1["toggle"].setSwitchState( pcf::IndiElement::On );
248 rule1.target( "On" );
250 REQUIRE( rule1.value() == false );
251 }
252
253 WHEN( "switch is off and should be equal and is" )
254 {
255 prop1["toggle"].setSwitchState( pcf::IndiElement::Off );
256 rule1.target( "Off" );
258 REQUIRE( rule1.value() == true );
259 }
260
261 WHEN( "switch is off and should be equal but isn't" )
262 {
263 prop1["toggle"].setSwitchState( pcf::IndiElement::Off );
264 rule1.target( "On" );
266 REQUIRE( rule1.value() == false );
267 }
268
269 WHEN( "switch is off and should be not equal and is not" )
270 {
271 prop1["toggle"].setSwitchState( pcf::IndiElement::Off );
272 rule1.target( "On" );
274 REQUIRE( rule1.value() == true );
275 }
276
277 WHEN( "switch is off and should be not equal but is" )
278 {
279 prop1["toggle"].setSwitchState( pcf::IndiElement::Off );
280 rule1.target( "Off" );
282 REQUIRE( rule1.value() == false );
283 }
284 }
285
286 GIVEN( "time-diff comparison" )
287 {
288 pcf::IndiProperty prop1( pcf::IndiProperty::Number );
289 prop1.setDevice( "ruleTest" );
290 prop1.setName( "prop1" );
291 prop1.setPerm( pcf::IndiProperty::ReadWrite );
292 prop1.setState( pcf::IndiProperty::Idle );
293 prop1.add( pcf::IndiElement( "current" ) );
294
295 timespec now;
296 clock_gettime( CLOCK_ISIO, &now );
297
298 prop1["current"].setValue( now.tv_sec );
299
300 timeDiffRule rule1;
301
302 rule1.property( &prop1 );
303 rule1.element( "current" );
304
305 WHEN( "time is less than target" )
306 {
308 rule1.target( 10 );
309 REQUIRE( rule1.value() == false );
310 }
311
312 WHEN( "time is greater than target" )
313 {
314 sleep( 5 ); // make sure
316 rule1.target( 3 );
317 REQUIRE( rule1.value() == true );
318 }
319 }
320}
321
322SCENARIO( "multiSwitchCombo rule evaluation", "[stateRuleEngine::rules]" )
323{
324 auto setStates = []( pcf::IndiProperty &property,
325 const std::initializer_list<std::string> &allNames,
326 const std::initializer_list<std::string> &onNames )
327 {
328 for( const auto &name : allNames )
329 {
330 property[name].setSwitchState( pcf::IndiElement::Off );
331 }
332
333 for( const auto &name : onNames )
334 {
335 property[name].setSwitchState( pcf::IndiElement::On );
336 }
337 };
338
339 GIVEN( "a two-switch combo rule" )
340 {
341 pcf::IndiProperty source1( pcf::IndiProperty::Switch );
342 source1.setDevice( "dev" );
343 source1.setName( "source1" );
344 source1.setPerm( pcf::IndiProperty::ReadWrite );
345 source1.setState( pcf::IndiProperty::Idle );
346 source1.add( pcf::IndiElement( "alpha" ) );
347 source1.add( pcf::IndiElement( "alpha-beta" ) );
348
349 pcf::IndiProperty source2( pcf::IndiProperty::Switch );
350 source2.setDevice( "dev" );
351 source2.setName( "source2" );
352 source2.setPerm( pcf::IndiProperty::ReadWrite );
353 source2.setState( pcf::IndiProperty::Idle );
354 source2.add( pcf::IndiElement( "gamma" ) );
355 source2.add( pcf::IndiElement( "delta" ) );
356
357 pcf::IndiProperty target( pcf::IndiProperty::Switch );
358 target.setDevice( "dev" );
359 target.setName( "target" );
360 target.setPerm( pcf::IndiProperty::ReadWrite );
361 target.setState( pcf::IndiProperty::Idle );
362 target.add( pcf::IndiElement( "alpha-gamma" ) );
363 target.add( pcf::IndiElement( "alpha-beta-gamma" ) );
364 target.add( pcf::IndiElement( "-gamma" ) );
365
367 rule.ruleName( "comboRule" );
368 rule.property( &source1, "dev.source1" );
369 rule.property( &source2, "dev.source2" );
370 rule.format( "{}-{}" );
371 rule.targetProperty( &target );
372 rule.targetPropertyKey( "dev.target" );
374
375 WHEN( "the combo matches with embedded hyphens" )
376 {
377 setStates( source1, { "alpha", "alpha-beta" }, { "alpha-beta" } );
378 setStates( source2, { "gamma", "delta" }, { "gamma" } );
379 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "alpha-beta-gamma" } );
380
381 REQUIRE( rule.value() == true );
382
383 std::string diagnostic;
384 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
385 }
386
387 WHEN( "the combo does not match" )
388 {
389 setStates( source1, { "alpha", "alpha-beta" }, { "alpha" } );
390 setStates( source2, { "gamma", "delta" }, { "gamma" } );
391 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "alpha-beta-gamma" } );
392
393 REQUIRE( rule.value() == false );
394 }
395
396 WHEN( "a source has zero active switches" )
397 {
398 setStates( source1, { "alpha", "alpha-beta" }, {} );
399 setStates( source2, { "gamma", "delta" }, { "gamma" } );
400 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "-gamma" } );
401
402 REQUIRE( rule.value() == true );
403
404 std::string diagnostic;
405 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
406 }
407
408 WHEN( "a source enters and leaves the multi-On state" )
409 {
410 setStates( source1, { "alpha", "alpha-beta" }, { "alpha", "alpha-beta" } );
411 setStates( source2, { "gamma", "delta" }, { "gamma" } );
412 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "-gamma" } );
413
414 REQUIRE( rule.value() == true );
415
416 std::string diagnostic;
417 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == true );
418 REQUIRE( diagnostic.find( "comboRule" ) != std::string::npos );
419 REQUIRE( diagnostic.find( "dev.source1" ) != std::string::npos );
420 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
421
422 REQUIRE( rule.value() == true );
423 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
424
425 setStates( source1, { "alpha", "alpha-beta" }, { "alpha" } );
426 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "alpha-gamma" } );
427
428 REQUIRE( rule.value() == true );
429 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
430
431 setStates( source1, { "alpha", "alpha-beta" }, { "alpha", "alpha-beta" } );
432 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "-gamma" } );
433
434 REQUIRE( rule.value() == true );
435 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == true );
436 REQUIRE( diagnostic.find( "dev.source1" ) != std::string::npos );
437 }
438
439 WHEN( "a compound rule drains child multiSwitchCombo diagnostics" )
440 {
441 setStates( source1, { "alpha", "alpha-beta" }, { "alpha", "alpha-beta" } );
442 setStates( source2, { "gamma", "delta" }, { "gamma" } );
443 setStates( target, { "alpha-gamma", "alpha-beta-gamma", "-gamma" }, { "-gamma" } );
444
445 pcf::IndiProperty txtProp( pcf::IndiProperty::Text );
446 txtProp.setDevice( "dev" );
447 txtProp.setName( "txt" );
448 txtProp.setPerm( pcf::IndiProperty::ReadWrite );
449 txtProp.setState( pcf::IndiProperty::Idle );
450 txtProp.add( pcf::IndiElement( "state" ) );
451 txtProp["state"] = "READY";
452
453 txtValRule txtRule;
454 txtRule.property( &txtProp );
455 txtRule.element( "state" );
456 txtRule.target( "READY" );
458
459 ruleCompRule parent;
460 parent.rule1( &rule );
461 parent.rule2( &txtRule );
463
464 REQUIRE( parent.value() == true );
465
466 std::string diagnostic;
467 REQUIRE( parent.popRuntimeDiagnostic( diagnostic ) == true );
468 REQUIRE( diagnostic.find( "dev.source1" ) != std::string::npos );
469 REQUIRE( parent.popRuntimeDiagnostic( diagnostic ) == false );
470 }
471 }
472
473 GIVEN( "a one-switch combo rule" )
474 {
475 pcf::IndiProperty source( pcf::IndiProperty::Switch );
476 source.setDevice( "dev" );
477 source.setName( "soloSource" );
478 source.setPerm( pcf::IndiProperty::ReadWrite );
479 source.setState( pcf::IndiProperty::Idle );
480 source.add( pcf::IndiElement( "solo" ) );
481 source.add( pcf::IndiElement( "other" ) );
482
483 pcf::IndiProperty target( pcf::IndiProperty::Switch );
484 target.setDevice( "dev" );
485 target.setName( "soloTarget" );
486 target.setPerm( pcf::IndiProperty::ReadWrite );
487 target.setState( pcf::IndiProperty::Idle );
488 target.add( pcf::IndiElement( "solo" ) );
489 target.add( pcf::IndiElement( "other" ) );
490
492 rule.ruleName( "singleRule" );
493 rule.property( &source, "dev.soloSource" );
494 rule.format( "{}" );
495 rule.targetProperty( &target );
496 rule.targetPropertyKey( "dev.soloTarget" );
497
498 WHEN( "the target has zero active switches" )
499 {
501 setStates( source, { "solo", "other" }, { "solo" } );
502 setStates( target, { "solo", "other" }, {} );
503
504 REQUIRE( rule.value() == true );
505
506 std::string diagnostic;
507 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
508 }
509
510 WHEN( "the target has multiple active switches" )
511 {
513 setStates( source, { "solo", "other" }, {} );
514 setStates( target, { "solo", "other" }, { "solo", "other" } );
515
516 REQUIRE( rule.value() == true );
517
518 std::string diagnostic;
519 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == true );
520 REQUIRE( diagnostic.find( "dev.soloTarget" ) != std::string::npos );
521 REQUIRE( rule.popRuntimeDiagnostic( diagnostic ) == false );
522 }
523 }
524}
525
526} // namespace stateRuleEngineTest
527
528} // namespace libXWCTest
529
530SCENARIO( "INDI element comparison", "[stateRuleEngine::rules]" )
531{
532 GIVEN( "string comparison within same property" )
533 {
534 pcf::IndiProperty prop1( pcf::IndiProperty::Text );
535 prop1.setDevice( "ruleTest" );
536 prop1.setName( "prop1" );
537 prop1.setPerm( pcf::IndiProperty::ReadWrite );
538 prop1.setState( pcf::IndiProperty::Idle );
539 prop1.add( pcf::IndiElement( "current" ) );
540 prop1.add( pcf::IndiElement( "target" ) );
541
542 elCompTxtRule rule1;
543 rule1.property1( &prop1 );
544 rule1.property2( &prop1 );
545 rule1.element1( "current" );
546 rule1.element2( "target" );
547
548 WHEN( "string elements wihtin same property should be equal and are" )
549 {
550 prop1["current"] = "test";
551 prop1["target"] = "test";
553
554 REQUIRE( rule1.value() == true );
555 }
556
557 WHEN( "string elements within same property should be equal and are not" )
558 {
559 prop1["current"] = "test";
560 prop1["target"] = "tset";
562
563 REQUIRE( rule1.value() == false );
564 }
565
566 WHEN( "string elements within same property should not be equal and are not" )
567 {
568 prop1["current"] = "test";
569 prop1["target"] = "tset";
571
572 REQUIRE( rule1.value() == true );
573 }
574
575 WHEN( "string elements within same property should not be equal and are" )
576 {
577 prop1["current"] = "test";
578 prop1["target"] = "test";
580
581 REQUIRE( rule1.value() == false );
582 }
583 }
584
585 GIVEN( "switch comparison" )
586 {
587 pcf::IndiProperty prop1( pcf::IndiProperty::Switch );
588 prop1.setDevice( "ruleTest1" );
589 prop1.setName( "prop1" );
590 prop1.setPerm( pcf::IndiProperty::ReadWrite );
591 prop1.setState( pcf::IndiProperty::Idle );
592 prop1.add( pcf::IndiElement( "nameTest" ) );
593
594 pcf::IndiProperty prop2( pcf::IndiProperty::Switch );
595 prop2.setDevice( "ruleTest2" );
596 prop2.setName( "prop2" );
597 prop2.setPerm( pcf::IndiProperty::ReadWrite );
598 prop2.setState( pcf::IndiProperty::Idle );
599 prop2.add( pcf::IndiElement( "badgeTest" ) );
600
601 elCompSwRule rule1;
602 rule1.property1( &prop1 );
603 rule1.property2( &prop2 );
604 rule1.element1( "nameTest" );
605 rule1.element2( "badgeTest" );
606
607 WHEN( "switches should be On and equal and are" )
608 {
609 prop1["nameTest"].setSwitchState( pcf::IndiElement::On );
610 prop2["badgeTest"].setSwitchState( pcf::IndiElement::On );
612
613 REQUIRE( rule1.value() == true );
614 }
615
616 WHEN( "switches should be On and equal but are not" )
617 {
618 prop1["nameTest"].setSwitchState( pcf::IndiElement::On );
619 prop2["badgeTest"].setSwitchState( pcf::IndiElement::Off );
621
622 REQUIRE( rule1.value() == false );
623 }
624
625 WHEN( "switches should be On and not equal and are not" )
626 {
627 prop1["nameTest"].setSwitchState( pcf::IndiElement::On );
628 prop2["badgeTest"].setSwitchState( pcf::IndiElement::Off );
630
631 REQUIRE( rule1.value() == true );
632 }
633
634 WHEN( "switches should be On and not equal but are" )
635 {
636 prop1["nameTest"].setSwitchState( pcf::IndiElement::On );
637 prop2["badgeTest"].setSwitchState( pcf::IndiElement::On );
639
640 REQUIRE( rule1.value() == false );
641 }
642
643 WHEN( "switches should be Off and equal and are" )
644 {
645 prop1["nameTest"].setSwitchState( pcf::IndiElement::Off );
646 prop2["badgeTest"].setSwitchState( pcf::IndiElement::Off );
648
649 REQUIRE( rule1.value() == true );
650 }
651
652 WHEN( "switches should be Off and equal but are not" )
653 {
654 prop1["nameTest"].setSwitchState( pcf::IndiElement::Off );
655 prop2["badgeTest"].setSwitchState( pcf::IndiElement::On );
657
658 REQUIRE( rule1.value() == false );
659 }
660
661 WHEN( "switches should be Off and not equal and are not" )
662 {
663 prop1["nameTest"].setSwitchState( pcf::IndiElement::Off );
664 prop2["badgeTest"].setSwitchState( pcf::IndiElement::On );
666
667 REQUIRE( rule1.value() == true );
668 }
669
670 WHEN( "switches should be Off and not equal but are" )
671 {
672 prop1["nameTest"].setSwitchState( pcf::IndiElement::Off );
673 prop2["badgeTest"].setSwitchState( pcf::IndiElement::Off );
675
676 REQUIRE( rule1.value() == false );
677 }
678 }
679 GIVEN( "numeric comparison" )
680 {
681 pcf::IndiProperty prop1( pcf::IndiProperty::Number );
682 prop1.setDevice( "ruleTest1" );
683 prop1.setName( "prop1" );
684 prop1.setPerm( pcf::IndiProperty::ReadWrite );
685 prop1.setState( pcf::IndiProperty::Idle );
686 prop1.add( pcf::IndiElement( "nameTest" ) );
687
688 pcf::IndiProperty prop2( pcf::IndiProperty::Number );
689 prop2.setDevice( "ruleTest2" );
690 prop2.setName( "prop2" );
691 prop2.setPerm( pcf::IndiProperty::ReadWrite );
692 prop2.setState( pcf::IndiProperty::Idle );
693 prop2.add( pcf::IndiElement( "badgeTest" ) );
694
695 elCompNumRule rule1;
696 rule1.property1( &prop1 );
697 rule1.property2( &prop2 );
698 rule1.element1( "nameTest" );
699 rule1.element2( "badgeTest" );
700
701 WHEN( "numbers should be equal and are" )
702 {
703 prop1["nameTest"].set( 2.5 );
704 prop2["badgeTest"].set( 2.5 );
706
707 REQUIRE( rule1.value() == true );
708 }
709
710 WHEN( "numbers should be equal but are not" )
711 {
712 prop1["nameTest"].set( 2.5 );
713 prop2["badgeTest"].set( 2.6 );
715
716 REQUIRE( rule1.value() == false );
717 }
718 }
719}
720
721SCENARIO( "basic rule comparisons", "[stateRuleEngine::rules]" )
722{
723 GIVEN( "INDI Property rule comparison" )
724 {
725 WHEN( "two strings should be equal and are" )
726 {
727 pcf::IndiProperty prop1( pcf::IndiProperty::Text );
728 prop1.setDevice( "ruleTest" );
729 prop1.setName( "prop1" );
730 prop1.setPerm( pcf::IndiProperty::ReadWrite );
731 prop1.setState( pcf::IndiProperty::Idle );
732 prop1.add( pcf::IndiElement( "current" ) );
733 prop1["current"] = "test";
734 prop1.add( pcf::IndiElement( "target" ) );
735 prop1["target"] = "tset";
736
737 txtValRule rule1;
738
739 rule1.property( &prop1 );
740 rule1.element( "current" );
742 rule1.target( "test" );
743
744 pcf::IndiProperty prop2( pcf::IndiProperty::Text );
745 prop2.setDevice( "ruleTest2" );
746 prop2.setName( "prop2" );
747 prop2.setPerm( pcf::IndiProperty::ReadWrite );
748 prop2.setState( pcf::IndiProperty::Idle );
749 prop2.add( pcf::IndiElement( "current" ) );
750 prop2["current"] = "fail";
751 prop2.add( pcf::IndiElement( "target" ) );
752 prop2["target"] = "liaf";
753
754 txtValRule rule2;
755
756 rule2.property( &prop2 );
757 rule2.element( "target" );
759 rule2.target( "liaf" );
760
761 ruleCompRule rule3;
762 rule3.rule1( &rule1 );
763 rule3.rule2( &rule2 );
765
766 REQUIRE( rule3.value() == true );
767 }
768 }
769}
770
771SCENARIO( "compound rule comparisons", "[stateRuleEngine::rules]" )
772{
773 GIVEN( "(A && B) || C" )
774 {
775 pcf::IndiProperty prop1( pcf::IndiProperty::Text );
776 prop1.setDevice( "ruleTest" );
777 prop1.setName( "prop1" );
778 prop1.setPerm( pcf::IndiProperty::ReadWrite );
779 prop1.setState( pcf::IndiProperty::Idle );
780 prop1.add( pcf::IndiElement( "current" ) );
781 prop1["current"] = "test";
782 prop1.add( pcf::IndiElement( "target" ) );
783 prop1["target"] = "tset";
784
785 txtValRule rule1; // A
786
787 rule1.property( &prop1 );
788 rule1.element( "current" );
790
791 pcf::IndiProperty prop2( pcf::IndiProperty::Text );
792 prop2.setDevice( "ruleTest2" );
793 prop2.setName( "prop2" );
794 prop2.setPerm( pcf::IndiProperty::ReadWrite );
795 prop2.setState( pcf::IndiProperty::Idle );
796 prop2.add( pcf::IndiElement( "current" ) );
797 prop2["current"] = "fail";
798 prop2.add( pcf::IndiElement( "target" ) );
799 prop2["target"] = "liaf";
800
801 txtValRule rule2; // B
802
803 rule2.property( &prop2 );
804 rule2.element( "target" );
806
807 ruleCompRule rule3; // A&&B
808 rule3.rule1( &rule1 );
809 rule3.rule2( &rule2 );
811
812 pcf::IndiProperty prop3( pcf::IndiProperty::Text );
813 prop3.setDevice( "ruleTest3" );
814 prop3.setName( "prop3" );
815 prop3.setPerm( pcf::IndiProperty::ReadWrite );
816 prop3.setState( pcf::IndiProperty::Idle );
817 prop3.add( pcf::IndiElement( "current" ) );
818 prop3["current"] = "pass";
819 prop3.add( pcf::IndiElement( "target" ) );
820 prop3["target"] = "ssap";
821
822 txtValRule rule4; // C
823
824 rule4.property( &prop3 );
825 rule4.element( "current" );
827
828 ruleCompRule rule5; // (A&&B) || C
829 rule5.rule1( &rule3 ); // A&&B
830 rule5.rule2( &rule4 ); // C
832
833 WHEN( "A==1, B==0, C==1" )
834 {
835 rule1.target( "test" ); // A==1
836 rule2.target( "fail" ); // B==0
837 rule4.target( "pass" ); // C==1
838
839 //(A && B) || C
840 REQUIRE( rule5.value() == true );
841 }
842
843 WHEN( "A==0, B==0, C==1" )
844 {
845 rule1.target( "tset" ); // A==0
846 rule2.target( "fail" ); // B==0
847 rule4.target( "pass" ); // C==1
848
849 //(A && B) || C
850 REQUIRE( rule5.value() == true );
851 }
852
853 WHEN( "A==1, B==0, C==0" )
854 {
855 rule1.target( "test" ); // A==1
856 rule2.target( "fail" ); // B==0
857 rule4.target( "ssap" ); // C==0
858
859 //(A && B) || C
860 REQUIRE( rule5.value() == false );
861 }
862
863 WHEN( "A==1, B==1, C==0" )
864 {
865 rule1.target( "test" ); // A==1
866 rule2.target( "liaf" ); // B==1
867 rule4.target( "ssap" ); // C==0
868
869 //(A && B) || C
870 REQUIRE( rule5.value() == true );
871 }
872 }
873}
@ Gt
Greater than.
@ Or
boolean or
@ Lt
Less than.
@ LtEq
Less than or equal to.
@ GtEq
Greater than or equal to.
@ And
boolean and
@ Neq
Not equal.
SCENARIO("INDI element comparison", "[stateRuleEngine::rules]")
SCENARIO("configuring basic rules", "[stateRuleEngine::ruleConfig]")
Namespace for all libXWC tests.
Compare two elements based on their numeric values.
virtual bool value()
Get the value of this rule.
Compare two elements based on their switch values.
virtual bool value()
Get the value of this rule.
Compare two elements based on their text values.
virtual bool value()
Get the value of this rule.
void comparison(const ruleComparison &c)
Set the comparison for this rule.
Build and compare a switch-name combination against a target switch vector.
void targetProperty(pcf::IndiProperty *property)
Set the target switch property.
void property(pcf::IndiProperty *property, const std::string &propertyKey)
Append one source switch property.
virtual bool popRuntimeDiagnostic(std::string &diagnostic)
Pop one pending runtime diagnostic, if any.
void format(const std::string &format)
Set the literal format string for the source switch names.
virtual bool value()
Get the value of this rule.
void targetPropertyKey(const std::string &propertyKey)
Set the target property key used in diagnostics.
void ruleName(const std::string &ruleName)
Set the rule name used in diagnostics.
Compare the value of a number element to a target.
void target(const double &tgt)
Set the target for the comparison.
void tol(const double &t)
Set the tolerance.
virtual bool value()
Get the value of this rule.
void property(pcf::IndiProperty *property)
Set the property pointer.
void element(const std::string &el)
Set the element name.
A rule to compare two rules.
void rule2(indiCompRule *r)
Set the pointer to the second rule.
void rule1(indiCompRule *r)
Set the pointer to the first rule.
virtual bool popRuntimeDiagnostic(std::string &diagnostic)
Pop one pending runtime diagnostic from either child rule.
virtual bool value()
Get the value of this rule.
Compare the value of a switch to a target value.
virtual bool value()
Get the value of this rule.
void target(const pcf::IndiElement::SwitchStateType &ss)
Set the target for the comparison.
Compare the difference in time between a value and now.
void target(const double &tgt)
Set the target for the comparison.
virtual bool value()
Get the value of this rule.
void property1(pcf::IndiProperty *property)
Set the first property pointer.
void element2(const std::string &el)
Set the second element name.
void element1(const std::string &el)
Set the first element name.
void property2(pcf::IndiProperty *property)
Set the second property pointer.
Compare the value of a text element to a target value.
void target(const std::string &target)
Set the target for the comparison.
virtual bool value()
Get the value of this rule.