From 22ce9e77048fbedb5c153a120f8aeab0658eae9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 18:42:16 +0000 Subject: [PATCH 1/2] :arrow_up: Bump phpstan/phpstan from 1.12.7 to 2.0.3 Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.12.7 to 2.0.3. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/2.0.x/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/1.12.7...2.0.3) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 5bc4758..a66505a 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ }, "require-dev": { "doctrine/coding-standard": "^12.0", - "phpstan/phpstan": "^1.9", + "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^11.1", "squizlabs/php_codesniffer": "^3.7" }, diff --git a/composer.lock b/composer.lock index 45f518c..d424f00 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "49459fbb6a0d2f8c47c68ebfba191466", + "content-hash": "438d28597d4a70e28bfffba471eb39fc", "packages": [ { "name": "league/flysystem", @@ -1412,20 +1412,20 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.7", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0" + "reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc2b9976bd8b0f84ec9b0e50cc35378551de7af0", - "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46b4d3529b12178112d9008337beda0cc2a1a6b4", + "reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -1466,7 +1466,7 @@ "type": "github" } ], - "time": "2024-10-18T11:12:07+00:00" + "time": "2024-11-28T22:19:37+00:00" }, { "name": "phpunit/php-code-coverage", From c1c084aad73db14d3442420b7fd190c195586078 Mon Sep 17 00:00:00 2001 From: homersimpsons Date: Sun, 1 Dec 2024 19:58:15 +0100 Subject: [PATCH 2/2] :rotating_light: Fix PHPStan's issues --- phpstan.neon | 3 ++ phpunit-tests/ApplicationTest.php | 41 ++++++++++++++++++++++++- src/DirectoryRepresenter.php | 50 ++++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index e45aeff..9f6b4bb 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,6 @@ +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon + parameters: level: max excludePaths: diff --git a/phpunit-tests/ApplicationTest.php b/phpunit-tests/ApplicationTest.php index 60b1479..38ae9d9 100644 --- a/phpunit-tests/ApplicationTest.php +++ b/phpunit-tests/ApplicationTest.php @@ -81,7 +81,33 @@ public function testConfigEmptyFilesSolution(): void $this->assertStringContainsString('.meta/config.json: `files.solution` key is empty', $display); } - public function testConfigInvalidFilesSolutionValue(): void + public function testConfigInvalidFilesValueNotArray(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('#^\.meta/config\.json: missing or invalid `files\.solution` key$#'); + $input = new InMemoryFilesystemAdapter(); + $inputFs = new Filesystem($input); + $inputFs->write('.meta/config.json', '{"files":true}'); + $output = new InMemoryFilesystemAdapter(); + + $application = new Application(); + $application->represent($inputFs, new Filesystem($output), new NullLogger()); + } + + public function testConfigInvalidFilesMissingSolution(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('#^\.meta/config\.json: missing or invalid `files\.solution` key$#'); + $input = new InMemoryFilesystemAdapter(); + $inputFs = new Filesystem($input); + $inputFs->write('.meta/config.json', '{"files":{}}'); + $output = new InMemoryFilesystemAdapter(); + + $application = new Application(); + $application->represent($inputFs, new Filesystem($output), new NullLogger()); + } + + public function testConfigInvalidFilesSolutionValueNotArray(): void { $this->expectException(RuntimeException::class); $this->expectExceptionMessageMatches('#^\.meta/config\.json: missing or invalid `files\.solution` key$#'); @@ -94,6 +120,19 @@ public function testConfigInvalidFilesSolutionValue(): void $application->represent($inputFs, new Filesystem($output), new NullLogger()); } + public function testConfigInvalidFilesSolutionValueNotArrayOfString(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('#^\.meta/config\.json: missing or invalid `files\.solution` key$#'); + $input = new InMemoryFilesystemAdapter(); + $inputFs = new Filesystem($input); + $inputFs->write('.meta/config.json', '{"files":{"solution":[true]}}'); + $output = new InMemoryFilesystemAdapter(); + + $application = new Application(); + $application->represent($inputFs, new Filesystem($output), new NullLogger()); + } + public function testConfigMissingFilesSolution(): void { $this->expectException(RuntimeException::class); diff --git a/src/DirectoryRepresenter.php b/src/DirectoryRepresenter.php index 628a7c3..aca6ca2 100644 --- a/src/DirectoryRepresenter.php +++ b/src/DirectoryRepresenter.php @@ -11,6 +11,7 @@ use function assert; use function implode; use function is_array; +use function is_string; use function json_decode; use const JSON_THROW_ON_ERROR; @@ -32,16 +33,7 @@ public function __construct( public function represent(): Result { $configJson = $this->solutionDir->read('/.meta/config.json'); - - $config = json_decode($configJson, true, flags: JSON_THROW_ON_ERROR); - assert(is_array($config), 'json_decode(..., true) should return an array'); - - if (! isset($config['files']['solution']) || ! is_array($config['files']['solution'])) { - throw new RuntimeException('.meta/config.json: missing or invalid `files.solution` key'); - } - - $solutions = $config['files']['solution']; - $this->logger->info('.meta/config.json: Solutions files: ' . implode(', ', $solutions)); + $solutions = $this->parseSolutions($configJson); $mapping = new Mapping(); $representer = new FilesRepresenter($mapping, $this->logger); @@ -66,4 +58,42 @@ public function represent(): Result $mapping->toJson(), ); } + + /** @return string[] */ + private function parseSolutions(string $configJson): array + { + $config = json_decode($configJson, true, flags: JSON_THROW_ON_ERROR); + assert(is_array($config), 'json_decode(..., true) should return an array'); + if ( + ! isset($config['files']) + || ! is_array($config['files']) + || ! isset($config['files']['solution']) + || ! is_array($config['files']['solution']) + || ! $this->isArrayOfString($config['files']['solution']) + ) { + throw new RuntimeException('.meta/config.json: missing or invalid `files.solution` key'); + } + + $solutions = $config['files']['solution']; + + $this->logger->info('.meta/config.json: Solutions files: ' . implode(', ', $solutions)); + + return $solutions; + } + + /** + * @param mixed[] $array + * + * @phpstan-assert-if-true string[] $array + */ + private function isArrayOfString(array $array): bool + { + foreach ($array as $element) { + if (! is_string($element)) { + return false; + } + } + + return true; + } }