diff --git a/Stdlib/Map/MultiMap.php b/Stdlib/Map/MultiMap.php index a0b4001d7..048547e68 100644 --- a/Stdlib/Map/MultiMap.php +++ b/Stdlib/Map/MultiMap.php @@ -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 []; diff --git a/Utils/Permutation.php b/Utils/Permutation.php index 80a629e35..fcfca34b8 100644 --- a/Utils/Permutation.php +++ b/Utils/Permutation.php @@ -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.'); diff --git a/tests/Stdlib/Map/MultiMapTest.php b/tests/Stdlib/Map/MultiMapTest.php index a76b8484e..5c33d6b3e 100644 --- a/tests/Stdlib/Map/MultiMapTest.php +++ b/tests/Stdlib/Map/MultiMapTest.php @@ -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'])); + } }