package dev.lions.unionflow.server.service; import static org.assertj.core.api.Assertions.assertThat; import dev.lions.unionflow.server.entity.Adresse; import dev.lions.unionflow.server.entity.Membre; import dev.lions.unionflow.server.entity.MembreOrganisation; import dev.lions.unionflow.server.entity.Organisation; import dev.lions.unionflow.server.repository.MembreRepository; import dev.lions.unionflow.server.repository.MembreRoleRepository; import dev.lions.unionflow.server.repository.TypeReferenceRepository; import dev.lions.unionflow.server.service.MembreImportExportService; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.test.InjectMock; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import java.lang.reflect.Method; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; /** * Tests ciblant les lambdas internes de {@code MembreService.calculateSearchStatistics} * (ligne 697-718) via réflexion. * *

Ces lambdas ne sont pas atteintes par {@link MembreServiceTest} car tous les membres * fixture y ont des listes vides ({@code membresOrganisations} et {@code adresses}). */ @QuarkusTest class MembreServiceSearchStatsLambdaTest { @Inject MembreService membreService; @InjectMock MembreRepository membreRepository; @InjectMock MembreRoleRepository membreRoleRepository; @InjectMock TypeReferenceRepository typeReferenceRepository; @InjectMock MembreImportExportService membreImportExportService; @InjectMock OrganisationService organisationService; @InjectMock SecurityIdentity securityIdentity; // ========================================================================= // Helpers // ========================================================================= private Object invokeCalculerStatistiques(List membres) throws Exception { Method method = MembreService.class.getDeclaredMethod("calculateSearchStatistics", List.class); method.setAccessible(true); return method.invoke(membreService, membres); } // ========================================================================= // Lambda ligne 697-703 : flatMap membresOrganisations + map organisation.getId() // ========================================================================= @Test @DisplayName("calculateSearchStatistics avec membresOrganisations non-null et organisation non-null couvre lambda$11 ligne 700") void calculateSearchStatistics_membresOrgNonNull_withOrg_coversMapOrgIdLambda() throws Exception { // Organisation avec un ID non-null Organisation org = new Organisation(); org.setId(UUID.randomUUID()); MembreOrganisation mo = new MembreOrganisation(); mo.setOrganisation(org); Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Diallo"); membre.setPrenom("Amadou"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1990, 1, 1)); membre.setMembresOrganisations(List.of(mo)); membre.setAdresses(new ArrayList<>()); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } @Test @DisplayName("calculateSearchStatistics avec MembreOrganisation.organisation null couvre branche false lambda ligne 700") void calculateSearchStatistics_membresOrgNonNull_orgNull_coversNullOrgBranch() throws Exception { // MembreOrganisation avec organisation null → map retourne null → filter(Objects::nonNull) retire MembreOrganisation moNullOrg = new MembreOrganisation(); moNullOrg.setOrganisation(null); Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Bah"); membre.setPrenom("Isatou"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1992, 5, 15)); membre.setMembresOrganisations(List.of(moNullOrg)); membre.setAdresses(new ArrayList<>()); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } @Test @DisplayName("calculateSearchStatistics avec membresOrganisations null couvre branche false flatMap ligne 697") void calculateSearchStatistics_membresOrgNull_coversStreamEmptyBranch() throws Exception { Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Camara"); membre.setPrenom("Fatou"); membre.setActif(false); membre.setDateNaissance(null); membre.setMembresOrganisations(null); // → Stream.empty() branch membre.setAdresses(new ArrayList<>()); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } // ========================================================================= // Lambda ligne 714-718 : flatMap adresses + map region + filter non-null non-empty // ========================================================================= @Test @DisplayName("calculateSearchStatistics avec adresses non-null et region non-vide couvre lambdas ligne 714-716") void calculateSearchStatistics_adressesNonNull_withRegion_coversAdresseLambdas() throws Exception { Adresse adresse = new Adresse(); adresse.setRegion("Dakar"); adresse.setTypeAdresse("DOMICILE"); Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Sow"); membre.setPrenom("Mariama"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1995, 3, 20)); membre.setMembresOrganisations(new ArrayList<>()); membre.setAdresses(List.of(adresse)); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } @Test @DisplayName("calculateSearchStatistics avec adresses null couvre branche false flatMap ligne 714") void calculateSearchStatistics_adressesNull_coversStreamEmptyBranch() throws Exception { Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Keita"); membre.setPrenom("Awa"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1988, 7, 10)); membre.setMembresOrganisations(new ArrayList<>()); membre.setAdresses(null); // → Stream.empty() branch at line 714 Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } @Test @DisplayName("calculateSearchStatistics avec adresse region null couvre filtre non-null ligne 716") void calculateSearchStatistics_adressesWithNullRegion_coversFilterNullRegion() throws Exception { Adresse adresseNullRegion = new Adresse(); adresseNullRegion.setRegion(null); // → filtrée par filter(r -> r != null && !r.isEmpty()) adresseNullRegion.setTypeAdresse("DOMICILE"); Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Traore"); membre.setPrenom("Hawa"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1993, 11, 5)); membre.setMembresOrganisations(new ArrayList<>()); membre.setAdresses(List.of(adresseNullRegion)); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } // ========================================================================= // Vérification que la liste vide déclenche le chemin early-return // ========================================================================= @Test @DisplayName("calculateSearchStatistics avec liste vide retourne des statistiques à 0") void calculateSearchStatistics_emptyList_returnsZeroStats() throws Exception { Object stats = invokeCalculerStatistiques(Collections.emptyList()); assertThat(stats).isNotNull(); } // ========================================================================= // L710: filter(r -> r != null && !r.isEmpty()) — branche r != null && r.isEmpty() (vide → filtre) // La branche r==null est couverte par calculateSearchStatistics_adressesWithNullRegion_coversFilterNullRegion // La branche r!= null && isEmpty() manque — couverte par region="" (chaîne vide) // ========================================================================= @Test @DisplayName("calculateSearchStatistics avec adresse region vide → L710 filter r.isEmpty() true → filtrée") void calculateSearchStatistics_adressesWithEmptyRegion_L710FilterEmptyTrue() throws Exception { // region = "" → r != null = true, r.isEmpty() = true → !r.isEmpty() = false → filtrée Adresse adresseEmptyRegion = new Adresse(); adresseEmptyRegion.setRegion(""); // vide → filter: r != null && !isEmpty() → false → filtrée adresseEmptyRegion.setTypeAdresse("DOMICILE"); Membre membre = new Membre(); membre.setId(UUID.randomUUID()); membre.setNom("Coulibaly"); membre.setPrenom("Fatoumata"); membre.setActif(true); membre.setDateNaissance(LocalDate.of(1995, 3, 10)); membre.setMembresOrganisations(new ArrayList<>()); membre.setAdresses(List.of(adresseEmptyRegion)); Object stats = invokeCalculerStatistiques(List.of(membre)); assertThat(stats).isNotNull(); } }