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())); } }