Fix multimap implementation and add tests

This commit is contained in:
Dennis Eichhorn 2018-09-09 20:06:18 +02:00
parent 5b3178e049
commit 105d4f355b
3 changed files with 203 additions and 71 deletions

View File

@ -90,7 +90,7 @@ class MultiMap implements \Countable
$inserted = false;
if ($this->keyType !== KeyType::SINGLE) {
$keys = [implode(':', $keys)];
$keys = [\implode(':', $keys)];
}
foreach ($keys as $key) {
@ -202,7 +202,7 @@ class MultiMap implements \Countable
{
if (\is_array($key)) {
if ($this->orderType === OrderType::LOOSE) {
$keys = Permutation::permut($key);
$keys = Permutation::permut($key, [], false);
foreach ($keys as $key => $value) {
$key = \implode(':', $value);
@ -231,7 +231,7 @@ class MultiMap implements \Countable
*/
public function set($key, $value) : bool
{
if ($this->keyType === KeyType::MULTIPLE && is_array($key)) {
if ($this->keyType === KeyType::MULTIPLE && \is_array($key)) {
return $this->setMultiple($key, $value);
}
@ -250,19 +250,17 @@ class MultiMap implements \Countable
*/
private function setMultiple($key, $value) : bool
{
if ($this->orderType !== OrderType::LOOSE) {
$permutation = Permutation::permut($key);
if ($this->orderType !== OrderType::STRICT) {
$permutation = Permutation::permut($key, [], false);
foreach ($permutation as $permut) {
if ($this->set(implode(':', $permut), $value)) {
if ($this->set(\implode(':', $permut), $value)) {
return true;
}
}
} else {
return $this->set(implode(':', $key), $value);
return $this->set(\implode(':', $key), $value);
}
return false;
}
/**
@ -297,7 +295,7 @@ class MultiMap implements \Countable
*/
public function remove($key) : bool
{
if ($this->keyType === KeyType::MULTIPLE && is_array($key)) {
if ($this->keyType === KeyType::MULTIPLE && \is_array($key)) {
return $this->removeMultiple($key);
}
@ -316,17 +314,17 @@ class MultiMap implements \Countable
private function removeMultiple($key) : bool
{
if ($this->orderType !== OrderType::LOOSE) {
return $this->remove(implode(':', $key));
return $this->remove(\implode(':', $key));
}
$keys = Permutation::permut($key);
$found = true;
$keys = Permutation::permut($key, [], false);
$found = false;
foreach ($keys as $key => $value) {
$allFound = $this->remove(implode(':', $value));
$allFound = $this->remove(\implode(':', $value));
if (!$allFound) {
$found = false;
if ($allFound) {
$found = true;
}
}
@ -399,43 +397,11 @@ class MultiMap implements \Countable
*/
public function removeKey($key) : bool
{
if ($this->keyType === KeyType::MULTIPLE && is_array($key)) {
return $this->removeKeyMultiple($key);
} else {
return $this->removeKeySingle($key);
if ($this->keyType === KeyType::MULTIPLE) {
return false;
}
}
/**
* Remove key.
*
* This only removes the value if no other key exists for this value.
*
* @param mixed $key Key used to identify value
*
* @return bool
*
* @since 1.0.0
*/
private function removeKeyMultiple($key) : bool
{
if ($this->orderType === OrderType::LOOSE) {
$keys = Permutation::permut($key);
$removed = false;
foreach ($keys as $key => $value) {
$removed = $this->removeKey(implode(':', $value));
if (!$removed) {
return false;
}
}
return $removed;
} else {
return $this->removeKey(implode(':', $key));
}
return $this->removeKeySingle($key);
}
/**
@ -493,7 +459,9 @@ class MultiMap implements \Countable
public function getSiblingsMultiple($key) : array
{
if ($this->orderType === OrderType::LOOSE) {
return Permutation::permut($key);
$key = \is_array($key) ? $key : [$key];
return Permutation::permut($key, [], false);
}
return [];

View File

@ -45,12 +45,12 @@ final class Permutation
*
* @since 1.0.0
*/
public static function permut(array $toPermute, array $result = []) : array
public static function permut(array $toPermute, array $result = [], bool $concat = true) : array
{
$permutations = [];
if (empty($toPermute)) {
$permutations[] = \implode('', $result);
$permutations[] = $concat ? \implode('', $result) : $result;
} else {
foreach ($toPermute as $key => $val) {
$newArr = $toPermute;
@ -59,7 +59,7 @@ final class Permutation
unset($newArr[$key]);
$permutations = array_merge($permutations, self::permut($newArr, $newres));
$permutations = \array_merge($permutations, self::permut($newArr, $newres, $concat));
}
}
@ -78,7 +78,7 @@ final class Permutation
*/
public static function isPermutation(string $a, string $b) : bool
{
return count_chars($a, 1) === count_chars($b, 1);
return \count_chars($a, 1) === \count_chars($b, 1);
}
/**
@ -93,7 +93,7 @@ final class Permutation
*/
public static function isPalindrome(string $a, string $filter = 'a-zA-Z0-9') : bool
{
$a = \strtolower(preg_replace('/[^' . $filter . ']/', '', $a));
$a = \strtolower(\preg_replace('/[^' . $filter . ']/', '', $a));
return $a === \strrev($a);
}
@ -112,11 +112,11 @@ final class Permutation
*/
public static function permutate($toPermute, array $key)
{
if (!is_array($toPermute) && !is_string($toPermute)) {
if (!\is_array($toPermute) && !\is_string($toPermute)) {
throw new \InvalidArgumentException('Parameter has to be array or string');
}
$length = is_array($toPermute) ? \count($toPermute) : \strlen($toPermute);
$length = \is_array($toPermute) ? \count($toPermute) : \strlen($toPermute);
if (\count($key) > $length) {
throw new \InvalidArgumentException('There mustn not be more keys than permutation elements.');

View File

@ -14,6 +14,8 @@
namespace phpOMS\tests\Stdlib\Map;
use phpOMS\Stdlib\Map\MultiMap;
use phpOMS\Stdlib\Map\KeyType;
use phpOMS\Stdlib\Map\OrderType;
class MultiMapTest extends \PHPUnit\Framework\TestCase
{
@ -43,7 +45,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertFalse($map->remove('someKey'));
}
public function testBasicAdd()
public function testBasicAddAny()
{
$map = new MultiMap();
@ -54,7 +56,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val1', $map->get('b'));
}
public function testOverwrite()
public function testOverwriteAny()
{
$map = new MultiMap();
@ -66,7 +68,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val2', $map->get('b'));
}
public function testOverwritePartialFalse()
public function testOverwritePartialFalseAny()
{
$map = new MultiMap();
@ -79,7 +81,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val3', $map->get('c'));
}
public function testOverwriteFalseFalse()
public function testOverwriteFalseFalseAny()
{
$map = new MultiMap();
@ -93,7 +95,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val3', $map->get('c'));
}
public function testSet()
public function testSetAny()
{
$map = new MultiMap();
@ -112,7 +114,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val3', $map->get('c'));
}
public function testRemap()
public function testRemapAny()
{
$map = new MultiMap();
@ -142,7 +144,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals('val3', $map->get('c'));
}
public function testMapInfo()
public function testMapInfoAny()
{
$map = new MultiMap();
@ -159,7 +161,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertTrue(\is_array($map->values()));
}
public function testSiblings()
public function testSiblingsAny()
{
$map = new MultiMap();
@ -177,7 +179,7 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals(['a'], $siblings);
}
public function testRemove()
public function testRemoveAny()
{
$map = new MultiMap();
@ -190,9 +192,6 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
$removed = $map->remove('d');
self::assertFalse($removed);
$removed = $map->remove('d');
self::assertFalse($removed);
$removed = $map->remove('c');
self::assertTrue($removed);
self::assertEquals(2, \count($map->keys()));
@ -206,4 +205,169 @@ class MultiMapTest extends \PHPUnit\Framework\TestCase
self::assertEquals(1, \count($map->keys()));
self::assertEquals(1, \count($map->values()));
}
public function testBasicAddExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val1');
self::assertEquals(1, $map->count());
self::assertTrue($inserted);
self::assertEquals('val1', $map->get(['a', 'b']));
self::assertEquals('val1', $map->get(['b', 'a']));
}
public function testBasicAddExactOrdered()
{
$map = new MultiMap(KeyType::MULTIPLE, OrderType::STRICT);
$inserted = $map->add(['a', 'b'], 'val1');
self::assertEquals(1, $map->count());
self::assertTrue($inserted);
self::assertEquals('val1', $map->get(['a', 'b']));
self::assertEquals(null, $map->get(['b', 'a']));
}
public function testOverwriteExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val1');
$inserted = $map->add(['a', 'b'], 'val2');
self::assertEquals(1, $map->count());
self::assertTrue($inserted);
self::assertEquals('val2', $map->get(['a', 'b']));
}
public function testOverwritePartialFalseExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
self::assertEquals(2, $map->count());
self::assertTrue($inserted);
self::assertEquals('val2', $map->get(['a', 'b']));
self::assertEquals('val3', $map->get(['c', 'a']));
}
public function testOverwriteFalseFalseExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
$inserted = $map->add(['a', 'c'], 'val4', false);
self::assertEquals(2, $map->count());
self::assertFalse($inserted);
self::assertEquals('val2', $map->get(['a', 'b']));
self::assertEquals('val3', $map->get(['a', 'c']));
}
public function testSetExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
$set = $map->set('d', 'val4');
self::assertFalse($set);
self::assertEquals(2, $map->count());
$set = $map->set(['a', 'b'], 'val4');
self::assertEquals(2, $map->count());
self::assertTrue($set);
self::assertEquals('val4', $map->get(['a', 'b']));
self::assertEquals('val4', $map->get(['b', 'a']));
}
public function testSetExactOrdered()
{
$map = new MultiMap(KeyType::MULTIPLE, OrderType::STRICT);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
$set = $map->set('c', 'val4');
self::assertFalse($set);
self::assertEquals(2, $map->count());
$set = $map->set(['a', 'b'], 'val4');
self::assertEquals(2, $map->count());
self::assertTrue($set);
self::assertEquals('val4', $map->get(['a', 'b']));
$set = $map->set(['b', 'a'], 'val5');
self::assertEquals(2, $map->count());
self::assertFalse($set);
}
public function testRemapExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
$remap = $map->remap(['a', 'b'], ['c', 'd']);
self::assertFalse($remap);
}
public function testSiblingsExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
self::assertEquals([['a', 'b'], ['b', 'a']], $map->getSiblings(['a', 'b']));
}
public function testSiblingsExactOrdered()
{
$map = new MultiMap(KeyType::MULTIPLE, OrderType::STRICT);
$inserted = $map->add(['a', 'b'], 'val2');
self::assertEquals([], $map->getSiblings(['a', 'b']));
}
public function testRemoveExact()
{
$map = new MultiMap(KeyType::MULTIPLE);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
self::assertEquals(2, \count($map->keys()));
self::assertEquals(2, \count($map->values()));
$removed = $map->remove('d');
self::assertFalse($removed);
$removed = $map->remove(['a', 'b']);
self::assertTrue($removed);
self::assertEquals(1, \count($map->keys()));
self::assertEquals(1, \count($map->values()));
self::assertFalse($map->removeKey(['a', 'b']));
}
public function testRemoveExactOrdered()
{
$map = new MultiMap(KeyType::MULTIPLE, OrderType::STRICT);
$inserted = $map->add(['a', 'b'], 'val2');
$inserted = $map->add(['a', 'c'], 'val3', false);
self::assertEquals(2, \count($map->keys()));
self::assertEquals(2, \count($map->values()));
$removed = $map->remove(['b', 'a']);
self::assertFalse($removed);
$removed = $map->remove(['a', 'b']);
self::assertTrue($removed);
self::assertEquals(1, \count($map->keys()));
self::assertEquals(1, \count($map->values()));
self::assertFalse($map->removeKey(['a', 'b']));
}
}