Skip to content

Commit

Permalink
Make kernel configurable via attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
jdreesen committed Mar 19, 2024
1 parent c35974e commit c10f76c
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 29 deletions.
23 changes: 23 additions & 0 deletions src/Test/Attribute/ConfigureContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class ConfigureContainer implements KernelConfiguration
{
/**
* @param string $config path to a config file
*/
public function __construct(
private readonly string $config,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestConfig($this->config);
}
}
24 changes: 24 additions & 0 deletions src/Test/Attribute/ConfigureExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class ConfigureExtension implements KernelConfiguration
{
/**
* @param array<string, array<mixed>> $extensionConfig
*/
public function __construct(
private readonly string $namespace,
private readonly array $extensionConfig,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestExtensionConfig($this->namespace, $this->extensionConfig);
}
}
11 changes: 11 additions & 0 deletions src/Test/Attribute/KernelConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

interface KernelConfiguration
{
public function configure(TestKernel $kernel): void;
}
24 changes: 24 additions & 0 deletions src/Test/Attribute/RegisterBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class RegisterBundle implements KernelConfiguration
{
/**
* @param class-string<BundleInterface> $bundle
*/
public function __construct(
private readonly string $bundle,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestBundle($this->bundle);
}
}
27 changes: 27 additions & 0 deletions src/Test/Attribute/RegisterCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class RegisterCompilerPass implements KernelConfiguration
{
/**
* @param PassConfig::TYPE_* $type
*/
public function __construct(
private readonly CompilerPassInterface $compilerPass,
private readonly string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION,
private readonly int $priority = 0,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestCompilerPass($this->compilerPass, $this->type, $this->priority);
}
}
25 changes: 25 additions & 0 deletions src/Test/ConfigurableKernelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
namespace Neusta\Pimcore\TestingFramework\Test;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Neusta\Pimcore\TestingFramework\Test\Attribute\KernelConfiguration;
use Neusta\Pimcore\TestingFramework\Test\Reflection\TestAttributeProvider;
use Pimcore\Test\KernelTestCase;

abstract class ConfigurableKernelTestCase extends KernelTestCase
{
/** @var list<KernelConfiguration> */
private static iterable $kernelConfigurations = [];

/**
* @param array<mixed> $options
*/
Expand All @@ -16,8 +21,28 @@ protected static function createKernel(array $options = []): TestKernel
$kernel = parent::createKernel($options);
\assert($kernel instanceof TestKernel);

foreach (self::$kernelConfigurations as $configuration) {
$configuration->configure($kernel);
}

$kernel->handleOptions($options);

return $kernel;
}

/**
* @internal
*
* @before
*/
public function _getKernelConfigurationFromAttributes(): void
{
self::$kernelConfigurations = (new TestAttributeProvider($this))->getKernelConfigurationAttributes();
}

protected function tearDown(): void
{
self::$kernelConfigurations = [];
parent::tearDown();
}
}
49 changes: 49 additions & 0 deletions src/Test/Reflection/TestAttributeProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Reflection;

use Neusta\Pimcore\TestingFramework\Test\Attribute\KernelConfiguration;
use PHPUnit\Framework\TestCase;

/**
* @internal
*/
final class TestAttributeProvider
{
private \ReflectionMethod $test;

public function __construct(TestCase $test)
{
$this->test = new \ReflectionMethod($test, $test->getName(false));
}

/**
* @return list<KernelConfiguration>
*/
public function getKernelConfigurationAttributes(): array
{
$attributes = [];
foreach ($this->getAttributes($this->test->getDeclaringClass(), KernelConfiguration::class) as $attribute) {
$attributes[] = $attribute->newInstance();
}

foreach ($this->getAttributes($this->test, KernelConfiguration::class) as $attribute) {
$attributes[] = $attribute->newInstance();
}

return $attributes;
}

/**
* @template T of object
*
* @param class-string<T> $attribute
*
* @return iterable<\ReflectionAttribute<T>>
*/
private function getAttributes(\ReflectionClass|\ReflectionMethod $source, string $attribute): iterable
{
yield from $source->getAttributes($attribute, \ReflectionAttribute::IS_INSTANCEOF);
}
}
35 changes: 33 additions & 2 deletions tests/Functional/CompilerPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Neusta\Pimcore\TestingFramework\Tests\Functional;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Neusta\Pimcore\TestingFramework\Test\Attribute\RegisterCompilerPass;
use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase;
use Neusta\Pimcore\TestingFramework\Tests\Fixtures\ConfigurationBundle\DependencyInjection\Compiler\DeregisterSomethingPass;
use Neusta\Pimcore\TestingFramework\Tests\Fixtures\ConfigurationBundle\DependencyInjection\Compiler\RegisterSomethingPass;
Expand All @@ -22,15 +23,15 @@ public function compiler_pass_priority(): void
$kernel->addTestCompilerPass(new RegisterSomethingPass());
}]);

