diff --git a/.gitignore b/.gitignore index 87904ec..30e934c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/.phpcs-cache +/.phpunit.result.cache /clover.xml /composer.lock /coveralls-upload.json diff --git a/.travis.yml b/.travis.yml index e810782..863f0ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,26 +12,28 @@ env: matrix: fast_finish: true include: - - php: 7.1 + - php: 7.3 env: - DEPS=lowest - - php: 7.1 + - php: 7.3 env: - DEPS=latest - CS_CHECK=true - TEST_COVERAGE=true - - php: 7.2 + - php: 7.4 env: - DEPS=lowest - - php: 7.2 + - php: 7.4 env: - DEPS=latest - - php: 7.3 + - php: 8.0 env: - DEPS=lowest - - php: 7.3 + - COMPOSER_ARGS="--no-interaction --ignore-platform-reqs" + - php: 8.0 env: - DEPS=latest + - COMPOSER_ARGS="--no-interaction --ignore-platform-reqs" before_install: - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi @@ -44,7 +46,7 @@ install: - stty cols 120 && composer show script: - - if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; else composer test ; fi + - if [[ $TEST_COVERAGE == 'true' ]]; then XDEBUG_MODE=coverage composer test-coverage ; else composer test ; fi - if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi after_script: diff --git a/composer.json b/composer.json index 827ff13..cdd96e4 100644 --- a/composer.json +++ b/composer.json @@ -29,17 +29,14 @@ } }, "require": { - "php": "^7.1", + "php": "^7.3 || ~8.0.0", "laminas/laminas-zendframework-bridge": "^1.0", "mezzio/mezzio-session": "^1.0", "psr/http-server-middleware": "^1.0" }, "require-dev": { - "laminas/laminas-coding-standard": "~1.0.0", - "phpunit/phpunit": "^7.0.2" - }, - "conflict": { - "phpspec/prophecy": "<1.7.2" + "laminas/laminas-coding-standard": "~2.1.0", + "phpunit/phpunit": "^9.3" }, "autoload": { "psr-4": { diff --git a/phpcs.xml b/phpcs.xml index 4da1eed..1efe663 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,8 +1,20 @@ - - + + + + + + + + + + src test + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b6d1f38..ed14e16 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,15 +3,14 @@ xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true"> - - - ./test - - - - - - ./src - - + + + ./src + + + + + ./test + + diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 6c51d7a..f8a2651 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -12,18 +12,18 @@ class ConfigProvider { - public function __invoke() : array + public function __invoke(): array { return [ 'dependencies' => $this->getDependencies(), ]; } - public function getDependencies() : array + public function getDependencies(): array { return [ // Legacy Zend Framework aliases - 'aliases' => [ + 'aliases' => [ \Zend\Expressive\Flash\FlashMessageMiddleware::class => FlashMessageMiddleware::class, ], 'invokables' => [ diff --git a/src/Exception/InvalidFlashMessagesImplementationException.php b/src/Exception/InvalidFlashMessagesImplementationException.php index 37400ee..0882e63 100644 --- a/src/Exception/InvalidFlashMessagesImplementationException.php +++ b/src/Exception/InvalidFlashMessagesImplementationException.php @@ -18,7 +18,7 @@ class InvalidFlashMessagesImplementationException extends InvalidArgumentException implements ExceptionInterface { - public static function forClass(string $class) : self + public static function forClass(string $class): self { return new self(sprintf( 'Cannot use "%s" within %s; does not implement %s', diff --git a/src/Exception/InvalidHopsValueException.php b/src/Exception/InvalidHopsValueException.php index a317a69..77d64a6 100644 --- a/src/Exception/InvalidHopsValueException.php +++ b/src/Exception/InvalidHopsValueException.php @@ -16,7 +16,7 @@ class InvalidHopsValueException extends InvalidArgumentException implements ExceptionInterface { - public static function valueTooLow(string $key, int $hops) : self + public static function valueTooLow(string $key, int $hops): self { return new self(sprintf( 'Hops value specified for flash message "%s" was too low; must be greater than 0, received %d', diff --git a/src/Exception/MissingSessionException.php b/src/Exception/MissingSessionException.php index 924f6d5..41d75cd 100644 --- a/src/Exception/MissingSessionException.php +++ b/src/Exception/MissingSessionException.php @@ -18,7 +18,7 @@ class MissingSessionException extends RuntimeException implements ExceptionInterface { - public static function forMiddleware(MiddlewareInterface $middleware) + public static function forMiddleware(MiddlewareInterface $middleware): MissingSessionException { return new self(sprintf( 'Unable to create flash messages in %s; missing session attribute', diff --git a/src/FlashMessageMiddleware.php b/src/FlashMessageMiddleware.php index b11ed76..62fafd0 100644 --- a/src/FlashMessageMiddleware.php +++ b/src/FlashMessageMiddleware.php @@ -25,19 +25,13 @@ class FlashMessageMiddleware implements MiddlewareInterface { public const FLASH_ATTRIBUTE = 'flash'; - /** - * @var string - */ + /** @var string */ private $attributeKey; - /** - * @var callable - */ + /** @var callable */ private $flashMessageFactory; - /** - * @var string - */ + /** @var string */ private $sessionKey; public function __construct( @@ -45,18 +39,19 @@ public function __construct( string $sessionKey = FlashMessagesInterface::FLASH_NEXT, string $attributeKey = self::FLASH_ATTRIBUTE ) { - if (! class_exists($flashMessagesClass) + if ( + ! class_exists($flashMessagesClass) || ! in_array(FlashMessagesInterface::class, class_implements($flashMessagesClass), true) ) { throw Exception\InvalidFlashMessagesImplementationException::forClass($flashMessagesClass); } $this->flashMessageFactory = [$flashMessagesClass, 'createFromSession']; - $this->sessionKey = $sessionKey; - $this->attributeKey = $attributeKey; + $this->sessionKey = $sessionKey; + $this->attributeKey = $attributeKey; } - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE, false); if (! $session instanceof SessionInterface) { diff --git a/src/FlashMessages.php b/src/FlashMessages.php index 9ecf1ab..c2d65ec 100644 --- a/src/FlashMessages.php +++ b/src/FlashMessages.php @@ -35,24 +35,18 @@ */ class FlashMessages implements FlashMessagesInterface { - /** - * @var array - */ + /** @var array */ private $currentMessages = []; - /** - * @var SessionInterface - */ + /** @var SessionInterface */ private $session; - /** - * @var string - */ + /** @var string */ private $sessionKey; private function __construct(SessionInterface $session, string $sessionKey) { - $this->session = $session; + $this->session = $session; $this->sessionKey = $sessionKey; $this->prepareMessages($session, $sessionKey); } @@ -63,7 +57,7 @@ private function __construct(SessionInterface $session, string $sessionKey) public static function createFromSession( SessionInterface $session, string $sessionKey = FlashMessagesInterface::FLASH_NEXT - ) : FlashMessagesInterface { + ): FlashMessagesInterface { return new self($session, $sessionKey); } @@ -77,13 +71,13 @@ public static function createFromSession( * @param mixed $value * @throws Exception\InvalidHopsValueException */ - public function flash(string $key, $value, int $hops = 1) : void + public function flash(string $key, $value, int $hops = 1): void { if ($hops < 1) { throw Exception\InvalidHopsValueException::valueTooLow($key, $hops); } - $messages = $this->session->get($this->sessionKey, []); + $messages = $this->session->get($this->sessionKey, []); $messages[$key] = [ 'value' => $value, 'hops' => $hops, @@ -100,7 +94,7 @@ public function flash(string $key, $value, int $hops = 1) : void * * @param mixed $value */ - public function flashNow(string $key, $value, int $hops = 1) : void + public function flashNow(string $key, $value, int $hops = 1): void { $this->currentMessages[$key] = $value; $this->flash($key, $value, $hops); @@ -132,7 +126,7 @@ public function getFlash(string $key, $default = null) * * @return array */ - public function getFlashes() : array + public function getFlashes(): array { return $this->currentMessages; } @@ -142,7 +136,7 @@ public function getFlashes() : array * * Affects the next and subsequent requests. */ - public function clearFlash() : void + public function clearFlash(): void { $this->session->unset($this->sessionKey); } @@ -150,7 +144,7 @@ public function clearFlash() : void /** * Prolongs any current flash messages for one more hop. */ - public function prolongFlash() : void + public function prolongFlash(): void { $messages = $this->session->get($this->sessionKey, []); foreach ($this->currentMessages as $key => $value) { @@ -162,7 +156,7 @@ public function prolongFlash() : void } } - public function prepareMessages(SessionInterface $session, string $sessionKey) : void + public function prepareMessages(SessionInterface $session, string $sessionKey): void { if (! $session->has($sessionKey)) { return; @@ -180,7 +174,7 @@ public function prepareMessages(SessionInterface $session, string $sessionKey) : continue; } - $data['hops'] -= 1; + $data['hops'] -= 1; $sessionMessages[$key] = $data; } diff --git a/src/FlashMessagesInterface.php b/src/FlashMessagesInterface.php index 00e55b8..dfc1ceb 100644 --- a/src/FlashMessagesInterface.php +++ b/src/FlashMessagesInterface.php @@ -28,7 +28,7 @@ interface FlashMessagesInterface public static function createFromSession( SessionInterface $session, string $sessionKey = self::FLASH_NEXT - ) : FlashMessagesInterface; + ): FlashMessagesInterface; /** * Set a flash value with the given key. @@ -39,7 +39,7 @@ public static function createFromSession( * * @param mixed $value */ - public function flash(string $key, $value, int $hops = 1) : void; + public function flash(string $key, $value, int $hops = 1): void; /** * Set a flash value with the given key, but allow access during this request. @@ -50,7 +50,7 @@ public function flash(string $key, $value, int $hops = 1) : void; * * @param mixed $value */ - public function flashNow(string $key, $value, int $hops = 1) : void; + public function flashNow(string $key, $value, int $hops = 1): void; /** * Retrieve a flash value. @@ -75,17 +75,17 @@ public function getFlash(string $key, $default = null); * * @return array */ - public function getFlashes() : array; + public function getFlashes(): array; /** * Clear all flash values. * * Affects the next and subsequent requests. */ - public function clearFlash() : void; + public function clearFlash(): void; /** * Prolongs any current flash messages for one more hop. */ - public function prolongFlash() : void; + public function prolongFlash(): void; } diff --git a/test/ConfigProviderTest.php b/test/ConfigProviderTest.php index 9e1b05e..dbbdae5 100644 --- a/test/ConfigProviderTest.php +++ b/test/ConfigProviderTest.php @@ -15,15 +15,18 @@ class ConfigProviderTest extends TestCase { - public function setUp() + /** @var ConfigProvider */ + private $provider; + + public function setUp(): void { $this->provider = new ConfigProvider(); } - public function testInvocationReturnsArray() + public function testInvocationReturnsArray(): array { $config = ($this->provider)(); - $this->assertInternalType('array', $config); + $this->assertIsArray($config); return $config; } @@ -33,6 +36,6 @@ public function testInvocationReturnsArray() public function testReturnedArrayContainsDependencies(array $config) { $this->assertArrayHasKey('dependencies', $config); - $this->assertInternalType('array', $config['dependencies']); + $this->assertIsArray($config['dependencies']); } } diff --git a/test/FlashMessageMiddlewareTest.php b/test/FlashMessageMiddlewareTest.php index 00f3a6d..3d35412 100644 --- a/test/FlashMessageMiddlewareTest.php +++ b/test/FlashMessageMiddlewareTest.php @@ -16,7 +16,6 @@ use Mezzio\Session\SessionInterface; use Mezzio\Session\SessionMiddleware; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -40,43 +39,64 @@ public function testConstructorRaisesExceptionIfFlashMessagesClassDoesNotImpleme public function testProcessRaisesExceptionIfRequestSessionAttributeDoesNotReturnSessionInterface() { - $request = $this->prophesize(ServerRequestInterface::class); - $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE, false)->willReturn(false); - $request->withAttribute( - FlashMessageMiddleware::FLASH_ATTRIBUTE, - Argument::type(FlashMessagesInterface::class) - )->shouldNotBeCalled(); - - $handler = $this->prophesize(RequestHandlerInterface::class); - $handler->handle(Argument::type(ServerRequestInterface::class))->shouldNotBeCalled(); + $request = $this->createMock(ServerRequestInterface::class); + $request + ->expects($this->once()) + ->method('getAttribute') + ->with(SessionMiddleware::SESSION_ATTRIBUTE, false) + ->willReturn(false); + $request + ->expects($this->never()) + ->method('withAttribute') + ->with( + FlashMessageMiddleware::FLASH_ATTRIBUTE, + $this->isInstanceOf(FlashMessagesInterface::class) + ); + + $handler = $this->createMock(RequestHandlerInterface::class); + $handler + ->expects($this->never()) + ->method('handle') + ->with($this->isInstanceOf(ServerRequestInterface::class)); $middleware = new FlashMessageMiddleware(); $this->expectException(Exception\MissingSessionException::class); $this->expectExceptionMessage(FlashMessageMiddleware::class); - $middleware->process($request->reveal(), $handler->reveal()); + $middleware->process($request, $handler); } public function testProcessUsesConfiguredClassAndSessionKeyAndAttributeKeyToCreateFlashMessagesAndPassToHandler() { - $session = $this->prophesize(SessionInterface::class)->reveal(); - - $request = $this->prophesize(ServerRequestInterface::class); - $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE, false)->willReturn($session); - $request->withAttribute( - 'non-standard-flash-attr', - Argument::that(function (TestAsset\FlashMessages $flash) use ($session) { - $this->assertSame($session, $flash->session); - $this->assertSame('non-standard-flash-next', $flash->sessionKey); - return $flash; - }) - )->will([$request, 'reveal']); - - $response = $this->prophesize(ResponseInterface::class)->reveal(); - - $handler = $this->prophesize(RequestHandlerInterface::class); - $handler->handle(Argument::that([$request, 'reveal']))->willReturn($response); + $session = $this->createMock(SessionInterface::class); + + $request = $this->createMock(ServerRequestInterface::class); + $request + ->expects($this->once()) + ->method('getAttribute') + ->with(SessionMiddleware::SESSION_ATTRIBUTE, false) + ->willReturn($session); + $request + ->expects($this->once()) + ->method('withAttribute') + ->with( + 'non-standard-flash-attr', + $this->callback(function (TestAsset\FlashMessages $flash) use ($session) { + $this->assertSame($session, $flash->session); + $this->assertSame('non-standard-flash-next', $flash->sessionKey); + return true; + }) + )->will($this->returnSelf()); + + $response = $this->createMock(ResponseInterface::class); + + $handler = $this->createMock(RequestHandlerInterface::class); + $handler + ->expects($this->once()) + ->method('handle') + ->with($request) + ->willReturn($response); $middleware = new FlashMessageMiddleware( TestAsset\FlashMessages::class, @@ -86,7 +106,7 @@ public function testProcessUsesConfiguredClassAndSessionKeyAndAttributeKeyToCrea $this->assertSame( $response, - $middleware->process($request->reveal(), $handler->reveal()) + $middleware->process($request, $handler) ); } } diff --git a/test/FlashMessagesTest.php b/test/FlashMessagesTest.php index 81ae495..530f9bc 100644 --- a/test/FlashMessagesTest.php +++ b/test/FlashMessagesTest.php @@ -10,32 +10,44 @@ namespace MezzioTest\Flash; +use Mezzio\Flash\Exception\InvalidHopsValueException; use Mezzio\Flash\FlashMessages; use Mezzio\Flash\FlashMessagesInterface; use Mezzio\Session\SessionInterface; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class FlashMessagesTest extends TestCase { - public function setUp() + /** @var SessionInterface|MockObject */ + private $session; + + public function setUp(): void { - $this->session = $this->prophesize(SessionInterface::class); + $this->session = $this->createMock(SessionInterface::class); } public function testCreationAggregatesNothingIfNoMessagesExistUnderSpecifiedSessionKey() { - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(false); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->shouldNotBeCalled(); + $this->session + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(false); + $this->session + ->expects($this->never()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); - $this->assertAttributeSame([], 'currentMessages', $flash); + $this->assertSame([], $flash->getFlashes()); } public function testCreationAggregatesItemsMarkedNextAndRemovesThemFromSession() { $messages = [ - 'test' => [ + 'test' => [ 'hops' => 1, 'value' => 'value1', ], @@ -45,11 +57,22 @@ public function testCreationAggregatesItemsMarkedNextAndRemovesThemFromSession() ], ]; - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(true); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->willReturn($messages); - $this->session->unset(FlashMessagesInterface::FLASH_NEXT)->shouldBeCalled(); + $this->session + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(true); + $this->session + ->expects($this->once()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn($messages); + $this->session + ->expects($this->once()) + ->method('unset') + ->with(FlashMessagesInterface::FLASH_NEXT); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); $this->assertSame('value1', $flash->getFlash('test')); @@ -59,8 +82,8 @@ public function testCreationAggregatesItemsMarkedNextAndRemovesThemFromSession() public function testCreationAggregatesPersistsItemsWithMultipleHopsInSessionWithDecrementedHops() { - $messages = [ - 'test' => [ + $messages = [ + 'test' => [ 'hops' => 3, 'value' => 'value1', ], @@ -69,20 +92,29 @@ public function testCreationAggregatesPersistsItemsWithMultipleHopsInSessionWith 'value' => 'value2', ], ]; - $messagesExpected = $messages; - $messagesExpected['test']['hops'] = 2; + $messagesExpected = $messages; + $messagesExpected['test']['hops'] = 2; $messagesExpected['test-2']['hops'] = 1; - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(true); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->willReturn($messages); $this->session - ->set( + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(true); + $this->session + ->expects($this->once()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn($messages); + $this->session + ->expects($this->once()) + ->method('set') + ->with( FlashMessagesInterface::FLASH_NEXT, $messagesExpected - ) - ->shouldBeCalled(); + ); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); $this->assertSame('value1', $flash->getFlash('test')); @@ -92,11 +124,20 @@ public function testCreationAggregatesPersistsItemsWithMultipleHopsInSessionWith public function testFlashingAValueMakesItAvailableInNextSessionButNotFlashMessages() { - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(false); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->shouldNotBeCalled(); - $this->session->get(FlashMessagesInterface::FLASH_NEXT, [])->willReturn([]); $this->session - ->set( + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(false); + $this->session + ->expects($this->once()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT, []) + ->willReturn([]); + $this->session + ->expects($this->once()) + ->method('set') + ->with( FlashMessagesInterface::FLASH_NEXT, [ 'test' => [ @@ -104,10 +145,9 @@ public function testFlashingAValueMakesItAvailableInNextSessionButNotFlashMessag 'hops' => 1, ], ] - ) - ->shouldBeCalled(); + ); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $flash->flash('test', 'value'); $this->assertNull($flash->getFlash('test')); @@ -116,11 +156,20 @@ public function testFlashingAValueMakesItAvailableInNextSessionButNotFlashMessag public function testFlashNowMakesValueAvailableBothInNextSessionAndCurrentFlashMessages() { - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(false); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->shouldNotBeCalled(); - $this->session->get(FlashMessagesInterface::FLASH_NEXT, [])->willReturn([]); $this->session - ->set( + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(false); + $this->session + ->expects($this->once()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT, []) + ->willReturn([]); + $this->session + ->expects($this->once()) + ->method('set') + ->with( FlashMessagesInterface::FLASH_NEXT, [ 'test' => [ @@ -128,10 +177,9 @@ public function testFlashNowMakesValueAvailableBothInNextSessionAndCurrentFlashM 'hops' => 1, ], ] - ) - ->shouldBeCalled(); + ); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $flash->flashNow('test', 'value'); $this->assertSame('value', $flash->getFlash('test')); @@ -141,7 +189,7 @@ public function testFlashNowMakesValueAvailableBothInNextSessionAndCurrentFlashM public function testProlongFlashAddsCurrentMessagesToNextSession() { $messages = [ - 'test' => [ + 'test' => [ 'hops' => 1, 'value' => 'value1', ], @@ -151,36 +199,47 @@ public function testProlongFlashAddsCurrentMessagesToNextSession() ], ]; - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(true); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->willReturn($messages); - $this->session->unset(FlashMessagesInterface::FLASH_NEXT)->shouldBeCalled(); - - $this->session->get(FlashMessagesInterface::FLASH_NEXT, [])->willReturn([]); + $this->session + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(true); + $this->session + ->method('get') + ->withConsecutive( + [FlashMessagesInterface::FLASH_NEXT], + [FlashMessagesInterface::FLASH_NEXT, []] + ) + ->willReturnOnConsecutiveCalls($messages, []); + $this->session + ->expects($this->once()) + ->method('unset') + ->with(FlashMessagesInterface::FLASH_NEXT); $this->session - ->set( - FlashMessagesInterface::FLASH_NEXT, + ->method('set') + ->withConsecutive( [ - 'test' => [ - 'value' => 'value1', - 'hops' => 1, + FlashMessagesInterface::FLASH_NEXT, + [ + 'test' => [ + 'value' => 'value1', + 'hops' => 1, + ], ], - ] - ) - ->shouldBeCalled(); - $this->session - ->set( - FlashMessagesInterface::FLASH_NEXT, + ], [ - 'test-2' => [ - 'value' => 'value2', - 'hops' => 1, + FlashMessagesInterface::FLASH_NEXT, + [ + 'test-2' => [ + 'value' => 'value2', + 'hops' => 1, + ], ], ] - ) - ->shouldBeCalled(); + ); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); $this->assertSame('value1', $flash->getFlash('test')); @@ -192,8 +251,8 @@ public function testProlongFlashAddsCurrentMessagesToNextSession() public function testProlongFlashDoesNotReFlashMessagesThatAlreadyHaveMoreHops() { - $messages = [ - 'test' => [ + $messages = [ + 'test' => [ 'hops' => 3, 'value' => 'value1', ], @@ -202,25 +261,32 @@ public function testProlongFlashDoesNotReFlashMessagesThatAlreadyHaveMoreHops() 'value' => 'value2', ], ]; - $messagesExpected = $messages; - $messagesExpected['test']['hops'] = 2; + $messagesExpected = $messages; + $messagesExpected['test']['hops'] = 2; $messagesExpected['test-2']['hops'] = 1; - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(true); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->willReturn($messages); $this->session - ->set( - FlashMessagesInterface::FLASH_NEXT, - $messagesExpected + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(true); + $this->session + ->expects($this->atMost(2)) + ->method('get') + ->withConsecutive( + [FlashMessagesInterface::FLASH_NEXT], + [FlashMessagesInterface::FLASH_NEXT, []] ) - ->shouldBeCalledTimes(1); - + ->willReturnOnConsecutiveCalls($messages, $messagesExpected); $this->session - ->get(FlashMessagesInterface::FLASH_NEXT, []) - ->willReturn($messagesExpected) - ->shouldBeCalledTimes(1); + ->expects($this->once()) + ->method('set') + ->with( + FlashMessagesInterface::FLASH_NEXT, + $messagesExpected + ); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); $this->assertSame('value1', $flash->getFlash('test')); @@ -232,8 +298,8 @@ public function testProlongFlashDoesNotReFlashMessagesThatAlreadyHaveMoreHops() public function testClearFlashShouldRemoveAnyUnexpiredMessages() { - $messages = [ - 'test' => [ + $messages = [ + 'test' => [ 'hops' => 3, 'value' => 'value1', ], @@ -242,21 +308,33 @@ public function testClearFlashShouldRemoveAnyUnexpiredMessages() 'value' => 'value2', ], ]; - $messagesExpected = $messages; - $messagesExpected['test']['hops'] = 2; + $messagesExpected = $messages; + $messagesExpected['test']['hops'] = 2; $messagesExpected['test-2']['hops'] = 1; - $this->session->has(FlashMessagesInterface::FLASH_NEXT)->willReturn(true); - $this->session->get(FlashMessagesInterface::FLASH_NEXT)->willReturn($messages); $this->session - ->set( + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(true); + $this->session + ->expects($this->once()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn($messages); + $this->session + ->expects($this->once()) + ->method('set') + ->with( FlashMessagesInterface::FLASH_NEXT, $messagesExpected - ) - ->shouldBeCalled(); - $this->session->unset(FlashMessagesInterface::FLASH_NEXT)->shouldBeCalled(); + ); + $this->session + ->expects($this->once()) + ->method('unset') + ->with(FlashMessagesInterface::FLASH_NEXT); - $flash = FlashMessages::createFromSession($this->session->reveal()); + $flash = FlashMessages::createFromSession($this->session); $this->assertInstanceOf(FlashMessages::class, $flash); $this->assertSame('value1', $flash->getFlash('test')); @@ -264,4 +342,30 @@ public function testClearFlashShouldRemoveAnyUnexpiredMessages() $this->assertSame(['test' => 'value1', 'test-2' => 'value2'], $flash->getFlashes()); $flash->clearFlash(); } + + public function testCreationAggregatesThrowsExceptionIfInvalidNumberOfHops() + { + $this->expectException(InvalidHopsValueException::class); + + $this->session + ->expects($this->once()) + ->method('has') + ->with(FlashMessagesInterface::FLASH_NEXT) + ->willReturn(false); + $this->session + ->expects($this->never()) + ->method('get') + ->with(FlashMessagesInterface::FLASH_NEXT, []) + ->willReturn([]); + $this->session + ->expects($this->never()) + ->method('set') + ->with( + $this->anything(), + $this->anything() + ); + + $flash = FlashMessages::createFromSession($this->session); + $flash->flashNow('test', 'value', 0); + } } diff --git a/test/TestAsset/FlashMessages.php b/test/TestAsset/FlashMessages.php index 0205524..292d9f5 100644 --- a/test/TestAsset/FlashMessages.php +++ b/test/TestAsset/FlashMessages.php @@ -15,44 +15,56 @@ class FlashMessages implements FlashMessagesInterface { + /** @var SessionInterface */ public $session; + /** @var string */ public $sessionKey; public function __construct(SessionInterface $session, string $sessionKey) { - $this->session = $session; + $this->session = $session; $this->sessionKey = $sessionKey; } public static function createFromSession( SessionInterface $session, string $sessionKey = 'this-should-not-be-used' - ) : FlashMessagesInterface { + ): FlashMessagesInterface { return new self($session, $sessionKey); } - public function flash(string $key, $value, int $hops = 1) : void + /** + * @param mixed $value + */ + public function flash(string $key, $value, int $hops = 1): void { } - public function flashNow(string $key, $value, int $hops = 1) : void + /** + * @param mixed $value + */ + public function flashNow(string $key, $value, int $hops = 1): void { } + /** + * @param null $default + * @return mixed|void + */ public function getFlash(string $key, $default = null) { } - public function getFlashes() : array + public function getFlashes(): array { return []; } - public function clearFlash() : void + public function clearFlash(): void { } - public function prolongFlash() : void + public function prolongFlash(): void { } }