From fd91da6bab68a977c6ff85a7865ccd8fd396f7e7 Mon Sep 17 00:00:00 2001 From: yisroel Date: Wed, 6 May 2026 15:26:28 +0300 Subject: [PATCH] test DeletePost use case 7 cases: zero postId or requesterId -> BadRequest; unknown post is idempotent no-op; author can delete own post; admin can delete anyone's post; non-author non-admin -> ForbiddenException; forbidden attempts leave post intact. --- .../Unit/Post/UseCases/DeletePostTest.php | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 backend/tests/Unit/Post/UseCases/DeletePostTest.php diff --git a/backend/tests/Unit/Post/UseCases/DeletePostTest.php b/backend/tests/Unit/Post/UseCases/DeletePostTest.php new file mode 100644 index 0000000..699c9d1 --- /dev/null +++ b/backend/tests/Unit/Post/UseCases/DeletePostTest.php @@ -0,0 +1,132 @@ +now = new DateTimeImmutable( + '2026-05-06T12:00:00', + new DateTimeZone('UTC') + ); + $this->postRepo = new FakePostRepository; + $this->useCase = new DeletePost($this->postRepo); + } + + private function seedPostByUser(int $userId): Post + { + return $this->postRepo->create(new CreatePostDto( + userId: $userId, + title: 'Some Post', + body: 'Some body.', + createdAt: $this->now, + )); + } + + public function test_zero_post_id_throws_bad_request(): void + { + $this->expectException(BadRequestException::class); + $this->useCase->execute(new DeletePostRequest( + postId: 0, + requesterId: 1, + requesterIsAdmin: false, + )); + } + + public function test_zero_requester_id_throws_bad_request(): void + { + $post = $this->seedPostByUser(1); + + $this->expectException(BadRequestException::class); + $this->useCase->execute(new DeletePostRequest( + postId: $post->getId(), + requesterId: 0, + requesterIsAdmin: false, + )); + } + + public function test_unknown_post_is_no_op(): void + { + $this->useCase->execute(new DeletePostRequest( + postId: 999, + requesterId: 1, + requesterIsAdmin: false, + )); + + // No exception thrown -> idempotent delete on missing post. + $this->assertNull($this->postRepo->find(999)); + } + + public function test_author_can_delete_own_post(): void + { + $post = $this->seedPostByUser(1); + + $this->useCase->execute(new DeletePostRequest( + postId: $post->getId(), + requesterId: 1, + requesterIsAdmin: false, + )); + + $this->assertNull($this->postRepo->find($post->getId())); + } + + public function test_admin_can_delete_anyones_post(): void + { + $post = $this->seedPostByUser(1); + + $this->useCase->execute(new DeletePostRequest( + postId: $post->getId(), + requesterId: 99, + requesterIsAdmin: true, + )); + + $this->assertNull($this->postRepo->find($post->getId())); + } + + public function test_other_user_cannot_delete_post(): void + { + $post = $this->seedPostByUser(1); + + $this->expectException(ForbiddenException::class); + $this->useCase->execute(new DeletePostRequest( + postId: $post->getId(), + requesterId: 2, + requesterIsAdmin: false, + )); + } + + public function test_forbidden_delete_does_not_remove_post(): void + { + $post = $this->seedPostByUser(1); + + try { + $this->useCase->execute(new DeletePostRequest( + postId: $post->getId(), + requesterId: 2, + requesterIsAdmin: false, + )); + } catch (ForbiddenException) { + // expected + } + + $this->assertNotNull($this->postRepo->find($post->getId())); + } +}