$this->assertTrue(self::getContainer()->has('something'));
self::assertTrue(self::getContainer()->has('something'));

// Case 2: Compiler pass with priority - it should be prioritized by priority
self::bootKernel(['config' => function (TestKernel $kernel) {
$kernel->addTestCompilerPass(new DeregisterSomethingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
$kernel->addTestCompilerPass(new RegisterSomethingPass());
}]);

$this->assertFalse(self::getContainer()->has('something'));
self::assertFalse(self::getContainer()->has('something'));

// Case 3: Compiler pass without priority - it should be prioritized by order of addition
self::bootKernel(['config' => function (TestKernel $kernel) {
Expand All @@ -39,6 +40,36 @@ public function compiler_pass_priority(): void
$kernel->addTestCompilerPass(new DeregisterSomethingPass());
}]);

self::assertFalse(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new DeregisterSomethingPass())]
#[RegisterCompilerPass(new RegisterSomethingPass())]
public function compiler_passes_via_attributes(): void
{
$this->assertTrue(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new DeregisterSomethingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5)]
#[RegisterCompilerPass(new RegisterSomethingPass())]
public function compiler_passes_with_priority_via_attributes(): void
{
$this->assertFalse(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new RegisterSomethingPass())]
#[RegisterCompilerPass(new DeregisterSomethingPass())]
public function compiler_passes_without_priority_via_attributes(): void
{
$this->assertFalse(self::getContainer()->has('something'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,16 @@
namespace Neusta\Pimcore\TestingFramework\Tests\Functional;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Neusta\Pimcore\TestingFramework\Test\Attribute\ConfigureContainer;
use Neusta\Pimcore\TestingFramework\Test\Attribute\RegisterBundle;
use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase;
use Neusta\Pimcore\TestingFramework\Tests\Fixtures\ConfigurationBundle\ConfigurationBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;

final class BundleConfigurationTest extends ConfigurableKernelTestCase
#[RegisterBundle(ConfigurationBundle::class)]
final class ContainerConfigurationTest extends ConfigurableKernelTestCase
{
/**
* @test
*/
public function extension_configuration(): void
{
self::bootKernel(['config' => function (TestKernel $kernel) {
$kernel->addTestBundle(ConfigurationBundle::class);
$kernel->addTestExtensionConfig('configuration', [
'foo' => 'value1',
'bar' => ['value2', 'value3'],
]);
}]);

$container = self::getContainer();

$this->assertEquals('value1', $container->getParameter('configuration.foo'));
$this->assertEquals(['value2', 'value3'], $container->getParameter('configuration.bar'));
}

public function provideDifferentConfigurationFormats(): iterable
{
yield 'YAML' => [__DIR__ . '/../Fixtures/Resources/ConfigurationBundle/config.yaml'];
Expand All @@ -52,15 +36,42 @@ public function provideDifferentConfigurationFormats(): iterable
*/
public function different_configuration_formats(string|callable $config): void
{
self::bootKernel(['config' => function (TestKernel $kernel) use ($config) {
$kernel->addTestBundle(ConfigurationBundle::class);
$kernel->addTestConfig($config);
}]);
self::bootKernel(['config' => fn (TestKernel $kernel) => $kernel->addTestConfig($config)]);

$container = self::getContainer();
self::assertContainerConfiguration(self::getContainer());
}

$this->assertEquals('value1', $container->getParameter('configuration.foo'));
$this->assertEquals(['value2', 'value3'], $container->getParameter('configuration.bar'));
/**
* @test
*/
#[ConfigureContainer(__DIR__ . '/../Fixtures/Resources/ConfigurationBundle/config.yaml')]
public function configuration_in_yaml_via_attribute(): void
{
self::assertContainerConfiguration(self::getContainer());
}

/**
* @test
*/
#[ConfigureContainer(__DIR__ . '/../Fixtures/Resources/ConfigurationBundle/config.xml')]
public function configuration_in_xml_via_attribute(): void
{
self::assertContainerConfiguration(self::getContainer());
}

/**
* @test
*/
#[ConfigureContainer(__DIR__ . '/../Fixtures/Resources/ConfigurationBundle/config.php')]
public function configuration_in_php_via_attribute(): void
{
self::assertContainerConfiguration(self::getContainer());
}

public static function assertContainerConfiguration(ContainerInterface $container): void
{
self::assertEquals('value1', $container->getParameter('configuration.foo'));
self::assertEquals(['value2', 'value3'], $container->getParameter('configuration.bar'));
self::assertInstanceOf(\stdClass::class, $container->get('something', ContainerInterface::NULL_ON_INVALID_REFERENCE));
}
}
Loading

0 comments on commit c10f76c

Please sign in to comment.