From 3610636cd72b7ca53cbf949c9e2583b500058b3c Mon Sep 17 00:00:00 2001 From: roquie Date: Tue, 11 Jan 2022 12:47:54 +0300 Subject: [PATCH] PHP 8.1 support (for static analyses), improve code quality with `infection` tool. --- composer.json | 11 +++++--- infection.json | 13 +++++++++ src/Dot.php | 40 +++++++++++++++++++--------- tests/DotTest.php | 68 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 96 insertions(+), 36 deletions(-) create mode 100644 infection.json diff --git a/composer.json b/composer.json index a875f3b..efa7e3f 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "php": ">=7.4" }, "require-dev": { - "phpstan/phpstan": "^0.12.5", + "infection/infection": "^0.26.0", + "phpstan/phpstan": "^1.3.3", "phpunit/phpunit": "^9", "symfony/var-dumper": "^5.0" }, @@ -28,7 +29,10 @@ } }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "infection/extension-installer": true + } }, "archive": { "exclude": ["obelix.jpg"] @@ -36,7 +40,8 @@ "scripts": { "check": [ "phpunit --stop-on-fail --coverage-text", - "phpstan analyse src --level 8" + "phpstan analyse src --level 8", + "infection --threads=4 -s" ] } } diff --git a/infection.json b/infection.json new file mode 100644 index 0000000..3de20a3 --- /dev/null +++ b/infection.json @@ -0,0 +1,13 @@ +{ + "$schema": "vendor/infection/infection/resources/schema.json", + "source": { + "directories": [ + "src" + ] + }, + "mutators": { + "@default": true + }, + "minMsi": 100, + "minCoveredMsi": 100 +} diff --git a/src/Dot.php b/src/Dot.php index c6198c9..74e2b0d 100644 --- a/src/Dot.php +++ b/src/Dot.php @@ -4,6 +4,7 @@ namespace Spacetab\Obelix; +use InvalidArgumentException; use RecursiveArrayIterator; use RecursiveIteratorIterator; @@ -12,48 +13,58 @@ final class Dot private const DELIMITER = '.'; private const WILDCARD = '*'; - /** - * @var array - */ + /** @var array */ private array $items; - /** - * @var array - */ + /** @var array */ private static array $cache = []; + /** @var non-empty-string */ private string $delimiter = self::DELIMITER; + + /** @var non-empty-string */ private string $wildcard = self::WILDCARD; /** * Dot constructor. * - * @param array|\Spacetab\Obelix\Dot $items + * @param array|Dot $items */ public function __construct($items = []) { - if ($items instanceof self) { + if (is_array($items)) { + $this->items = $items; + } elseif (/** @infection-ignore-all */ $items instanceof self) { $this->items = $items->toArray(); self::$cache = $items->getCache(); } else { - $this->items = (array) $items; + throw new InvalidArgumentException('The items argument must be an array or Dot instance.'); } } public function setDelimiter(string $delimiter): void { + if ($delimiter === '') { + throw new InvalidArgumentException('The delimiter must not be an empty string.'); + } + $this->delimiter = $delimiter; } public function setWildcard(string $wildcard): void { + if ($wildcard === '') { + throw new InvalidArgumentException('The wildcard must not be an empty string.'); + } + $this->wildcard = $wildcard; } /** * @param string $path * @param mixed|null $default - * @return \Spacetab\Obelix\ResultSet + * + * @return ResultSet */ public function get(string $path, $default = null): ResultSet { @@ -72,8 +83,8 @@ public function get(string $path, $default = null): ResultSet $pathway = []; $flatArray = null; - $segments = (array) explode($this->delimiter, $path); - $countSegments = count($segments); + $segments = explode($this->delimiter, $path); + $countSegments = count($segments); $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->items), RecursiveIteratorIterator::SELF_FIRST); @@ -92,6 +103,7 @@ public function get(string $path, $default = null): ResultSet } $value = $flatArray === null ? $default : array_values($flatArray); + $flatArray = $flatArray ?? [$path => $default]; if (is_countable($value) && count($value) === 1) { // @phpstan-ignore-next-line @@ -100,7 +112,7 @@ public function get(string $path, $default = null): ResultSet self::$cache[$path] = [$value, $flatArray]; - return new ResultSet($value, $flatArray ?? []); + return new ResultSet($value, $flatArray); } /** @@ -115,9 +127,11 @@ private function isUserPathEqualsRealPath(array $user, array $real): bool } $i = 0; + // @infection-ignore-all $equals = false; foreach ($user as $item) { + // @infection-ignore-all $val = $real[$i] ?? false; // to work with integer indexes in string path (for cases like "foo.0") diff --git a/tests/DotTest.php b/tests/DotTest.php index 1879d3b..a936bf9 100644 --- a/tests/DotTest.php +++ b/tests/DotTest.php @@ -4,12 +4,40 @@ namespace Spacetab\Tests\Obelix; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Spacetab\Obelix; +use stdClass; class DotTest extends TestCase { - public function testGetItemsFromSimpleArrayAndSingleValue() + public function testWhenDeveloperPassInvalidValueToConstructor(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The items argument must be an array or Dot instance.'); + + new Obelix\Dot(new stdClass()); + } + + public function testWhenDeveloperPassInvalidValueToDelimiterSetter(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The delimiter must not be an empty string.'); + + $dot = new Obelix\Dot([]); + $dot->setDelimiter(''); + } + + public function testWhenDeveloperPassInvalidValueToWildcardSetter(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The wildcard must not be an empty string.'); + + $dot = new Obelix\Dot([]); + $dot->setWildcard(''); + } + + public function testGetItemsFromSimpleArrayAndSingleValue(): void { $array = [ 'foo' => [ @@ -28,7 +56,7 @@ public function testGetItemsFromSimpleArrayAndSingleValue() ], $result->getMap()); } - public function testGetItemsFromSimpleArrayAndItReturnsCorrectAssociativeArray() + public function testGetItemsFromSimpleArrayAndItReturnsCorrectAssociativeArray(): void { $array = [ 'foo' => [ @@ -58,7 +86,7 @@ public function testGetItemsFromSimpleArrayAndItReturnsCorrectAssociativeArray() ], $result->getMap()); } - public function testGetItemsFromSimpleArrayAndItReturnsCorrectIndexedArray() + public function testGetItemsFromSimpleArrayAndItReturnsCorrectIndexedArray(): void { $array = [ 'foo' => [ @@ -88,7 +116,7 @@ public function testGetItemsFromSimpleArrayAndItReturnsCorrectIndexedArray() ], $result->getMap()); } - public function testGetNotExistingItemsFromArray() + public function testGetNotExistingItemsFromArray(): void { $array = [ 'foo' => [ @@ -104,10 +132,10 @@ public function testGetNotExistingItemsFromArray() $result = $dot->get('foo.bar.40', 'default'); $this->assertSame('default', $result->getValue()); - $this->assertSame([], $result->getMap()); + $this->assertSame(['foo.bar.40' => 'default'], $result->getMap()); } - public function testGetItemByIndexFromArray() + public function testGetItemByIndexFromArray(): void { $array = [ 'foo' => [ @@ -124,7 +152,7 @@ public function testGetItemByIndexFromArray() ], $result->getMap()); } - public function testGetItemsSelectedByWildcardSimpleCase() + public function testGetItemsSelectedByWildcardSimpleCase(): void { $array = [ 'foo' => [ @@ -152,7 +180,7 @@ public function testGetItemsSelectedByWildcardSimpleCase() ], $result->getMap()); } - public function testGetItemsSelectedByWildcardAtEndPathString() + public function testGetItemsSelectedByWildcardAtEndPathString(): void { $k = [ ['key' => 1], @@ -180,7 +208,7 @@ public function testGetItemsSelectedByWildcardAtEndPathString() ], $result->getMap()); } - public function testGetItemsSelectedByWildcardHardCase() + public function testGetItemsSelectedByWildcardHardCase(): void { $array = [ 'test' => [ @@ -246,7 +274,7 @@ public function testGetItemsSelectedByWildcardHardCase() ], $result->getMap()); } - public function testDotReturnsCorrectCacheKeyValues() + public function testDotReturnsCorrectCacheKeyValues(): void { $array = [ 'foo' => [ @@ -264,7 +292,7 @@ public function testDotReturnsCorrectCacheKeyValues() ], $dot->getCache()); } - public function testDotCacheHit() + public function testDotCacheHit(): void { $array = [ 'foo' => [ @@ -295,7 +323,7 @@ public function testDotCacheHit() ], $keyHit->getMap()); } - public function testCacheClearedOnDestructorCall() + public function testCacheClearedOnDestructorCall(): void { $array = [ 'foo' => [ @@ -318,7 +346,7 @@ public function testCacheClearedOnDestructorCall() $this->assertSame([], $dot->toArray()); } - public function testHowToDotObjectAcceptsDotObject() + public function testHowToDotObjectAcceptsDotObject(): void { $array = [ 'foo' => [ @@ -340,7 +368,7 @@ public function testHowToDotObjectAcceptsDotObject() $this->assertSame($array, $dot2->toArray()); } - public function testHowToDotObjectWorksWithOtherDelimiterAndWildcard() + public function testHowToDotObjectWorksWithOtherDelimiterAndWildcard(): void { $array = [ 'foo' => [ @@ -359,7 +387,7 @@ public function testHowToDotObjectWorksWithOtherDelimiterAndWildcard() $this->assertSame([1, 2], $dot->get('foo:bar:@:key')->getValue()); } - public function testGetItemWithWildcardAndAssociativeArray() + public function testGetItemWithWildcardAndAssociativeArray(): void { $array = [ 'foo' => [ @@ -385,7 +413,7 @@ public function testGetItemWithWildcardAndAssociativeArray() ], $dot->get('foo.*.*')->getMap()); } - public function testGetItemWhereWildcardPassedAsSingleSymbol() + public function testGetItemWhereWildcardPassedAsSingleSymbol(): void { $array = [ [1, 3, 4] @@ -400,7 +428,7 @@ public function testGetItemWhereWildcardPassedAsSingleSymbol() ], $result->getMap()); } - public function testGetItemWhenSecondKeyIsNotUniqueInSubArrays() + public function testGetItemWhenSecondKeyIsNotUniqueInSubArrays(): void { $array = [ 'server' => [ @@ -435,7 +463,7 @@ public function testGetItemWhenSecondKeyIsNotUniqueInSubArrays() ], $dot->get('server.headers')->getMap()); } - public function testWhenALotOfManyKeysAndValuesAreSameAkaHardestTest() + public function testWhenALotOfManyKeysAndValuesAreSameAkaHardestTest(): void { $array = [ 'foo' => [ @@ -482,7 +510,7 @@ public function testWhenALotOfManyKeysAndValuesAreSameAkaHardestTest() ], true, [], - new \stdClass() + new stdClass() ] ], 'bar' => 1, @@ -519,7 +547,7 @@ public function testWhenALotOfManyKeysAndValuesAreSameAkaHardestTest() $this->assertSame(['foo.baz.acme' => $expected], $result->getMap()); $result = $dot->get('foo.faa.2'); - $this->assertInstanceOf(\stdClass::class, $result->getValue()); + $this->assertInstanceOf(stdClass::class, $result->getValue()); $this->assertSame($array['foo']['faa'][2], $result->getValue()); $this->assertSame(['foo.faa.2' => $array['foo']['faa'][2]], $result->getMap());