Files
unionflow-server-impl-quarkus/src/test/java/dev/lions/unionflow/server/service/DemandeAideServiceL99L214Test.java
2026-03-28 14:21:30 +00:00

223 lines
10 KiB
Java

package dev.lions.unionflow.server.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import dev.lions.unionflow.server.api.dto.solidarite.HistoriqueStatutDTO;
import dev.lions.unionflow.server.api.dto.solidarite.response.DemandeAideResponse;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.entity.DemandeAide;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.mapper.DemandeAideMapper;
import io.quarkus.test.InjectMock;
import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Tests ciblant les branches L99 et L214 de {@link DemandeAideService}.
*
* <p>Ces branches nécessitent de contrôler ce que retourne {@link DemandeAideMapper#toDTO},
* tout en utilisant les vrais repositories pour éviter les NPE causés par le champ
* {@code entityManager} null dans les spies Quarkus {@code @InjectMock} sur les dépôts
* qui surchargent {@code findById(UUID)}.
*
* <p>Stratégie : {@code @InjectMock} uniquement sur le mapper, repos réels via
* {@code @TestTransaction} + entités persistées manuellement.
*
* <ul>
* <li><b>L99</b> — {@code creerDemande()} : ternaire
* {@code response.getMembreDemandeurId() != null ? ... : null} — branche false.</li>
* <li><b>L214</b> — {@code changerStatut()} : ternaire
* {@code response.getHistoriqueStatuts() != null} — branche true.</li>
* </ul>
*/
@QuarkusTest
@DisplayName("DemandeAideService — branches L99 et L214 (vrais repositories)")
class DemandeAideServiceL99L214Test {
@Inject
DemandeAideService demandeAideService;
/** Seul mock : le mapper, pour contrôler ce que retourne toDTO() */
@InjectMock
DemandeAideMapper demandeAideMapper;
@Inject
EntityManager entityManager;
// =========================================================================
// Helpers — persistance d'entités minimales valides
// =========================================================================
private Membre creerMembre() {
Membre m = Membre.builder()
.numeroMembre("UF-L99-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase())
.prenom("Test")
.nom("L99")
.email("l99." + UUID.randomUUID() + "@test.com")
.dateNaissance(LocalDate.of(1990, 1, 1))
.build();
m.setDateCreation(LocalDateTime.now());
m.setActif(true);
m.setStatutCompte("ACTIF");
entityManager.persist(m);
entityManager.flush();
return m;
}
private Organisation creerOrganisation() {
Organisation org = Organisation.builder()
.nom("Org L99 " + UUID.randomUUID().toString().substring(0, 8))
.email("org.l99." + UUID.randomUUID() + "@test.com")
.typeOrganisation("ASSOCIATION")
.statut("ACTIF")
.build();
org.setDateCreation(LocalDateTime.now());
org.setActif(true);
entityManager.persist(org);
entityManager.flush();
return org;
}
// =========================================================================
// L99 — creerDemande() — ternaire false :
// auteurId(response.getMembreDemandeurId() != null ? ... : null)
//
// Le mapper mock retourne un DTO avec membreDemandeurId = null.
// → auteurId du HistoriqueStatutDTO initial est null (branche false L99).
// =========================================================================
@Test
@TestTransaction
@DisplayName("L99 branche false : auteurId=null dans l'historique initial quand mapper retourne membreDemandeurId=null")
void creerDemande_mapperRetourneMembreDemandeurIdNull_auteurIdNullDansHistorique_L99() {
Membre membre = creerMembre();
Organisation org = creerOrganisation();
// L'entité retournée par le mapper mock doit être persistable : on lui donne
// le vrai demandeur et la vraie organisation pour satisfaire les contraintes NOT NULL.
DemandeAide entityMockRetour = DemandeAide.builder()
.titre("Demande L99")
.description("Desc L99")
.typeAide(TypeAide.AIDE_ALIMENTAIRE)
.statut(StatutAide.EN_ATTENTE)
.demandeur(membre)
.organisation(org)
.build();
when(demandeAideMapper.toEntity(any(), any(), any(), any())).thenReturn(entityMockRetour);
// toDTO retourne un DTO SANS membreDemandeurId (null)
// → condition L99 : response.getMembreDemandeurId() != null → false
// → auteurId = null dans le HistoriqueStatutDTO initial
DemandeAideResponse dtoNull = new DemandeAideResponse();
dtoNull.setId(UUID.randomUUID());
dtoNull.setStatut(StatutAide.EN_ATTENTE);
dtoNull.setPriorite(PrioriteAide.NORMALE);
dtoNull.setTypeAide(TypeAide.AIDE_ALIMENTAIRE);
dtoNull.setMontantDemande(new BigDecimal("200.00"));
dtoNull.setDateCreation(LocalDateTime.now());
dtoNull.setMembreDemandeurId(null); // ← null → L99 branche false → auteurId = null
when(demandeAideMapper.toDTO(any(DemandeAide.class))).thenReturn(dtoNull);
dev.lions.unionflow.server.api.dto.solidarite.request.CreateDemandeAideRequest request =
dev.lions.unionflow.server.api.dto.solidarite.request.CreateDemandeAideRequest.builder()
.titre("Demande L99")
.description("Description L99")
.typeAide(TypeAide.AIDE_ALIMENTAIRE)
.priorite(PrioriteAide.NORMALE)
.membreDemandeurId(membre.getId())
.associationId(org.getId())
.build();
DemandeAideResponse result = demandeAideService.creerDemande(request);
assertThat(result).isNotNull();
// Le service crée un HistoriqueStatutDTO initial avec auteurId = null (L99 branche false)
assertThat(result.getHistoriqueStatuts())
.as("Un historique initial doit être présent")
.isNotNull()
.hasSize(1);
assertThat(result.getHistoriqueStatuts().get(0).getAuteurId())
.as("L99 branche false : auteurId doit être null quand membreDemandeurId est null")
.isNull();
}
// =========================================================================
// L214 — changerStatut() — branche true :
// response.getHistoriqueStatuts() != null → utilise la liste existante
//
// Le mapper mock retourne un DTO avec historiqueStatuts déjà renseigné (non-null).
// → l'historique existant est combiné avec le nouveau → L214 branche true.
// =========================================================================
@Test
@TestTransaction
@DisplayName("L214 branche true : historique existant conservé quand mapper retourne historiqueStatuts non-null")
void changerStatut_mapperRetourneHistoriqueNonNull_historiqueCombine_L214() {
Membre membre = creerMembre();
Organisation org = creerOrganisation();
// Persister une vraie DemandeAide (statut EN_ATTENTE → transition vers EN_COURS_EVALUATION valide)
DemandeAide demande = DemandeAide.builder()
.titre("Demande L214")
.description("Desc L214")
.typeAide(TypeAide.AIDE_ALIMENTAIRE)
.statut(StatutAide.EN_ATTENTE)
.demandeur(membre)
.organisation(org)
.build();
entityManager.persist(demande);
entityManager.flush();
UUID demandeId = demande.getId();
// Le mapper retourne un DTO avec historiqueStatuts DÉJÀ NON-NULL
// → L214 branche true : la liste existante est utilisée + le nouvel historique s'y ajoute
HistoriqueStatutDTO historiqueExistant = HistoriqueStatutDTO.builder()
.id(UUID.randomUUID().toString())
.ancienStatut(null)
.nouveauStatut(StatutAide.EN_ATTENTE)
.dateChangement(LocalDateTime.now().minusHours(1))
.motif("Création initiale")
.estAutomatique(true)
.build();
DemandeAideResponse dtoAvecHistorique = new DemandeAideResponse();
dtoAvecHistorique.setId(demandeId);
dtoAvecHistorique.setStatut(StatutAide.EN_COURS_EVALUATION);
dtoAvecHistorique.setPriorite(PrioriteAide.NORMALE);
dtoAvecHistorique.setTypeAide(TypeAide.AIDE_ALIMENTAIRE);
dtoAvecHistorique.setMontantDemande(new BigDecimal("100.00"));
dtoAvecHistorique.setDateCreation(LocalDateTime.now().minusDays(1));
dtoAvecHistorique.setMembreDemandeurId(membre.getId());
dtoAvecHistorique.setHistoriqueStatuts(List.of(historiqueExistant)); // ← non-null → L214 true
when(demandeAideMapper.toDTO(any(DemandeAide.class))).thenReturn(dtoAvecHistorique);
DemandeAideResponse result = demandeAideService.changerStatut(
demandeId, StatutAide.EN_COURS_EVALUATION, "Évaluation débutée");
// L214 branche true : 1 historique existant + 1 nouvel historique = 2 entrées
assertThat(result.getHistoriqueStatuts())
.as("L214 branche true : historique existant (1) + nouveau (1) = 2 entrées")
.hasSize(2);
assertThat(result.getHistoriqueStatuts().get(0).getMotif())
.isEqualTo("Création initiale");
assertThat(result.getHistoriqueStatuts().get(1).getNouveauStatut())
.isEqualTo(StatutAide.EN_COURS_EVALUATION);
}
}