Skip to content

Commit

Permalink
add integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yceruto committed Sep 5, 2024
1 parent 5c52453 commit 31912e2
Show file tree
Hide file tree
Showing 22 changed files with 672 additions and 9 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

permissions:
contents: read

jobs:
tests:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
php:
- 8.2
- 8.3
- 8.4

steps:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
ini-values: zend.assertions=1

- name: Checkout code
uses: actions/checkout@v3

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --classmap-authoritative

- name: Run tests
run: vendor/bin/phpunit tests
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ class MyController
}
```

## Custom Decorator

Create a class that implement `DecoratorInterface` and add the basic decoration logic:

```php

```

## License

This software is published under the [MIT License](LICENSE)
8 changes: 7 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@
"symfony/framework-bundle": "^6.4|^7.0"
},
"require-dev": {
"doctrine/doctrine-bundle": "^2.13",
"doctrine/orm": "^3.2",
"friendsofphp/php-cs-fixer": "^3.64"
"friendsofphp/php-cs-fixer": "^3.64",
"phpunit/phpunit": "^11.3",
"symfony/browser-kit": "^7.1",
"symfony/mime": "^7.1",
"symfony/serializer": "^7.1",
"symfony/yaml": "^7.1"
},
"config": {
"sort-packages": true
Expand Down
16 changes: 16 additions & 0 deletions config/serializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Yceruto\DecoratorBundle\Decorator\Serializer\SerializerDecorator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

return static function (ContainerConfigurator $container): void {
$container->services()
->set(SerializerDecorator::class)
->args([
service('serializer'),
service('mime_types'),
])
->tag('decorator');
};
34 changes: 34 additions & 0 deletions src/Decorator/Serializer/Serialize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

/*
* This file is part of Decorator Bundle package.
*
* (c) Yonel Ceruto <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Yceruto\DecoratorBundle\Decorator\Serializer;

use Yceruto\Decorator\Attribute\Decorate;

#[\Attribute(\Attribute::TARGET_METHOD)]
final class Serialize extends Decorate
{
public function __construct(
string $format = 'json',
array $context = [],
int $status = 200,
array $headers = [],
) {
parent::__construct(SerializerDecorator::class, [
'format' => $format,
'context' => $context,
'status' => $status,
'headers' => $headers,
]);
}
}
51 changes: 51 additions & 0 deletions src/Decorator/Serializer/SerializerDecorator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

/*
* This file is part of Decorator Bundle package.
*
* (c) Yonel Ceruto <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Yceruto\DecoratorBundle\Decorator\Serializer;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mime\MimeTypesInterface;
use Symfony\Component\Serializer\Exception\UnsupportedFormatException;
use Symfony\Component\Serializer\SerializerInterface;
use Yceruto\Decorator\DecoratorInterface;

final readonly class SerializerDecorator implements DecoratorInterface
{
public function __construct(
private SerializerInterface $serializer,
private MimeTypesInterface $mimeTypes,
) {
}

public function decorate(\Closure $func, string $format = 'json', array $context = [], int $status = 200, array $headers = []): \Closure
{
$headers['Content-Type'] ??= current($this->mimeTypes->getMimeTypes($format)) ?: throw new UnsupportedFormatException(sprintf('Format "%s" is not supported.', $format));

return function (mixed ...$args) use ($func, $format, $context, $status, $headers): Response {
$result = $func(...$args);

if ($result instanceof RedirectResponse) {
return $result;
}

if (null === $result || '' === $result) {
return new Response(null, 204, $headers);
}

$content = $this->serializer->serialize($result, $format, $context);

return new Response($content, $status, $headers);
};
}
}
5 changes: 5 additions & 0 deletions src/DecoratorBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
use Symfony\Component\Serializer\SerializerInterface;
use Yceruto\Decorator\DecoratorInterface;
use Yceruto\DecoratorBundle\DependencyInjection\DecoratorsPass;

Expand All @@ -37,5 +38,9 @@ public function loadExtension(array $config, ContainerConfigurator $container, C
if (interface_exists(EntityManagerInterface::class)) {
$container->import('../config/doctrine.php');
}

if (interface_exists(SerializerInterface::class)) {
$container->import('../config/serializer.php');
}
}
}
88 changes: 88 additions & 0 deletions tests/Integration/AbstractWebTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

/*
* This file is part of Decorator Bundle package.
*
* (c) Yonel Ceruto <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Yceruto\DecoratorBundle\Tests\Integration;

use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
use Yceruto\DecoratorBundle\Tests\Integration\App\AppKernel;

class AbstractWebTestCase extends WebTestCase
{
public static function setUpBeforeClass(): void
{
static::deleteTmpDir();
}

public static function tearDownAfterClass(): void
{
static::deleteTmpDir();
}

protected static function deleteTmpDir(): void
{
if (!file_exists($dir = sys_get_temp_dir().'/'.static::getVarDir())) {
return;
}

$fs = new Filesystem();
$fs->remove($dir);
}

protected static function getKernelClass(): string
{
require_once __DIR__.'/App/AppKernel.php';

return AppKernel::class;
}

protected static function createClient(array $options = [], array $server = []): KernelBrowser
{
if (!isset($options['test_case'])) {
$options['test_case'] = static::getTestCase();
}

return parent::createClient($options, $server);
}

protected static function createKernel(array $options = []): KernelInterface
{
$class = self::getKernelClass();

if (!isset($options['test_case'])) {
$options['test_case'] = static::getTestCase();
}

return new $class(
static::getVarDir(),
$options['test_case'],
$options['root_config'] ?? 'config.yaml',
$options['environment'] ?? 'test',
$options['debug'] ?? true,
);
}

protected static function getVarDir(): string
{
return 'Decorator'.substr(strrchr(static::class, '\\'), 1);
}

protected static function getTestCase(): string
{
$parts = explode('\\', static::class);

return substr(end($parts), 0, -4);
}
}
92 changes: 92 additions & 0 deletions tests/Integration/App/AppKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

/*
* This file is part of Decorator Bundle package.
*
* (c) Yonel Ceruto <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Yceruto\DecoratorBundle\Tests\Integration\App;

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;

class AppKernel extends Kernel
{
use MicroKernelTrait;

private string $varDir;
private string $testCase;
private string $rootConfig;

public function __construct($varDir, $testCase, $rootConfig, $environment, $debug)
{
if (!is_dir(__DIR__.'/'.$testCase)) {
throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase));
}
$this->varDir = $varDir;
$this->testCase = $testCase;

$fs = new Filesystem();
if (!$fs->isAbsolutePath($rootConfig) && !file_exists($rootConfig = __DIR__.'/'.$testCase.'/'.$rootConfig)) {
$rootConfig = __DIR__.'/config.yaml';
}
$this->rootConfig = $rootConfig;

parent::__construct($environment, $debug);
}

public function registerBundles(): iterable
{
if (!file_exists($filename = $this->getProjectDir().'/'.$this->testCase.'/bundles.php')) {
$filename = $this->getProjectDir().'/bundles.php';
}

return include $filename;
}

public function getProjectDir(): string
{
return __DIR__;
}

public function getCacheDir(): string
{
return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/cache/'.$this->environment;
}

public function getLogDir(): string
{
return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/logs';
}

public function registerContainerConfiguration(LoaderInterface $loader): void
{
$loader->load($this->rootConfig);
}

public function __sleep(): array
{
return ['varDir', 'testCase', 'rootConfig', 'environment', 'debug'];
}

public function __wakeup(): void
{
$this->__construct($this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug);
}

protected function getKernelParameters(): array
{
$parameters = parent::getKernelParameters();
$parameters['kernel.test_case'] = $this->testCase;

return $parameters;
}
}
Loading

0 comments on commit 31912e2

Please sign in to comment.