makeFkException( 'FOREIGN KEY constraint failed INSERT INTO theses (title, orientation_id) VALUES (?,?)' ); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Orientation', $user); $this->assertStringContainsString('AP', $user); $this->assertStringContainsString('Licence', $user); $this->assertStringNotContainsString('FOREIGN KEY', $user); } public function testFkApPrograms(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO theses (ap_program_id) VALUES (?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('AP', $user); } public function testFkFinalityTypes(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO theses (finality_id) VALUES (?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Finalité', $user); } public function testFkThesisLanguages(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?,?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Langue(s)', $user); } public function testFkThesisFormats(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?,?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Format(s)', $user); } public function testFkThesisTags(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_tags (thesis_id, tag_id) VALUES (?,?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Mots-clés', $user); } public function testFkThesisSupervisors(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_supervisors (thesis_id, supervisor_id) VALUES (?,?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Composition du jury', $user); } public function testFkAccessTypes(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO theses (access_type_id) VALUES (?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString("Type d'accès", $user); } public function testFkLicenseTypes(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO theses (license_id) VALUES (?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Licence', $user); } public function testFkAuthors(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_authors (thesis_id, author_id) VALUES (?,?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Auteur·ice', $user); } // ── FK constraint: "table" pattern (SQLite 3.37+) ──────────────────────── public function testFkQuotedTableName(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed (table "orientations")'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Orientation', $user); } public function testFkQuotedLanguages(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed (table "languages")'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Langue(s)', $user); } public function testFkQuotedFormatTypes(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed (table "format_types")'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Format(s)', $user); } // ── FK constraint: REFERENCES pattern ──────────────────────────────────── public function testFkReferencesTags(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed (REFERENCES tags(id))'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Mots-clés', $user); } public function testFkReferencesOrientations(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed (REFERENCES orientations(id))'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Orientation', $user); } // ── FK constraint: unknown table → generic ─────────────────────────────── public function testFkUnknownTableGenericFallback(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO unknown_table VALUES (?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('contrainte de référence est invalide', $user); $this->assertStringNotContainsString('unknown_table', $user); } public function testFkEmptyMessageGenericFallback(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('contrainte de référence est invalide', $user); } // ── UNIQUE constraint ──────────────────────────────────────────────────── public function testUniqueConstraint(): void { $msg = new PDOException('UNIQUE constraint failed: thesis_tags.tag_id, thesis_tags.thesis_id', 2067); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('valeur en double', $user); $this->assertStringNotContainsString('UNIQUE', $user); $this->assertStringNotContainsString('thesis_tags', $user); } // ── NOT NULL constraint ────────────────────────────────────────────────── public function testNotNullConstraint(): void { $msg = new PDOException('NOT NULL constraint failed: theses.title', 1299); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('champ obligatoire est manquant', $user); $this->assertStringNotContainsString('NOT NULL', $user); } // ── Generic PDO error ──────────────────────────────────────────────────── public function testGenericPdoError(): void { $msg = new PDOException('database disk image is malformed', 11); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Une erreur de base de données est survenue', $user); $this->assertStringNotContainsString('disk image', $user); } // ── Domain exceptions pass through ─────────────────────────────────────── public function testDuplicateThesisExceptionPassesThrough(): void { $dup = new DuplicateThesisException(42, '2025-ABC12345', 'Test titre', 'Auteur', 2025); $user = ErrorHandler::userMessage($dup); $this->assertStringContainsString('2025-ABC12345', $user); $this->assertStringContainsString('Auteur', $user); } public function testValidationExceptionPassesThrough(): void { $val = new RuntimeException('Le titre est requis.'); $user = ErrorHandler::userMessage($val); $this->assertSame('Le titre est requis.', $user); } // ── Unknown exception types → generic fallback ─────────────────────────── public function testGenericExceptionPassesThrough(): void { $gen = new Exception('Something went wrong'); $user = ErrorHandler::userMessage($gen); $this->assertStringContainsString('Something went wrong', $user); } public function testTypeErrorReturnsGeneric(): void { $typeErr = new TypeError('htmlspecialchars(): Argument #1 must be string, array given'); $user = ErrorHandler::userMessage($typeErr); $this->assertStringContainsString('Une erreur inattendue est survenue', $user); $this->assertStringNotContainsString('htmlspecialchars', $user); } // ── log() does not crash ───────────────────────────────────────────────── public function testLogWithContext(): void { // Should not throw ErrorHandler::log('test_context', new Exception('test message'), [ 'thesis_id' => 42, 'slug' => '20250101-TEST1234', ]); $this->assertTrue(true); // reached here = no crash } public function testLogWithNullValues(): void { ErrorHandler::log('test_null', new PDOException('test'), ['id' => null, 'name' => 'foo']); $this->assertTrue(true); } public function testLogWithEmptyExtra(): void { ErrorHandler::log('test_empty', new RuntimeException('bare')); $this->assertTrue(true); } // ── Real-world FK error patterns ───────────────────────────────────────── public function testFkQuotedColumnNames(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_formats ("thesis_id", "format_id") VALUES (?, ?)'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Format(s)', $user); } public function testFkUpdateStatement(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed UPDATE theses SET orientation_id = ? WHERE id = ?'); $user = ErrorHandler::userMessage($msg); $this->assertStringContainsString('Orientation', $user); } public function testFkWithReferencesAndInsert(): void { $msg = $this->makeFkException('FOREIGN KEY constraint failed INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?, ?) REFERENCES format_types'); $user = ErrorHandler::userMessage($msg); // First matcher wins (INSERT table) $this->assertStringContainsString('Format(s)', $user); } }