From e24ee5d62288946986e581bcd190a2be24888ecc Mon Sep 17 00:00:00 2001 From: julien Date: Mon, 16 Mar 2026 09:46:48 +0100 Subject: [PATCH] Working state --- tests/Post/PostExtensionTest.php | 22 ++++++- tests/Post/PostServiceCoverageTest.php | 66 +++++++++++++++++++ tests/Shared/ClientIpResolverCoverageTest.php | 35 ++++++++++ tests/Shared/FlashServiceCoverageTest.php | 26 ++++++++ tests/Shared/SessionManagerCoverageTest.php | 32 +++++++++ 5 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 tests/Post/PostServiceCoverageTest.php create mode 100644 tests/Shared/ClientIpResolverCoverageTest.php create mode 100644 tests/Shared/FlashServiceCoverageTest.php create mode 100644 tests/Shared/SessionManagerCoverageTest.php diff --git a/tests/Post/PostExtensionTest.php b/tests/Post/PostExtensionTest.php index 15b087e..74b5cd2 100644 --- a/tests/Post/PostExtensionTest.php +++ b/tests/Post/PostExtensionTest.php @@ -9,7 +9,6 @@ use PHPUnit\Framework\TestCase; use Twig\TwigFunction; #[\PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations] - final class PostExtensionTest extends TestCase { /** @var array */ @@ -25,6 +24,16 @@ final class PostExtensionTest extends TestCase } } + public function testRegistersExpectedTwigFunctions(): void + { + self::assertSame([ + 'post_excerpt', + 'post_url', + 'post_thumbnail', + 'post_initials', + ], array_keys($this->functions)); + } + public function testPostUrlUsesStoredSlug(): void { $post = new Post(1, 'Mon article', '

Contenu

', 'mon-article-2'); @@ -45,6 +54,13 @@ final class PostExtensionTest extends TestCase self::assertStringEndsWith('…', $excerpt); } + public function testPostExcerptReturnsOriginalHtmlWhenAlreadyShortEnough(): void + { + $post = new Post(10, 'Titre', '

Bonjour monde

', 'titre-10'); + + self::assertSame('Bonjour monde', $this->call('post_excerpt', $post, 100)); + } + public function testPostThumbnailReturnsFirstImageSource(): void { $post = new Post(1, 'Titre', '

a

', 'titre'); @@ -63,11 +79,11 @@ final class PostExtensionTest extends TestCase { $post = new Post(1, 'Article de Blog', '

Contenu

', 'slug'); $single = new Post(2, 'A B', '

Contenu

', 'slug-2'); - $emptyLike = new Post(3, 'A', '

Contenu

', 'slug-3'); + $stopWordsOnly = new Post(3, 'de la', '

Contenu

', 'slug-3'); self::assertSame('AB', $this->call('post_initials', $post)); self::assertSame('A', $this->call('post_initials', $single)); - self::assertSame('A', $this->call('post_initials', $emptyLike)); + self::assertSame('D', $this->call('post_initials', $stopWordsOnly)); } private function call(string $name, mixed ...$args): mixed diff --git a/tests/Post/PostServiceCoverageTest.php b/tests/Post/PostServiceCoverageTest.php new file mode 100644 index 0000000..0bb77f0 --- /dev/null +++ b/tests/Post/PostServiceCoverageTest.php @@ -0,0 +1,66 @@ +repository = $this->createMock(PostRepositoryInterface::class); + $this->sanitizer = $this->createMock(HtmlSanitizerInterface::class); + $this->service = new PostService($this->repository, $this->sanitizer); + } + + public function testGetAllPostsPassesCategoryIdToRepository(): void + { + $posts = [$this->makePost(1, 'Titre', 'titre')]; + $this->repository->expects($this->once())->method('findAll')->with(9)->willReturn($posts); + + self::assertSame($posts, $this->service->getAllPosts(9)); + } + + public function testGetRecentPostsPassesLimitToRepository(): void + { + $posts = [$this->makePost(2, 'Titre', 'titre-2')]; + $this->repository->expects($this->once())->method('findRecent')->with(7)->willReturn($posts); + + self::assertSame($posts, $this->service->getRecentPosts(7)); + } + + public function testCreatePostAddsNumericSuffixWhenBaseSlugAlreadyExists(): void + { + $this->sanitizer->expects($this->once())->method('sanitize')->with('

Brut

')->willReturn('

Sur

'); + $this->repository->expects($this->exactly(2)) + ->method('slugExists') + ->withAnyParameters() + ->willReturnOnConsecutiveCalls(true, false); + $this->repository->expects($this->once()) + ->method('create') + ->with($this->isInstanceOf(Post::class), 'mon-titre-1', 4, 8) + ->willReturn(99); + + self::assertSame(99, $this->service->createPost('Mon titre', '

Brut

', 4, 8)); + } + + private function makePost(int $id, string $title, string $slug, string $content = '

Contenu

'): Post + { + return new Post($id, $title, $content, $slug); + } +} diff --git a/tests/Shared/ClientIpResolverCoverageTest.php b/tests/Shared/ClientIpResolverCoverageTest.php new file mode 100644 index 0000000..0627b77 --- /dev/null +++ b/tests/Shared/ClientIpResolverCoverageTest.php @@ -0,0 +1,35 @@ +createServerRequest('GET', '/', [ + 'REMOTE_ADDR' => '127.0.0.1', + ]); + + $resolver = new ClientIpResolver(['127.0.0.1']); + + self::assertSame('127.0.0.1', $resolver->resolve($request)); + } + + public function testResolveTrimsForwardedIpWhenProxyWildcardIsTrusted(): void + { + $request = (new ServerRequestFactory())->createServerRequest('GET', '/', [ + 'REMOTE_ADDR' => '10.0.0.1', + 'HTTP_X_FORWARDED_FOR' => ' 203.0.113.77 , 198.51.100.12', + ]); + + $resolver = new ClientIpResolver(['*']); + + self::assertSame('203.0.113.77', $resolver->resolve($request)); + } +} diff --git a/tests/Shared/FlashServiceCoverageTest.php b/tests/Shared/FlashServiceCoverageTest.php new file mode 100644 index 0000000..edc0b46 --- /dev/null +++ b/tests/Shared/FlashServiceCoverageTest.php @@ -0,0 +1,26 @@ +get('flag')); + self::assertArrayNotHasKey('flag', $_SESSION['flash']); + } +} diff --git a/tests/Shared/SessionManagerCoverageTest.php b/tests/Shared/SessionManagerCoverageTest.php new file mode 100644 index 0000000..7272a35 --- /dev/null +++ b/tests/Shared/SessionManagerCoverageTest.php @@ -0,0 +1,32 @@ +manager = new SessionManager(); + } + + protected function tearDown(): void + { + $_SESSION = []; + } + + public function testGetUserIdCastsNumericStringToInteger(): void + { + $_SESSION['user_id'] = '42'; + + self::assertSame(42, $this->manager->getUserId()); + self::assertTrue($this->manager->isAuthenticated()); + } +}