ExtensibleSet: basic implementation & tests

This commit is contained in:
Thomas Gelf 2016-02-29 12:23:08 +01:00
parent 40d2e9f120
commit 23dd4721ec
2 changed files with 334 additions and 0 deletions

View File

@ -0,0 +1,199 @@
<?php
namespace Icinga\Module\Director\IcingaConfig;
use Icinga\Exception\InvalidPropertyException;
class ExtensibleSet
{
protected $ownValues;
protected $plusValues = array();
protected $minusValues = array();
protected $resolvedValues;
protected $allowedValues;
protected $inheritedValues = array();
public function __construct($values = null)
{
if (null !== $values) {
$this->override($values);
}
}
public function override($values)
{
$this->ownValues = array();
$this->inheritedValues = array();
$this->addValuesTo($this->ownValues, $values);
return $this->addResolvedValues($values);
}
public function extend($values)
{
$this->addValuesTo($this->plusValues, $values);
return $this->addResolvedValues($values);
}
public function blacklist($values)
{
$this->addValuesTo($this->minusValues, $values);
if ($this->hasBeenResolved()) {
$this->removeValuesFrom($this->resolvedValues, $values);
}
return $this;
}
public function getResolvedValues()
{
if (! $this->hasBeenResolved()) {
$this->recalculate();
}
sort($this->resolvedValues);
return $this->resolvedValues;
}
protected function hasBeenResolved()
{
return $this->resolvedValues !== null;
}
public function inheritFrom(ExtensibleSet $parent)
{
if ($this->ownValues !== null) {
return $this;
}
if ($this->hasBeenResolved()) {
$this->reset();
}
$this->inheritedValues = array();
$this->addValuesTo(
$this->inheritedValues,
$this->stripBlacklistedValues($parent->getResolvedValues())
);
return $this->recalculate();
}
protected function stripBlacklistedValues($array)
{
$this->removeValuesFrom($array, $this->minusValues);
return $array;
}
public function forgetInheritedValues()
{
$this->inheritedValues = array();
return $this;
}
protected function assertValidValue($value)
{
if (null === $this->allowedValues) {
return $this;
}
if (in_array($value, $this->allowedValues)) {
return $this;
}
throw new InvalidPropertyException(
'Got invalid property "%s", allowed are: (%s)',
$value,
implode(', ', $this->allowedValues)
);
}
protected function addValuesTo(&$array, $values)
{
foreach ($this->wantArray($values) as $value) {
$this->addTo($array, $value);
}
return $this;
}
protected function addResolvedValues($values)
{
if (! $this->hasBeenResolved()) {
$this->resolvedValues = array();
}
return $this->addValuesTo(
$this->resolvedValues,
$this->stripBlacklistedValues($this->wantArray($values))
);
}
protected function removeValuesFrom(&$array, $values)
{
foreach ($this->wantArray($values) as $value) {
$this->removeFrom($array, $value);
}
return $this;
}
protected function addTo(&$array, $value)
{
if (! in_array($value, $array)) {
$this->assertValidValue($value);
$array[] = $value;
}
return $this;
}
protected function removeFrom(&$array, $value)
{
if (false !== ($pos = array_search($value, $array))) {
unset($array[$pos]);
}
return $this;
}
protected function recalculate()
{
$this->resolvedValues = array();
if ($this->ownValues === null) {
$this->addValuesTo($this->resolvedValues, $this->inheritedValues);
} else {
$this->addValuesTo($this->resolvedValues, $this->ownValues);
}
$this->addValuesTo($this->resolvedValues, $this->plusValues);
$this->removeFrom($this->resolvedValues, $this->minusValues);
return $this;
}
protected function reset()
{
$this->resolvedValues = null;
return $this;
}
protected function wantArray($values)
{
if (is_array($values)) {
return $values;
}
return array($values);
}
}

View File

@ -0,0 +1,135 @@
<?php
namespace Tests\Icinga\Module\Director\IcingaConfig;
use Icinga\Module\Director\IcingaConfig\ExtensibleSet;
use Icinga\Module\Director\Test\BaseTestCase;
class ExtensibleSetTest extends BaseTestCase
{
public function testNoValuesResultInEmptySet()
{
$set = new ExtensibleSet();
$this->assertEquals(
array(),
$set->getResolvedValues()
);
}
public function testValuesPassedToConstructorAreAccepted()
{
$values = array('Val1', 'Val2', 'Val4');
$set = new ExtensibleSet($values);
$this->assertEquals(
$values,
$set->getResolvedValues()
);
}
public function testSingleValuesCanBeBlacklisted()
{
$values = array('Val1', 'Val2', 'Val4');
$set = new ExtensibleSet($values);
$set->blacklist('Val2');
$this->assertEquals(
array('Val1', 'Val4'),
$set->getResolvedValues()
);
}
public function testMultipleValuesCanBeBlacklisted()
{
$values = array('Val1', 'Val2', 'Val4');
$set = new ExtensibleSet($values);
$set->blacklist(array('Val4', 'Val1'));
$this->assertEquals(
array('Val2'),
$set->getResolvedValues()
);
}
public function testSimpleInheritanceWorksFine()
{
$values = array('Val1', 'Val2', 'Val4');
$parent = new ExtensibleSet($values);
$child = new ExtensibleSet();
$child->inheritFrom($parent);
$this->assertEquals(
$values,
$child->getResolvedValues()
);
}
public function testWeCanInheritFromMultipleParents()
{
$p1set = array('p1a', 'p1c');
$p2set = array('p2a', 'p2d');
$parent1 = new ExtensibleSet($p1set);
$parent2 = new ExtensibleSet($p2set);
$child = new ExtensibleSet();
$child->inheritFrom($parent1)->inheritFrom($parent2);
$this->assertEquals(
$p2set,
$child->getResolvedValues()
);
}
public function testOwnValuesOverrideParents()
{
$cset = array('p1a', 'p1c');
$pset = array('p2a', 'p2d');
$child = new ExtensibleSet($cset);
$parent = new ExtensibleSet($pset);
$child->inheritFrom($parent);
$this->assertEquals(
$cset,
$child->getResolvedValues()
);
}
public function testInheritedValuesCanBeBlacklisted()
{
$pset = array('p1', 'p2', 'p3');
$child = new ExtensibleSet();
$child->blacklist('p2');
$parent = new ExtensibleSet($pset);
$child->inheritFrom($parent);
$child->blacklist(array('not', 'yet', 'p1'));
$this->assertEquals(
array('p3'),
$child->getResolvedValues()
);
$child->blacklist(array('p3'));
$this->assertEquals(
array(),
$child->getResolvedValues()
);
}
public function testInheritedValuesCanBeExtended()
{
$pset = array('p1', 'p2', 'p3');
$child = new ExtensibleSet();
$child->extend('p5');
$parent = new ExtensibleSet($pset);
$child->inheritFrom($parent);
$this->assertEquals(
array('p1', 'p2', 'p3', 'p5'),
$child->getResolvedValues()
);
}
}