From 2175b8a7bba08622f2213c3f89dd8e7af9558cd3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 16 Feb 2019 21:58:14 +0100 Subject: [PATCH] Improved tests to increase MSI to 70% --- CHANGELOG.md | 1 + composer.json | 6 +- .../src/Exception/AuthenticationException.php | 4 +- .../JsonErrorResponseGeneratorTest.php | 30 ++++-- .../Exception/AuthenticationExceptionTest.php | 31 +++++++ .../VerifyAuthenticationExceptionTest.php | 93 +++++++++++++++++++ 6 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 module/Rest/test/Exception/AuthenticationExceptionTest.php create mode 100644 module/Rest/test/Exception/VerifyAuthenticationExceptionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 55963587..5a83475c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this * [#330](https://github.com/shlinkio/shlink/issues/330) No longer allow failures on PHP 7.3 envs during project CI build. * [#335](https://github.com/shlinkio/shlink/issues/335) Renamed functional test suite to database test suite, since that better describes what it actually does. * [#346](https://github.com/shlinkio/shlink/issues/346) Extracted installer as an independent tool. +* [#261](https://github.com/shlinkio/shlink/issues/261) Increased mutation score to 70%. #### Deprecated diff --git a/composer.json b/composer.json index ffdc2652..ed431a24 100644 --- a/composer.json +++ b/composer.json @@ -123,9 +123,9 @@ ], "test:unit:pretty": "phpdbg -qrr vendor/bin/phpunit --coverage-html build/coverage --order-by=random", - "infect": "infection --threads=4 --min-msi=65 --log-verbosity=default --only-covered", - "infect:ci": "infection --threads=4 --min-msi=65 --log-verbosity=default --only-covered --coverage=build", - "infect:show": "infection --threads=4 --min-msi=65 --log-verbosity=default --only-covered --show-mutations", + "infect": "infection --threads=4 --min-msi=70 --log-verbosity=default --only-covered", + "infect:ci": "infection --threads=4 --min-msi=70 --log-verbosity=default --only-covered --coverage=build", + "infect:show": "infection --threads=4 --min-msi=70 --log-verbosity=default --only-covered --show-mutations", "infect:test": [ "@test:unit:ci", "@infect:ci" diff --git a/module/Rest/src/Exception/AuthenticationException.php b/module/Rest/src/Exception/AuthenticationException.php index e1e0c9e4..2258ab30 100644 --- a/module/Rest/src/Exception/AuthenticationException.php +++ b/module/Rest/src/Exception/AuthenticationException.php @@ -3,11 +3,11 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Rest\Exception; -use Exception; +use Throwable; class AuthenticationException extends RuntimeException { - public static function expiredJWT(Exception $prev = null): self + public static function expiredJWT(?Throwable $prev = null): self { return new self('The token has expired.', -1, $prev); } diff --git a/module/Rest/test/ErrorHandler/JsonErrorResponseGeneratorTest.php b/module/Rest/test/ErrorHandler/JsonErrorResponseGeneratorTest.php index 3cb288da..22821854 100644 --- a/module/Rest/test/ErrorHandler/JsonErrorResponseGeneratorTest.php +++ b/module/Rest/test/ErrorHandler/JsonErrorResponseGeneratorTest.php @@ -7,6 +7,8 @@ use PHPUnit\Framework\TestCase; use Shlinkio\Shlink\Rest\ErrorHandler\JsonErrorResponseGenerator; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; +use function array_map; +use function range; class JsonErrorResponseGeneratorTest extends TestCase { @@ -18,27 +20,41 @@ class JsonErrorResponseGeneratorTest extends TestCase $this->errorHandler = new JsonErrorResponseGenerator(); } - /** - * @test - */ - public function noErrorStatusReturnsInternalServerError() + /** @test */ + public function noErrorStatusReturnsInternalServerError(): void { + /** @var Response\JsonResponse $response */ $response = $this->errorHandler->__invoke(null, new ServerRequest(), new Response()); + $payload = $response->getPayload(); + $this->assertInstanceOf(Response\JsonResponse::class, $response); $this->assertEquals(500, $response->getStatusCode()); + $this->assertEquals('Internal Server Error', $payload['message']); } /** * @test + * @dataProvider provideStatus */ - public function errorStatusReturnsThatStatus() + public function errorStatusReturnsThatStatus(int $status, string $message): void { + /** @var Response\JsonResponse $response */ $response = $this->errorHandler->__invoke( null, new ServerRequest(), - (new Response())->withStatus(405) + (new Response())->withStatus($status, $message) ); + $payload = $response->getPayload(); + $this->assertInstanceOf(Response\JsonResponse::class, $response); - $this->assertEquals(405, $response->getStatusCode()); + $this->assertEquals($status, $response->getStatusCode()); + $this->assertEquals($message, $payload['message']); + } + + public function provideStatus(): iterable + { + return array_map(function (int $status) { + return [$status, 'Some message']; + }, range(400, 500, 20)); } } diff --git a/module/Rest/test/Exception/AuthenticationExceptionTest.php b/module/Rest/test/Exception/AuthenticationExceptionTest.php new file mode 100644 index 00000000..f953d40e --- /dev/null +++ b/module/Rest/test/Exception/AuthenticationExceptionTest.php @@ -0,0 +1,31 @@ +assertEquals($prev, $e->getPrevious()); + $this->assertEquals(-1, $e->getCode()); + $this->assertEquals('The token has expired.', $e->getMessage()); + } + + public function providePrev() + { + yield 'with previous exception' => [new Exception('Prev')]; + yield 'without previous exception' => [null]; + } +} diff --git a/module/Rest/test/Exception/VerifyAuthenticationExceptionTest.php b/module/Rest/test/Exception/VerifyAuthenticationExceptionTest.php new file mode 100644 index 00000000..74fe9fc2 --- /dev/null +++ b/module/Rest/test/Exception/VerifyAuthenticationExceptionTest.php @@ -0,0 +1,93 @@ +assertEquals(0, $e->getCode()); + $this->assertEquals( + sprintf('Authentication verification failed with the public message "%s"', $message), + $e->getMessage() + ); + $this->assertEquals($code, $e->getErrorCode()); + $this->assertEquals($message, $e->getPublicMessage()); + $this->assertEquals($prev, $e->getPrevious()); + } + + public function provideExceptionData(): iterable + { + return array_map(function () { + return [ + $this->generateRandomString(), + $this->generateRandomString(50), + random_int(0, 1) === 1 ? new Exception('Prev') : null, + ]; + }, range(1, 10)); + } + + /** + * @test + * @dataProvider provideConstructorData + */ + public function constructCreatesExpectedException( + string $errorCode, + string $publicMessage, + string $message, + int $code, + ?Throwable $prev + ): void { + $e = new VerifyAuthenticationException($errorCode, $publicMessage, $message, $code, $prev); + + $this->assertEquals($code, $e->getCode()); + $this->assertEquals($message, $e->getMessage()); + $this->assertEquals($errorCode, $e->getErrorCode()); + $this->assertEquals($publicMessage, $e->getPublicMessage()); + $this->assertEquals($prev, $e->getPrevious()); + } + + public function provideConstructorData(): iterable + { + return array_map(function (int $i) { + return [ + $this->generateRandomString(), + $this->generateRandomString(30), + $this->generateRandomString(50), + $i, + random_int(0, 1) === 1 ? new Exception('Prev') : null, + ]; + }, range(10, 20)); + } + + /** @test */ + public function defaultConstructorValuesAreKept(): void + { + $e = new VerifyAuthenticationException('foo', 'bar'); + + $this->assertEquals(0, $e->getCode()); + $this->assertEquals('', $e->getMessage()); + $this->assertEquals('foo', $e->getErrorCode()); + $this->assertEquals('bar', $e->getPublicMessage()); + $this->assertNull($e->getPrevious()); + } +}