diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 89c48eb1..9b07dcc9 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -8,7 +8,7 @@ on: jobs: phpstan-src: - name: PHPStan src + name: PHPStan runs-on: ubuntu-latest steps: @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v4 - name: Pull in optional dependencies - run: composer require --no-update phpunit/phpunit toflar/psr6-symfony-http-cache-store:^4.2 symfony/process + run: composer require --no-update phpunit/phpunit toflar/psr6-symfony-http-cache-store:^4.2 symfony/process mockery/mockery phpstan/phpstan-mockery guzzlehttp/guzzle php-http/mock-client - name: Cache Vendor id: cache-vendor @@ -30,31 +30,6 @@ jobs: with: args: analyze --no-progress - phpstan-tests: - name: PHPStan tests - runs-on: ubuntu-latest - env: - REQUIRE_DEV: "true" - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Pull in optional dependencies - run: composer require --no-update phpunit/phpunit toflar/psr6-symfony-http-cache-store:^4.2 - - - name: Cache Vendor - id: cache-vendor - uses: actions/cache@v4 - with: - path: vendor - key: ${{ runner.os }}-vendor - - - name: PHPStan - uses: docker://oskarstark/phpstan-ga - with: - args: analyze --no-progress -c phpstan.tests.neon.dist - php-cs-fixer: name: PHP-CS-Fixer runs-on: ubuntu-latest diff --git a/doc/Makefile b/doc/Makefile index 1a35bb06..d3813085 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -154,5 +154,5 @@ doctest: "results in $(BUILDDIR)/doctest/output.txt." spelling: - $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) -w $(BUILDDIR)/spelling/output.txt $(BUILDDIR)/spelling + $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) -w $(BUILDDIR)/spelling/output.txt $(BUILDDIR)/spelling @echo "Spelling report generated in $(BUILDDIR)/spelling/output.txt" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 77c3651a..e03bb8ad 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,4 +1,7 @@ parameters: - level: 1 + level: 4 paths: - src + - tests + + treatPhpDocTypesAsCertain: false diff --git a/phpstan.tests.neon.dist b/phpstan.tests.neon.dist deleted file mode 100644 index 0efe94d4..00000000 --- a/phpstan.tests.neon.dist +++ /dev/null @@ -1,4 +0,0 @@ -parameters: - level: 1 - paths: - - tests diff --git a/src/ProxyClient/Cloudflare.php b/src/ProxyClient/Cloudflare.php index 8f9bad97..785a7bf4 100644 --- a/src/ProxyClient/Cloudflare.php +++ b/src/ProxyClient/Cloudflare.php @@ -81,7 +81,7 @@ public function invalidateTags(array $tags): static sprintf(self::API_ENDPOINT.'/zones/%s/purge_cache', $this->options['zone_identifier']), [], false, - $this->json_encode(['tags' => $tags]) + json_encode(['tags' => $tags], JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES) ); return $this; @@ -115,7 +115,7 @@ public function clear(): static sprintf(self::API_ENDPOINT.'/zones/%s/purge_cache', $this->options['zone_identifier']), ['Accept' => 'application/json'], false, - $this->json_encode(['purge_everything' => true]) + json_encode(['purge_everything' => true], JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES) ); return $this; @@ -130,7 +130,7 @@ public function flush(): int sprintf(self::API_ENDPOINT.'/zones/%s/purge_cache', $this->options['zone_identifier']), [], false, - $this->json_encode(['files' => $urlChunk]) + json_encode(['files' => $urlChunk], JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES) ); } $this->purgeByUrlsData = []; @@ -165,14 +165,4 @@ protected function configureOptions(): OptionsResolver return $resolver; } - - private function json_encode(array $data): string - { - $json = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES); - if (false === $json) { - throw new \InvalidArgumentException(sprintf('Cannot encode "$data": %s', json_last_error_msg())); - } - - return $json; - } } diff --git a/src/ProxyClient/MultiplexerClient.php b/src/ProxyClient/MultiplexerClient.php index e31d5bc5..896fbbe1 100644 --- a/src/ProxyClient/MultiplexerClient.php +++ b/src/ProxyClient/MultiplexerClient.php @@ -133,7 +133,7 @@ public function clear(): static * Invoke the given $method on all available ProxyClients implementing the * given $interface. * - * @param string $interface The FQN of the interface + * @param class-string $interface The FQN of the interface * @param string $method The method to invoke * @param array $arguments The arguments to be passed to the method */ @@ -155,7 +155,9 @@ private function getProxyClients(string $interface): array { return array_filter( $this->proxyClients, - static function ($proxyClient) use ($interface) { + static function (ProxyClient $proxyClient) use ($interface) { + // https://github.com/phpstan/phpstan/issues/8464 + // @phpstan-ignore-next-line return is_subclass_of($proxyClient, $interface); } ); diff --git a/src/SymfonyCache/PurgeTagsListener.php b/src/SymfonyCache/PurgeTagsListener.php index acf863c8..7ed4c2ec 100644 --- a/src/SymfonyCache/PurgeTagsListener.php +++ b/src/SymfonyCache/PurgeTagsListener.php @@ -118,7 +118,7 @@ public function handlePurgeTags(CacheEvent $event): void if (1 === $reflection->getMethod('all')->getNumberOfParameters()) { $headers = $request->headers->all($this->tagsHeader); } else { - $headers = $request->headers->get($this->tagsHeader, '', false); + $headers = $request->headers->get($this->tagsHeader, ''); } $tags = $this->tagsParser->parseTagsHeaderValue($headers); diff --git a/src/Test/EventDispatchingHttpCacheTestCase.php b/src/Test/EventDispatchingHttpCacheTestCase.php index 99a4a59e..8cc80dad 100644 --- a/src/Test/EventDispatchingHttpCacheTestCase.php +++ b/src/Test/EventDispatchingHttpCacheTestCase.php @@ -251,6 +251,7 @@ public function testPreStoreResponseNoStore() $httpCache = $this->getHttpCachePartialMock(); $testListener = new TestListener($this, $httpCache, $request); $testListener->preStoreResponse = $preStoreResponse; + $this->assertTrue(method_exists($httpCache, 'addSubscriber')); $httpCache->addSubscriber($testListener); $store = $this->createMock(StoreInterface::class); @@ -279,8 +280,8 @@ public function testPreInvalidateCalled(): void $httpCache = $this->getHttpCachePartialMock(['pass']); $testListener = new TestListener($this, $httpCache, $request); - $httpCache->addSubscriber($testListener); $this->assertTrue(method_exists($httpCache, 'addSubscriber')); + $httpCache->addSubscriber($testListener); $httpCache ->method('pass') ->with($request) @@ -307,8 +308,8 @@ public function testPreInvalidateReturnEarly(): void $httpCache = $this->getHttpCachePartialMock(['pass']); $testListener = new TestListener($this, $httpCache, $request); $testListener->preInvalidateResponse = $response; - $httpCache->addSubscriber($testListener); $this->assertTrue(method_exists($httpCache, 'addSubscriber')); + $httpCache->addSubscriber($testListener); $httpCache ->expects($this->never()) ->method('pass') @@ -327,6 +328,7 @@ public function testAddListener(): void $httpCache = $this->getHttpCachePartialMock(['lookup']); $simpleListener = new SimpleListener($this, $httpCache, $request); + $this->assertTrue(method_exists($httpCache, 'addListener')); $httpCache->addListener(Events::PRE_HANDLE, [$simpleListener, 'callback']); $httpCache diff --git a/src/Test/WebServerSubscriber.php b/src/Test/WebServerSubscriber.php index 8d25bb19..82b9aca2 100644 --- a/src/Test/WebServerSubscriber.php +++ b/src/Test/WebServerSubscriber.php @@ -11,7 +11,6 @@ namespace FOS\HttpCache\Test; -use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\TestRunner\ExecutionStarted; use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; use PHPUnit\Event\TestSuite\TestSuite; @@ -52,8 +51,6 @@ private function hasTestsWithGroup(TestSuite $testSuite, string $group): bool continue; } - assert($test instanceof TestMethod); - foreach ($test->metadata()->isGroup() as $testGroup) { assert($testGroup instanceof Group); @@ -83,7 +80,7 @@ public function startPhpWebServer(): int $this->waitFor($this->getHostName(), (int) $this->getPort(), 2000); - return $output[0]; + return (int) $output[0]; } public function getHostName(): string diff --git a/tests/Functional/ProxyClient/NginxProxyClientTest.php b/tests/Functional/ProxyClient/NginxProxyClientTest.php index e9ee423f..2df464e0 100644 --- a/tests/Functional/ProxyClient/NginxProxyClientTest.php +++ b/tests/Functional/ProxyClient/NginxProxyClientTest.php @@ -35,7 +35,7 @@ public function testPurgeContentType(): void { $this->markTestSkipped('Not working with nginx, it can only purge one type'); - $this->assertPurgeContentType($this->getProxyClient()); + // $this->assertPurgeContentType($this->getProxyClient()); } public function testPurgeSeparateLocationHost(): void @@ -57,6 +57,6 @@ public function testRefreshContentType(): void { $this->markTestSkipped('TODO: is nginx mixing up variants?'); - $this->assertRefreshContentType($this->getProxyClient()); + // $this->assertRefreshContentType($this->getProxyClient()); } } diff --git a/tests/Functional/Symfony/EventDispatchingHttpCacheTest.php b/tests/Functional/Symfony/EventDispatchingHttpCacheTest.php index e2c1bafa..ef76c7e4 100644 --- a/tests/Functional/Symfony/EventDispatchingHttpCacheTest.php +++ b/tests/Functional/Symfony/EventDispatchingHttpCacheTest.php @@ -44,6 +44,8 @@ public function testEventListeners(): void ->shouldReceive('handle') ->andReturn($expectedResponse) ->getMock(); + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $store = \Mockery::mock(StoreInterface::class) ->shouldReceive('lookup')->andReturn(null)->times(1) ->shouldReceive('write')->times(1) diff --git a/tests/Unit/CacheInvalidatorTest.php b/tests/Unit/CacheInvalidatorTest.php index 71becd08..db50f578 100644 --- a/tests/Unit/CacheInvalidatorTest.php +++ b/tests/Unit/CacheInvalidatorTest.php @@ -78,6 +78,8 @@ public function testSupportsInvalid(): void public function testInvalidatePath(): void { /** @var MockInterface&PurgeCapable $purge */ + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $purge = \Mockery::mock(PurgeCapable::class) ->shouldReceive('purge')->once()->with('/my/route', []) ->shouldReceive('purge')->once()->with('/my/route', ['X-Test-Header' => 'xyz']) @@ -97,6 +99,8 @@ public function testRefreshPath(): void { $headers = ['X' => 'Y']; /** @var MockInterface&RefreshCapable $refresh */ + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $refresh = \Mockery::mock(RefreshCapable::class) ->shouldReceive('refresh')->once()->with('/my/route', $headers) ->shouldReceive('flush')->never() @@ -190,6 +194,8 @@ public function testProxyClientExceptionsAreLogged(): void $unreachableException = ProxyUnreachableException::proxyUnreachable($clientException); + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $response = \Mockery::mock(ResponseInterface::class) ->shouldReceive('getStatusCode')->andReturn(403) ->shouldReceive('getReasonPhrase')->andReturn('Forbidden') @@ -206,6 +212,8 @@ public function testProxyClientExceptionsAreLogged(): void $cacheInvalidator = new CacheInvalidator($proxyClient); + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $logger = \Mockery::mock(LoggerInterface::class) ->shouldReceive('log')->once() ->with( diff --git a/tests/Unit/ResponseTaggerTest.php b/tests/Unit/ResponseTaggerTest.php index d87537f2..a8309624 100644 --- a/tests/Unit/ResponseTaggerTest.php +++ b/tests/Unit/ResponseTaggerTest.php @@ -48,6 +48,8 @@ public function testGetTagsHeaderValue(): void public function testTagResponseReplace(): void { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') ->with(['tag-1', 'tag-2']) @@ -73,6 +75,8 @@ public function testTagResponseReplace(): void public function testTagResponseAdd(): void { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') ->with(['tag-1', 'tag-2']) @@ -105,6 +109,8 @@ public function testTagResponseNoTags(): void $tagger = new ResponseTagger(['header_formatter' => $headerFormatter]); + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $response = \Mockery::mock(ResponseInterface::class) ->shouldReceive('withHeader')->never() ->shouldReceive('withAddedHeader')->never() diff --git a/tests/Unit/SymfonyCache/CacheAwareTest.php b/tests/Unit/SymfonyCache/CacheAwareTest.php new file mode 100644 index 00000000..382ab6fc --- /dev/null +++ b/tests/Unit/SymfonyCache/CacheAwareTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\HttpCache\Tests\Unit\SymfonyCache; + +use FOS\HttpCache\SymfonyCache\HttpCacheAware; +use FOS\HttpCache\SymfonyCache\HttpCacheProvider; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpKernel\HttpKernelInterface; + +class CacheAwareTest extends TestCase +{ + private HttpKernelInterface $cacheKernel; + + protected function setUp(): void + { + $this->cacheKernel = $this->createMock(HttpKernelInterface::class); + } + + public function testCacheGetterSetter(): void + { + $aware = new AppHttpCacheAware(); + $aware->setHttpCache($this->cacheKernel); + $this->assertSame($this->cacheKernel, $aware->getHttpCache()); + } +} + +class AppHttpCacheAware implements HttpCacheProvider +{ + use HttpCacheAware; +} diff --git a/tests/Unit/SymfonyCache/KernelDispatcherTest.php b/tests/Unit/SymfonyCache/KernelDispatcherTest.php index 0008e2d2..8820a109 100644 --- a/tests/Unit/SymfonyCache/KernelDispatcherTest.php +++ b/tests/Unit/SymfonyCache/KernelDispatcherTest.php @@ -33,8 +33,7 @@ public function testFlush(): void ->with($this->callback(function (Request $request) { // Test if the Symfony request contains the relevant information // from the PSR-7 request - $valid = true; - $valid = $valid && 'PURGETAGS' === $request->getMethod(); + $valid = 'PURGETAGS' === $request->getMethod(); $valid = $valid && 'foobar' === $request->headers->get('content-type'); $valid = $valid && 'foo,bar,stuff' === $request->headers->get('x-cache-tags'); $valid = $valid && ['query' => 'string', 'more' => 'stuff'] === $request->query->all(); diff --git a/tests/Unit/SymfonyCache/PurgeListenerTest.php b/tests/Unit/SymfonyCache/PurgeListenerTest.php index a8396bd3..86b4c9ce 100644 --- a/tests/Unit/SymfonyCache/PurgeListenerTest.php +++ b/tests/Unit/SymfonyCache/PurgeListenerTest.php @@ -187,6 +187,8 @@ public function testInvalidConfiguration(): void private function getKernelMock(StoreInterface $store): MockInterface&CacheInvalidation { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /* @phpstan-ignore-next-line */ return \Mockery::mock(CacheInvalidation::class) ->shouldReceive('getStore') ->once() @@ -196,6 +198,8 @@ private function getKernelMock(StoreInterface $store): MockInterface&CacheInvali private function getUnusedKernelMock(): CacheInvalidation&MockInterface { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /* @phpstan-ignore-next-line */ return \Mockery::mock(CacheInvalidation::class) ->shouldNotReceive('getStore') ->getMock(); diff --git a/tests/Unit/SymfonyCache/PurgeTagsListenerTest.php b/tests/Unit/SymfonyCache/PurgeTagsListenerTest.php index 8e06ff30..9bafeb49 100644 --- a/tests/Unit/SymfonyCache/PurgeTagsListenerTest.php +++ b/tests/Unit/SymfonyCache/PurgeTagsListenerTest.php @@ -180,6 +180,8 @@ public function testInvalidConfiguration(): void private function getKernelMock(StoreInterface $store): CacheInvalidation&MockInterface { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /* @phpstan-ignore-next-line */ return \Mockery::mock(CacheInvalidation::class) ->shouldReceive('getStore') ->once() @@ -189,6 +191,8 @@ private function getKernelMock(StoreInterface $store): CacheInvalidation&MockInt private function getUnusedKernelMock(): CacheInvalidation&MockInterface { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /* @phpstan-ignore-next-line */ return \Mockery::mock(CacheInvalidation::class) ->shouldNotReceive('getStore') ->getMock(); diff --git a/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php b/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php index 195df43a..58bda109 100644 --- a/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php +++ b/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php @@ -26,6 +26,8 @@ public function setUp(): void public function testMatches(): void { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $response = $this->getResponseMock() ->shouldReceive('hasHeader')->with('cache-header')->andReturn(true) ->shouldReceive('getHeaderLine')->with('cache-header')->once()->andReturn('MISS') @@ -44,6 +46,8 @@ public function testMatchesThrowsExceptionIfHeaderIsMissing(): void $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Response has no "cache-header" header'); + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $response = $this->getResponseMock() ->shouldReceive('hasHeader')->with('cache-header')->once()->andReturn(false) ->shouldReceive('getStatusCode')->andReturn(200) diff --git a/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php b/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php index e86c3051..4f4133bc 100644 --- a/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php +++ b/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php @@ -25,6 +25,8 @@ public function setUp(): void public function testMatches(): void { + // https://github.com/phpstan/phpstan-mockery/issues/8 + /** @phpstan-ignore-next-line */ $response = $this->getResponseMock() ->shouldReceive('hasHeader')->with('cache-header')->andReturn(true) ->shouldReceive('getHeaderLine')->with('cache-header')->once()->andReturn('HIT')