diff --git a/modules/monitoring/library/Monitoring/MonitoringWizard.php b/modules/monitoring/library/Monitoring/MonitoringWizard.php index e746db0338..6399862461 100644 --- a/modules/monitoring/library/Monitoring/MonitoringWizard.php +++ b/modules/monitoring/library/Monitoring/MonitoringWizard.php @@ -148,9 +148,10 @@ public function getRequirements() ) ))); - $idoSet = new RequirementSet(RequirementSet::MODE_OR); - $mysqlSet = new RequirementSet(); + $idoSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mysqlSet = new RequirementSet(true); $mysqlSet->add(new PhpModuleRequirement(array( + 'optional' => true, 'condition' => 'mysql', 'alias' => 'PDO-MySQL', 'description' => mt( @@ -159,6 +160,7 @@ public function getRequirements() ) ))); $mysqlSet->add(new ClassRequirement(array( + 'optional' => true, 'condition' => 'Zend_Db_Adapter_Pdo_Mysql', 'alias' => mt('monitoring', 'Zend database adapter for MySQL'), 'description' => mt( @@ -167,8 +169,9 @@ public function getRequirements() ) ))); $idoSet->merge($mysqlSet); - $pgsqlSet = new RequirementSet(); + $pgsqlSet = new RequirementSet(true); $pgsqlSet->add(new PhpModuleRequirement(array( + 'optional' => true, 'condition' => 'pgsql', 'alias' => 'PDO-PostgreSQL', 'description' => mt( @@ -177,6 +180,7 @@ public function getRequirements() ) ))); $pgsqlSet->add(new ClassRequirement(array( + 'optional' => true, 'condition' => 'Zend_Db_Adapter_Pdo_Pgsql', 'alias' => mt('monitoring', 'Zend database adapter for PostgreSQL'), 'description' => mt( diff --git a/modules/setup/library/Setup/RequirementSet.php b/modules/setup/library/Setup/RequirementSet.php index 6ffce61fb7..966cf98ccc 100644 --- a/modules/setup/library/Setup/RequirementSet.php +++ b/modules/setup/library/Setup/RequirementSet.php @@ -12,17 +12,31 @@ class RequirementSet implements RecursiveIterator { /** - * Mode AND (all requirements must met) + * Mode AND (all requirements must be met) */ const MODE_AND = 0; /** - * Mode OR (at least one requirement must met) + * Mode OR (at least one requirement must be met) */ const MODE_OR = 1; /** - * The mode by with the requirements are evaluated + * Whether all requirements meet their condition + * + * @var bool + */ + protected $state; + + /** + * Whether this set is optional + * + * @var bool + */ + protected $optional; + + /** + * The mode by which the requirements are evaluated * * @var string */ @@ -36,26 +50,75 @@ class RequirementSet implements RecursiveIterator protected $requirements; /** - * Whether there is any mandatory requirement part of this set + * The raw state of this set's requirements * * @var bool */ - protected $containsMandatoryRequirements; + private $forcedState; /** - * Create a new set of requirements + * Initialize a new set of requirements * - * @param int $mode The mode by with to evaluate the requirements + * @param bool $optional Whether this set is optional + * @param int $mode The mode by which to evaluate this set */ - public function __construct($mode = null) + public function __construct($optional = false, $mode = null) { + $this->optional = $optional; $this->requirements = array(); - $this->containsMandatoryRequirements = false; $this->setMode($mode ?: static::MODE_AND); } /** - * Set the mode by with to evaluate the requirements + * Set the state of this set + * + * @param bool $state + * + * @return RequirementSet + */ + public function setState($state) + { + $this->state = (bool) $state; + return $this; + } + + /** + * Return the state of this set + * + * Alias for RequirementSet::fulfilled(true). + * + * @return bool + */ + public function getState() + { + return $this->fulfilled(true); + } + + /** + * Set whether this set of requirements should be optional + * + * @param bool $state + * + * @return RequirementSet + */ + public function setOptional($state = true) + { + $this->optional = (bool) $state; + return $this; + } + + /** + * Return whether this set of requirements is optional + * + * @return bool + */ + public function isOptional() + { + return $this->optional; + } + + /** + * Set the mode by which to evaluate the requirements * * @param int $mode * @@ -74,7 +137,7 @@ public function setMode($mode) } /** - * Return the mode by with the requirements are evaluated + * Return the mode by which the requirements are evaluated * * @return int */ @@ -95,10 +158,7 @@ public function add(Requirement $requirement) $merged = false; foreach ($this->requirements as $knownRequirement) { if ($knownRequirement instanceof Requirement && $requirement->equals($knownRequirement)) { - if ($this->getMode() === static::MODE_AND && !$requirement->isOptional()) { - $knownRequirement->setOptional(false); - } - + $knownRequirement->setOptional($requirement->isOptional()); foreach ($requirement->getDescriptions() as $description) { $knownRequirement->addDescription($description); } @@ -109,12 +169,6 @@ public function add(Requirement $requirement) } if (! $merged) { - if ($this->getMode() === static::MODE_OR) { - $requirement->setOptional(); - } elseif (! $requirement->isOptional()) { - $this->containsMandatoryRequirements = true; - } - $this->requirements[] = $requirement; } @@ -132,25 +186,15 @@ public function getAll() } /** - * Return whether there is any mandatory requirement part of this set - * - * @return bool - */ - public function hasAnyMandatoryRequirement() - { - return $this->containsMandatoryRequirements || $this->getMode() === static::MODE_OR; - } - - /** - * Register the given requirements + * Register the given set of requirements * - * @param RequirementSet $set The requirements to register + * @param RequirementSet $set The set to register * * @return RequirementSet */ public function merge(RequirementSet $set) { - if ($this->getMode() === static::MODE_OR && $set->getMode() === static::MODE_OR) { + if ($this->getMode() === $set->getMode() && $this->isOptional() === $set->isOptional()) { foreach ($set->getAll() as $requirement) { if ($requirement instanceof static) { $this->merge($requirement); @@ -159,10 +203,6 @@ public function merge(RequirementSet $set) } } } else { - if ($set->getMode() === static::MODE_OR) { - $this->containsMandatoryRequirements = true; - } - $this->requirements[] = $set; } @@ -172,40 +212,45 @@ public function merge(RequirementSet $set) /** * Return whether all requirements can successfully be evaluated based on the current mode * + * In case this is a optional set of requirements (and $force is false), true is returned immediately. + * + * @param bool $force Whether to ignore the optionality of a set or single requirement + * * @return bool */ - public function fulfilled() + public function fulfilled($force = false) { - $state = false; - foreach ($this->requirements as $requirement) { - if ($requirement instanceof static) { - if ($requirement->fulfilled()) { - if ($this->getMode() === static::MODE_OR) { - return true; - } - - $state = true; - } elseif ($this->getMode() === static::MODE_AND && $requirement->hasAnyMandatoryRequirement()) { - return false; + $state = $this->isOptional(); + if (! $force && $state) { + return true; + } + + if (! $force && $this->state !== null) { + return $this->state; + } elseif ($force && $this->forcedState !== null) { + return $this->forcedState; + } + + $self = $this->requirements; + foreach ($self as $requirement) { + if ($requirement->getState()) { + $state = true; + if ($this->getMode() === static::MODE_OR) { + break; } - } else { - if ($requirement->getState()) { - if ($this->getMode() === static::MODE_OR) { - return true; - } - - $state = true; - } elseif ($this->getMode() === static::MODE_AND) { - if (! $requirement->isOptional()) { - return false; - } - - $state = true; // There may only be optional requirements... + } elseif ($force || !$requirement->isOptional()) { + $state = false; + if ($this->getMode() === static::MODE_AND) { + break; } } } - return $state; + if ($force) { + return $this->forcedState = $state; + } + + return $this->state = $state; } /** diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index d3bb71bfa4..e3091bd4d2 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -451,7 +451,7 @@ public function getRequirements() ) ))); - $mysqlSet = new RequirementSet(); + $mysqlSet = new RequirementSet(true); $mysqlSet->add(new PhpModuleRequirement(array( 'optional' => true, 'condition' => 'mysql', @@ -472,7 +472,7 @@ public function getRequirements() ))); $set->merge($mysqlSet); - $pgsqlSet = new RequirementSet(); + $pgsqlSet = new RequirementSet(true); $pgsqlSet->add(new PhpModuleRequirement(array( 'optional' => true, 'condition' => 'pgsql', diff --git a/modules/setup/test/php/library/Setup/RequirementSetTest.php b/modules/setup/test/php/library/Setup/RequirementSetTest.php new file mode 100644 index 0000000000..d2c4d20291 --- /dev/null +++ b/modules/setup/test/php/library/Setup/RequirementSetTest.php @@ -0,0 +1,496 @@ +assertFalse($emptySet->fulfilled(), 'A empty mandatory set of type and is fulfilled'); + + $singleTrueSet = new RequirementSet(); + $singleTrueSet->add(new TrueRequirement()); + $this->assertTrue( + $singleTrueSet->fulfilled(), + 'A mandatory set of type and with a single TrueRequirement is not fulfilled' + ); + + $singleFalseSet = new RequirementSet(); + $singleFalseSet->add(new FalseRequirement()); + $this->assertFalse( + $singleFalseSet->fulfilled(), + 'A mandatory set of type and with a single FalseRequirement is fulfilled' + ); + + $mixedSet = new RequirementSet(); + $mixedSet->add(new TrueRequirement()); + $mixedSet->add(new FalseRequirement()); + $this->assertFalse( + $mixedSet->fulfilled(), + 'A mandatory set of type and with one True- and one FalseRequirement is fulfilled' + ); + } + + public function testFlatOptionalRequirementsOfTypeAnd() + { + $emptySet = new RequirementSet(true); + $this->assertTrue($emptySet->fulfilled(), 'A empty optional set of type and is not fulfilled'); + + $singleTrueSet = new RequirementSet(true); + $singleTrueSet->add(new TrueRequirement()); + $this->assertTrue( + $singleTrueSet->fulfilled(), + 'A optional set of type and with a single TrueRequirement is not fulfilled' + ); + + $singleFalseSet = new RequirementSet(true); + $singleFalseSet->add(new FalseRequirement()); + $this->assertTrue( + $singleFalseSet->fulfilled(), + 'A optional set of type and with a single FalseRequirement is not fulfilled' + ); + + $mixedSet = new RequirementSet(true); + $mixedSet->add(new TrueRequirement()); + $mixedSet->add(new FalseRequirement()); + $this->assertTrue( + $mixedSet->fulfilled(), + 'A optional set of type and with one True- and one FalseRequirement is not fulfilled' + ); + } + + public function testFlatMixedRequirementsOfTypeAnd() + { + $mandatoryOptionalTrueSet = new RequirementSet(); + $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $mandatoryOptionalTrueSet->add(new FalseRequirement()); + $this->assertFalse( + $mandatoryOptionalTrueSet->fulfilled(), + 'A mandatory set of type and with one optional True- and one mandatory FalseRequirement is fulfilled' + ); + + $mandatoryOptionalFalseSet = new RequirementSet(); + $mandatoryOptionalFalseSet->add(new TrueRequirement()); + $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $this->assertTrue( + $mandatoryOptionalFalseSet->fulfilled(), + 'A mandatory set of type and with one mandatory True- and one optional FalseRequirement is not fulfilled' + ); + + $optionalOptionalTrueSet = new RequirementSet(true); + $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $optionalOptionalTrueSet->add(new FalseRequirement()); + $this->assertTrue( + $optionalOptionalTrueSet->fulfilled(), + 'A optional set of type and with one optional True- and one mandatory FalseRequirement is not fulfilled' + ); + + $optionalOptionalFalseSet = new RequirementSet(true); + $optionalOptionalFalseSet->add(new TrueRequirement()); + $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $this->assertTrue( + $optionalOptionalFalseSet->fulfilled(), + 'A optional set of type and with one mandatory True- and one optional FalseRequirement is not fulfilled' + ); + } + + public function testFlatMandatoryRequirementsOfTypeOr() + { + $emptySet = new RequirementSet(false, RequirementSet::MODE_OR); + $this->assertFalse($emptySet->fulfilled(), 'A empty mandatory set of type or is fulfilled'); + + $singleTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $singleTrueSet->add(new TrueRequirement()); + $this->assertTrue( + $singleTrueSet->fulfilled(), + 'A mandatory set of type or with a single TrueRequirement is not fulfilled' + ); + + $singleFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $singleFalseSet->add(new FalseRequirement()); + $this->assertFalse( + $singleFalseSet->fulfilled(), + 'A mandatory set of type or with a single FalseRequirement is fulfilled' + ); + + $mixedSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mixedSet->add(new TrueRequirement()); + $mixedSet->add(new FalseRequirement()); + $this->assertTrue( + $mixedSet->fulfilled(), + 'A mandatory set of type or with one True- and one FalseRequirement is not fulfilled' + ); + } + + public function testFlatOptionalRequirementsOfTypeOr() + { + $emptySet = new RequirementSet(true, RequirementSet::MODE_OR); + $this->assertTrue($emptySet->fulfilled(), 'A empty optional set of type or is not fulfilled'); + + $singleTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $singleTrueSet->add(new TrueRequirement()); + $this->assertTrue( + $singleTrueSet->fulfilled(), + 'A optional set of type or with a single TrueRequirement is not fulfilled' + ); + + $singleFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $singleFalseSet->add(new FalseRequirement()); + $this->assertTrue( + $singleFalseSet->fulfilled(), + 'A optional set of type or with a single FalseRequirement is not fulfilled' + ); + + $mixedSet = new RequirementSet(true, RequirementSet::MODE_OR); + $mixedSet->add(new TrueRequirement()); + $mixedSet->add(new FalseRequirement()); + $this->assertTrue( + $mixedSet->fulfilled(), + 'A optional set of type or with one True- and one FalseRequirement is not fulfilled' + ); + } + + public function testFlatMixedRequirementsOfTypeOr() + { + $mandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $mandatoryOptionalTrueSet->add(new FalseRequirement()); + $this->assertTrue( + $mandatoryOptionalTrueSet->fulfilled(), + 'A mandatory set of type or with one optional True- and one mandatory FalseRequirement is not fulfilled' + ); + + $mandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryOptionalFalseSet->add(new TrueRequirement()); + $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $this->assertTrue( + $mandatoryOptionalFalseSet->fulfilled(), + 'A mandatory set of type or with one mandatory True- and one optional FalseRequirement is not fulfilled' + ); + + $optionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $optionalOptionalTrueSet->add(new FalseRequirement()); + $this->assertTrue( + $optionalOptionalTrueSet->fulfilled(), + 'A optional set of type or with one optional True- and one mandatory FalseRequirement is not fulfilled' + ); + + $optionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalFalseSet->add(new TrueRequirement()); + $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $this->assertTrue( + $optionalOptionalFalseSet->fulfilled(), + 'A optional set of type or with one mandatory True- and one optional FalseRequirement is not fulfilled' + ); + } + + public function testNestedMandatoryRequirementsOfTypeAnd() + { + $trueSet = new RequirementSet(); + $trueSet->add(new TrueRequirement()); + $falseSet = new RequirementSet(); + $falseSet->add(new FalseRequirement()); + + $nestedTrueSet = new RequirementSet(); + $nestedTrueSet->merge($trueSet); + $this->assertTrue( + $nestedTrueSet->fulfilled(), + 'A nested mandatory set of type and with one mandatory TrueRequirement is not fulfilled' + ); + + $nestedFalseSet = new RequirementSet(); + $nestedFalseSet->merge($falseSet); + $this->assertFalse( + $nestedFalseSet->fulfilled(), + 'A nested mandatory set of type and with one mandatory FalseRequirement is fulfilled' + ); + + $nestedMixedSet = new RequirementSet(); + $nestedMixedSet->merge($trueSet); + $nestedMixedSet->merge($falseSet); + $this->assertFalse( + $nestedMixedSet->fulfilled(), + 'Two nested mandatory sets of type and with one mandatory True- and' + . ' one mandatory FalseRequirement respectively are fulfilled' + ); + } + + public function testNestedOptionalRequirementsOfTypeAnd() + { + $trueSet = new RequirementSet(true); + $trueSet->add(new TrueRequirement()); + $falseSet = new RequirementSet(true); + $falseSet->add(new FalseRequirement()); + + $nestedTrueSet = new RequirementSet(true); + $nestedTrueSet->merge($trueSet); + $this->assertTrue( + $nestedTrueSet->fulfilled(), + 'A nested optional set of type and with one mandatory TrueRequirement is not fulfilled' + ); + + $nestedFalseSet = new RequirementSet(true); + $nestedFalseSet->merge($falseSet); + $this->assertTrue( + $nestedFalseSet->fulfilled(), + 'A nested optional set of type and with one mandatory FalseRequirement is not fulfilled' + ); + + $nestedMixedSet = new RequirementSet(true); + $nestedMixedSet->merge($trueSet); + $nestedMixedSet->merge($falseSet); + $this->assertTrue( + $nestedMixedSet->fulfilled(), + 'Two nested optional sets of type and with one mandatory True- and' + . ' one mandatory FalseRequirement respectively are not fulfilled' + ); + } + + public function testNestedMixedRequirementsOfTypeAnd() + { + $mandatoryMandatoryTrueSet = new RequirementSet(); + $mandatoryMandatoryTrueSet->add(new TrueRequirement()); + $mandatoryOptionalTrueSet = new RequirementSet(); + $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $mandatoryMandatoryFalseSet = new RequirementSet(); + $mandatoryMandatoryFalseSet->add(new FalseRequirement()); + $mandatoryOptionalFalseSet = new RequirementSet(); + $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $optionalMandatoryTrueSet = new RequirementSet(true); + $optionalMandatoryTrueSet->add(new TrueRequirement()); + $optionalOptionalTrueSet = new RequirementSet(true); + $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $optionalMandatoryFalseSet = new RequirementSet(true); + $optionalMandatoryFalseSet->add(new FalseRequirement()); + $optionalOptionalFalseSet = new RequirementSet(true); + $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + + $mandatoryMandatoryOptionalTrueSet = new RequirementSet(); + $mandatoryMandatoryOptionalTrueSet->merge($mandatoryOptionalTrueSet); + $mandatoryMandatoryOptionalTrueSet->merge($mandatoryMandatoryFalseSet); + $this->assertFalse( + $mandatoryMandatoryOptionalTrueSet->fulfilled(), + 'A mandatory set of type and with two nested mandatory sets of type and where one has a optional' + . ' TrueRequirement and the other one has a mandatory FalseRequirement is fulfilled' + ); + + $mandatoryMandatoryOptionalFalseSet = new RequirementSet(); + $mandatoryMandatoryOptionalFalseSet->merge($mandatoryOptionalFalseSet); + $mandatoryMandatoryOptionalFalseSet->merge($mandatoryMandatoryTrueSet); + $this->assertTrue( + $mandatoryMandatoryOptionalFalseSet->fulfilled(), + 'A mandatory set of type and with two nested mandatory sets of type and where one has a mandatory' + . ' TrueRequirement and the other one has a optional FalseRequirement is not fulfilled' + ); + + $optionalOptionalOptionalTrueSet = new RequirementSet(true); + $optionalOptionalOptionalTrueSet->merge($optionalOptionalTrueSet); + $optionalOptionalOptionalTrueSet->merge($optionalMandatoryFalseSet); + $this->assertTrue( + $optionalOptionalOptionalTrueSet->fulfilled(), + 'A optional set of type and with two nested optional sets of type and where one has a optional' + . ' TrueRequirement and the other one has a mandatory FalseRequirement is not fulfilled' + ); + + $optionalOptionalOptionalFalseSet = new RequirementSet(true); + $optionalOptionalOptionalFalseSet->merge($optionalOptionalFalseSet); + $optionalOptionalOptionalFalseSet->merge($optionalMandatoryTrueSet); + $this->assertTrue( + $optionalOptionalOptionalFalseSet->fulfilled(), + 'A optional set of type and with two nested optional sets of type and where one has a mandatory' + . ' TrueRequirement and the other one has a optional FalseRequirement is not fulfilled' + ); + } + + public function testNestedMandatoryRequirementsOfTypeOr() + { + $trueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $trueSet->add(new TrueRequirement()); + $falseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $falseSet->add(new FalseRequirement()); + + $nestedTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $nestedTrueSet->merge($trueSet); + $this->assertTrue( + $nestedTrueSet->fulfilled(), + 'A nested mandatory set of type or with one mandatory TrueRequirement is not fulfilled' + ); + + $nestedFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $nestedFalseSet->merge($falseSet); + $this->assertFalse( + $nestedFalseSet->fulfilled(), + 'A nested mandatory set of type or with one mandatory FalseRequirement is fulfilled' + ); + + $nestedMixedSet = new RequirementSet(false, RequirementSet::MODE_OR); + $nestedMixedSet->merge($trueSet); + $nestedMixedSet->merge($falseSet); + $this->assertTrue( + $nestedMixedSet->fulfilled(), + 'Two nested mandatory sets of type or with one mandatory True- and' + . ' one mandatory FalseRequirement respectively are not fulfilled' + ); + } + + public function testNestedOptionalRequirementsOfTypeOr() + { + $trueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $trueSet->add(new TrueRequirement()); + $falseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $falseSet->add(new FalseRequirement()); + + $nestedTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $nestedTrueSet->merge($trueSet); + $this->assertTrue( + $nestedTrueSet->fulfilled(), + 'A nested optional set of type or with one mandatory TrueRequirement is not fulfilled' + ); + + $nestedFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $nestedFalseSet->merge($falseSet); + $this->assertTrue( + $nestedFalseSet->fulfilled(), + 'A nested optional set of type or with one mandatory FalseRequirement is not fulfilled' + ); + + $nestedMixedSet = new RequirementSet(true, RequirementSet::MODE_OR); + $nestedMixedSet->merge($trueSet); + $nestedMixedSet->merge($falseSet); + $this->assertTrue( + $nestedMixedSet->fulfilled(), + 'Two nested optional sets of type or with one mandatory True- and' + . ' one mandatory FalseRequirement respectively are not fulfilled' + ); + } + + public function testNestedMixedRequirementsOfTypeOr() + { + $mandatoryMandatoryTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryMandatoryTrueSet->add(new TrueRequirement()); + $mandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $mandatoryMandatoryFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryMandatoryFalseSet->add(new FalseRequirement()); + $mandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + $optionalMandatoryTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalMandatoryTrueSet->add(new TrueRequirement()); + $optionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true))); + $optionalMandatoryFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalMandatoryFalseSet->add(new FalseRequirement()); + $optionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true))); + + $mandatoryMandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryMandatoryOptionalTrueSet->merge($mandatoryOptionalTrueSet); + $mandatoryMandatoryOptionalTrueSet->merge($mandatoryMandatoryFalseSet); + $this->assertTrue($mandatoryMandatoryOptionalTrueSet->fulfilled()); + + $mandatoryMandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR); + $mandatoryMandatoryOptionalFalseSet->merge($mandatoryOptionalFalseSet); + $mandatoryMandatoryOptionalFalseSet->merge($mandatoryMandatoryTrueSet); + $this->assertTrue($mandatoryMandatoryOptionalFalseSet->fulfilled()); + + $optionalOptionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalOptionalTrueSet->merge($optionalOptionalTrueSet); + $optionalOptionalOptionalTrueSet->merge($optionalMandatoryFalseSet); + $this->assertTrue($optionalOptionalOptionalTrueSet->fulfilled()); + + $optionalOptionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR); + $optionalOptionalOptionalFalseSet->merge($optionalOptionalFalseSet); + $optionalOptionalOptionalFalseSet->merge($optionalMandatoryTrueSet); + $this->assertTrue($optionalOptionalOptionalFalseSet->fulfilled()); + } + + public function testNestedMandatoryRequirementsOfDifferentTypes() + { + $true = new TrueRequirement(); + $false = new FalseRequirement(); + + $level1And = new RequirementSet(); + $level2FirstOr = new RequirementSet(false, RequirementSet::MODE_OR); + $level2SecondOr = new RequirementSet(false, RequirementSet::MODE_OR); + $level1And->merge($level2FirstOr)->merge($level2SecondOr); + $level3FirstAnd = new RequirementSet(); + $level3SecondAnd = new RequirementSet(); + $level2FirstOr->merge($level3FirstAnd)->merge($level3SecondAnd); + $level2SecondOr->merge($level3FirstAnd)->merge($level3SecondAnd); + $level3FirstAnd->add($true)->add($true); + $level3SecondAnd->add($false)->add($true); + $this->assertTrue($level1And->fulfilled()); + + $level1Or = new RequirementSet(false, RequirementSet::MODE_OR); + $level2FirstAnd = new RequirementSet(); + $level2SecondAnd = new RequirementSet(); + $level1Or->merge($level2FirstAnd)->merge($level2SecondAnd); + $level3FirstOr = new RequirementSet(false, RequirementSet::MODE_OR); + $level3SecondOr = new RequirementSet(false, RequirementSet::MODE_OR); + $level2FirstAnd->merge($level3FirstOr)->merge($level3SecondOr); + $level2SecondAnd->merge($level3FirstOr)->merge($level3SecondOr); + $level3FirstOr->add($false); + $level3SecondOr->add($true); + $this->assertFalse($level1Or->fulfilled()); + } + + public function testNestedOptionalRequirementsOfDifferentTypes() + { + $true = new TrueRequirement(); + $false = new FalseRequirement(); + + $level1And = new RequirementSet(); + $level2FirstAnd = new RequirementSet(true); + $level2SecondAnd = new RequirementSet(true); + $level1And->merge($level2FirstAnd)->merge($level2SecondAnd); + $level3FirstOr = new RequirementSet(true, RequirementSet::MODE_OR); + $level3SecondOr = new RequirementSet(true, RequirementSet::MODE_OR); + $level2FirstAnd->merge($level3FirstOr)->merge($level3SecondOr); + $level2SecondAnd->merge($level3FirstOr)->merge($level3SecondOr); + $level3FirstOr->add($false); + $level3SecondOr->add($false); + $this->assertFalse($level1And->fulfilled()); + $this->assertTrue($level2FirstAnd->fulfilled()); + $this->assertTrue($level2SecondAnd->fulfilled()); + + $level1Or = new RequirementSet(false, RequirementSet::MODE_OR); + $level2FirstOr = new RequirementSet(true, RequirementSet::MODE_OR); + $level2SecondOr = new RequirementSet(true, RequirementSet::MODE_OR); + $level1Or->merge($level2FirstOr)->merge($level2SecondOr); + $level3FirstAnd = new RequirementSet(true); + $level3SecondAnd = new RequirementSet(true); + $level2FirstOr->merge($level3FirstAnd)->merge($level3SecondAnd); + $level2SecondOr->merge($level3FirstAnd)->merge($level3SecondAnd); + $level3FirstAnd->add($true)->add($true); + $level3SecondAnd->add($false)->add($true); + $this->assertTrue($level1Or->fulfilled()); + } + + public function testNestedMixedRequirementsOfDifferentTypes() + { + $this->markTestIncomplete(); + } +}