8#include "../../../tests/testXWC.hpp"
10#include "../indiCompRules.hpp"
24namespace stateRuleEngineTest
27SCENARIO(
"basic INDI Property Element-value rules",
"[stateRuleEngine::rules]" )
30 #ifdef STATERULEENGINE_TEST_DOXYGEN_REF
38 GIVEN(
"string comparison" )
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";
55 WHEN(
"string should be equal and is" )
60 REQUIRE( rule1.
value() ==
true );
63 WHEN(
"string should be equal and is not" )
68 REQUIRE( rule1.
value() ==
false );
71 WHEN(
"string should be not equal and is not equal" )
76 REQUIRE( rule1.
value() ==
true );
79 WHEN(
"string should be not equal and is equal" )
84 REQUIRE( rule1.
value() ==
false );
88 GIVEN(
"float comparison" )
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 );
105 WHEN(
"float should be equal and is" )
109 REQUIRE( rule1.
value() ==
true );
112 WHEN(
"float should be equal and aren't" )
116 REQUIRE( rule1.
value() ==
false );
119 WHEN(
"float should be equal and aren't within tol" )
124 REQUIRE( rule1.
value() ==
false );
127 WHEN(
"float should be equal and are within tol" )
133 REQUIRE( rule1.
value() ==
true );
136 WHEN(
"float should be less than and is" )
140 REQUIRE( rule1.
value() ==
true );
143 WHEN(
"float should be less than but is not" )
147 REQUIRE( rule1.
value() ==
false );
150 WHEN(
"float should be greater than and is" )
154 REQUIRE( rule1.
value() ==
true );
157 WHEN(
"float should be greater than but is not" )
161 REQUIRE( rule1.
value() ==
false );
164 WHEN(
"float should be less-or-equal than and is less than" )
168 REQUIRE( rule1.
value() ==
true );
171 WHEN(
"float should be less-or-equal than and is equal" )
175 REQUIRE( rule1.
value() ==
true );
178 WHEN(
"float should be less-or-equal than but is not" )
182 REQUIRE( rule1.
value() ==
false );
185 WHEN(
"float should be greater-or-equal than and is greater than" )
189 REQUIRE( rule1.
value() ==
true );
192 WHEN(
"float should be greater-or-equal than and is equal" )
196 REQUIRE( rule1.
value() ==
true );
199 WHEN(
"float should be greater-or-equal than but is not" )
203 REQUIRE( rule1.
value() ==
false );
207 GIVEN(
"switch comparison" )
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" ) );
221 WHEN(
"switch is on and should be equal and is" )
223 prop1[
"toggle"].setSwitchState( pcf::IndiElement::On );
226 REQUIRE( rule1.
value() ==
true );
229 WHEN(
"switch is on and should be equal but isn't" )
231 prop1[
"toggle"].setSwitchState( pcf::IndiElement::On );
234 REQUIRE( rule1.
value() ==
false );
237 WHEN(
"switch is on and should be not equal and is not" )
239 prop1[
"toggle"].setSwitchState( pcf::IndiElement::On );
242 REQUIRE( rule1.
value() ==
true );
245 WHEN(
"switch is on and should be not equal but is" )
247 prop1[
"toggle"].setSwitchState( pcf::IndiElement::On );
250 REQUIRE( rule1.
value() ==
false );
253 WHEN(
"switch is off and should be equal and is" )
255 prop1[
"toggle"].setSwitchState( pcf::IndiElement::Off );
258 REQUIRE( rule1.
value() ==
true );
261 WHEN(
"switch is off and should be equal but isn't" )
263 prop1[
"toggle"].setSwitchState( pcf::IndiElement::Off );
266 REQUIRE( rule1.
value() ==
false );
269 WHEN(
"switch is off and should be not equal and is not" )
271 prop1[
"toggle"].setSwitchState( pcf::IndiElement::Off );
274 REQUIRE( rule1.
value() ==
true );
277 WHEN(
"switch is off and should be not equal but is" )
279 prop1[
"toggle"].setSwitchState( pcf::IndiElement::Off );
282 REQUIRE( rule1.
value() ==
false );
286 GIVEN(
"time-diff comparison" )
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" ) );
296 clock_gettime( CLOCK_ISIO, &now );
298 prop1[
"current"].setValue( now.tv_sec );
305 WHEN(
"time is less than target" )
309 REQUIRE( rule1.
value() ==
false );
312 WHEN(
"time is greater than target" )
317 REQUIRE( rule1.
value() ==
true );
322SCENARIO(
"multiSwitchCombo rule evaluation",
"[stateRuleEngine::rules]" )
324 auto setStates = []( pcf::IndiProperty &property,
325 const std::initializer_list<std::string> &allNames,
326 const std::initializer_list<std::string> &onNames )
328 for(
const auto &name : allNames )
330 property[name].setSwitchState( pcf::IndiElement::Off );
333 for(
const auto &name : onNames )
335 property[name].setSwitchState( pcf::IndiElement::On );
339 GIVEN(
"a two-switch combo rule" )
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" ) );
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" ) );
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" ) );
368 rule.
property( &source1,
"dev.source1" );
369 rule.
property( &source2,
"dev.source2" );
375 WHEN(
"the combo matches with embedded hyphens" )
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" } );
381 REQUIRE( rule.
value() ==
true );
383 std::string diagnostic;
387 WHEN(
"the combo does not match" )
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" } );
393 REQUIRE( rule.
value() ==
false );
396 WHEN(
"a source has zero active switches" )
398 setStates( source1, {
"alpha",
"alpha-beta" }, {} );
399 setStates( source2, {
"gamma",
"delta" }, {
"gamma" } );
400 setStates( target, {
"alpha-gamma",
"alpha-beta-gamma",
"-gamma" }, {
"-gamma" } );
402 REQUIRE( rule.
value() ==
true );
404 std::string diagnostic;
408 WHEN(
"a source enters and leaves the multi-On state" )
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" } );
414 REQUIRE( rule.
value() ==
true );
416 std::string diagnostic;
418 REQUIRE( diagnostic.find(
"comboRule" ) != std::string::npos );
419 REQUIRE( diagnostic.find(
"dev.source1" ) != std::string::npos );
422 REQUIRE( rule.
value() ==
true );
425 setStates( source1, {
"alpha",
"alpha-beta" }, {
"alpha" } );
426 setStates( target, {
"alpha-gamma",
"alpha-beta-gamma",
"-gamma" }, {
"alpha-gamma" } );
428 REQUIRE( rule.
value() ==
true );
431 setStates( source1, {
"alpha",
"alpha-beta" }, {
"alpha",
"alpha-beta" } );
432 setStates( target, {
"alpha-gamma",
"alpha-beta-gamma",
"-gamma" }, {
"-gamma" } );
434 REQUIRE( rule.
value() ==
true );
436 REQUIRE( diagnostic.find(
"dev.source1" ) != std::string::npos );
439 WHEN(
"a compound rule drains child multiSwitchCombo diagnostics" )
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" } );
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";
456 txtRule.
target(
"READY" );
460 parent.
rule1( &rule );
461 parent.
rule2( &txtRule );
464 REQUIRE( parent.
value() ==
true );
466 std::string diagnostic;
468 REQUIRE( diagnostic.find(
"dev.source1" ) != std::string::npos );
473 GIVEN(
"a one-switch combo rule" )
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" ) );
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" ) );
493 rule.
property( &source,
"dev.soloSource" );
498 WHEN(
"the target has zero active switches" )
501 setStates( source, {
"solo",
"other" }, {
"solo" } );
502 setStates( target, {
"solo",
"other" }, {} );
504 REQUIRE( rule.
value() ==
true );
506 std::string diagnostic;
510 WHEN(
"the target has multiple active switches" )
513 setStates( source, {
"solo",
"other" }, {} );
514 setStates( target, {
"solo",
"other" }, {
"solo",
"other" } );
516 REQUIRE( rule.
value() ==
true );
518 std::string diagnostic;
520 REQUIRE( diagnostic.find(
"dev.soloTarget" ) != std::string::npos );
530SCENARIO(
"INDI element comparison",
"[stateRuleEngine::rules]" )
532 GIVEN(
"string comparison within same property" )
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" ) );
548 WHEN(
"string elements wihtin same property should be equal and are" )
550 prop1[
"current"] =
"test";
551 prop1[
"target"] =
"test";
554 REQUIRE( rule1.
value() ==
true );
557 WHEN(
"string elements within same property should be equal and are not" )
559 prop1[
"current"] =
"test";
560 prop1[
"target"] =
"tset";
563 REQUIRE( rule1.
value() ==
false );
566 WHEN(
"string elements within same property should not be equal and are not" )
568 prop1[
"current"] =
"test";
569 prop1[
"target"] =
"tset";
572 REQUIRE( rule1.
value() ==
true );
575 WHEN(
"string elements within same property should not be equal and are" )
577 prop1[
"current"] =
"test";
578 prop1[
"target"] =
"test";
581 REQUIRE( rule1.
value() ==
false );
585 GIVEN(
"switch comparison" )
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" ) );
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" ) );
607 WHEN(
"switches should be On and equal and are" )
609 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::On );
610 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::On );
613 REQUIRE( rule1.
value() ==
true );
616 WHEN(
"switches should be On and equal but are not" )
618 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::On );
619 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::Off );
622 REQUIRE( rule1.
value() ==
false );
625 WHEN(
"switches should be On and not equal and are not" )
627 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::On );
628 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::Off );
631 REQUIRE( rule1.
value() ==
true );
634 WHEN(
"switches should be On and not equal but are" )
636 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::On );
637 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::On );
640 REQUIRE( rule1.
value() ==
false );
643 WHEN(
"switches should be Off and equal and are" )
645 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::Off );
646 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::Off );
649 REQUIRE( rule1.
value() ==
true );
652 WHEN(
"switches should be Off and equal but are not" )
654 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::Off );
655 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::On );
658 REQUIRE( rule1.
value() ==
false );
661 WHEN(
"switches should be Off and not equal and are not" )
663 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::Off );
664 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::On );
667 REQUIRE( rule1.
value() ==
true );
670 WHEN(
"switches should be Off and not equal but are" )
672 prop1[
"nameTest"].setSwitchState( pcf::IndiElement::Off );
673 prop2[
"badgeTest"].setSwitchState( pcf::IndiElement::Off );
676 REQUIRE( rule1.
value() ==
false );
679 GIVEN(
"numeric comparison" )
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" ) );
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" ) );
701 WHEN(
"numbers should be equal and are" )
703 prop1[
"nameTest"].set( 2.5 );
704 prop2[
"badgeTest"].set( 2.5 );
707 REQUIRE( rule1.
value() ==
true );
710 WHEN(
"numbers should be equal but are not" )
712 prop1[
"nameTest"].set( 2.5 );
713 prop2[
"badgeTest"].set( 2.6 );
716 REQUIRE( rule1.
value() ==
false );
721SCENARIO(
"basic rule comparisons",
"[stateRuleEngine::rules]" )
723 GIVEN(
"INDI Property rule comparison" )
725 WHEN(
"two strings should be equal and are" )
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";
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";
762 rule3.
rule1( &rule1 );
763 rule3.
rule2( &rule2 );
766 REQUIRE( rule3.
value() ==
true );
771SCENARIO(
"compound rule comparisons",
"[stateRuleEngine::rules]" )
773 GIVEN(
"(A && B) || C" )
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";
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";
808 rule3.
rule1( &rule1 );
809 rule3.
rule2( &rule2 );
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";
829 rule5.
rule1( &rule3 );
830 rule5.
rule2( &rule4 );
833 WHEN(
"A==1, B==0, C==1" )
840 REQUIRE( rule5.
value() ==
true );
843 WHEN(
"A==0, B==0, C==1" )
850 REQUIRE( rule5.
value() ==
true );
853 WHEN(
"A==1, B==0, C==0" )
860 REQUIRE( rule5.
value() ==
false );
863 WHEN(
"A==1, B==1, C==0" )
870 REQUIRE( rule5.
value() ==
true );
@ LtEq
Less than or equal to.
@ GtEq
Greater than or equal to.
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.