From 4b66272215315127d8921c40b4da4a6cdca80dc7 Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 13 Mar 2024 00:27:57 +0300 Subject: [PATCH 1/5] ArrayMaskView tests added. --- tests/unit/ArrayMaskView/ReadTest.php | 77 +++++++++++++++++++++ tests/unit/ArrayMaskView/WriteTest.php | 95 ++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 tests/unit/ArrayMaskView/ReadTest.php create mode 100644 tests/unit/ArrayMaskView/WriteTest.php diff --git a/tests/unit/ArrayMaskView/ReadTest.php b/tests/unit/ArrayMaskView/ReadTest.php new file mode 100644 index 0000000..c2d57da --- /dev/null +++ b/tests/unit/ArrayMaskView/ReadTest.php @@ -0,0 +1,77 @@ +subview(new MaskSelector($mask)); + + $this->assertInstanceOf(ArrayMaskView::class, $subview); + + $this->assertSame($expected, [...$subview]); + $this->assertSame(\count($expected), \count($subview)); + + for ($i = 0; $i < \count($subview); ++$i) { + $this->assertSame($expected[$i], $subview[$i]); + } + + for ($i = 0; $i < \count($view); ++$i) { + $this->assertSame($source[$i], $view[$i]); + } + + $this->assertSame($source, $view->toArray()); + $this->assertSame($expected, $subview->toArray()); + + $this->assertSame($source, [...$view]); + $this->assertSame($expected, [...$subview]); + } + + /** + * @dataProvider dataProviderForRead + */ + public function testReadByIndex(array $source, array $mask, array $expected) + { + $view = ArrayView::toView($source); + $subArray = $view[new MaskSelector($mask)]; + + $this->assertSame($expected, $subArray); + $this->assertSame(\count($expected), \count($subArray)); + + for ($i = 0; $i < \count($subArray); ++$i) { + $this->assertSame($expected[$i], $subArray[$i]); + } + + for ($i = 0; $i < \count($view); ++$i) { + $this->assertSame($source[$i], $view[$i]); + } + + $this->assertSame($source, $view->toArray()); + $this->assertSame($source, [...$view]); + $this->assertSame($expected, $subArray); + } + + public function dataProviderForRead(): array + { + return [ + [[], [], []], + [[1], [0], []], + [[1, 2, 3], [0, 0, 0], []], + [[1], [1], [1]], + [[1, 2], [1, 0], [1]], + [[1, 2], [0, 1], [2]], + [[1, 2], [1, 1], [1, 2]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 0, 1, 0, 1, 0, 1, 0], [2, 4, 6, 8]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 1, 0, 0, 0, 0, 0, 1], [1, 2, 3, 9]], + ]; + } +} diff --git a/tests/unit/ArrayMaskView/WriteTest.php b/tests/unit/ArrayMaskView/WriteTest.php new file mode 100644 index 0000000..c6358cd --- /dev/null +++ b/tests/unit/ArrayMaskView/WriteTest.php @@ -0,0 +1,95 @@ +assertSame($expected, [...$view]); + $this->assertSame($expected, $source); + } + + /** + * @dataProvider dataProviderForMaskSubviewWrite + */ + public function testWriteBySubview(array $source, $config, array $toWrite, array $expected) + { + $view = ArrayView::toView($source); + + $view->subview(new MaskSelector($config))[':'] = $toWrite; + + $this->assertSame($expected, [...$view]); + $this->assertSame($expected, $source); + } + + public function dataProviderForMaskSubviewWrite(): array + { + return [ + [ + [], + [], + [], + [], + ], + [ + [1], + [0], + [], + [1], + ], + [ + [1, 2, 3], + [0, 0, 0], + [], + [1, 2, 3], + ], + [ + [1], + [1], + [2], + [2], + ], + [ + [1, 2], + [1, 0], + [2], + [2, 2], + ], + [ + [1, 2], + [0, 1], + [3], + [1, 3], + ], + [ + [1, 2], + [1, 1], + [2, 3], + [2, 3], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [0, 1, 0, 1, 0, 1, 0, 1, 0], + [3, 5, 7, 9], + [1, 3, 3, 5, 5, 7, 7, 9, 9], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 1, 1, 0, 0, 0, 0, 0, 1], + [2, 3, 4, 10], + [2, 3, 4, 4, 5, 6, 7, 8, 10], + ], + ]; + } +} From bcd913212e0440aa4c69cf7855758087fe98d46c Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 13 Mar 2024 00:34:51 +0300 Subject: [PATCH 2/5] IndexListView tests added. --- tests/unit/ArrayIndexListView/ReadTest.php | 83 +++++++++++++ tests/unit/ArrayIndexListView/WriteTest.php | 126 ++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 tests/unit/ArrayIndexListView/ReadTest.php create mode 100644 tests/unit/ArrayIndexListView/WriteTest.php diff --git a/tests/unit/ArrayIndexListView/ReadTest.php b/tests/unit/ArrayIndexListView/ReadTest.php new file mode 100644 index 0000000..4c9b4e6 --- /dev/null +++ b/tests/unit/ArrayIndexListView/ReadTest.php @@ -0,0 +1,83 @@ +subview(new IndexListSelector($indexes)); + + $this->assertInstanceOf(ArrayIndexListView::class, $subview); + + $this->assertSame($expected, [...$subview]); + $this->assertSame(\count($expected), \count($subview)); + + for ($i = 0; $i < \count($subview); ++$i) { + $this->assertSame($expected[$i], $subview[$i]); + } + + for ($i = 0; $i < \count($view); ++$i) { + $this->assertSame($source[$i], $view[$i]); + } + + $this->assertSame($source, $view->toArray()); + $this->assertSame($expected, $subview->toArray()); + + $this->assertSame($source, [...$view]); + $this->assertSame($expected, [...$subview]); + } + + /** + * @dataProvider dataProviderForRead + */ + public function testReadByIndex(array $source, array $mask, array $expected) + { + $view = ArrayView::toView($source); + $subArray = $view[new IndexListSelector($mask)]; + + $this->assertSame($expected, $subArray); + $this->assertSame(\count($expected), \count($subArray)); + + for ($i = 0; $i < \count($subArray); ++$i) { + $this->assertSame($expected[$i], $subArray[$i]); + } + + for ($i = 0; $i < \count($view); ++$i) { + $this->assertSame($source[$i], $view[$i]); + } + + $this->assertSame($source, $view->toArray()); + $this->assertSame($source, [...$view]); + $this->assertSame($expected, $subArray); + } + + public function dataProviderForRead(): array + { + return [ + [[], [], []], + [[1], [], []], + [[1, 2, 3], [], []], + [[1], [0], [1]], + [[1], [0, 0], [1, 1]], + [[1], [0, 0, 0], [1, 1, 1]], + [[1, 2], [0], [1]], + [[1, 2], [1], [2]], + [[1, 2], [0, 1], [1, 2]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 5, 7], [2, 4, 6, 8]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [7, 5, 3, 1], [8, 6, 4, 2]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 3, 7], [2, 6, 4, 8]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 7, 8], [1, 2, 8, 9]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 5, 5, 3], [2, 2, 6, 6, 4]], + ]; + } +} diff --git a/tests/unit/ArrayIndexListView/WriteTest.php b/tests/unit/ArrayIndexListView/WriteTest.php new file mode 100644 index 0000000..2d47a84 --- /dev/null +++ b/tests/unit/ArrayIndexListView/WriteTest.php @@ -0,0 +1,126 @@ +assertSame($expected, [...$view]); + $this->assertSame($expected, $source); + } + + /** + * @dataProvider dataProviderForMaskSubviewWrite + */ + public function testWriteBySubview(array $source, $config, array $toWrite, array $expected) + { + $view = ArrayView::toView($source); + + $view->subview(new IndexListSelector($config))[':'] = $toWrite; + + $this->assertSame($expected, [...$view]); + $this->assertSame($expected, $source); + } + + public function dataProviderForMaskSubviewWrite(): array + { + return [ + [ + [], + [], + [], + [], + ], + [ + [1], + [], + [], + [1], + ], + [ + [1, 2, 3], + [], + [], + [1, 2, 3], + ], + [ + [1], + [0], + [2], + [2], + ], + [ + [1], + [0, 0], + [3, 3], + [3], + ], + [ + [1], + [0, 0, 0], + [4, 4, 4], + [4], + ], + [ + [1, 2], + [0], + [2], + [2, 2], + ], + [ + [1, 2], + [1], + [3], + [1, 3], + ], + [ + [1, 2], + [0, 1], + [2, 3], + [2, 3], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 3, 5, 7], + [3, 5, 7, 9], + [1, 3, 3, 5, 5, 7, 7, 9, 9], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [7, 5, 3, 1], + [9, 7, 5, 3], + [1, 3, 3, 5, 5, 7, 7, 9, 9], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 5, 3, 7], + [3, 7, 5, 9], + [1, 3, 3, 5, 5, 7, 7, 9, 9], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [0, 1, 7, 8], + [2, 3, 9, 10], + [2, 3, 3, 4, 5, 6, 7, 9, 10], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 1, 5, 5, 3], + [4, 4, 8, 8, 5], + [1, 4, 3, 5, 5, 8, 7, 8, 9], + ], + ]; + } +} From eed4412783b02e842ba477a2e6591526b963121e Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 13 Mar 2024 00:36:42 +0300 Subject: [PATCH 3/5] Minor changes. --- tests/unit/ArrayIndexListView/WriteTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/ArrayIndexListView/WriteTest.php b/tests/unit/ArrayIndexListView/WriteTest.php index 2d47a84..11c3034 100644 --- a/tests/unit/ArrayIndexListView/WriteTest.php +++ b/tests/unit/ArrayIndexListView/WriteTest.php @@ -3,7 +3,6 @@ namespace Smoren\ArrayView\Tests\Unit\ArrayIndexListView; use Smoren\ArrayView\Selectors\IndexListSelector; -use Smoren\ArrayView\Selectors\MaskSelector; use Smoren\ArrayView\Views\ArrayView; class WriteTest extends \Codeception\Test\Unit From b8d88a08e86de5fd4f37400d7ed5b79c26393c2f Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 13 Mar 2024 00:51:40 +0300 Subject: [PATCH 4/5] ArrayIndexListView: isset test added. --- tests/unit/ArrayIndexListView/IssetTest.php | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/unit/ArrayIndexListView/IssetTest.php diff --git a/tests/unit/ArrayIndexListView/IssetTest.php b/tests/unit/ArrayIndexListView/IssetTest.php new file mode 100644 index 0000000..f6bf645 --- /dev/null +++ b/tests/unit/ArrayIndexListView/IssetTest.php @@ -0,0 +1,79 @@ +subview(new IndexListSelector($indexes)); + + $existIndexes = [ + ...range(0, \count($indexes) - 1), + ...range(-1, -\count($indexes)), + ]; + + foreach ($existIndexes as $index) { + $this->assertTrue(isset($subview[$index]), $index); + } + } + + /** + * @dataProvider dataProviderForIssetFalse + */ + public function testIssetFalse(array $source, array $indexes, array $expected) + { + $view = ArrayView::toView($source); + $subview = $view->subview(new IndexListSelector($indexes)); + + foreach ($expected as $index) { + $this->assertFalse(isset($subview[$index]), $index); + } + } + + public function dataProviderForIssetTrue(): array + { + return [ + [[1], [0]], + [[1], [0, 0]], + [[1], [0, 0, 0]], + [[1, 2], [0]], + [[1, 2], [1]], + [[1, 2], [0, 1]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 5, 7]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [7, 5, 3, 1]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 3, 7]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 7, 8]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 5, 5, 3]], + ]; + } + + public static function dataProviderForIssetFalse(): array + { + return [ + [[], [], [-2, -1, 0, 1, 2]], + [[1], [], [-2, -1, 0, 1, 2]], + [[1, 2, 3], [], [-2, -1, 0, 1, 2]], + [[1], [0], [-3, -2, 1, 2]], + [[1], [0, 0], [-5, -4, -3, 2, 3, 4]], + [[1], [0, 0, 0], [-6, -5, -4, 3, 4, 5]], + [[1, 2], [0], [-3, -2, 1, 2]], + [[1, 2], [1], [-3, -2, 1, 2]], + [[1, 2], [0, 1], [-5, -4, -3, 2, 3, 4]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 5, 7], [-7, -6, -5, 4, 5, 6]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [7, 5, 3, 1], [-7, -6, -5, 4, 5, 6]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 3, 7], [-7, -6, -5, 4, 5, 6]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 7, 8], [-7, -6, -5, 4, 5, 6]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 5, 5, 3], [-8, -7, -6, 5, 6, 7]], + ]; + } +} From 03b80d06a0c98992ca1a9081203b214c8e2692cf Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 13 Mar 2024 01:25:39 +0300 Subject: [PATCH 5/5] Selectors: compatibleWith() method added. --- src/Interfaces/ArraySelectorInterface.php | 11 +++ src/Selectors/IndexListSelector.php | 16 ++++ src/Selectors/MaskSelector.php | 16 ++++ src/Selectors/SliceSelector.php | 16 ++++ src/Traits/ArrayViewAccessTrait.php | 2 +- tests/unit/ArrayIndexListView/IssetTest.php | 86 +++++++++++++++++++-- 6 files changed, 138 insertions(+), 9 deletions(-) diff --git a/src/Interfaces/ArraySelectorInterface.php b/src/Interfaces/ArraySelectorInterface.php index 8b00f6b..787ada9 100644 --- a/src/Interfaces/ArraySelectorInterface.php +++ b/src/Interfaces/ArraySelectorInterface.php @@ -21,6 +21,17 @@ interface ArraySelectorInterface */ public function select(ArrayViewInterface $source, ?bool $readonly = null): ArrayViewInterface; + /** + * Checks if the selector is compatible with the given view. + * + * @template T View elements type. + * + * @param ArrayViewInterface $view the view to check compatibility with. + * + * @return bool true if the element is compatible, false otherwise + */ + public function compatibleWith(ArrayViewInterface $view): bool; + /** * Return value of the selector. * diff --git a/src/Selectors/IndexListSelector.php b/src/Selectors/IndexListSelector.php index 1867ca3..360ad14 100644 --- a/src/Selectors/IndexListSelector.php +++ b/src/Selectors/IndexListSelector.php @@ -45,6 +45,22 @@ public function select(ArrayViewInterface $source, ?bool $readonly = null): Arra return new ArrayIndexListView($source, $this->value, $readonly ?? $source->isReadonly()); } + /** + * Checks if the selector is compatible with the given view. + * + * @template T View elements type. + * + * @param ArrayViewInterface $view the view to check compatibility with. + * + * @return bool true if the element is compatible, false otherwise + * + * {@inheritDoc} + */ + public function compatibleWith(ArrayViewInterface $view): bool + { + return \count($this->value) === 0 || \max($this->value) < \count($view) && \min($this->value) >= -\count($view); + } + /** * {@inheritDoc} */ diff --git a/src/Selectors/MaskSelector.php b/src/Selectors/MaskSelector.php index 9bd2e3b..f861589 100644 --- a/src/Selectors/MaskSelector.php +++ b/src/Selectors/MaskSelector.php @@ -45,6 +45,22 @@ public function select(ArrayViewInterface $source, ?bool $readonly = null): Arra return new ArrayMaskView($source, $this->value, $readonly ?? $source->isReadonly()); } + /** + * Checks if the selector is compatible with the given view. + * + * @template T View elements type. + * + * @param ArrayViewInterface $view the view to check compatibility with. + * + * @return bool true if the element is compatible, false otherwise + * + * {@inheritDoc} + */ + public function compatibleWith(ArrayViewInterface $view): bool + { + return \count($this->value) === \count($view); + } + /** * {@inheritDoc} */ diff --git a/src/Selectors/SliceSelector.php b/src/Selectors/SliceSelector.php index 5591b8a..1625121 100644 --- a/src/Selectors/SliceSelector.php +++ b/src/Selectors/SliceSelector.php @@ -42,6 +42,22 @@ public function select(ArrayViewInterface $source, ?bool $readonly = null): Arra return new ArraySliceView($source, $this, $readonly ?? $source->isReadonly()); } + /** + * Checks if the selector is compatible with the given view. + * + * @template T View elements type. + * + * @param ArrayViewInterface $view the view to check compatibility with. + * + * @return bool true if the element is compatible, false otherwise + * + * {@inheritDoc} + */ + public function compatibleWith(ArrayViewInterface $view): bool + { + return true; + } + /** * {@inheritDoc} */ diff --git a/src/Traits/ArrayViewAccessTrait.php b/src/Traits/ArrayViewAccessTrait.php index fd15e97..9ff93c3 100644 --- a/src/Traits/ArrayViewAccessTrait.php +++ b/src/Traits/ArrayViewAccessTrait.php @@ -42,7 +42,7 @@ public function offsetExists($offset): bool } if ($offset instanceof ArraySelectorInterface) { - return true; + return $offset->compatibleWith($this); } return false; diff --git a/tests/unit/ArrayIndexListView/IssetTest.php b/tests/unit/ArrayIndexListView/IssetTest.php index f6bf645..430204e 100644 --- a/tests/unit/ArrayIndexListView/IssetTest.php +++ b/tests/unit/ArrayIndexListView/IssetTest.php @@ -2,17 +2,16 @@ namespace Smoren\ArrayView\Tests\Unit\ArrayIndexListView; +use Smoren\ArrayView\Exceptions\IndexError; use Smoren\ArrayView\Selectors\IndexListSelector; -use Smoren\ArrayView\Selectors\MaskSelector; -use Smoren\ArrayView\Views\ArrayIndexListView; use Smoren\ArrayView\Views\ArrayView; class IssetTest extends \Codeception\Test\Unit { /** - * @dataProvider dataProviderForIssetTrue + * @dataProvider dataProviderForIssetSingleTrue */ - public function testIssetTrue(array $source, array $indexes) + public function testIssetSingleTrue(array $source, array $indexes) { $view = ArrayView::toView($source); $subview = $view->subview(new IndexListSelector($indexes)); @@ -28,9 +27,9 @@ public function testIssetTrue(array $source, array $indexes) } /** - * @dataProvider dataProviderForIssetFalse + * @dataProvider dataProviderForIssetSingleFalse */ - public function testIssetFalse(array $source, array $indexes, array $expected) + public function testIssetSingleFalse(array $source, array $indexes, array $expected) { $view = ArrayView::toView($source); $subview = $view->subview(new IndexListSelector($indexes)); @@ -40,7 +39,36 @@ public function testIssetFalse(array $source, array $indexes, array $expected) } } - public function dataProviderForIssetTrue(): array + /** + * @dataProvider dataProviderForIssetSelectorTrue + */ + public function testIssetSelectorTrue(array $source, array $indexes) + { + $view = ArrayView::toView($source); + + $this->assertTrue(isset($view[new IndexListSelector($indexes)])); + + $subview = $view->subview(new IndexListSelector($indexes)); + $this->assertSame(\count($indexes), \count($subview)); + + $subview = $view[new IndexListSelector($indexes)]; + $this->assertSame(\count($indexes), \count($subview)); + } + + /** + * @dataProvider dataProviderForIssetSelectorFalse + */ + public function testIssetSelectorFalse(array $source, array $indexes) + { + $view = ArrayView::toView($source); + + $this->assertFalse(isset($view[new IndexListSelector($indexes)])); + + $this->expectException(IndexError::class); + $_ = $view[new IndexListSelector($indexes)]; + } + + public function dataProviderForIssetSingleTrue(): array { return [ [[1], [0]], @@ -57,7 +85,7 @@ public function dataProviderForIssetTrue(): array ]; } - public static function dataProviderForIssetFalse(): array + public function dataProviderForIssetSingleFalse(): array { return [ [[], [], [-2, -1, 0, 1, 2]], @@ -76,4 +104,46 @@ public static function dataProviderForIssetFalse(): array [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 5, 5, 3], [-8, -7, -6, 5, 6, 7]], ]; } + + public function dataProviderForIssetSelectorTrue(): array + { + return [ + [[1], []], + [[1], [0]], + [[1], [-1]], + [[1], [0, 0]], + [[1], [0, 0, 0]], + [[1, 2], []], + [[1, 2], [0]], + [[1, 2], [-1, -2]], + [[1, 2], [1]], + [[1, 2], [0, 1]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], []], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 5, 7]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [7, 5, 3, 1]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 3, 7]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 7, 8]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], []], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 5, 5, 3]], + ]; + } + + public function dataProviderForIssetSelectorFalse(): array + { + return [ + [[1], [0, 1]], + [[1], [1, -1, -2]], + [[1], [0, 1, 0, -1, -2]], + [[1], [1, -1]], + [[1], [0, 0, -2]], + [[1, 2], [2]], + [[1, 2], [1, 2]], + [[1, 2], [0, 1, 2]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 5, -10]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 5, 3, 1]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 10, 9, 7]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [-10, 1, 7, 10]], + [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 1, 50, 5, 3]], + ]; + } }