diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..f5980e7 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,53 @@ +on: + - push + +name: Run Codecov checks + +jobs: + code-coverage: + name: Code Coverage + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.1" + - "8.2" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + coverage: pcov + ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + tools: composer:v2, cs2pr + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + + - name: Install dependencies with composer + run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Collect code coverage with PHPUnit + run: vendor/bin/phpunit --colors=always --coverage-clover clover.xml + + - name: Send code coverage report to Codecov.io + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/cs-tests.yml b/.github/workflows/cs-tests.yml new file mode 100644 index 0000000..3da9965 --- /dev/null +++ b/.github/workflows/cs-tests.yml @@ -0,0 +1,46 @@ +on: + - push + +name: Run phpcs checks + +jobs: + mutation: + name: PHP ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.1" + - "8.2" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + tools: composer:v2, cs2pr + coverage: none + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Run phpcs checks + run: vendor/bin/phpcs diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..74550fc --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,46 @@ +on: + - push + +name: Run static analysis + +jobs: + mutation: + name: PHP ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.1" + - "8.2" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + tools: composer:v2, cs2pr + coverage: none + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Run static analysis + run: vendor/bin/psalm --no-cache --output-format=github --show-info=false --threads=4 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..d2ab8e7 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,47 @@ +on: + - push + +name: Run PHPUnit tests + +jobs: + mutation: + name: PHP ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.1" + - "8.2" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + tools: composer:v2, cs2pr + coverage: none + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + + - name: Install dependencies with composer + run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Run PHPUnit tests + run: vendor/bin/phpunit --colors=always diff --git a/.gitignore b/.gitignore index f3e6777..bb774fc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ composer.lock # User-specific stuff: .idea +.phpunit.result.cache +.phpcs-cache ## File-based project format: *.iws diff --git a/README.md b/README.md index 78e96c7..ce59c26 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,17 @@ ![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-flashmessenger) -![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-flashmessenger/3.2.0) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-flashmessenger/3.4.0) [![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-flashmessenger)](https://github.com/dotkernel/dot-flashmessenger/issues) [![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-flashmessenger)](https://github.com/dotkernel/dot-flashmessenger/network) [![GitHub stars](https://img.shields.io/github/stars/dotkernel/dot-flashmessenger)](https://github.com/dotkernel/dot-flashmessenger/stargazers) -[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-flashmessenger)](https://github.com/dotkernel/dot-flashmessenger/blob/3.2.0/LICENSE.md) +[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-flashmessenger)](https://github.com/dotkernel/dot-flashmessenger/blob/3.0/LICENSE.md) + +[![Build Static](https://github.com/dotkernel/dot-flashmessenger/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-flashmessenger/actions/workflows/static-analysis.yml) + +[![SymfonyInsight](https://insight.symfony.com/projects/94ace687-5124-446f-a324-0ecca1b47f88/big.svg)](https://insight.symfony.com/projects/94ace687-5124-446f-a324-0ecca1b47f88) + Flash messenger library for session messages between redirects. A flash message, or session message is a piece of text data that survives one requests(available only in the next request). This library accepts session data as well, not just string messages, with the same behaviour. @@ -111,4 +116,4 @@ The flash messenger service Dot\FlashMessenger\View\RendererInterface::class ``` -The registered renderer class \ No newline at end of file +The registered renderer class diff --git a/composer.json b/composer.json index 0743596..6bd41c3 100644 --- a/composer.json +++ b/composer.json @@ -15,16 +15,23 @@ "flashmessenger", "laminas" ], + "config": { + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, "require": { - "php": "^7.4 || ~8.0.0 || ~8.1.0", - "psr/http-message": "^1.0.1", - "laminas/laminas-servicemanager": "^3.11.2", - "laminas/laminas-session": "^2.12" + "php": "~8.1.0 || ~8.2.0", + "psr/http-message": "^1.0 || ^2.0", + "laminas/laminas-servicemanager": "^3.21.0", + "laminas/laminas-session": "^2.16.0", + "mezzio/mezzio-template": "^2.8.0" }, "require-dev": { - "phpunit/phpunit": "^9.5.20", - "squizlabs/php_codesniffer": "^3.6.2", - "mezzio/mezzio-template": "^2.4.0" + "laminas/laminas-coding-standard": "^2.5.0", + "phpunit/phpunit": "^10.3.2", + "vimeo/psalm": "^5.14.1" }, "autoload": { "psr-4": { @@ -35,5 +42,16 @@ "psr-4": { "DotTest\\FlashMessenger\\": "test/" } + }, + "scripts": { + "check": [ + "@cs-check", + "@test" + ], + "cs-check": "phpcs", + "cs-fix": "phpcbf", + "test": "phpunit --colors=always", + "test-coverage": "phpunit --colors=always --coverage-clover clover.xml", + "static-analysis": "psalm --shepherd --stats" } } diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..1efe663 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + src + test + + + + diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..d6550d9 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + ./test + + + + + + ./src + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..7272b57 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 1e52ce4..a5aa06f 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -1,11 +1,6 @@ $this->getDependencyConfig(), - + 'dependencies' => $this->getDependencyConfig(), 'dot_flashmessenger' => [ 'options' => [ 'namespace' => 'dot_messenger', @@ -35,22 +25,19 @@ public function __invoke(): array ]; } - /** - * @return array - */ public function getDependencyConfig(): array { return [ 'factories' => [ - FlashMessenger::class => FlashMessengerFactory::class, - FlashMessengerOptions::class => FlashMessengerOptionsFactory::class, + FlashMessenger::class => FlashMessengerFactory::class, + FlashMessengerOptions::class => FlashMessengerOptionsFactory::class, FlashMessengerRenderer::class => FlashMessengerRendererFactory::class, ], - 'aliases' => [ + 'aliases' => [ FlashMessengerInterface::class => FlashMessenger::class, - RendererInterface::class => FlashMessengerRenderer::class, - 'FlashMessenger' => FlashMessenger::class, - ] + RendererInterface::class => FlashMessengerRenderer::class, + 'FlashMessenger' => FlashMessenger::class, + ], ]; } } diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php index 5708c1b..6c5ffe5 100644 --- a/src/Exception/ExceptionInterface.php +++ b/src/Exception/ExceptionInterface.php @@ -1,19 +1,9 @@ get(FlashMessengerOptions::class); - $options = $moduleOptions->getOptions() ?? []; + $options = $moduleOptions->getOptions() ?? []; if (isset($options['session_manager']) && is_string($options['session_manager'])) { if ($container->has($options['session_manager'])) { $options['session_manager'] = $container->get($options['session_manager']); } elseif (class_exists($options['session_manager'])) { - $class = $options['session_manager']; + $class = $options['session_manager']; $options['session_manager'] = new $class(); } } elseif ($container->has(ManagerInterface::class)) { diff --git a/src/Factory/FlashMessengerOptionsFactory.php b/src/Factory/FlashMessengerOptionsFactory.php index 4f1afb8..2ae9652 100644 --- a/src/Factory/FlashMessengerOptionsFactory.php +++ b/src/Factory/FlashMessengerOptionsFactory.php @@ -1,28 +1,21 @@ get('config')['dot_flashmessenger']); } diff --git a/src/Factory/FlashMessengerRendererFactory.php b/src/Factory/FlashMessengerRendererFactory.php index 455a7ba..37a265d 100644 --- a/src/Factory/FlashMessengerRendererFactory.php +++ b/src/Factory/FlashMessengerRendererFactory.php @@ -1,30 +1,23 @@ get(TemplateRendererInterface::class), diff --git a/src/FlashMessenger.php b/src/FlashMessenger.php index a106e84..4be3a18 100644 --- a/src/FlashMessenger.php +++ b/src/FlashMessenger.php @@ -1,11 +1,6 @@ setNamespace($options['namespace']); + } else { + throw new RuntimeException('Flash messenger need a namespace to be set'); } if (isset($options['session_manager']) && $options['session_manager'] instanceof ManagerInterface) { $this->setSessionManager($options['session_manager']); } - if (empty($this->namespace)) { - throw new RuntimeException('Flash messenger need a namespace to be set'); - } - $this->init(); } /** * Initialize the messenger with the previous session messages */ - public function init() + public function init(): void { $container = $this->getSessionContainer(); //get the messages and data that was set in the previous request @@ -76,12 +58,9 @@ public function init() } } - /** - * @return Container - */ public function getSessionContainer(): Container { - if (!$this->sessionContainer) { + if (! $this->sessionContainer) { $this->sessionContainer = new Container($this->namespace, $this->getSessionManager()); //start the session if not started already $this->sessionContainer->getManager()->start(); @@ -89,72 +68,51 @@ public function getSessionContainer(): Container return $this->sessionContainer; } - /** - * @param Container $container - */ - public function setSessionContainer(Container $container) + public function setSessionContainer(Container $container): void { $this->sessionContainer = $container; } - /** - * @return ManagerInterface - */ public function getSessionManager(): ManagerInterface { - if (!$this->sessionManager) { + if (! $this->sessionManager) { $this->sessionManager = new SessionManager(); } return $this->sessionManager; } - /** - * @param ManagerInterface $sessionManager - */ - public function setSessionManager(ManagerInterface $sessionManager) + public function setSessionManager(ManagerInterface $sessionManager): void { $this->sessionManager = $sessionManager; } - /** - * @param string $key - * @param mixed $value - * @param string $channel - */ - public function addData(string $key, $value, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) - { + public function addData( + string $key, + mixed $value, + string $channel = FlashMessengerInterface::DEFAULT_CHANNEL + ): void { $container = $this->getSessionContainer(); - if (!isset($container->data)) { + if (! isset($container->data)) { $container->data = []; } - if (!isset($container->data[$channel])) { + if (! isset($container->data[$channel])) { $container->data[$channel] = []; } $container->data[$channel][$key] = $value; } - /** - * @param string $key - * @param string $channel - * @return mixed|null - */ - public function getData(string $key, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) + public function getData(string $key, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): mixed { return isset($this->data[$channel]) ? $this->data[$channel][$key] ?? null : null; } - /** - * @param string|null $type - * @param string $channel - * @return array - */ public function getMessages( - string $type = null, + ?string $type = null, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL ): array { - if (!$type) { + if (! $type) { return $this->messages[$channel] ?? []; } @@ -162,90 +120,59 @@ public function getMessages( return isset($this->messages[$channel]) ? $this->messages[$channel][$type] ?? [] : []; } - /** - * @param mixed $error - * @param string $channel - */ - public function addError($error, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) - { - $this->addMessage(FlashMessengerInterface::ERROR, $error, $channel); - } - - /** - * Add flash message - * - * @param string $type The namespace to store the message under - * @param mixed $message Message to show on next request - * @param string $channel - */ - public function addMessage(string $type, $message, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) - { - if (!is_string($message) && !is_array($message)) { - throw new InvalidArgumentException('Flash message must be a string or an array of strings'); - } - + public function addMessage( + string $type, + string|array $message, + string $channel = FlashMessengerInterface::DEFAULT_CHANNEL + ): void { $container = $this->getSessionContainer(); - if (!isset($container->messages)) { + if (! isset($container->messages)) { $container->messages = []; } - if (!isset($container->messages[$channel])) { + if (! isset($container->messages[$channel])) { $container->messages[$channel] = []; } - if (!isset($container->messages[$channel][$type])) { + if (! isset($container->messages[$channel][$type])) { $container->messages[$channel][$type] = []; } - $message = (array)$message; - + $message = (array) $message; foreach ($message as $msg) { - if (!is_string($msg)) { + if (! is_string($msg)) { throw new InvalidArgumentException('Flash message must be a string or an array of strings'); } $container->messages[$channel][$type][] = $msg; } } - /** - * @param mixed $message - * @param string $channel - */ - public function addWarning($message, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) + public function addError(string|array $error, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): void { - $this->addMessage(FlashMessengerInterface::WARNING, $message, $channel); + $this->addMessage(FlashMessengerInterface::ERROR, $error, $channel); } - /** - * @param mixed $message - * @param string $channel - */ - public function addInfo($message, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) + public function addWarning(string|array $warning, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): void { - $this->addMessage(FlashMessengerInterface::INFO, $message, $channel); + $this->addMessage(FlashMessengerInterface::WARNING, $warning, $channel); } - /** - * @param mixed $message - * @param string $channel - */ - public function addSuccess($message, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL) + public function addInfo(string|array $info, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): void { - $this->addMessage(FlashMessengerInterface::SUCCESS, $message, $channel); + $this->addMessage(FlashMessengerInterface::INFO, $info, $channel); + } + + public function addSuccess(string|array $success, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): void + { + $this->addMessage(FlashMessengerInterface::SUCCESS, $success, $channel); } - /** - * @return string - */ public function getNamespace(): string { return $this->namespace; } - /** - * @param string $namespace - */ - public function setNamespace(string $namespace) + public function setNamespace(string $namespace): void { $this->namespace = $namespace; } diff --git a/src/FlashMessengerInterface.php b/src/FlashMessengerInterface.php index bac838a..973441d 100644 --- a/src/FlashMessengerInterface.php +++ b/src/FlashMessengerInterface.php @@ -1,83 +1,42 @@ options; } - /** - * @param array $options - */ - public function setOptions(array $options) + public function setOptions(array $options): void { $this->options = $options; } diff --git a/src/View/FlashMessengerRenderer.php b/src/View/FlashMessengerRenderer.php index dee0e72..c8e25d5 100644 --- a/src/View/FlashMessengerRenderer.php +++ b/src/View/FlashMessengerRenderer.php @@ -1,62 +1,47 @@ template = $template; + $this->template = $template; $this->flashMessenger = $flashMessenger; } - /** - * @param null|string $type - * @param string $channel - * @return string - */ - public function render(string $type = null, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL): string - { - //TODO: implement a default html rendering of the messages - return ''; + public function render( + string $template, + array $params = [], + ?string $type = null, + string $channel = FlashMessengerInterface::DEFAULT_CHANNEL + ): string { + $messages = $this->flashMessenger->getMessages($type, $channel); + + return $this->template->render( + $template, + array_merge( + ['messages' => $messages, 'messenger' => $this->flashMessenger, 'renderer' => $this], + $params + ) + ); } - /** - * @param string $partial - * @param array $params - * @param string|null $type - * @param string $channel - * @return string - */ public function renderPartial( string $partial, array $params = [], - string $type = null, + ?string $type = null, string $channel = FlashMessengerInterface::DEFAULT_CHANNEL ): string { $messages = $this->flashMessenger->getMessages($type, $channel); diff --git a/src/View/RendererInterface.php b/src/View/RendererInterface.php index b1a1987..2dffe54 100644 --- a/src/View/RendererInterface.php +++ b/src/View/RendererInterface.php @@ -1,43 +1,24 @@ [ + 'options' => [ + 'namespace' => 'dot_messenger', + 'session_manager' => SessionManager::class, + ], + ], + ]; +} diff --git a/test/ConfigProviderTest.php b/test/ConfigProviderTest.php new file mode 100644 index 0000000..08a8b83 --- /dev/null +++ b/test/ConfigProviderTest.php @@ -0,0 +1,70 @@ +config = (new ConfigProvider())(); + } + + public function testHasConfig(): void + { + $this->assertArrayHasKey('dependencies', $this->config); + $this->assertArrayHasKey('dot_flashmessenger', $this->config); + $this->assertArrayHasKey('options', $this->config['dot_flashmessenger']); + $this->assertArrayHasKey('namespace', $this->config['dot_flashmessenger']['options']); + + $this->assertSame('dot_messenger', $this->config['dot_flashmessenger']['options']['namespace']); + } + + public function testDependenciesHasFactories(): void + { + $this->assertArrayHasKey('factories', $this->config['dependencies']); + $this->assertSame( + FlashMessengerFactory::class, + $this->config['dependencies']['factories'][FlashMessenger::class] + ); + $this->assertSame( + FlashMessengerOptionsFactory::class, + $this->config['dependencies']['factories'][FlashMessengerOptions::class] + ); + $this->assertSame( + FlashMessengerRendererFactory::class, + $this->config['dependencies']['factories'][FlashMessengerRenderer::class] + ); + } + + public function testDependenciesHasAliases(): void + { + $this->assertArrayHasKey('aliases', $this->config['dependencies']); + $this->assertSame( + FlashMessenger::class, + $this->config['dependencies']['aliases'][FlashMessengerInterface::class] + ); + $this->assertSame( + FlashMessengerRenderer::class, + $this->config['dependencies']['aliases'][RendererInterface::class] + ); + $this->assertSame( + FlashMessenger::class, + $this->config['dependencies']['aliases']['FlashMessenger'] + ); + } +} diff --git a/test/Factory/FlashMessengerFactoryTest.php b/test/Factory/FlashMessengerFactoryTest.php new file mode 100644 index 0000000..f3dc097 --- /dev/null +++ b/test/Factory/FlashMessengerFactoryTest.php @@ -0,0 +1,149 @@ +container = $this->createMock(ContainerInterface::class); + $this->options = $this->createMock(FlashMessengerOptions::class); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + public function testCreateFlashMessengerWithFoundSessionManager(): void + { + $managerInterface = $this->createMock(ManagerInterface::class); + $this->options->expects($this->once()) + ->method('getOptions') + ->willReturn($this->config['dot_flashmessenger']['options']); + + $this->container->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + [FlashMessengerOptions::class, $this->options], + [$this->config['dot_flashmessenger']['options']['session_manager'], $managerInterface], + ]); + + $this->container->expects($this->once()) + ->method('has') + ->willReturn(true); + + $result = (new FlashMessengerFactory())($this->container, FlashMessenger::class); + + $this->assertInstanceOf(FlashMessenger::class, $result); + $this->assertSame('dot_messenger', $result->getNamespace()); + $this->assertSame($managerInterface, $result->getSessionManager()); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + public function testCreateFlashMessengerWithSessionManagerClass(): void + { + $this->options->expects($this->once()) + ->method('getOptions') + ->willReturn($this->config['dot_flashmessenger']['options']); + + $this->container->expects($this->once()) + ->method('get') + ->willReturn($this->options); + + $this->container->expects($this->once()) + ->method('has') + ->willReturn(false); + + $result = (new FlashMessengerFactory())($this->container, FlashMessenger::class); + + $this->assertInstanceOf(FlashMessenger::class, $result); + $this->assertSame('dot_messenger', $result->getNamespace()); + $this->assertInstanceOf( + $this->config['dot_flashmessenger']['options']['session_manager'], + $result->getSessionManager() + ); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + public function testCreateFlashMessengerWithDefaultSessionManager(): void + { + $managerInterface = $this->createMock(ManagerInterface::class); + $this->options->expects($this->once()) + ->method('getOptions') + ->willReturn(['namespace' => 'test_namespace']); + + $this->container->expects($this->once()) + ->method('has') + ->willReturn(true); + + $this->container->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + [FlashMessengerOptions::class, $this->options], + [ManagerInterface::class, $managerInterface], + ]); + + $result = (new FlashMessengerFactory())($this->container, FlashMessenger::class); + + $this->assertInstanceOf(FlashMessenger::class, $result); + $this->assertSame('test_namespace', $result->getNamespace()); + $this->assertInstanceOf(ManagerInterface::class, $result->getSessionManager()); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + public function testFlashMessengerNotCreatedWithoutNamespace(): void + { + $this->options->expects($this->once()) + ->method('getOptions') + ->willReturn(['namespace' => ['invalid namespace format']]); + + $this->container->expects($this->once()) + ->method('get') + ->willReturn($this->options); + + $this->container->expects($this->once()) + ->method('has') + ->willReturn(false); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Flash messenger need a namespace to be set'); + + (new FlashMessengerFactory())($this->container, FlashMessenger::class); + } +} diff --git a/test/Factory/FlashMessengerOptionsFactoryTest.php b/test/Factory/FlashMessengerOptionsFactoryTest.php new file mode 100644 index 0000000..7b39e47 --- /dev/null +++ b/test/Factory/FlashMessengerOptionsFactoryTest.php @@ -0,0 +1,35 @@ +createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('get') + ->willReturn($this->config); + + $result = (new FlashMessengerOptionsFactory())($container); + $this->assertInstanceOf(FlashMessengerOptions::class, $result); + } +} diff --git a/test/Factory/FlashMessengerRendererFactoryTest.php b/test/Factory/FlashMessengerRendererFactoryTest.php new file mode 100644 index 0000000..fb9790c --- /dev/null +++ b/test/Factory/FlashMessengerRendererFactoryTest.php @@ -0,0 +1,37 @@ +createMock(ContainerInterface::class); + $container->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + [TemplateRendererInterface::class, $this->createMock(TemplateRendererInterface::class)], + [FlashMessengerInterface::class, $this->createMock(FlashMessengerInterface::class)], + ]); + + $result = (new FlashMessengerRendererFactory())($container); + $this->assertInstanceOf(FlashMessengerRenderer::class, $result); + } +} diff --git a/test/FlashMessengerTest.php b/test/FlashMessengerTest.php index 50b2b27..1a0079e 100644 --- a/test/FlashMessengerTest.php +++ b/test/FlashMessengerTest.php @@ -1,20 +1,117 @@ subject = new FlashMessenger($this->config['dot_flashmessenger']['options']); + } + + /** + * @throws Exception + */ + public function testGettersAndSetters(): void + { + $namespace = 'test_namespace'; + $sessionManager = $this->createMock(ManagerInterface::class); + $sessionContainer = $this->createMock(Container::class); + + $this->subject->setNamespace($namespace); + $this->subject->setSessionManager($sessionManager); + $this->subject->setSessionContainer($sessionContainer); + + $this->assertSame($namespace, $this->subject->getNamespace()); + $this->assertSame($sessionManager, $this->subject->getSessionManager()); + $this->assertSame($sessionContainer, $this->subject->getSessionContainer()); + } + + public function testAddMessageRaisesExceptionForInvalidMessageFormat(): void + { + $invalidMessage = ['Invalid array format' => ['Invalid Key' => 'Invalid value']]; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Flash message must be a string or an array of strings'); + $this->subject->addMessage('error', $invalidMessage); + } + + public function testMessageAddingAndRetrieval(): void { - //... + $this->subject->addInfo('info message', 'success-channel'); + $this->subject->addSuccess('success message', 'success-channel'); + $this->subject->addWarning(['warning message'], 'error-channel'); + $this->subject->addError(['first error message', 'second error message'], 'error-channel'); + + $ref = new ReflectionObject($this->subject); + $container = $ref->getProperty('sessionContainer'); + $sessionContainer = $container->getValue($this->subject); + + $messages = $sessionContainer->messages; + + $this->assertArrayHasKey('success-channel', $messages); + $this->assertArrayHasKey('error-channel', $messages); + $this->assertArrayHasKey(FlashMessengerInterface::INFO, $messages['success-channel']); + $this->assertArrayHasKey(FlashMessengerInterface::SUCCESS, $messages['success-channel']); + $this->assertArrayHasKey(FlashMessengerInterface::WARNING, $messages['error-channel']); + $this->assertArrayHasKey(FlashMessengerInterface::ERROR, $messages['error-channel']); + $this->assertContains('info message', $messages['success-channel'][FlashMessengerInterface::INFO]); + $this->assertContains('success message', $messages['success-channel'][FlashMessengerInterface::SUCCESS]); + $this->assertContains('warning message', $messages['error-channel'][FlashMessengerInterface::WARNING]); + $this->assertContains('first error message', $messages['error-channel'][FlashMessengerInterface::ERROR]); + + //move messages from Session to FlashMessenger + $this->subject->init(); + + $successMessages = $this->subject->getMessages(null, 'success-channel'); + $errorMessages = $this->subject->getMessages(null, 'error-channel'); + $this->assertArrayHasKey(FlashMessengerInterface::INFO, $successMessages); + $this->assertArrayHasKey(FlashMessengerInterface::SUCCESS, $successMessages); + $this->assertArrayHasKey(FlashMessengerInterface::WARNING, $errorMessages); + $this->assertArrayHasKey(FlashMessengerInterface::ERROR, $errorMessages); + $this->assertContains('info message', $successMessages[FlashMessengerInterface::INFO]); + $this->assertContains('success message', $successMessages[FlashMessengerInterface::SUCCESS]); + $this->assertContains('warning message', $errorMessages[FlashMessengerInterface::WARNING]); + $this->assertContains('first error message', $errorMessages[FlashMessengerInterface::ERROR]); + + $this->assertContains( + 'info message', + $this->subject->getMessages(FlashMessengerInterface::INFO, 'success-channel') + ); + } + + public function testDataAddingAndRetrieval(): void + { + $this->subject->addData('test key', 'test data'); + + $ref = new ReflectionObject($this->subject); + $container = $ref->getProperty('sessionContainer'); + $sessionContainer = $container->getValue($this->subject); + + $sessionData = $sessionContainer->data; + + $this->assertArrayHasKey(FlashMessengerInterface::DEFAULT_CHANNEL, $sessionData); + $this->assertContains('test data', $sessionData[FlashMessengerInterface::DEFAULT_CHANNEL]); + + //move data from Session to FlashMessenger + $this->subject->init(); + + $data = $this->subject->getData('test key'); + $this->assertSame('test data', $data); } } diff --git a/test/Options/FlashMessengerOptionsTest.php b/test/Options/FlashMessengerOptionsTest.php new file mode 100644 index 0000000..ca599c2 --- /dev/null +++ b/test/Options/FlashMessengerOptionsTest.php @@ -0,0 +1,21 @@ + 'testValue']; + $subject = new FlashMessengerOptions(); + + $subject->setOptions($options); + $this->assertSame($options, $subject->getOptions()); + $this->assertArrayHasKey('testKey', $subject->getOptions()); + } +} diff --git a/test/View/FlashMessengerRendererTest.php b/test/View/FlashMessengerRendererTest.php new file mode 100644 index 0000000..701d8b9 --- /dev/null +++ b/test/View/FlashMessengerRendererTest.php @@ -0,0 +1,46 @@ +createMock(TemplateRendererInterface::class); + $flashMessenger = $this->createMock(FlashMessengerInterface::class); + $flashMessenger->expects($this->once()) + ->method('getMessages') + ->willReturn(['First error message', 'Second error message']); + + $subject = new FlashMessengerRenderer($rendererInterface, $flashMessenger); + $html = $subject->renderPartial('partial::test-partial', ['testParam'], 'error', 'test-channel'); + $this->assertIsString($html); + } + + /** + * @throws Exception + */ + public function testWillRenderTemplate(): void + { + $rendererInterface = $this->createMock(TemplateRendererInterface::class); + $flashMessenger = $this->createMock(FlashMessengerInterface::class); + $flashMessenger->expects($this->once()) + ->method('getMessages') + ->willReturn(['First error message', 'Second error message']); + + $subject = new FlashMessengerRenderer($rendererInterface, $flashMessenger); + $html = $subject->render('templateRoot::template', ['testParam'], 'error', 'test-channel'); + $this->assertIsString($html); + } +}