view = $this->makeTwigMock(); $this->taxonomyService = $this->createMock(TaxonomyServiceInterface::class); $this->flash = $this->createMock(FlashServiceInterface::class); $this->controller = new TaxonomyController( $this->view, $this->taxonomyService, $this->flash, ); } // ── index ──────────────────────────────────────────────────────── /** * index() doit rendre la vue avec la liste des taxons. */ public function testIndexRendersWithCategories(): void { $this->taxonomyService->method('findPaginated')->willReturn(new PaginatedResult([], 0, 1, 20)); $this->view->expects($this->once()) ->method('render') ->with($this->anything(), '@Taxonomy/admin/index.twig', $this->anything()) ->willReturnArgument(0); $res = $this->controller->index($this->makeGet('/admin/categories'), $this->makeResponse()); $this->assertStatus($res, 200); } // ── create ─────────────────────────────────────────────────────── /** * create() doit flasher un succès et rediriger en cas de création réussie. */ public function testCreateRedirectsWithSuccessFlash(): void { $this->taxonomyService->method('create')->willReturn(1); $this->flash->expects($this->once())->method('set') ->with('taxonomy_success', $this->stringContains('PHP')); $req = $this->makePost('/admin/categories/create', ['name' => 'PHP']); $res = $this->controller->create($req, $this->makeResponse()); $this->assertRedirectTo($res, '/admin/categories'); } /** * create() doit flasher une erreur si le service lève une InvalidArgumentException. */ public function testCreateRedirectsWithErrorOnInvalidArgument(): void { $this->taxonomyService->method('create') ->willThrowException(new \InvalidArgumentException('Ce terme existe déjà')); $this->flash->expects($this->once())->method('set') ->with('taxonomy_error', 'Ce terme existe déjà'); $req = $this->makePost('/admin/categories/create', ['name' => 'Duplicate']); $res = $this->controller->create($req, $this->makeResponse()); $this->assertRedirectTo($res, '/admin/categories'); } /** * create() doit flasher une erreur générique pour toute autre exception. */ public function testCreateRedirectsWithGenericErrorOnUnexpectedException(): void { $this->taxonomyService->method('create') ->willThrowException(new \RuntimeException('DB error')); $this->flash->expects($this->once())->method('set') ->with('taxonomy_error', $this->stringContains('inattendue')); $req = $this->makePost('/admin/categories/create', ['name' => 'PHP']); $res = $this->controller->create($req, $this->makeResponse()); $this->assertRedirectTo($res, '/admin/categories'); } // ── delete ─────────────────────────────────────────────────────── /** * delete() doit flasher une erreur et rediriger si le taxon est introuvable. */ public function testDeleteRedirectsWithErrorWhenNotFound(): void { $this->taxonomyService->method('findById')->willReturn(null); $this->flash->expects($this->once())->method('set') ->with('taxonomy_error', 'Terme de taxonomie introuvable'); $res = $this->controller->delete( $this->makePost('/admin/categories/delete/99'), $this->makeResponse(), ['id' => '99'], ); $this->assertRedirectTo($res, '/admin/categories'); } /** * delete() doit flasher un succès et rediriger en cas de suppression réussie. */ public function testDeleteRedirectsWithSuccessFlash(): void { $category = new Taxon(3, 'PHP', 'php'); $this->taxonomyService->method('findById')->willReturn($category); $this->flash->expects($this->once())->method('set') ->with('taxonomy_success', $this->stringContains('PHP')); $res = $this->controller->delete( $this->makePost('/admin/categories/delete/3'), $this->makeResponse(), ['id' => '3'], ); $this->assertRedirectTo($res, '/admin/categories'); } /** * delete() doit flasher une erreur si le service refuse la suppression * (ex: des contenus sont rattachés au taxon). */ public function testDeleteRedirectsWithErrorWhenServiceRefuses(): void { $category = new Taxon(3, 'PHP', 'php'); $this->taxonomyService->method('findById')->willReturn($category); $this->taxonomyService->method('delete') ->willThrowException(new \InvalidArgumentException('Le terme « PHP » est encore utilisé et ne peut pas être supprimé')); $this->flash->expects($this->once())->method('set') ->with('taxonomy_error', 'Le terme « PHP » est encore utilisé et ne peut pas être supprimé'); $res = $this->controller->delete( $this->makePost('/admin/categories/delete/3'), $this->makeResponse(), ['id' => '3'], ); $this->assertRedirectTo($res, '/admin/categories'); } /** * delete() doit passer l'identifiant de route au service findById(). */ public function testDeletePassesCorrectIdToService(): void { $this->taxonomyService->expects($this->once()) ->method('findById') ->with(7) ->willReturn(null); $this->flash->method('set'); $this->controller->delete( $this->makePost('/admin/categories/delete/7'), $this->makeResponse(), ['id' => '7'], ); } }