From 3ac2464f795a10ee7d2620c87c01bed1b6e50276 Mon Sep 17 00:00:00 2001 From: Richard van Laak Date: Thu, 5 Jan 2023 19:49:03 +0100 Subject: [PATCH] Add PHP 8.1 and PHP 8.2 test support (#87) * Make doctrine/annotations hard dependency Doctrine bundle did make annotations optional dependency due to transitioning to attributes * Update BundleInitializationTest.php * Update BreadcrumbListenerTest.php * Update BreadcrumbTrailExtensionTest.php * Upgrade Nyholm test bundle to 2.x * Drop Symfony 3.4 support Add Symfony 6.x support Add PHP 8.1 and 8.2 test coverage * Only test PHP <8.1 on `test-lowest` * Fix running CI, as jakzal latest does not have php-cs-fixer yet * Fix tests Co-authored-by: Richard van Laak --- .github/workflows/ci.yml | 18 +++++---- Makefile | 37 +++++++++++------- composer.json | 6 +-- phpunit.xml.dist | 2 +- src/BreadcrumbTrail/Trail.php | 3 +- .../APYBreadcrumbTrailExtension.php | 1 + src/DependencyInjection/Configuration.php | 4 +- tests/BundleInitializationTest.php | 25 +++++++++--- .../EventListener/BreadcrumbListenerTest.php | 37 +++++++++++------- tests/Twig/BreadcrumbTrailExtensionTest.php | 38 +++++++++++-------- 10 files changed, 106 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2508bd0..8a85c6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0'] - symfony: ['3.4', '4.4', '5.1', '5.2', '5.3'] + php: ['8.1', '8.2'] + symfony: ['4.4.*', '5.4.*', '6.1.*', '6.2.*'] steps: - name: Set up PHP @@ -22,7 +22,7 @@ jobs: php-version: ${{ matrix.php }} coverage: none extensions: mbstring, intl - tools: composer:v2 + tools: composer:v2, flex - name: Setup Problem Matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" @@ -30,8 +30,10 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - name: Select supported Symfony version - run: composer require symfony/framework-bundle:"^${{ matrix.symfony }}" --no-update + - name: Download dependencies + env: + SYMFONY_REQUIRE: ${{ matrix.symfony }} + uses: ramsey/composer-install@v1 - name: Run tests run: make test @@ -42,7 +44,7 @@ jobs: strategy: max-parallel: 10 matrix: - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] steps: - name: Set up PHP @@ -51,7 +53,7 @@ jobs: php-version: ${{ matrix.php }} coverage: none extensions: mbstring, intl - tools: composer:v2 + tools: composer:v2, flex - name: Setup Problem Matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" @@ -65,7 +67,7 @@ jobs: codestyle: name: Code style runs-on: ubuntu-latest - container: jakzal/phpqa + container: jakzal/phpqa:php8.1 steps: - uses: actions/checkout@v2 - name: PHP CS Fixer (via jakzal/phpqa) diff --git a/Makefile b/Makefile index 36ff730..14c1583 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,47 @@ DIR := ${CURDIR} test-php72: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.2 $(MAKE) test + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.2 make test test-php73: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.3 $(MAKE) test + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.3 make test test-php74: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.4 $(MAKE) test + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.4 make test + +test-php80: + docker run --rm -v $(DIR):/project -w /project webdevops/php:8.0 make test + +test-php81: + docker run --rm -v $(DIR):/project -w /project webdevops/php:8.1 make test + +test-php82: + docker run --rm -v $(DIR):/project -w /project webdevops/php:8.2 make test test: composer update --prefer-dist --no-interaction ${COMPOSER_PARAMS} composer test test-lowest: - COMPOSER_PARAMS='--prefer-lowest' $(MAKE) test + COMPOSER_PARAMS='--prefer-lowest' make test test-php72-lowest: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.2 $(MAKE) test-lowest + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.2 make test-lowest test-php73-lowest: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.3 $(MAKE) test-lowest + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.3 make test-lowest test-php74-lowest: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.4 $(MAKE) test-lowest + docker run --rm -v $(DIR):/project -w /project webdevops/php:7.4 make test-lowest -cs: - docker run --rm -v $(DIR):/project -w /project jakzal/phpqa php-cs-fixer fix -vv ${CS_PARAMS} +cs: composer.lock + docker run --rm -v $(DIR):/project -w /project jakzal/phpqa:php8.1 php-cs-fixer fix -vv ${CS_PARAMS} -test-cs: - CS_PARAMS='--dry-run' $(MAKE) cs +test-cs: composer.lock + CS_PARAMS='--dry-run' make cs -static: +static: composer.lock docker run --rm -v $(DIR):/project -w /project jakzal/phpqa phpstan analyze -c .phpstan.neon -composer: - docker run --rm -v $(DIR):/project -w /project webdevops/php:7.2 composer install +composer.lock: + docker run --rm -v $(DIR):/project -w /project jakzal/phpqa composer install diff --git a/composer.json b/composer.json index ade9ea8..5c6004e 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "license": "MIT", "require": { "php": ">=7.2", - "symfony/framework-bundle": "^3.4|^4.0|^5.0|^6.0", + "symfony/framework-bundle": "^4.0|^5.0|^6.0", "twig/twig": "^1.41|^2.7|^3.0", "symfony/deprecation-contracts": "^2.4|^3.0" }, @@ -23,13 +23,13 @@ }, "require-dev": { "symfony/phpunit-bridge": "^5.0|^6.0", - "nyholm/symfony-bundle-test": "^1.5", + "nyholm/symfony-bundle-test": "^v2.0", "matthiasnoback/symfony-dependency-injection-test": "^4.0", "doctrine/doctrine-bundle": "^v1.0|^v2.0", + "doctrine/annotations": "^v1.7", "symfony/twig-bundle": "^3.4|^4.0|^5.0|^6.0" }, "conflict": { - "doctrine/annotations": "< 1.7", "symfony/framework-bundle": "<3.4.26 || >4 <4.1.12 || >4.2 <4.2.7", "twig/twig": ">=2.0 <2.15.3" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5938b32..58fb7f8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,7 +14,7 @@ - + diff --git a/src/BreadcrumbTrail/Trail.php b/src/BreadcrumbTrail/Trail.php index d3e005f..9a28223 100644 --- a/src/BreadcrumbTrail/Trail.php +++ b/src/BreadcrumbTrail/Trail.php @@ -13,7 +13,6 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Traversable; class Trail implements \IteratorAggregate, \Countable { @@ -197,7 +196,7 @@ public function count(): int /** * {@inheritDoc} */ - public function getIterator(): Traversable + public function getIterator(): \Traversable { $this->breadcrumbs->rewind(); diff --git a/src/DependencyInjection/APYBreadcrumbTrailExtension.php b/src/DependencyInjection/APYBreadcrumbTrailExtension.php index 158c345..ff0acf4 100644 --- a/src/DependencyInjection/APYBreadcrumbTrailExtension.php +++ b/src/DependencyInjection/APYBreadcrumbTrailExtension.php @@ -42,6 +42,7 @@ private function deprecateService(ContainerBuilder $container, string $id) if (version_compare(Kernel::VERSION, '5.1.0', '>=')) { $alias->setDeprecated('APY/BreadcrumbTrailBundle', '1.7', 'The service is deprecated, use "%alias_id%" FQCN as service id instead.'); } elseif (version_compare(Kernel::VERSION, '4.3.0', '>=')) { + /* @phpstan-ignore-next-line */ $alias->setDeprecated(); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 9dfb2ef..46e48d6 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -15,9 +15,7 @@ class Configuration implements ConfigurationInterface { - /** - * {@inheritDoc} - */ + #[\ReturnTypeWillChange] public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder('apy_breadcrumb_trail'); diff --git a/tests/BundleInitializationTest.php b/tests/BundleInitializationTest.php index 4456c34..fc14cda 100644 --- a/tests/BundleInitializationTest.php +++ b/tests/BundleInitializationTest.php @@ -2,19 +2,32 @@ namespace APY\BreadcrumbTrailBundle; -use Nyholm\BundleTest\BaseBundleTestCase; +use Nyholm\BundleTest\TestKernel; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\HttpKernel\KernelInterface; -class BundleInitializationTest extends BaseBundleTestCase +class BundleInitializationTest extends KernelTestCase { - protected function getBundleClass() + protected static function getKernelClass(): string { - return APYBreadcrumbTrailBundle::class; + return TestKernel::class; + } + + protected static function createKernel(array $options = []): KernelInterface + { + /** + * @var TestKernel $kernel + */ + $kernel = parent::createKernel($options); + $kernel->addTestBundle(APYBreadcrumbTrailBundle::class); + $kernel->handleOptions($options); + + return $kernel; } public function testServicesAreRegisteredToContainer() { - $this->bootKernel(); - $container = $this->getContainer(); + $container = self::bootKernel()->getContainer(); $this->assertTrue($container->has('apy_breadcrumb_trail')); $this->assertTrue($container->has('apy_breadcrumb_trail.annotation.listener')); diff --git a/tests/EventListener/BreadcrumbListenerTest.php b/tests/EventListener/BreadcrumbListenerTest.php index b761483..357a8cc 100644 --- a/tests/EventListener/BreadcrumbListenerTest.php +++ b/tests/EventListener/BreadcrumbListenerTest.php @@ -10,15 +10,16 @@ use APY\BreadcrumbTrailBundle\Fixtures\InvokableControllerWithAnnotations; use APY\BreadcrumbTrailBundle\Fixtures\ResetTrailAttribute; use APY\BreadcrumbTrailBundle\MixedAnnotationWithAttributeBreadcrumbsException; -use Nyholm\BundleTest\AppKernel; -use Nyholm\BundleTest\BaseBundleTestCase; +use Nyholm\BundleTest\TestKernel; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; -class BreadcrumbListenerTest extends BaseBundleTestCase +class BreadcrumbListenerTest extends KernelTestCase { /** @var BreadcrumbListener */ private $listener; @@ -26,16 +27,26 @@ class BreadcrumbListenerTest extends BaseBundleTestCase /** @var Trail */ private $breadcrumbTrail; - /** @var AppKernel */ - private $kernel; + protected static function getKernelClass(): string + { + return TestKernel::class; + } + + protected static function createKernel(array $options = []): KernelInterface + { + /** @var TestKernel $kernel */ + $kernel = parent::createKernel($options); + $kernel->addTestBundle(APYBreadcrumbTrailBundle::class); + $kernel->handleOptions($options); + + return $kernel; + } protected function setUpTest(): void { - // TODO rename this to setUp method once bumping PHP to supporting return type declarations - $this->kernel = $this->createKernel(); - $this->kernel->boot(); - $this->listener = $this->getContainer()->get('apy_breadcrumb_trail.annotation.listener'); - $this->breadcrumbTrail = $this->getContainer()->get('apy_breadcrumb_trail'); + $kernel = self::bootKernel(); + $this->listener = $kernel->getContainer()->get('apy_breadcrumb_trail.annotation.listener'); + $this->breadcrumbTrail = $kernel->getContainer()->get('apy_breadcrumb_trail'); } public function testAnnotations() @@ -101,7 +112,7 @@ public function testResetTrailAttribute() self::assertCount(1, $this->breadcrumbTrail); } - protected function getBundleClass() + protected function getBundleClass(): string { return APYBreadcrumbTrailBundle::class; } @@ -113,9 +124,9 @@ private function createControllerEvent($controller) { $callable = \is_callable($controller) ? $controller : [$controller, 'indexAction']; if (Kernel::MAJOR_VERSION <= 4) { - return new FilterControllerEvent($this->kernel, $callable, new Request(), HttpKernelInterface::MASTER_REQUEST); + return new FilterControllerEvent(self::$kernel, $callable, new Request(), HttpKernelInterface::MASTER_REQUEST); } - return new ControllerEvent($this->kernel, $callable, new Request(), HttpKernelInterface::MASTER_REQUEST); + return new ControllerEvent(self::$kernel, $callable, new Request(), HttpKernelInterface::MASTER_REQUEST); } } diff --git a/tests/Twig/BreadcrumbTrailExtensionTest.php b/tests/Twig/BreadcrumbTrailExtensionTest.php index a55b561..3994ddd 100644 --- a/tests/Twig/BreadcrumbTrailExtensionTest.php +++ b/tests/Twig/BreadcrumbTrailExtensionTest.php @@ -3,36 +3,44 @@ namespace APY\BreadcrumbTrailBundle\Twig; use APY\BreadcrumbTrailBundle\APYBreadcrumbTrailBundle; -use Nyholm\BundleTest\BaseBundleTestCase; +use Nyholm\BundleTest\TestKernel; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Bundle\TwigBundle\TwigBundle; -use Twig\Environment; +use Symfony\Component\HttpKernel\KernelInterface; /** * @coversDefaultClass \APY\BreadcrumbTrailBundle\Twig\BreadcrumbTrailExtension */ -class BreadcrumbTrailExtensionTest extends BaseBundleTestCase +class BreadcrumbTrailExtensionTest extends KernelTestCase { - protected function getBundleClass() + protected static function getKernelClass(): string { - return APYBreadcrumbTrailBundle::class; + return TestKernel::class; } - protected function setUp(): void + protected static function createKernel(array $options = []): KernelInterface { - $kernel = $this->createKernel(); - $kernel->addBundle(TwigBundle::class); - $kernel->boot(); + /** @var TestKernel $kernel */ + $kernel = parent::createKernel($options); + $kernel->addTestBundle(APYBreadcrumbTrailBundle::class); + $kernel->addTestBundle(TwigBundle::class); + $kernel->handleOptions($options); + + return $kernel; } + /** + * @requires PHP >= 8.0 + */ public function testTwigFunctionGetsRegistered() { - $container = $this->getContainer(); + $container = self::getContainer(); + + /** @var BreadcrumbTrailExtension $extension */ + $extension = $container->get(BreadcrumbTrailExtension::class); - /** @var Environment $twig */ - $twig = $container->get('twig'); + $function = current($extension->getFunctions()); - self::assertNotNull( - $twig->getFunction('apy_breadcrumb_trail_render') - ); + self::assertEquals('apy_breadcrumb_trail_render', $function->getName()); } }