diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88af801..8befaeb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,8 +33,18 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - name: Install + - name: Install Composer dependencies run: composer install --prefer-dist + # —— QA ✔️‍️ ——————————————————————————————————————————————————————————————— - name: Qualimetry run: make qa + + # —— Tests 🧪 ———————————————————————————————————————————————————————————— + - name: Phpunit tests + run: XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-clover coverage.xml + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: "Upload coverage to Codecov" + uses: codecov/codecov-action@v1 diff --git a/.gitignore b/.gitignore index 7c43e86..109ec1c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ composer.lock /phpmetrics/ coverage.* .php_cs.cache +.phpunit.result.cache +/var/ diff --git a/Makefile b/Makefile index d13f082..9f323aa 100644 --- a/Makefile +++ b/Makefile @@ -54,8 +54,16 @@ metrics: ## Build static analysis from the php in src. Repports available in ./p .PHONY: phpstan phpstan: ## Launch PHP Static Analysis - vendor/bin/phpstan analyse src --level=6 + vendor/bin/phpstan analyse src tests --level=6 -c phpstan.neon .PHONY: qa qualimetry qa: qualimetry ## Launch all qualimetry rules qualimetry: checkstyle lint-php cpd composer-validate metrics phpstan + +# ==================== +## Testing +phpunit: + vendor/bin/phpunit + +phpunit-coverage: + XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text diff --git a/README.md b/README.md index 4130ee8..2c166a1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![License](http://poser.pugx.org/smartbooster/parameter-bundle/license)](https://packagist.org/packages/smartbooster/parameter-bundle) ![CI workflow](https://github.com/smartbooster/parameter-bundle/actions/workflows/ci.yml/badge.svg) +[![codecov](https://codecov.io/gh/smartbooster/parameter-bundle/branch/master/graph/badge.svg?token=QQZPRVXGL8)](https://codecov.io/gh/smartbooster/parameter-bundle) ## Installation diff --git a/composer.json b/composer.json index ca5bada..1373aa2 100644 --- a/composer.json +++ b/composer.json @@ -12,11 +12,21 @@ "homepage": "https://www.smartbooster.io" } ], + "require": { + "php": "^7.4", + "symfony/http-kernel": "^4.4", + "symfony/config": "^4.4", + "symfony/yaml": "^4.4", + "symfony/dependency-injection": "^4.4" + }, "require-dev": { "squizlabs/php_codesniffer": "^3.6", "sebastian/phpcpd": "^6.0", "phpmetrics/phpmetrics": "^2.7", - "phpstan/phpstan": "^0.12.90" + "phpstan/phpstan": "^0.12.90", + "phpunit/phpunit": "^9.5", + "phpstan/phpstan-symfony": "^0.12.37", + "symfony/framework-bundle": "^4.4" }, "autoload": { "psr-4": { diff --git a/src/.gitkeep b/config/.gitkeep similarity index 100% rename from src/.gitkeep rename to config/.gitkeep diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..d7b3498 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +includes: + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-symfony/rules.neon + +parameters: + checkMissingIterableValueType: false diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..99ad480 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,25 @@ + + + + + + + + + ./tests + + + + + ./src + + + ./src/SmartParameterBundle.php + + + diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php new file mode 100644 index 0000000..53780f5 --- /dev/null +++ b/src/DependencyInjection/Configuration.php @@ -0,0 +1,41 @@ + + */ +class Configuration implements ConfigurationInterface +{ + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder('smart_parameter'); + $root = $treeBuilder->getRootNode(); + + $root + ->children() + ->append($this->getParametersNode()) + ->end() + ; + + return $treeBuilder; + } + + private function getParametersNode(): NodeDefinition + { + return (new TreeBuilder('parameters'))->getRootNode() + ->requiresAtLeastOneElement() + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->scalarNode('value')->isRequired()->end() + ->scalarNode('help')->end() + ->end() + ->end() + ; + } +} diff --git a/src/DependencyInjection/SmartParameterExtension.php b/src/DependencyInjection/SmartParameterExtension.php new file mode 100644 index 0000000..6fe34b1 --- /dev/null +++ b/src/DependencyInjection/SmartParameterExtension.php @@ -0,0 +1,23 @@ + + */ +class SmartParameterExtension extends Extension +{ + /** + * @param array $configs + * @param ContainerBuilder $container + * @throws \Exception + * @return void + */ + public function load(array $configs, ContainerBuilder $container) + { + $this->processConfiguration(new Configuration(), $configs); + } +} diff --git a/src/SmartParameterBundle.php b/src/SmartParameterBundle.php new file mode 100644 index 0000000..9f94b05 --- /dev/null +++ b/src/SmartParameterBundle.php @@ -0,0 +1,16 @@ + + */ +class SmartParameterBundle extends Bundle +{ + public function getPath(): string + { + return \dirname(__DIR__); + } +} diff --git a/src/tmp.php b/src/tmp.php deleted file mode 100644 index 0fb968e..0000000 --- a/src/tmp.php +++ /dev/null @@ -1,3 +0,0 @@ - + */ +class AppKernel extends Kernel +{ + public function registerBundles() + { + return [ + new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), + new SmartParameterBundle(), + ]; + } + + public function registerContainerConfiguration(LoaderInterface $loader): void + { + $loader->load(__DIR__ . '/../fixtures/config/full.yml'); + } +} diff --git a/tests/App/AppKernelTest.php b/tests/App/AppKernelTest.php new file mode 100644 index 0000000..3f749e5 --- /dev/null +++ b/tests/App/AppKernelTest.php @@ -0,0 +1,26 @@ + + * + * vendor/bin/phpunit tests/App/AppKernelTest.php + */ +class AppKernelTest extends WebTestCase +{ + protected static function getKernelClass() + { + return AppKernel::class; + } + + public function testBootingKernel(): void + { + self::bootKernel(); + + $this->assertInstanceOf(KernelInterface::class, self::$kernel); + } +} diff --git a/tests/DependencyInjection/DependencyInjectionTest.php b/tests/DependencyInjection/DependencyInjectionTest.php new file mode 100644 index 0000000..d47b1c4 --- /dev/null +++ b/tests/DependencyInjection/DependencyInjectionTest.php @@ -0,0 +1,84 @@ + + * + * vendor/bin/phpunit tests/DependencyInjection/DependencyInjectionTest.php + */ +class DependencyInjectionTest extends TestCase +{ + private ContainerBuilder $container; + + protected function setUp(): void + { + $bundle = new SmartParameterBundle(); + $this->container = new ContainerBuilder(); + + $this->container->setParameter('kernel.debug', true); + $this->container->setParameter('kernel.bundles', [ + 'FrameworkBundle' => \Symfony\Bundle\FrameworkBundle\FrameworkBundle::class, + ]); + $this->container->setParameter('kernel.environment', 'test'); + + $this->container->registerExtension($bundle->getContainerExtension()); + $bundle->build($this->container); + } + + /** + * @dataProvider invalidConfigurationProvider + */ + public function testInvalidConfigurationParsing(string $resource, string $message): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage($message); + + $loader = new YamlFileLoader($this->container, new FileLocator(__DIR__ . '/../fixtures/config/')); + $loader->load($resource . ".yml"); + $this->container->compile(); + } + + public function invalidConfigurationProvider(): array + { + return [ + 'invalid_no_parameter_defined' => [ + 'ressource' => 'invalid_no_parameter_defined', + 'message' => 'The path "smart_parameter.parameters" should have at least 1 element(s) defined.', + ], + 'invalid_missing_parameter_value' => [ + 'ressource' => 'invalid_missing_parameter_value', + 'message' => 'The child node "value" at path "smart_parameter.parameters.parameter_without_value" must be configured.', + ], + ]; + } + + /** + * @dataProvider configurationProvider + */ + public function testValidConfigurationParsing(string $resource): void + { + $loader = new YamlFileLoader($this->container, new FileLocator(__DIR__ . '/../fixtures/config/')); + $loader->load($resource . ".yml"); + $this->container->compile(); + // This assertion is already true with the setUp but it valid the fact that the container did compile with the given configuration + $this->assertNotNull($this->container->getExtension("smart_parameter")); + } + + public function configurationProvider(): array + { + return [ + 'full' => ['full'], + 'minimal' => ['minimal'], + 'none' => ['none'], + ]; + } +} diff --git a/tests/fixtures/config/full.yml b/tests/fixtures/config/full.yml new file mode 100644 index 0000000..aac4eb4 --- /dev/null +++ b/tests/fixtures/config/full.yml @@ -0,0 +1,11 @@ +# Full config fixture +smart_parameter: + parameters: + # Textual paramter + dummy_support_emails: + value: "support@example.com, technical-support@example.com" + help: "This parameter is used by the mailer for support recipients. Format : Separate email by comma." + # Number parameter + dummy_homepage_cache_duration: + value: 3600 + help: "This parameter is used by the backend to set the duration of cache applied to the Homepage. Set the duration in second." diff --git a/tests/fixtures/config/invalid_missing_parameter_value.yml b/tests/fixtures/config/invalid_missing_parameter_value.yml new file mode 100644 index 0000000..c47846b --- /dev/null +++ b/tests/fixtures/config/invalid_missing_parameter_value.yml @@ -0,0 +1,4 @@ +# +smart_parameter: + parameters: + parameter_without_value: diff --git a/tests/fixtures/config/invalid_no_parameter_defined.yml b/tests/fixtures/config/invalid_no_parameter_defined.yml new file mode 100644 index 0000000..d5bc9d2 --- /dev/null +++ b/tests/fixtures/config/invalid_no_parameter_defined.yml @@ -0,0 +1,3 @@ +# +smart_parameter: + parameters: diff --git a/tests/fixtures/config/minimal.yml b/tests/fixtures/config/minimal.yml new file mode 100644 index 0000000..4524bbc --- /dev/null +++ b/tests/fixtures/config/minimal.yml @@ -0,0 +1,5 @@ +# Config with only minimal parameter configuration +smart_parameter: + parameters: + dummy_parameter: + value: "some value" diff --git a/tests/fixtures/config/none.yml b/tests/fixtures/config/none.yml new file mode 100644 index 0000000..acdf27c --- /dev/null +++ b/tests/fixtures/config/none.yml @@ -0,0 +1,2 @@ +# Empty config +smart_parameter: ~