ContratSyncFixturesTest.kt
112 lignes · 4541 octets
package fr.ebii.card2vcf.sync import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test /** * Décode les fixtures de contrat de synchronisation avec les vrais DTO. * * Si un champ serveur est renommé, ce test devient rouge immédiatement. * Preuve de rougeur (vérifiée) : en renommant `transcription_erreur` → `transcription_error` * dans `interaction_note_vocale.json`, l'assertion suivante échoue : * expected:<Modèle ASR indisponible> but was:<null> */ class ContratSyncFixturesTest { private fun fixture(nom: String): String { val stream = javaClass.classLoader!!.getResourceAsStream("contrats/$nom") ?: error("Fixture introuvable : contrats/$nom") return stream.bufferedReader().readText() } // ---- sync_pull.json ---- @Test fun syncPull_decodeSyncPullResponse() { val json = fixture("sync_pull.json") val pull = syncJson.decodeFromString<SyncPullResponse>(json) assertTrue("contacts doit contenir au moins un élément", pull.contacts.isNotEmpty()) assertTrue("interactions doit contenir au moins un élément", pull.interactions.isNotEmpty()) assertTrue("notes doit contenir au moins un élément", pull.notes.isNotEmpty()) } @Test fun syncPull_contactChampsCritiques() { val json = fixture("sync_pull.json") val pull = syncJson.decodeFromString<SyncPullResponse>(json) val contact = pull.contacts.first() assertNotNull("id contact ne doit pas être null", contact.id) assertNotNull("creeLe contact ne doit pas être null", contact.creeLe) } /** * Contrat de planification : si le serveur renomme un de ces champs, le * téléphone cesserait silencieusement d'afficher dates, étiquettes ou * sous-tâches. Ce test rend la rupture immédiate. */ @Test fun syncPull_planificationDesTaches() { val json = fixture("sync_pull.json") val pull = syncJson.decodeFromString<SyncPullResponse>(json) val projet = pull.projets.first() assertTrue("planification doit être transportée", projet.planification) assertEquals(5, projet.joursOuvres) assertEquals("2026-09-30", projet.echeance) val tache = pull.taches.first() assertEquals("2026-09-21", tache.debut) assertEquals(3, tache.dureeJours) assertEquals("contrat", tache.etiquette) assertEquals(2, tache.sousTaches.size) assertTrue("l'état coché doit survivre au transport", tache.sousTaches.first().fait) } /** La fin affichée sur le téléphone doit être celle du Gantt web. */ @Test fun syncPull_periodeCalculeeCommeLeServeur() { val json = fixture("sync_pull.json") val pull = syncJson.decodeFromString<SyncPullResponse>(json) val projet = pull.projets.first() val tache = pull.taches.first() // Lundi 2026-09-21 + 3 jours ouvrés en rythme 5 : mercredi 23. val periode = fr.ebii.card2vcf.planning.CalendrierOuvre(projet.joursOuvres) .periodeAffichee(java.time.LocalDate.parse(tache.debut!!), tache.dureeJours!!) assertEquals("21/09 → 23/09", periode) } // ---- interaction_note_vocale.json ---- @Test fun interaction_decodeInteractionDto() { val json = fixture("interaction_note_vocale.json") val dto = syncJson.decodeFromString<InteractionDto>(json) assertEquals("note_vocale", dto.typeInteraction) assertEquals("vocale_contrat_1.wav", dto.pieceJointe) assertEquals("echec", dto.transcription) // Champ critique : si transcription_erreur est renommé côté serveur, // cette assertion devient rouge : expected:<Modèle ASR indisponible> but was:<null> assertEquals("Modèle ASR indisponible", dto.transcriptionErreur) } // ---- note_projet.json ---- @Test fun noteProjet_decodeNoteProjetDto() { val json = fixture("note_projet.json") val dto = syncJson.decodeFromString<NoteProjetDto>(json) assertEquals("projet-contrat-1", dto.projetId) assertEquals("note_contrat_1.wav", dto.audio) assertEquals("terminee", dto.transcription) // transcription_erreur doit être null pour cette note (transcription réussie) assertNull("transcriptionErreur doit être null pour une transcription réussie", dto.transcriptionErreur) } }
GitRust