diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7b23fd6..a57628f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -15,54 +15,79 @@ jobs: include: - php: '7.2' symfony: '2.8.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '3.0.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '3.1.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '3.2.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '3.3.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '3.4.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '4.0.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '4.1.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_4.neon - php: '7.2' symfony: '4.2.*' + geoip2: '~2.0' phpstan: .phpstan/default.neon - php: '7.2' symfony: '4.3.*' + geoip2: '~2.0' phpstan: .phpstan/default.neon - php: '7.2' symfony: '4.4.*' + geoip2: '~2.0' phpstan: .phpstan/default.neon - php: '7.2' symfony: '5.0.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_5.neon - php: '7.2' symfony: '5.1.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_5.neon - php: '7.2' symfony: '5.2.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_5.neon - php: '8.0' symfony: '5.2.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_5.neon - php: '8.1' symfony: '6.4.*' + geoip2: '~2.0' phpstan: .phpstan/symfony_6.neon - php: '8.2' symfony: '7.0.*' + geoip2: '~2.0' + phpstan: .phpstan/symfony_6.neon + - php: '8.3' + symfony: '7.0.*' + geoip2: '~2.0' + phpstan: .phpstan/symfony_6.neon + - php: '8.3' + symfony: '7.0.*' + geoip2: '~3.0' phpstan: .phpstan/symfony_6.neon steps: - name: Checkout @@ -82,6 +107,9 @@ jobs: - name: Install Symfony run: composer require symfony/symfony:"${{ matrix.symfony }}" --no-update + - name: Install GeoIP2-php + run: composer require geoip2/geoip2:"${{ matrix.geoip2 }}" --no-update + - name: 'Install Composer dependencies (highest)' uses: 'ramsey/composer-install@v1' with: @@ -91,7 +119,7 @@ jobs: run: vendor/bin/phpunit --coverage-clover build/coverage-clover.xml - name: Send coverage results to Scrutinizer CI - if: matrix.php != '8.0' && matrix.php != '8.1' && matrix.php != '8.2' + if: matrix.php != '8.0' && matrix.php != '8.1' && matrix.php != '8.2' && matrix.php != '8.3' run: | wget https://scrutinizer-ci.com/ocular.phar php ocular.phar code-coverage:upload --format=php-clover build/coverage-clover.xml @@ -101,7 +129,7 @@ jobs: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_PARALLEL: true COVERALLS_FLAG_NAME: 'PHP ${{ matrix.php }} + ${{ matrix.symfony }}' - if: matrix.php != '8.0' && matrix.php != '8.1' && matrix.php != '8.2' + if: matrix.php != '8.0' && matrix.php != '8.1' && matrix.php != '8.2' && matrix.php != '8.3' run: | composer global require php-coveralls/php-coveralls php-coveralls -x build/coverage-clover.xml -o build/coveralls-upload.json -v diff --git a/composer.json b/composer.json index 26875ad..1c50703 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "ext-phar": "*", "ext-zlib": "*", "php": ">=7.2.0", - "geoip2/geoip2": "~2.0", + "geoip2/geoip2": "~2.0|~3.0", "symfony/http-kernel": "~2.8|~3.0|~4.0|~5.0|~6.0|~7.0", "symfony/dependency-injection": "~2.8|~3.0|~4.0|~5.0|~6.0|~7.0", "symfony/expression-language": "~2.8|~3.0|~4.0|~5.0|~6.0|~7.0", diff --git a/src/Reader/ReaderFactory.php b/src/Reader/ReaderFactory.php index a8847d6..8be1daf 100644 --- a/src/Reader/ReaderFactory.php +++ b/src/Reader/ReaderFactory.php @@ -41,7 +41,7 @@ public function __construct(array $databases, string $reader_class = Reader::cla * * @return Reader */ - public function create(string $database, array $locales = null): Reader + public function create(string $database, ?array $locales = null): Reader { if (!array_key_exists($database, $this->databases)) { $databases = implode('", "', array_keys($this->databases)); diff --git a/tests/Command/DownloadDatabaseCommandTest.php b/tests/Command/DownloadDatabaseCommandTest.php index 299a09b..75c1c14 100644 --- a/tests/Command/DownloadDatabaseCommandTest.php +++ b/tests/Command/DownloadDatabaseCommandTest.php @@ -78,11 +78,14 @@ public function testInvalidURLArgument(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('URL of downloaded GeoIP2 database should be a string, got ["https:\/\/example.com\/GeoIP2.tar.gz"] instead.'); + $url = ['https://example.com/GeoIP2.tar.gz']; + $target = '/tmp/GeoIP2.mmdb'; + $this->input - ->expects($this->at(4)) + ->expects($this->exactly(2)) ->method('getArgument') - ->with('url') - ->willReturn(['https://example.com/GeoIP2.tar.gz']); + ->withConsecutive(['url'], ['target']) + ->willReturnOnConsecutiveCalls($url, $target); $this->command->run($this->input, $this->output); } @@ -92,11 +95,14 @@ public function testNoTargetArgument(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Target download path should be a string, got null instead.'); + $url = 'https://example.com/GeoIP2.tar.gz'; + $target = null; + $this->input - ->expects($this->at(4)) + ->expects($this->exactly(2)) ->method('getArgument') - ->with('url') - ->willReturn('https://example.com/GeoIP2.tar.gz'); + ->withConsecutive(['url'], ['target']) + ->willReturnOnConsecutiveCalls($url, $target); $this->command->run($this->input, $this->output); } @@ -106,16 +112,14 @@ public function testInvalidTargetArgument(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Target download path should be a string, got ["\/tmp\/GeoIP2.mmdb"] instead.'); + $url = 'https://example.com/GeoIP2.tar.gz'; + $target = ['/tmp/GeoIP2.mmdb']; + $this->input - ->expects($this->at(4)) - ->method('getArgument') - ->with('url') - ->willReturn('https://example.com/GeoIP2.tar.gz'); - $this->input - ->expects($this->at(5)) + ->expects($this->exactly(2)) ->method('getArgument') - ->with('target') - ->willReturn(['/tmp/GeoIP2.mmdb']); + ->withConsecutive(['url'], ['target']) + ->willReturnOnConsecutiveCalls($url, $target); $this->command->run($this->input, $this->output); } @@ -126,15 +130,10 @@ public function testDownload(): void $target = '/tmp/GeoIP2.mmdb'; $this->input - ->expects($this->at(4)) - ->method('getArgument') - ->with('url') - ->willReturn($url); - $this->input - ->expects($this->at(5)) + ->expects($this->exactly(2)) ->method('getArgument') - ->with('target') - ->willReturn($target); + ->withConsecutive(['url'], ['target']) + ->willReturnOnConsecutiveCalls($url, $target); $this->downloader ->expects($this->once()) diff --git a/tests/Command/UpdateDatabaseCommandTest.php b/tests/Command/UpdateDatabaseCommandTest.php index 2c84694..78a689a 100644 --- a/tests/Command/UpdateDatabaseCommandTest.php +++ b/tests/Command/UpdateDatabaseCommandTest.php @@ -74,7 +74,7 @@ public function testInvalidDatabasesArgument(): void $this->expectExceptionMessage('Updated databases should be a array, got "" instead.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(''); @@ -89,7 +89,7 @@ public function testUndefinedDatabase(): void $this->expectExceptionMessage('Undefined "default" database.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -104,7 +104,7 @@ public function testUndefinedDatabase2(): void $this->expectExceptionMessage('Undefined "foo" database.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['foo']); @@ -121,7 +121,7 @@ public function testNoDatabaseURL(): void $this->expectExceptionMessage('Invalid "default" database config.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -138,7 +138,7 @@ public function testNoDatabasePath(): void $this->expectExceptionMessage('Invalid "default" database config.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -157,7 +157,7 @@ public function testInvalidDatabaseURL(): void $this->expectExceptionMessage('Invalid "default" database config.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -176,7 +176,7 @@ public function testInvalidDatabasePath(): void $this->expectExceptionMessage('Invalid "default" database config.'); $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -193,7 +193,7 @@ public function testInvalidDatabasePath(): void public function testDownloadOneDatabases(): void { $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['default']); @@ -215,7 +215,7 @@ public function testDownloadOneDatabases(): void public function testDownloadSeveralDatabases(): void { $this->input - ->expects($this->at(4)) + ->expects($this->once()) ->method('getArgument') ->with('databases') ->willReturn(['second', 'first']); @@ -232,13 +232,12 @@ public function testDownloadSeveralDatabases(): void ]; $this->downloader - ->expects($this->at(0)) - ->method('download') - ->with($databases['second']['url'], $databases['second']['path']); - $this->downloader - ->expects($this->at(1)) + ->expects($this->exactly(2)) ->method('download') - ->with($databases['first']['url'], $databases['first']['path']); + ->withConsecutive( + [$databases['second']['url'], $databases['second']['path']], + [$databases['first']['url'], $databases['first']['path']] + ); $command = new UpdateDatabaseCommand($this->downloader, $databases); $command->run($this->input, $this->output); diff --git a/tests/Downloader/MaxMindDownloaderTest.php b/tests/Downloader/MaxMindDownloaderTest.php index b875114..9be5900 100644 --- a/tests/Downloader/MaxMindDownloaderTest.php +++ b/tests/Downloader/MaxMindDownloaderTest.php @@ -69,9 +69,8 @@ public function testNotFoundDatabase(): void ->expects($this->atLeastOnce()) ->method('debug'); - $fs_call = 0; $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->once()) ->method('remove') ->willReturnCallback(function ($files) use ($tmp_zip_regexp, $tmp_unzip_regexp, $tmp_untar_regexp) { $this->assertIsArray($files); @@ -82,12 +81,12 @@ public function testNotFoundDatabase(): void $this->assertIsString($files[0]); $this->assertIsString($files[1]); $this->assertIsString($files[2]); - $this->assertRegExp($tmp_zip_regexp, $files[0]); - $this->assertRegExp($tmp_unzip_regexp, $files[1]); - $this->assertRegExp($tmp_untar_regexp, $files[2]); + $this->assertMatchesRegularExpression($tmp_zip_regexp, $files[0]); + $this->assertMatchesRegularExpression($tmp_unzip_regexp, $files[1]); + $this->assertMatchesRegularExpression($tmp_untar_regexp, $files[2]); }); $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->once()) ->method('copy') ->willReturnCallback(function ($origin_file, $target_file, $overwrite_newer_files) use ( $url, @@ -96,13 +95,13 @@ public function testNotFoundDatabase(): void $this->assertSame($url, $origin_file); $this->assertIsString($target_file); $this->assertTrue($overwrite_newer_files); - $this->assertRegExp($tmp_zip_regexp, $target_file); + $this->assertMatchesRegularExpression($tmp_zip_regexp, $target_file); // make test GeoLite2 db file_put_contents($target_file, base64_decode(self::TAR_GZ_BAD)); }); $this->fs - ->expects($this->at($fs_call)) + ->expects($this->once()) ->method('mkdir') ->with(dirname($target), 0755); @@ -124,9 +123,8 @@ public function testDownload(): void ->expects($this->atLeastOnce()) ->method('debug'); - $fs_call = 0; $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->exactly(2)) ->method('remove') ->willReturnCallback(function ($files) use ($tmp_zip_regexp, $tmp_unzip_regexp, $tmp_untar_regexp) { $this->assertIsArray($files); @@ -137,69 +135,61 @@ public function testDownload(): void $this->assertIsString($files[0]); $this->assertIsString($files[1]); $this->assertIsString($files[2]); - $this->assertRegExp($tmp_zip_regexp, $files[0]); - $this->assertRegExp($tmp_unzip_regexp, $files[1]); - $this->assertRegExp($tmp_untar_regexp, $files[2]); + $this->assertMatchesRegularExpression($tmp_zip_regexp, $files[0]); + $this->assertMatchesRegularExpression($tmp_unzip_regexp, $files[1]); + $this->assertMatchesRegularExpression($tmp_untar_regexp, $files[2]); }); $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->exactly(2)) ->method('copy') ->willReturnCallback(function ($origin_file, $target_file, $overwrite_newer_files) use ( $url, - $tmp_zip_regexp + $tmp_zip_regexp, + $target, + $path_quote ) { - $this->assertSame($url, $origin_file); + $this->assertIsString($origin_file); $this->assertIsString($target_file); $this->assertTrue($overwrite_newer_files); - $this->assertRegExp($tmp_zip_regexp, $target_file); - // make test GeoLite2 db - file_put_contents($target_file, base64_decode(self::TAR_GZ)); + if ($target === $target_file) { + $this->assertSame($target, $target_file); + $regexp = sprintf( + '#^%s/[\da-f]+\.\d+_GeoLite2/GeoLite2-City_20200114/GeoLite2.mmdb$#', + $path_quote + ); + $this->assertMatchesRegularExpression($regexp, $origin_file); + $this->assertFileExists($origin_file); + $this->assertSame('TestGeoLite2', file_get_contents($origin_file)); + } else { + $this->assertSame($url, $origin_file); + $this->assertMatchesRegularExpression($tmp_zip_regexp, $target_file); + + // make test GeoLite2 db + file_put_contents($target_file, base64_decode(self::TAR_GZ)); + } }); $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->once()) ->method('mkdir') ->with(dirname($target), 0755); $this->fs - ->expects($this->at($fs_call++)) - ->method('copy') - ->willReturnCallback(function ( - $origin_file, - $target_file, - $overwrite_newer_files - ) use ($target, $path_quote) { - $this->assertIsString($origin_file); - $this->assertSame($target, $target_file); - $this->assertTrue($overwrite_newer_files); - $regexp = sprintf( - '#^%s/[\da-f]+\.\d+_GeoLite2/GeoLite2-City_20200114/GeoLite2.mmdb$#', - $path_quote - ); - $this->assertRegExp($regexp, $origin_file); - $this->assertFileExists($origin_file); - $this->assertSame('TestGeoLite2', file_get_contents($origin_file)); - }); - $this->fs - ->expects($this->at($fs_call++)) + ->expects($this->once()) ->method('chmod') ->with($target, 0755); - $this->fs - ->expects($this->at($fs_call)) - ->method('remove') - ->willReturnCallback(function ($files) use ($tmp_zip_regexp, $tmp_unzip_regexp, $tmp_untar_regexp) { - $this->assertIsArray($files); - $this->assertCount(3, $files); - $this->assertArrayHasKey(0, $files); - $this->assertArrayHasKey(1, $files); - $this->assertArrayHasKey(2, $files); - $this->assertIsString($files[0]); - $this->assertIsString($files[1]); - $this->assertIsString($files[2]); - $this->assertRegExp($tmp_zip_regexp, $files[0]); - $this->assertRegExp($tmp_unzip_regexp, $files[1]); - $this->assertRegExp($tmp_untar_regexp, $files[2]); - }); $this->downloader->download($url, $target); } + + /** + * Hook for BC. + */ + public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + if (method_exists(parent::class, 'assertMatchesRegularExpression')) { + parent::assertMatchesRegularExpression($pattern, $string, $message); + } else { + parent::assertRegExp($pattern, $string, $message); + } + } }