diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementDTO.java new file mode 100644 index 0000000..cfa8da6 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementDTO.java @@ -0,0 +1,48 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class AbonnementDTO { + + private final String clientId; + private final int duree; + private final String modePaiement; + private final LocalDate dateDebut; + private final LocalDate dateFin; + private final BigDecimal montantMensuel; + + public AbonnementDTO(String clientId, int duree, String modePaiement, + LocalDate dateDebut, LocalDate dateFin, BigDecimal montantMensuel) { + this.clientId = clientId; + this.duree = duree; + this.modePaiement = modePaiement; + this.dateDebut = dateDebut; + this.dateFin = dateFin; + this.montantMensuel = montantMensuel; + } + + public String getClientId() { + return clientId; + } + + public int getDuree() { + return duree; + } + + public String getModePaiement() { + return modePaiement; + } + + public LocalDate getDateDebut() { + return dateDebut; + } + + public LocalDate getDateFin() { + return dateFin; + } + + public BigDecimal getMontantMensuel() { + return montantMensuel; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementInfo.java new file mode 100644 index 0000000..4eb5cdc --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/AbonnementInfo.java @@ -0,0 +1,26 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto; + +public class AbonnementInfo { + + private final String clientId; + private final int duree; + private final String modePaiement; + + public AbonnementInfo(String clientId, int duree, String modePaiement) { + this.clientId = clientId; + this.duree = duree; + this.modePaiement = modePaiement; + } + + public String getClientId() { + return clientId; + } + + public int getDuree() { + return duree; + } + + public String getModePaiement() { + return modePaiement; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverter.java new file mode 100644 index 0000000..1cb4241 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverter.java @@ -0,0 +1,41 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto.AbonnementDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto.AbonnementInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; + +public class AbonnementConverter { + + public AbonnementDTO toDTO(Abonnement abonnement) { + if (abonnement == null) return null; + return new AbonnementDTO( + abonnement.getClientId(), + abonnement.getDuree(), + abonnement.getModePaiement(), + abonnement.getDateDebut(), + abonnement.getDateFin(), + abonnement.getMontantMensuel() + ); + } + + public Abonnement toDomain(AbonnementDTO dto) { + if (dto == null) return null; + return new Abonnement( + dto.getClientId(), + dto.getDuree(), + dto.getModePaiement(), + dto.getDateDebut(), + dto.getDateFin(), + dto.getMontantMensuel() + ); + } + + public AbonnementInfo toInfo(Abonnement abonnement) { + if (abonnement == null) return null; + return new AbonnementInfo( + abonnement.getClientId(), + abonnement.getDuree(), + abonnement.getModePaiement() + ); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/Abonnement.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/Abonnement.java new file mode 100644 index 0000000..b091777 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/Abonnement.java @@ -0,0 +1,77 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Objects; + +public class Abonnement { + + private final String clientId; + private final int duree; + private final String modePaiement; + private final LocalDate dateDebut; + private final LocalDate dateFin; + private final BigDecimal montantMensuel; + + public Abonnement(String clientId, int duree, String modePaiement, LocalDate dateDebut, LocalDate dateFin, BigDecimal montantMensuel) { + this.clientId = clientId; + this.duree = duree; + this.modePaiement = modePaiement; + this.dateDebut = dateDebut; + this.dateFin = dateFin; + this.montantMensuel = montantMensuel; + } + + public String getClientId() { + return clientId; + } + + public int getDuree() { + return duree; + } + + public String getModePaiement() { + return modePaiement; + } + + public LocalDate getDateDebut() { + return dateDebut; + } + + public LocalDate getDateFin() { + return dateFin; + } + + public BigDecimal getMontantMensuel() { + return montantMensuel; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Abonnement that)) return false; + return duree == that.duree && + Objects.equals(clientId, that.clientId) && + Objects.equals(modePaiement, that.modePaiement) && + Objects.equals(dateDebut, that.dateDebut) && + Objects.equals(dateFin, that.dateFin) && + Objects.equals(montantMensuel, that.montantMensuel); + } + + @Override + public int hashCode() { + return Objects.hash(clientId, duree, modePaiement, dateDebut, dateFin, montantMensuel); + } + + @Override + public String toString() { + return "Abonnement{" + + "clientId='" + clientId + '\'' + + ", duree=" + duree + + ", modePaiement='" + modePaiement + '\'' + + ", dateDebut=" + dateDebut + + ", dateFin=" + dateFin + + ", montantMensuel=" + montantMensuel + + '}'; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundException.java new file mode 100644 index 0000000..5b77df6 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception; + +public class AbonnementNotFoundException extends RuntimeException { + + public AbonnementNotFoundException(String message) { + super(message); + } + + public AbonnementNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementException.java new file mode 100644 index 0000000..f9d602c --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception; + +public class NotValidAbonnementException extends RuntimeException { + + public NotValidAbonnementException(String message) { + super(message); + } + + public NotValidAbonnementException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepository.java new file mode 100644 index 0000000..bda79e1 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepository.java @@ -0,0 +1,17 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; + +import java.util.List; +import java.util.Optional; + +public interface AbonnementRepository { + + Abonnement save(Abonnement abonnement); + + Optional findByClientId(String clientId); + + void deleteByClientId(String clientId); + + List findAll(); +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCase.java new file mode 100644 index 0000000..9827dbb --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCase.java @@ -0,0 +1,44 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.AbonnementNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository.AbonnementRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.validator.AbonnementValidator; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class AbonnementUseCase { + + private final AbonnementRepository repository; + private final AbonnementValidator validator; + + public AbonnementUseCase(AbonnementRepository repository, AbonnementValidator validator) { + this.repository = repository; + this.validator = validator; + } + + public Abonnement creerAbonnement(String clientId, int duree, String modePaiement, LocalDate dateDebutSouhaitee) { + LocalDate dateFin = dateDebutSouhaitee.plusMonths(duree); + BigDecimal montant = calculerMontantMensuel(duree); + + Abonnement abonnement = new Abonnement(clientId, duree, modePaiement.toUpperCase(), dateDebutSouhaitee, dateFin, montant); + + validator.valider(abonnement); + return repository.save(abonnement); + } + + public Abonnement trouverParClientId(String clientId) { + return repository.findByClientId(clientId) + .orElseThrow(() -> new AbonnementNotFoundException("Aucun abonnement pour ce client")); + } + + private BigDecimal calculerMontantMensuel(int duree) { + return switch (duree) { + case 3 -> new BigDecimal("15.00"); + case 6 -> new BigDecimal("12.50"); + case 12 -> new BigDecimal("10.00"); + default -> throw new IllegalArgumentException("Durée d’abonnement non prise en charge : " + duree); + }; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidator.java new file mode 100644 index 0000000..ce30fd8 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidator.java @@ -0,0 +1,39 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.NotValidAbonnementException; + +import java.math.BigDecimal; +import java.util.Set; + +public class AbonnementValidator { + + private static final Set DUREES_VALIDES = Set.of(3, 6, 12); + private static final Set MODES_VALIDES = Set.of("CB", "PAYPAL"); + + public void valider(Abonnement abonnement) { + if (abonnement == null) { + throw new NotValidAbonnementException("Abonnement null"); + } + + if (abonnement.getClientId() == null || abonnement.getClientId().isBlank()) { + throw new NotValidAbonnementException("Client ID manquant ou vide"); + } + + if (!DUREES_VALIDES.contains(abonnement.getDuree())) { + throw new NotValidAbonnementException("La durée doit être 3, 6 ou 12 mois"); + } + + if (abonnement.getModePaiement() == null || !MODES_VALIDES.contains(abonnement.getModePaiement().toUpperCase())) { + throw new NotValidAbonnementException("Mode de paiement invalide (CB ou PAYPAL attendu)"); + } + + if (abonnement.getDateDebut() == null) { + throw new NotValidAbonnementException("La date de début est obligatoire"); + } + + if (abonnement.getMontantMensuel() == null || abonnement.getMontantMensuel().compareTo(BigDecimal.ZERO) <= 0) { + throw new NotValidAbonnementException("Le montant mensuel doit être positif"); + } + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java new file mode 100644 index 0000000..798bc96 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java @@ -0,0 +1,64 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.dto; + +import java.time.LocalDate; + +public class AvisDTO { + + private String clientId; + private String livreId; + private int note; + private String commentaire; + private LocalDate dateAchat; + + public AvisDTO() { + // constructeur par défaut + } + + public AvisDTO(String clientId, String livreId, int note, String commentaire, LocalDate dateAchat) { + this.clientId = clientId; + this.livreId = livreId; + this.note = note; + this.commentaire = commentaire; + this.dateAchat = dateAchat; + } + + public String getClientId() { + return clientId; + } + + public String getLivreId() { + return livreId; + } + + public int getNote() { + return note; + } + + public String getCommentaire() { + return commentaire; + } + + public LocalDate getDateAchat() { + return dateAchat; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public void setLivreId(String livreId) { + this.livreId = livreId; + } + + public void setNote(int note) { + this.note = note; + } + + public void setCommentaire(String commentaire) { + this.commentaire = commentaire; + } + + public void setDateAchat(LocalDate dateAchat) { + this.dateAchat = dateAchat; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java new file mode 100644 index 0000000..38bff73 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java @@ -0,0 +1,40 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.dto; + +public class AvisInfo { + + private String clientId; + private int note; + private String commentaire; + + public AvisInfo() {} + + public AvisInfo(String clientId, int note, String commentaire) { + this.clientId = clientId; + this.note = note; + this.commentaire = commentaire; + } + + public String getClientId() { + return clientId; + } + + public int getNote() { + return note; + } + + public String getCommentaire() { + return commentaire; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public void setNote(int note) { + this.note = note; + } + + public void setCommentaire(String commentaire) { + this.commentaire = commentaire; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java new file mode 100644 index 0000000..ce05296 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java @@ -0,0 +1,39 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.dto.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.dto.AvisInfo; + +public class AvisConverter { + + public AvisDTO toDTO(Avis avis) { + if (avis == null) return null; + return new AvisDTO( + avis.getClientId(), + avis.getLivreId(), + avis.getNote(), + avis.getCommentaire(), + avis.getDateAchat() + ); + } + + public Avis toDomain(AvisDTO dto) { + if (dto == null) return null; + return new Avis( + dto.getClientId(), + dto.getLivreId(), + dto.getNote(), + dto.getCommentaire(), + dto.getDateAchat() + ); + } + + public AvisInfo toInfo(Avis avis) { + if (avis == null) return null; + return new AvisInfo( + avis.getClientId(), + avis.getNote(), + avis.getCommentaire() + ); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java new file mode 100644 index 0000000..1d2f73b --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java @@ -0,0 +1,76 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; + +import java.time.LocalDate; +import java.util.Objects; + +public class Avis { + + private final String clientId; + private final String livreId; + private int note; + private String commentaire; + private final LocalDate dateAchat; + + public Avis(String clientId, String livreId, int note, String commentaire, LocalDate dateAchat) { + this.clientId = clientId; + this.livreId = livreId; + this.note = note; + this.commentaire = commentaire; + this.dateAchat = dateAchat; + } + + public String getClientId() { + return clientId; + } + + public String getLivreId() { + return livreId; + } + + public int getNote() { + return note; + } + + public String getCommentaire() { + return commentaire; + } + + public LocalDate getDateAchat() { + return dateAchat; + } + + public void setNote(int note) { + this.note = note; + } + + public void setCommentaire(String commentaire) { + this.commentaire = commentaire; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Avis avis)) return false; + return Objects.equals(clientId, avis.clientId) + && Objects.equals(livreId, avis.livreId) + && note == avis.note + && Objects.equals(commentaire, avis.commentaire) + && Objects.equals(dateAchat, avis.dateAchat); + } + + @Override + public int hashCode() { + return Objects.hash(clientId, livreId, note, commentaire, dateAchat); + } + + @Override + public String toString() { + return "Avis{" + + "clientId='" + clientId + '\'' + + ", livreId='" + livreId + '\'' + + ", note=" + note + + ", commentaire='" + commentaire + '\'' + + ", dateAchat=" + dateAchat + + '}'; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java new file mode 100644 index 0000000..30cde02 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +public class AvisNotFoundException extends RuntimeException { + + public AvisNotFoundException(String message) { + super(message); + } + + public AvisNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java new file mode 100644 index 0000000..0eb1730 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +public class NotValidAvisException extends RuntimeException { + + public NotValidAvisException(String message) { + super(message); + } + + public NotValidAvisException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java new file mode 100644 index 0000000..a0040cd --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java @@ -0,0 +1,15 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; + +import java.util.List; +import java.util.Optional; + +public interface AvisRepository { + Avis save(Avis avis); + Optional findByClientAndLivre(String clientId, String livreId); + void deleteByClientAndLivre(String clientId, String livreId); + List findAll(); + List findByLivre(String livreId); + List findByClient(String clientId); +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java new file mode 100644 index 0000000..9e2fca5 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.AvisNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.validator.AvisValidator; + +import java.util.*; + +public class AvisUseCase { + + private final AvisRepository repository; + private final AvisValidator validator; + + // Simule les achats dans un vrai système : clientId + "_" + livreId + private final Set achatsValidés = new HashSet<>(); + + public AvisUseCase(AvisRepository repository, AvisValidator validator) { + this.repository = repository; + this.validator = validator; + } + + public void ajouterAvis(Avis avis) { + validator.valider(avis); + String clé = avis.getClientId() + "_" + avis.getLivreId(); + if (!achatsValidés.contains(clé)) { + throw new NotValidAvisException("Le client ne peut évaluer un livre qu’il n’a pas acheté"); + } + repository.save(avis); + } + + public void modifierAvis(String clientId, String livreId, int nouvelleNote, String nouveauCommentaire) { + Avis existant = repository.findByClientAndLivre(clientId, livreId) + .orElseThrow(() -> new AvisNotFoundException("Aucun avis trouvé pour ce client et ce livre.")); + + existant.setNote(nouvelleNote); + existant.setCommentaire(nouveauCommentaire); + + validator.valider(existant); + repository.save(existant); + } + + public void supprimerAvis(String clientId, String livreId) { + repository.deleteByClientAndLivre(clientId, livreId); + } + + public List recupererAvisParLivre(String livreId) { + return repository.findByLivre(livreId); + } + + public List recupererAvisParClient(String clientId) { + return repository.findByClient(clientId); + } + + // Pour les tests uniquement + public void simulerAchat(String clientId, String livreId) { + achatsValidés.add(clientId + "_" + livreId); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java new file mode 100644 index 0000000..6e93dc4 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java @@ -0,0 +1,33 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; + +public class AvisValidator { + + public void valider(Avis avis) { + if (avis == null) { + throw new NotValidAvisException("L'avis ne peut pas être null"); + } + + if (avis.getNote() < 1 || avis.getNote() > 5) { + throw new NotValidAvisException("La note doit être entre 1 et 5"); + } + + if (avis.getCommentaire() == null || avis.getCommentaire().isBlank()) { + throw new NotValidAvisException("Le commentaire ne peut pas être vide"); + } + + if (avis.getClientId() == null || avis.getClientId().isBlank()) { + throw new NotValidAvisException("Le client est obligatoire"); + } + + if (avis.getLivreId() == null || avis.getLivreId().isBlank()) { + throw new NotValidAvisException("Le livre est obligatoire"); + } + + if (avis.getDateAchat() == null) { + throw new NotValidAvisException("La date d'achat est obligatoire"); + } + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java new file mode 100644 index 0000000..980c8b2 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java @@ -0,0 +1,74 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; + +import java.time.LocalDate; +import java.util.List; + +public class BookDTO { + private String isbn; + private String title; + private String author; + private String publisher; + private LocalDate publicationDate; + private double price; + private int stock; + private List categories; + private String description; + private String language; + + public BookDTO(String isbn, String title, String author, String publisher, + LocalDate publicationDate, double price, int stock, + List categories, String description, String language) { + this.isbn = isbn; + this.title = title; + this.author = author; + this.publisher = publisher; + this.publicationDate = publicationDate; + this.price = price; + this.stock = stock; + this.categories = categories; + this.description = description; + this.language = language; + } + + public String getIsbn() { + return isbn; + } + + public String getTitle() { + return title; + } + + public String getAuthor() { + return author; + } + + public String getPublisher() { + return publisher; + } + + public LocalDate getPublicationDate() { + return publicationDate; + } + + public double getPrice() { + return price; + } + + public int getStock() { + return stock; + } + + public List getCategories() { + return categories; + } + + public String getDescription() { + return description; + } + + public String getLanguage() { + return language; + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java new file mode 100644 index 0000000..ad7f79c --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java @@ -0,0 +1,74 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; + +import java.time.LocalDate; +import java.util.List; + +public class BookInfo { + private String isbn; + private String title; + private String author; + private String publisher; + private LocalDate publicationDate; + private double price; + private int stock; + private List categories; + private String description; + private String language; + + public BookInfo(String isbn, String title, String author, String publisher, + LocalDate publicationDate, double price, int stock, + List categories, String description, String language) { + this.isbn = isbn; + this.title = title; + this.author = author; + this.publisher = publisher; + this.publicationDate = publicationDate; + this.price = price; + this.stock = stock; + this.categories = categories; + this.description = description; + this.language = language; + } + + public String getIsbn() { + return isbn; + } + + public String getTitle() { + return title; + } + + public String getAuthor() { + return author; + } + + public String getPublisher() { + return publisher; + } + + public LocalDate getPublicationDate() { + return publicationDate; + } + + public double getPrice() { + return price; + } + + public int getStock() { + return stock; + } + + public List getCategories() { + return categories; + } + + public String getDescription() { + return description; + } + + public String getLanguage() { + return language; + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java new file mode 100644 index 0000000..90bc1ee --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book; + +public enum Category { + ROMAN, + DRAME, + SCIENCE_FICTION, + JEUNESSE, + PHILOSOPHIE, + POESIE, + CLASSIQUE, + SCIENCE +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java new file mode 100644 index 0000000..8608c90 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java @@ -0,0 +1,37 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.*; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; + +public class BookConverter { + + public static BookDTO toDTO(Book book) { + return new BookDTO( + book.getIsbn(), + book.getTitle(), + book.getAuthor(), + book.getPublisher(), + book.getPublicationDate(), + book.getPrice(), + book.getStock(), + book.getCategories(), + book.getDescription(), + book.getLanguage() + ); + } + + public static Book fromInfo(BookInfo info) { + return Book.builder() + .isbn(info.getIsbn()) + .title(info.getTitle()) + .author(info.getAuthor()) + .publisher(info.getPublisher()) + .publicationDate(info.getPublicationDate()) + .price(info.getPrice()) + .stock(info.getStock()) + .categories(info.getCategories()) + .description(info.getDescription()) + .language(info.getLanguage()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java new file mode 100644 index 0000000..062012e --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java @@ -0,0 +1,125 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.entity; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; + +import java.time.LocalDate; +import java.util.List; + +public class Book { + private String isbn; + private String title; + private String author; + private String publisher; + private LocalDate publicationDate; + private double price; + private int stock; + private List categories; + private String description; + private String language; + + private Book() { + // constructeur privé pour builder + } + + public String getIsbn() { + return isbn; + } + + public String getTitle() { + return title; + } + + public String getAuthor() { + return author; + } + + public String getPublisher() { + return publisher; + } + + public LocalDate getPublicationDate() { + return publicationDate; + } + + public double getPrice() { + return price; + } + + public int getStock() { + return stock; + } + + public List getCategories() { + return categories; + } + + public String getDescription() { + return description; + } + + public String getLanguage() { + return language; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final Book book = new Book(); + + public Builder isbn(String isbn) { + book.isbn = isbn; + return this; + } + + public Builder title(String title) { + book.title = title; + return this; + } + + public Builder author(String author) { + book.author = author; + return this; + } + + public Builder publisher(String publisher) { + book.publisher = publisher; + return this; + } + + public Builder publicationDate(LocalDate publicationDate) { + book.publicationDate = publicationDate; + return this; + } + + public Builder price(double price) { + book.price = price; + return this; + } + + public Builder stock(int stock) { + book.stock = stock; + return this; + } + + public Builder categories(List categories) { + book.categories = categories; + return this; + } + + public Builder description(String description) { + book.description = description; + return this; + } + + public Builder language(String language) { + book.language = language; + return this; + } + + public Book build() { + return book; + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java new file mode 100644 index 0000000..3686843 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java @@ -0,0 +1,11 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +public class BookNotFoundException extends RuntimeException { + public BookNotFoundException() { + super(); + } + + public BookNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnException.java new file mode 100644 index 0000000..c6e5387 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnException.java @@ -0,0 +1,11 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +public class InvalidIsbnException extends RuntimeException { + public InvalidIsbnException() { + super(); + } + + public InvalidIsbnException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java new file mode 100644 index 0000000..0735a58 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java @@ -0,0 +1,11 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +public class NotValidBookException extends RuntimeException { + public NotValidBookException() { + super(); + } + + public NotValidBookException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java new file mode 100644 index 0000000..ed70f9c --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java @@ -0,0 +1,13 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; + +import java.util.List; +import java.util.Optional; + +public interface BookRepository { + Optional findByIsbn(String isbn); + Book save(Book book); + void delete(Book book); + List findByTitleContaining(String title); +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java new file mode 100644 index 0000000..e211839 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java @@ -0,0 +1,98 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.*; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.book.validator.BookValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.book.converter.BookConverter; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class BookUseCase { + + private final BookRepository repository; + + public BookUseCase(BookRepository repository) { + this.repository = repository; + } + + public String registerBook(BookInfo info) throws NotValidBookException { + if (!BookValidator.isValid(info)) { + throw new NotValidBookException("Informations du livre invalides"); + } + Book book = BookConverter.fromInfo(info); + return repository.save(book).getIsbn(); + } + + public BookDTO findBookByIsbn(String isbn) { + return repository.findByIsbn(isbn) + .map(BookConverter::toDTO) + .orElseThrow(() -> new BookNotFoundException("Livre non trouvé avec ISBN: " + isbn)); + } + + public BookDTO updateBook(String isbn, BookInfo info) throws NotValidBookException, BookNotFoundException { + if (!BookValidator.isValid(info)) { + throw new NotValidBookException("Informations du livre invalides"); + } + + Book existing = repository.findByIsbn(isbn) + .orElseThrow(() -> new BookNotFoundException("Livre introuvable")); + + Book updated = BookConverter.fromInfo(info); + return BookConverter.toDTO(repository.save(updated)); + } + + public void deleteBook(String isbn) throws BookNotFoundException { + Book book = repository.findByIsbn(isbn) + .orElseThrow(() -> new BookNotFoundException("Livre introuvable")); + repository.delete(book); + } + + public int addStock(String isbn, int quantity) { + Book book = repository.findByIsbn(isbn) + .orElseThrow(() -> new BookNotFoundException("Livre introuvable")); + book = Book.builder() + .isbn(book.getIsbn()) + .title(book.getTitle()) + .author(book.getAuthor()) + .publisher(book.getPublisher()) + .publicationDate(book.getPublicationDate()) + .price(book.getPrice()) + .stock(book.getStock() + quantity) + .categories(book.getCategories()) + .description(book.getDescription()) + .language(book.getLanguage()) + .build(); + repository.save(book); + return book.getStock(); + } + + public int removeStock(String isbn, int quantity) { + Book book = repository.findByIsbn(isbn) + .orElseThrow(() -> new BookNotFoundException("Livre introuvable")); + book = Book.builder() + .isbn(book.getIsbn()) + .title(book.getTitle()) + .author(book.getAuthor()) + .publisher(book.getPublisher()) + .publicationDate(book.getPublicationDate()) + .price(book.getPrice()) + .stock(book.getStock() - quantity) + .categories(book.getCategories()) + .description(book.getDescription()) + .language(book.getLanguage()) + .build(); + repository.save(book); + return book.getStock(); + } + + public List findBooksByTitleContaining(String title) { + return repository.findByTitleContaining(title).stream() + .map(BookConverter::toDTO) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java new file mode 100644 index 0000000..c76dfac --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java @@ -0,0 +1,21 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; + +public class BookValidator { + + public static boolean isValid(BookInfo info) { + if (info == null) return false; + if (info.getIsbn() == null || !info.getIsbn().matches("\\\\d{13}")) return false; + if (info.getTitle() == null || info.getTitle().isBlank()) return false; + if (info.getAuthor() == null || info.getAuthor().isBlank()) return false; + if (info.getPublisher() == null || info.getPublisher().isBlank()) return false; + if (info.getPublicationDate() == null) return false; + if (info.getPrice() <= 0) return false; + if (info.getStock() < 0) return false; + if (info.getCategories() == null || info.getCategories().isEmpty()) return false; + if (info.getDescription() == null || info.getDescription().isBlank()) return false; + if (info.getLanguage() == null || info.getLanguage().isBlank()) return false; + return true; + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeDTO.java new file mode 100644 index 0000000..5712f3b --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeDTO.java @@ -0,0 +1,54 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.dto; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.AdresseLivraison; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.LigneCommande; + +import java.util.List; +import java.util.Objects; + +public class CommandeDTO { + + private final String clientId; + private final String methodePaiement; + private final List lignes; + private final AdresseLivraison adresseLivraison; + + public CommandeDTO(String clientId, String methodePaiement, List lignes, AdresseLivraison adresseLivraison) { + this.clientId = clientId; + this.methodePaiement = methodePaiement; + this.lignes = lignes; + this.adresseLivraison = adresseLivraison; + } + + public String getClientId() { + return clientId; + } + + public String getMethodePaiement() { + return methodePaiement; + } + + public List getLignes() { + return lignes; + } + + public AdresseLivraison getAdresseLivraison() { + return adresseLivraison; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CommandeDTO)) return false; + CommandeDTO that = (CommandeDTO) o; + return Objects.equals(clientId, that.clientId) + && Objects.equals(methodePaiement, that.methodePaiement) + && Objects.equals(lignes, that.lignes) + && Objects.equals(adresseLivraison, that.adresseLivraison); + } + + @Override + public int hashCode() { + return Objects.hash(clientId, methodePaiement, lignes, adresseLivraison); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeInfo.java new file mode 100644 index 0000000..cda28ce --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/CommandeInfo.java @@ -0,0 +1,59 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.dto; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Objects; + +public class CommandeInfo { + + private final String commandeId; + private final String clientId; + private final BigDecimal total; + private final String methodePaiement; + private final LocalDate dateCommande; + + public CommandeInfo(String commandeId, String clientId, BigDecimal total, String methodePaiement, LocalDate dateCommande) { + this.commandeId = commandeId; + this.clientId = clientId; + this.total = total; + this.methodePaiement = methodePaiement; + this.dateCommande = dateCommande; + } + + public String getCommandeId() { + return commandeId; + } + + public String getClientId() { + return clientId; + } + + public BigDecimal getTotal() { + return total; + } + + public String getMethodePaiement() { + return methodePaiement; + } + + public LocalDate getDateCommande() { + return dateCommande; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CommandeInfo)) return false; + CommandeInfo that = (CommandeInfo) o; + return Objects.equals(commandeId, that.commandeId) + && Objects.equals(clientId, that.clientId) + && Objects.equals(total, that.total) + && Objects.equals(methodePaiement, that.methodePaiement) + && Objects.equals(dateCommande, that.dateCommande); + } + + @Override + public int hashCode() { + return Objects.hash(commandeId, clientId, total, methodePaiement, dateCommande); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverter.java new file mode 100644 index 0000000..aa92a30 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverter.java @@ -0,0 +1,66 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.dto.CommandeDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.dto.CommandeInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.Commande; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CommandeConverter { + + public CommandeDTO toDTO(Commande commande) { + if (commande == null) return null; + + return new CommandeDTO( + commande.getClientId(), + commande.getMethodePaiement(), + commande.getLignes(), + commande.getAdresseLivraison() + ); + } + + public CommandeInfo toInfo(Commande commande) { + if (commande == null) return null; + + return new CommandeInfo( + commande.getCommandeId(), + commande.getClientId(), + commande.getTotal(), + commande.getMethodePaiement(), + commande.getDateCommande() + ); + } + + public static Map toMap(Commande commande) { + if (commande == null) return null; + + Map map = new HashMap<>(); + map.put("id", commande.getCommandeId()); + map.put("clientId", commande.getClientId()); + map.put("date", commande.getDateCommande()); + map.put("prixTotal", commande.getTotal()); + map.put("methodePaiement", commande.getMethodePaiement()); + + Map adresse = new HashMap<>(); + adresse.put("rue", commande.getAdresseLivraison().getRue()); + adresse.put("ville", commande.getAdresseLivraison().getVille()); + adresse.put("codePostal", commande.getAdresseLivraison().getCodePostal()); + adresse.put("pays", commande.getAdresseLivraison().getPays()); + map.put("adresseLivraison", adresse); + + List> lignes = commande.getLignes().stream() + .map(l -> { + Map ligneMap = new HashMap<>(); + ligneMap.put("isbn", l.getIsbn()); + ligneMap.put("quantite", l.getQuantite()); + ligneMap.put("prixUnitaire", l.getPrixUnitaire()); + return ligneMap; + }).toList(); + + map.put("lignes", lignes); + return map; + } + +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/AdresseLivraison.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/AdresseLivraison.java new file mode 100644 index 0000000..06bc8f0 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/AdresseLivraison.java @@ -0,0 +1,55 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.entity; + +import java.util.Objects; + +public class AdresseLivraison { + + private final String rue; + private final String ville; + private final String codePostal; + private final String pays; + + public AdresseLivraison(String rue, String ville, String codePostal, String pays) { + this.rue = rue; + this.ville = ville; + this.codePostal = codePostal; + this.pays = pays; + } + + public String getRue() { + return rue; + } + + public String getVille() { + return ville; + } + + public String getCodePostal() { + return codePostal; + } + + public String getPays() { + return pays; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AdresseLivraison)) return false; + AdresseLivraison that = (AdresseLivraison) o; + return Objects.equals(rue, that.rue) && + Objects.equals(ville, that.ville) && + Objects.equals(codePostal, that.codePostal) && + Objects.equals(pays, that.pays); + } + + @Override + public int hashCode() { + return Objects.hash(rue, ville, codePostal, pays); + } + + @Override + public String toString() { + return rue + ", " + codePostal + " " + ville + ", " + pays; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/Commande.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/Commande.java new file mode 100644 index 0000000..923b508 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/Commande.java @@ -0,0 +1,81 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.entity; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Objects; + +public class Commande { + + private final String commandeId; + private final String clientId; + private final List lignes; + private final AdresseLivraison adresseLivraison; + private final BigDecimal total; + private final String methodePaiement; + private final LocalDate dateCommande; + + public Commande(String commandeId, String clientId, List lignes, + AdresseLivraison adresseLivraison, BigDecimal total, + String methodePaiement, LocalDate dateCommande) { + this.commandeId = commandeId; + this.clientId = clientId; + this.lignes = lignes; + this.adresseLivraison = adresseLivraison; + this.total = total; + this.methodePaiement = methodePaiement; + this.dateCommande = dateCommande; + } + + public String getCommandeId() { + return commandeId; + } + + public String getClientId() { + return clientId; + } + + public List getLignes() { + return lignes; + } + + public AdresseLivraison getAdresseLivraison() { + return adresseLivraison; + } + + public BigDecimal getTotal() { + return total; + } + + public String getMethodePaiement() { + return methodePaiement; + } + + public LocalDate getDateCommande() { + return dateCommande; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Commande)) return false; + Commande commande = (Commande) o; + return Objects.equals(commandeId, commande.commandeId); + } + + @Override + public int hashCode() { + return Objects.hash(commandeId); + } + + @Override + public String toString() { + return "Commande{" + + "commandeId='" + commandeId + '\'' + + ", clientId='" + clientId + '\'' + + ", total=" + total + + ", paiement='" + methodePaiement + '\'' + + ", date=" + dateCommande + + '}'; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/LigneCommande.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/LigneCommande.java new file mode 100644 index 0000000..c67c7a1 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/LigneCommande.java @@ -0,0 +1,53 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.entity; + +import java.math.BigDecimal; +import java.util.Objects; + +public class LigneCommande { + + private final String isbn; + private final int quantite; + private final BigDecimal prixUnitaire; + + public LigneCommande(String isbn, int quantite, BigDecimal prixUnitaire) { + this.isbn = isbn; + this.quantite = quantite; + this.prixUnitaire = prixUnitaire; + } + + public String getIsbn() { + return isbn; + } + + public int getQuantite() { + return quantite; + } + + public BigDecimal getPrixUnitaire() { + return prixUnitaire; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LigneCommande)) return false; + LigneCommande that = (LigneCommande) o; + return quantite == that.quantite && + Objects.equals(isbn, that.isbn) && + Objects.equals(prixUnitaire, that.prixUnitaire); + } + + @Override + public int hashCode() { + return Objects.hash(isbn, quantite, prixUnitaire); + } + + @Override + public String toString() { + return "LigneCommande{" + + "isbn='" + isbn + '\'' + + ", quantite=" + quantite + + ", prixUnitaire=" + prixUnitaire + + '}'; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundException.java new file mode 100644 index 0000000..175aabb --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.exception; + +public class CommandeNotFoundException extends RuntimeException { + + public CommandeNotFoundException(String message) { + super(message); + } + + public CommandeNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeException.java new file mode 100644 index 0000000..ddcf96e --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeException.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.exception; + +public class NotValidCommandeException extends RuntimeException { + + public NotValidCommandeException(String message) { + super(message); + } + + public NotValidCommandeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepository.java new file mode 100644 index 0000000..dea8055 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepository.java @@ -0,0 +1,17 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.Commande; + +import java.util.List; +import java.util.Optional; + +public interface CommandeRepository { + + Commande save(Commande commande); + + Optional findById(String commandeId); + + List findByClientId(String clientId); + + List findAll(); +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCase.java new file mode 100644 index 0000000..885fd66 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCase.java @@ -0,0 +1,119 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.CommandeNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.NotValidCommandeException; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.repository.CommandeRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.validator.CommandeValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.converter.CommandeConverter; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.*; + +public class CommandeUseCase { + + private final CommandeRepository repository; + private final CommandeValidator validator; + private final Map stockParLivre; + private final Map pointsFideliteParClient; + + public CommandeUseCase( + CommandeRepository repository, + CommandeValidator validator, + Map stockParLivre, + Map pointsFideliteParClient + ) { + this.repository = repository; + this.validator = validator; + this.stockParLivre = stockParLivre; + this.pointsFideliteParClient = pointsFideliteParClient; + } + + public Commande creerCommande(String clientId, String methodePaiement, + List lignes, AdresseLivraison adresse) { + + if (!pointsFideliteParClient.containsKey(clientId)) { + throw new NotValidCommandeException("Le client n'existe pas"); + } + + // Vérifier le stock pour chaque livre + for (LigneCommande ligne : lignes) { + int stockDispo = stockParLivre.getOrDefault(ligne.getIsbn(), 0); + if (ligne.getQuantite() > stockDispo) { + throw new NotValidCommandeException("Stock insuffisant pour le livre : " + ligne.getIsbn()); + } + } + + // Calcul du total + BigDecimal total = lignes.stream() + .map(l -> l.getPrixUnitaire().multiply(BigDecimal.valueOf(l.getQuantite()))) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + // Déduire points de fidélité si nécessaire + if ("LOYALTY_POINTS".equalsIgnoreCase(methodePaiement)) { + int pointsDispo = pointsFideliteParClient.get(clientId); + int pointsRequis = total.multiply(BigDecimal.valueOf(20)).intValue(); // 1€ = 20pts + + if (pointsRequis > pointsDispo) { + throw new NotValidCommandeException("Pas assez de points fidélité pour payer cette commande"); + } + pointsFideliteParClient.put(clientId, pointsDispo - pointsRequis); + } + + // Décrémenter le stock + for (LigneCommande ligne : lignes) { + stockParLivre.put(ligne.getIsbn(), + stockParLivre.get(ligne.getIsbn()) - ligne.getQuantite()); + } + + // Générer et valider commande + String id = UUID.randomUUID().toString(); + Commande commande = new Commande( + id, + clientId, + lignes, + adresse, + total, + methodePaiement, + LocalDate.now() + ); + + validator.valider(commande); + return repository.save(commande); + } + + public Commande trouverParId(String commandeId) { + return repository.findById(commandeId) + .orElseThrow(() -> new CommandeNotFoundException("Commande non trouvée : " + commandeId)); + } + + public List trouverParClientId(String clientId) { + if (!pointsFideliteParClient.containsKey(clientId)) { + throw new NotValidCommandeException("Client non trouvé"); + } + return repository.findByClientId(clientId); + } + + public Map recupererCommandeParId(String commandeId) { + Optional optCommande = repository.findById(commandeId); + if (optCommande.isEmpty()) { + throw new IllegalArgumentException("Commande non trouvée"); + } + return CommandeConverter.toMap(trouverParId(commandeId)); + } + + public List> recupererCommandesParClient(String clientId) { + if (!pointsFideliteParClient.containsKey(clientId)) { + throw new NotValidCommandeException("Client non trouvé"); + } + return repository.findByClientId(clientId).stream() + .map(CommandeConverter::toMap) + .toList(); + } + + public CommandeRepository getRepository() { + return this.repository; + } + +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidator.java new file mode 100644 index 0000000..9a40395 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidator.java @@ -0,0 +1,61 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.NotValidCommandeException; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; + +public class CommandeValidator { + + private static final Set MODES_VALIDES = Set.of("CREDIT_CARD", "LOYALTY_POINTS"); + + public void valider(Commande commande) { + if (commande == null) { + throw new NotValidCommandeException("Commande null"); + } + + if (commande.getClientId() == null || commande.getClientId().isBlank()) { + throw new NotValidCommandeException("Client ID manquant"); + } + + List lignes = commande.getLignes(); + if (lignes == null || lignes.isEmpty()) { + throw new NotValidCommandeException("La commande doit contenir au moins un livre"); + } + + for (LigneCommande ligne : lignes) { + if (ligne.getIsbn() == null || ligne.getIsbn().isBlank()) { + throw new NotValidCommandeException("ISBN manquant dans une ligne de commande"); + } + if (ligne.getQuantite() <= 0) { + throw new NotValidCommandeException("Quantité invalide pour un livre"); + } + if (ligne.getPrixUnitaire() == null || ligne.getPrixUnitaire().compareTo(BigDecimal.ZERO) <= 0) { + throw new NotValidCommandeException("Prix unitaire invalide pour un livre"); + } + } + + AdresseLivraison adresse = commande.getAdresseLivraison(); + if (adresse == null || + adresse.getRue() == null || adresse.getRue().isBlank() || + adresse.getVille() == null || adresse.getVille().isBlank() || + adresse.getCodePostal() == null || adresse.getCodePostal().isBlank() || + adresse.getPays() == null || adresse.getPays().isBlank()) { + throw new NotValidCommandeException("Adresse de livraison incomplète"); + } + + if (commande.getMethodePaiement() == null || !MODES_VALIDES.contains(commande.getMethodePaiement().toUpperCase())) { + throw new NotValidCommandeException("Mode de paiement invalide"); + } + + if (commande.getTotal() == null || commande.getTotal().compareTo(BigDecimal.ZERO) <= 0) { + throw new NotValidCommandeException("Total invalide"); + } + + if (commande.getDateCommande() == null) { + throw new NotValidCommandeException("Date de commande manquante"); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverterTest.java new file mode 100644 index 0000000..a70af7b --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/converter/AbonnementConverterTest.java @@ -0,0 +1,68 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto.AbonnementDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.dto.AbonnementInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementConverterTest { + + private AbonnementConverter converter; + + @BeforeEach + public void setup() { + converter = new AbonnementConverter(); + } + + @Test + public void testToDTO() { + Abonnement a = new Abonnement("client-1", 12, "CB", LocalDate.of(2025, 1, 1), LocalDate.of(2026, 1, 1), new BigDecimal("10.00")); + AbonnementDTO dto = converter.toDTO(a); + + assertNotNull(dto); + assertEquals("client-1", dto.getClientId()); + assertEquals(12, dto.getDuree()); + assertEquals("CB", dto.getModePaiement()); + assertEquals(LocalDate.of(2025, 1, 1), dto.getDateDebut()); + assertEquals(LocalDate.of(2026, 1, 1), dto.getDateFin()); + assertEquals(new BigDecimal("10.00"), dto.getMontantMensuel()); + } + + @Test + public void testToDomain() { + AbonnementDTO dto = new AbonnementDTO("client-2", 6, "PAYPAL", LocalDate.of(2025, 3, 1), LocalDate.of(2025, 9, 1), new BigDecimal("8.50")); + Abonnement a = converter.toDomain(dto); + + assertNotNull(a); + assertEquals("client-2", a.getClientId()); + assertEquals(6, a.getDuree()); + assertEquals("PAYPAL", a.getModePaiement()); + assertEquals(LocalDate.of(2025, 3, 1), a.getDateDebut()); + assertEquals(LocalDate.of(2025, 9, 1), a.getDateFin()); + assertEquals(new BigDecimal("8.50"), a.getMontantMensuel()); + } + + @Test + public void testToInfo() { + Abonnement a = new Abonnement("client-3", 3, "CB", LocalDate.of(2025, 5, 1), LocalDate.of(2025, 8, 1), new BigDecimal("12.00")); + AbonnementInfo info = converter.toInfo(a); + + assertNotNull(info); + assertEquals("client-3", info.getClientId()); + assertEquals(3, info.getDuree()); + assertEquals("CB", info.getModePaiement()); + } + + @Test + public void testNullInputs() { + assertNull(converter.toDTO(null)); + assertNull(converter.toDomain(null)); + assertNull(converter.toInfo(null)); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/AbonnementTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/AbonnementTest.java new file mode 100644 index 0000000..d78e472 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/entity/AbonnementTest.java @@ -0,0 +1,44 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementTest { + + @Test + public void testConstructeurEtGetters() { + LocalDate debut = LocalDate.of(2025, 6, 1); + LocalDate fin = debut.plusMonths(6); + Abonnement a = new Abonnement("client-1", 6, "CB", debut, fin, new BigDecimal("10.00")); + + assertEquals("client-1", a.getClientId()); + assertEquals(6, a.getDuree()); + assertEquals("CB", a.getModePaiement()); + assertEquals(debut, a.getDateDebut()); + assertEquals(fin, a.getDateFin()); + assertEquals(new BigDecimal("10.00"), a.getMontantMensuel()); + } + + @Test + public void testEqualsEtHashCode() { + LocalDate debut = LocalDate.of(2025, 1, 1); + Abonnement a1 = new Abonnement("client-2", 3, "PAYPAL", debut, debut.plusMonths(3), new BigDecimal("9.99")); + Abonnement a2 = new Abonnement("client-2", 3, "PAYPAL", debut, debut.plusMonths(3), new BigDecimal("9.99")); + Abonnement a3 = new Abonnement("autre", 12, "CB", debut, debut.plusMonths(12), new BigDecimal("15.00")); + + assertEquals(a1, a2); + assertEquals(a1.hashCode(), a2.hashCode()); + assertNotEquals(a1, a3); + } + + @Test + public void testToStringNonVide() { + Abonnement a = new Abonnement("client-4", 12, "CB", LocalDate.now(), LocalDate.now().plusMonths(12), new BigDecimal("13.99")); + assertNotNull(a.toString()); + assertFalse(a.toString().isBlank()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundExceptionTest.java new file mode 100644 index 0000000..73021d1 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/AbonnementNotFoundExceptionTest.java @@ -0,0 +1,28 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementNotFoundExceptionTest { + + @Test + public void testConstructeurAvecMessage() { + AbonnementNotFoundException e = new AbonnementNotFoundException("Abonnement introuvable"); + assertEquals("Abonnement introuvable", e.getMessage()); + } + + @Test + public void testConstructeurAvecCause() { + Throwable cause = new RuntimeException("Cause d'origine"); + AbonnementNotFoundException e = new AbonnementNotFoundException("Erreur", cause); + assertEquals("Erreur", e.getMessage()); + assertEquals(cause, e.getCause()); + } + + @Test + public void testEstRuntimeException() { + AbonnementNotFoundException e = new AbonnementNotFoundException("test"); + assertTrue(e instanceof RuntimeException); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementExceptionTest.java new file mode 100644 index 0000000..db3e47a --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/exception/NotValidAbonnementExceptionTest.java @@ -0,0 +1,28 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class NotValidAbonnementExceptionTest { + + @Test + public void testConstructeurAvecMessage() { + NotValidAbonnementException e = new NotValidAbonnementException("Abonnement invalide"); + assertEquals("Abonnement invalide", e.getMessage()); + } + + @Test + public void testConstructeurAvecCause() { + Throwable cause = new IllegalArgumentException("champ manquant"); + NotValidAbonnementException e = new NotValidAbonnementException("Erreur de validation", cause); + assertEquals("Erreur de validation", e.getMessage()); + assertEquals(cause, e.getCause()); + } + + @Test + public void testEstRuntimeException() { + NotValidAbonnementException e = new NotValidAbonnementException("test"); + assertTrue(e instanceof RuntimeException); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepositoryTest.java new file mode 100644 index 0000000..fe4cff5 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/AbonnementRepositoryTest.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementRepositoryTest { + + private AbonnementRepository repository; + private Abonnement a1, a2; + + @BeforeEach + public void setup() { + repository = new InMemoryAbonnementRepository(); + + a1 = new Abonnement("client-1", 12, "CB", LocalDate.of(2025, 1, 1), LocalDate.of(2026, 1, 1), new BigDecimal("10.0")); + a2 = new Abonnement("client-2", 6, "PAYPAL", LocalDate.of(2025, 2, 1), LocalDate.of(2025, 8, 1), new BigDecimal("12.5")); + + repository.save(a1); + repository.save(a2); + } + + @Test + public void testFindByClientId() { + Optional found = repository.findByClientId("client-1"); + assertTrue(found.isPresent()); + assertEquals("CB", found.get().getModePaiement()); + } + + @Test + public void testSaveOverridesExisting() { + Abonnement updated = new Abonnement("client-1", 3, "PAYPAL", LocalDate.of(2025, 3, 1), LocalDate.of(2025, 6, 1), new BigDecimal("8.0")); + repository.save(updated); + + Optional found = repository.findByClientId("client-1"); + assertTrue(found.isPresent()); + assertEquals(3, found.get().getDuree()); + assertEquals("PAYPAL", found.get().getModePaiement()); + } + + @Test + public void testFindAll() { + List all = repository.findAll(); + assertEquals(2, all.size()); + } + + @Test + public void testDeleteByClientId() { + repository.deleteByClientId("client-2"); + assertFalse(repository.findByClientId("client-2").isPresent()); + assertEquals(1, repository.findAll().size()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/InMemoryAbonnementRepository.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/InMemoryAbonnementRepository.java new file mode 100644 index 0000000..9da264f --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/repository/InMemoryAbonnementRepository.java @@ -0,0 +1,31 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; + +import java.util.*; + +public class InMemoryAbonnementRepository implements AbonnementRepository { + + private final Map abonnementsParClientId = new HashMap<>(); + + @Override + public Abonnement save(Abonnement abonnement) { + abonnementsParClientId.put(abonnement.getClientId(), abonnement); + return abonnement; + } + + @Override + public Optional findByClientId(String clientId) { + return Optional.ofNullable(abonnementsParClientId.get(clientId)); + } + + @Override + public void deleteByClientId(String clientId) { + abonnementsParClientId.remove(clientId); + } + + @Override + public List findAll() { + return new ArrayList<>(abonnementsParClientId.values()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCaseTest.java new file mode 100644 index 0000000..ed7fd7a --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/usecase/AbonnementUseCaseTest.java @@ -0,0 +1,65 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.AbonnementNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.NotValidAbonnementException; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository.InMemoryAbonnementRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.validator.AbonnementValidator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementUseCaseTest { + + private AbonnementUseCase useCase; + + @BeforeEach + public void setup() { + useCase = new AbonnementUseCase( + new InMemoryAbonnementRepository(), + new AbonnementValidator() + ); + } + + @Test + public void testCreerAbonnementValideFonctionne() { + LocalDate dateDebut = LocalDate.of(2025, 6, 1); + Abonnement a = useCase.creerAbonnement("client-1", 12, "CB", dateDebut); + + assertNotNull(a); + assertEquals("client-1", a.getClientId()); + assertEquals(12, a.getDuree()); + assertEquals("CB", a.getModePaiement()); + assertEquals(dateDebut, a.getDateDebut()); + assertEquals(dateDebut.plusMonths(12), a.getDateFin()); + assertTrue(a.getMontantMensuel().compareTo(BigDecimal.ZERO) > 0); + } + + @Test + public void testCreerAbonnementAvecDureeInvalide() { + LocalDate date = LocalDate.now(); + assertThrows(NotValidAbonnementException.class, () -> + useCase.creerAbonnement("client-2", 5, "CB", date) + ); + } + + @Test + public void testTrouverParClientIdFonctionne() { + Abonnement a = useCase.creerAbonnement("client-3", 6, "PAYPAL", LocalDate.now()); + Abonnement trouvé = useCase.trouverParClientId("client-3"); + + assertEquals(a.getClientId(), trouvé.getClientId()); + assertEquals(a.getDuree(), trouvé.getDuree()); + } + + @Test + public void testTrouverParClientIdInexistantÉchoue() { + assertThrows(AbonnementNotFoundException.class, () -> + useCase.trouverParClientId("inexistant-uuid") + ); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidatorTest.java new file mode 100644 index 0000000..966926d --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/abonnement/validator/AbonnementValidatorTest.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.abonnement.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.NotValidAbonnementException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbonnementValidatorTest { + + private AbonnementValidator validator; + private final String clientId = "client-1"; + + @BeforeEach + public void setup() { + validator = new AbonnementValidator(); + } + + @Test + public void testAbonnementValideNeLèvePasException() { + Abonnement a = new Abonnement(clientId, 6, "CB", LocalDate.now(), LocalDate.now().plusMonths(6), new BigDecimal("9.99")); + assertDoesNotThrow(() -> validator.valider(a)); + } + + @Test + public void testClientIdInvalide() { + Abonnement a = new Abonnement(null, 6, "CB", LocalDate.now(), LocalDate.now().plusMonths(6), new BigDecimal("9.99")); + assertThrows(NotValidAbonnementException.class, () -> validator.valider(a)); + } + + @Test + public void testDureeInvalide() { + Abonnement a = new Abonnement(clientId, 5, "CB", LocalDate.now(), LocalDate.now().plusMonths(5), new BigDecimal("9.99")); + NotValidAbonnementException e = assertThrows(NotValidAbonnementException.class, () -> validator.valider(a)); + assertTrue(e.getMessage().contains("durée")); + } + + @Test + public void testModePaiementInvalide() { + Abonnement a = new Abonnement(clientId, 6, "CHEQUE", LocalDate.now(), LocalDate.now().plusMonths(6), new BigDecimal("9.99")); + NotValidAbonnementException e = assertThrows(NotValidAbonnementException.class, () -> validator.valider(a)); + assertTrue(e.getMessage().contains("mode de paiement")); + } + + @Test + public void testDateDebutNulle() { + Abonnement a = new Abonnement(clientId, 6, "CB", null, LocalDate.now().plusMonths(6), new BigDecimal("9.99")); + assertThrows(NotValidAbonnementException.class, () -> validator.valider(a)); + } + + @Test + public void testMontantNégatifOuNul() { + Abonnement a = new Abonnement(clientId, 6, "CB", LocalDate.now(), LocalDate.now().plusMonths(6), BigDecimal.ZERO); + assertThrows(NotValidAbonnementException.class, () -> validator.valider(a)); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java new file mode 100644 index 0000000..f76fdf2 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java @@ -0,0 +1,73 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.dto.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.dto.AvisInfo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisConverterTest { + + private AvisConverter converter; + + @BeforeEach + public void setup() { + converter = new AvisConverter(); + } + + @Test + public void testToDTO() { + Avis avis = new Avis("client-1", "livre-1", 4, "Bon livre", LocalDate.of(2023, 1, 1)); + AvisDTO dto = converter.toDTO(avis); + + assertNotNull(dto); + assertEquals("client-1", dto.getClientId()); + assertEquals("livre-1", dto.getLivreId()); + assertEquals(4, dto.getNote()); + assertEquals("Bon livre", dto.getCommentaire()); + assertEquals(LocalDate.of(2023, 1, 1), dto.getDateAchat()); + } + + @Test + public void testToDomain() { + AvisDTO dto = new AvisDTO("client-1", "livre-1", 5, "Excellent", LocalDate.of(2023, 2, 1)); + Avis avis = converter.toDomain(dto); + + assertNotNull(avis); + assertEquals("client-1", avis.getClientId()); + assertEquals("livre-1", avis.getLivreId()); + assertEquals(5, avis.getNote()); + assertEquals("Excellent", avis.getCommentaire()); + assertEquals(LocalDate.of(2023, 2, 1), avis.getDateAchat()); + } + + @Test + public void testToInfo() { + Avis avis = new Avis("client-2", "livre-9", 3, "Pas mal", LocalDate.of(2022, 10, 10)); + AvisInfo info = converter.toInfo(avis); + + assertNotNull(info); + assertEquals("client-2", info.getClientId()); + assertEquals(3, info.getNote()); + assertEquals("Pas mal", info.getCommentaire()); + } + + @Test + public void testToDTO_NullInput() { + assertNull(converter.toDTO(null)); + } + + @Test + public void testToDomain_NullInput() { + assertNull(converter.toDomain(null)); + } + + @Test + public void testToInfo_NullInput() { + assertNull(converter.toInfo(null)); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java new file mode 100644 index 0000000..0780034 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java @@ -0,0 +1,46 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisTest { + + @Test + public void testConstructeurEtGetters() { + String clientId = "client-1"; + String livreId = "livre-1"; + int note = 5; + String commentaire = "Excellent livre !"; + LocalDate dateAchat = LocalDate.of(2023, 6, 1); + + Avis avis = new Avis(clientId, livreId, note, commentaire, dateAchat); + + assertEquals(clientId, avis.getClientId()); + assertEquals(livreId, avis.getLivreId()); + assertEquals(note, avis.getNote()); + assertEquals(commentaire, avis.getCommentaire()); + assertEquals(dateAchat, avis.getDateAchat()); + } + + @Test + public void testEqualsEtHashCode() { + Avis a1 = new Avis("c1", "l1", 4, "Bien", LocalDate.of(2023, 1, 1)); + Avis a2 = new Avis("c1", "l1", 4, "Bien", LocalDate.of(2023, 1, 1)); + Avis a3 = new Avis("c2", "l2", 3, "Bof", LocalDate.of(2023, 2, 2)); + + assertEquals(a1, a2); + assertEquals(a1.hashCode(), a2.hashCode()); + + assertNotEquals(a1, a3); + } + + @Test + public void testToStringNonVide() { + Avis avis = new Avis("client", "livre", 5, "Très bon", LocalDate.now()); + assertNotNull(avis.toString()); + assertFalse(avis.toString().isBlank()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java new file mode 100644 index 0000000..c19654b --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java @@ -0,0 +1,28 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisNotFoundExceptionTest { + + @Test + public void testConstructeurAvecMessage() { + AvisNotFoundException e = new AvisNotFoundException("Avis introuvable"); + assertEquals("Avis introuvable", e.getMessage()); + } + + @Test + public void testConstructeurAvecMessageEtCause() { + Throwable cause = new RuntimeException("Cause réelle"); + AvisNotFoundException e = new AvisNotFoundException("Erreur", cause); + assertEquals("Erreur", e.getMessage()); + assertEquals(cause, e.getCause()); + } + + @Test + public void testEstRuntimeException() { + AvisNotFoundException e = new AvisNotFoundException("message"); + assertTrue(e instanceof RuntimeException); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java new file mode 100644 index 0000000..4180d3c --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java @@ -0,0 +1,28 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class NotValidAvisExceptionTest { + + @Test + public void testConstructeurAvecMessage() { + NotValidAvisException e = new NotValidAvisException("Validation échouée"); + assertEquals("Validation échouée", e.getMessage()); + } + + @Test + public void testConstructeurAvecMessageEtCause() { + Throwable cause = new IllegalArgumentException("champ manquant"); + NotValidAvisException e = new NotValidAvisException("Erreur de validation", cause); + assertEquals("Erreur de validation", e.getMessage()); + assertEquals(cause, e.getCause()); + } + + @Test + public void testEstRuntimeException() { + NotValidAvisException e = new NotValidAvisException("erreur"); + assertTrue(e instanceof RuntimeException); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java new file mode 100644 index 0000000..a040c40 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java @@ -0,0 +1,86 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisRepositoryTest { + + private AvisRepository repository; + + private final String clientId1 = "client-1"; + private final String clientId2 = "client-2"; + private final String livreId1 = "livre-1"; + private final String livreId2 = "livre-2"; + + private Avis avis1; + private Avis avis2; + + @BeforeEach + public void setup() { + repository = new InMemoryAvisRepository(); + + avis1 = new Avis(clientId1, livreId1, 5, "Super", LocalDate.of(2023, 1, 1)); + avis2 = new Avis(clientId2, livreId1, 4, "Bien", LocalDate.of(2023, 2, 1)); + + repository.save(avis1); + repository.save(avis2); + } + + @Test + public void testSaveAndFindByClientAndLivre() { + Optional found = repository.findByClientAndLivre(clientId1, livreId1); + assertTrue(found.isPresent()); + assertEquals(avis1.getCommentaire(), found.get().getCommentaire()); + } + + @Test + public void testSaveOverridesExisting() { + Avis updated = new Avis(clientId1, livreId1, 3, "Moyen", LocalDate.of(2023, 1, 1)); + repository.save(updated); + + List all = repository.findAll(); + assertEquals(2, all.size()); + + Optional result = repository.findByClientAndLivre(clientId1, livreId1); + assertTrue(result.isPresent()); + assertEquals(3, result.get().getNote()); + assertEquals("Moyen", result.get().getCommentaire()); + } + + @Test + public void testFindAll() { + List all = repository.findAll(); + assertEquals(2, all.size()); + } + + @Test + public void testFindByLivre() { + List avis = repository.findByLivre(livreId1); + assertEquals(2, avis.size()); + + List vide = repository.findByLivre("inexistant"); + assertTrue(vide.isEmpty()); + } + + @Test + public void testFindByClient() { + List avis = repository.findByClient(clientId1); + assertEquals(1, avis.size()); + assertEquals("Super", avis.get(0).getCommentaire()); + } + + @Test + public void testDeleteByClientAndLivre() { + repository.deleteByClientAndLivre(clientId1, livreId1); + Optional result = repository.findByClientAndLivre(clientId1, livreId1); + assertTrue(result.isEmpty()); + assertEquals(1, repository.findAll().size()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/InMemoryAvisRepository.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/InMemoryAvisRepository.java new file mode 100644 index 0000000..08ec4ed --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/InMemoryAvisRepository.java @@ -0,0 +1,49 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; + +import java.util.*; +import java.util.stream.Collectors; + +public class InMemoryAvisRepository implements AvisRepository { + + private final List avisList = new ArrayList<>(); + + @Override + public Avis save(Avis avis) { + deleteByClientAndLivre(avis.getClientId(), avis.getLivreId()); + avisList.add(avis); + return avis; + } + + @Override + public Optional findByClientAndLivre(String clientId, String livreId) { + return avisList.stream() + .filter(a -> a.getClientId().equals(clientId) && a.getLivreId().equals(livreId)) + .findFirst(); + } + + @Override + public void deleteByClientAndLivre(String clientId, String livreId) { + avisList.removeIf(a -> a.getClientId().equals(clientId) && a.getLivreId().equals(livreId)); + } + + @Override + public List findAll() { + return new ArrayList<>(avisList); // copie défensive + } + + @Override + public List findByLivre(String livreId) { + return avisList.stream() + .filter(a -> a.getLivreId().equals(livreId)) + .collect(Collectors.toList()); + } + + @Override + public List findByClient(String clientId) { + return avisList.stream() + .filter(a -> a.getClientId().equals(clientId)) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java new file mode 100644 index 0000000..a82f3f3 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java @@ -0,0 +1,89 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.InMemoryAvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.validator.AvisValidator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisUseCaseTest { + + private AvisUseCase useCase; + + private final String clientId = "client-1"; + private final String livreId = "livre-1"; + + @BeforeEach + public void setup() { + useCase = new AvisUseCase(new InMemoryAvisRepository(), new AvisValidator()); + } + + @Test + public void testAjouterAvisValideFonctionne() { + Avis avis = new Avis(clientId, livreId, 5, "Très bon", LocalDate.now()); + useCase.simulerAchat(clientId, livreId); + useCase.ajouterAvis(avis); + + List liste = useCase.recupererAvisParLivre(livreId); + assertEquals(1, liste.size()); + assertEquals("Très bon", liste.get(0).getCommentaire()); + } + + @Test + public void testAjouterAvisAvecNoteInvalideÉchoue() { + Avis avis = new Avis(clientId, livreId, 6, "Trop bien", LocalDate.now()); + useCase.simulerAchat(clientId, livreId); + assertThrows(NotValidAvisException.class, () -> useCase.ajouterAvis(avis)); + } + + @Test + public void testAjouterAvisSansAchatÉchoue() { + Avis avis = new Avis(clientId, livreId, 4, "Correct", LocalDate.now()); + // pas de simulerAchat ici + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> useCase.ajouterAvis(avis)); + assertTrue(e.getMessage().contains("n’a pas acheté le livre")); + } + + @Test + public void testModifierAvisExistant() { + Avis avis = new Avis(clientId, livreId, 4, "OK", LocalDate.of(2023, 1, 1)); + useCase.simulerAchat(clientId, livreId); + useCase.ajouterAvis(avis); + + useCase.modifierAvis(clientId, livreId, 3, "Moyen"); + + List liste = useCase.recupererAvisParLivre(livreId); + assertEquals(1, liste.size()); + assertEquals(3, liste.get(0).getNote()); + assertEquals("Moyen", liste.get(0).getCommentaire()); + } + + @Test + public void testSupprimerAvisFonctionne() { + Avis avis = new Avis(clientId, livreId, 5, "À lire", LocalDate.now()); + useCase.simulerAchat(clientId, livreId); + useCase.ajouterAvis(avis); + + useCase.supprimerAvis(clientId, livreId); + + List liste = useCase.recupererAvisParLivre(livreId); + assertTrue(liste.isEmpty()); + } + + @Test + public void testRecupererAvisParClient() { + useCase.simulerAchat(clientId, livreId); + Avis avis = new Avis(clientId, livreId, 5, "Cool", LocalDate.now()); + useCase.ajouterAvis(avis); + + List clientAvis = useCase.recupererAvisParClient(clientId); + assertEquals(1, clientAvis.size()); + assertEquals("Cool", clientAvis.get(0).getCommentaire()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java new file mode 100644 index 0000000..6832c07 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java @@ -0,0 +1,70 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; + +public class AvisValidatorTest { + + private AvisValidator validator; + private final String clientId = "client-1"; + private final String livreId = "livre-1"; + + @BeforeEach + public void setup() { + validator = new AvisValidator(); + } + + @Test + public void testAvisValideNeLèvePasException() { + Avis avis = new Avis(clientId, livreId, 4, "Bon livre", LocalDate.now()); + assertDoesNotThrow(() -> validator.valider(avis)); + } + + @Test + public void testNoteTropBasse() { + Avis avis = new Avis(clientId, livreId, 0, "Commentaire", LocalDate.now()); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("La note doit être entre 1 et 5")); + } + + @Test + public void testNoteTropHaute() { + Avis avis = new Avis(clientId, livreId, 6, "Commentaire", LocalDate.now()); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("La note doit être entre 1 et 5")); + } + + @Test + public void testCommentaireVide() { + Avis avis = new Avis(clientId, livreId, 3, "", LocalDate.now()); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("Le commentaire ne peut pas être vide")); + } + + @Test + public void testClientIdNull() { + Avis avis = new Avis(null, livreId, 4, "Commentaire", LocalDate.now()); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("Le client est obligatoire")); + } + + @Test + public void testLivreIdVide() { + Avis avis = new Avis(clientId, "", 4, "Commentaire", LocalDate.now()); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("Le livre est obligatoire")); + } + + @Test + public void testDateAchatNulle() { + Avis avis = new Avis(clientId, livreId, 4, "Commentaire", null); + NotValidAvisException e = assertThrows(NotValidAvisException.class, () -> validator.valider(avis)); + assertTrue(e.getMessage().contains("La date d'achat est obligatoire")); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java new file mode 100644 index 0000000..f3dc938 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java @@ -0,0 +1,59 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class BookConverterTest { + + @Test + void shouldConvertBookToDTO() { + Book book = Book.builder() + .isbn("9782253004201") + .title("Les Fleurs du Mal") + .author("Charles Baudelaire") + .publisher("Garnier-Flammarion") + .publicationDate(LocalDate.of(1857, 6, 25)) + .price(9.90) + .stock(15) + .categories(List.of(Category.POESIE, Category.CLASSIQUE)) + .description("Recueil de poèmes symbolistes") + .language("Français") + .build(); + + BookDTO dto = BookConverter.toDTO(book); + + assertEquals("9782253004201", dto.getIsbn()); + assertEquals("Les Fleurs du Mal", dto.getTitle()); + assertEquals("Charles Baudelaire", dto.getAuthor()); + } + + @Test + void shouldConvertBookInfoToEntity() { + BookInfo info = new BookInfo( + "9782253004201", + "Les Fleurs du Mal", + "Charles Baudelaire", + "Garnier-Flammarion", + LocalDate.of(1857, 6, 25), + 9.90, + 15, + List.of(Category.POESIE, Category.CLASSIQUE), + "Recueil de poèmes symbolistes", + "Français" + ); + + Book book = BookConverter.fromInfo(info); + + assertEquals("9782253004201", book.getIsbn()); + assertEquals("Les Fleurs du Mal", book.getTitle()); + assertEquals(15, book.getStock()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java new file mode 100644 index 0000000..9f15c2a --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java @@ -0,0 +1,39 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.entity; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class BookTest { + + @Test + void shouldCreateBookWithAllFields() { + Book book = Book.builder() + .isbn("9782253004201") + .title("Les Fleurs du Mal") + .author("Charles Baudelaire") + .publisher("Garnier-Flammarion") + .publicationDate(LocalDate.of(1857, 6, 25)) + .price(9.90) + .stock(15) + .categories(List.of(Category.POESIE, Category.CLASSIQUE)) + .description("Recueil de poèmes symbolistes") + .language("Français") + .build(); + + assertEquals("9782253004201", book.getIsbn()); + assertEquals("Les Fleurs du Mal", book.getTitle()); + assertEquals("Charles Baudelaire", book.getAuthor()); + assertEquals("Garnier-Flammarion", book.getPublisher()); + assertEquals(LocalDate.of(1857, 6, 25), book.getPublicationDate()); + assertEquals(9.90, book.getPrice()); + assertEquals(15, book.getStock()); + assertTrue(book.getCategories().contains(Category.POESIE)); + assertEquals("Recueil de poèmes symbolistes", book.getDescription()); + assertEquals("Français", book.getLanguage()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java new file mode 100644 index 0000000..6daf4b3 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java @@ -0,0 +1,21 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class BookNotFoundExceptionTest { + + @Test + void shouldCreateExceptionWithDefaultConstructor() { + BookNotFoundException exception = new BookNotFoundException(); + assertNotNull(exception); + } + + @Test + void shouldCreateExceptionWithMessage() { + String message = "Livre non trouvé"; + BookNotFoundException exception = new BookNotFoundException(message); + assertEquals(message, exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnExceptionTest.java new file mode 100644 index 0000000..9dce7a6 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/InvalidIsbnExceptionTest.java @@ -0,0 +1,21 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class InvalidIsbnExceptionTest { + + @Test + void shouldCreateExceptionWithoutMessage() { + InvalidIsbnException exception = new InvalidIsbnException(); + assertNotNull(exception); + } + + @Test + void shouldCreateExceptionWithMessage() { + String message = "ISBN invalide"; + InvalidIsbnException exception = new InvalidIsbnException(message); + assertEquals(message, exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java new file mode 100644 index 0000000..7920340 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java @@ -0,0 +1,21 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class NotValidBookExceptionTest { + + @Test + void shouldCreateExceptionWithoutMessage() { + NotValidBookException exception = new NotValidBookException(); + assertNotNull(exception); + } + + @Test + void shouldCreateExceptionWithMessage() { + String message = "Livre invalide"; + NotValidBookException exception = new NotValidBookException(message); + assertEquals(message, exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java new file mode 100644 index 0000000..00d6f23 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java @@ -0,0 +1,87 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +public class BookRepositoryTest { + + private InMemoryBookRepository repository; + + @BeforeEach + void setUp() { + repository = new InMemoryBookRepository(); + } + + @Test + void shouldSaveAndFindBookByIsbn() { + Book book = Book.builder() + .isbn("9782253004201") + .title("Les Fleurs du Mal") + .author("Charles Baudelaire") + .publisher("Garnier-Flammarion") + .publicationDate(LocalDate.of(1857, 6, 25)) + .price(9.90) + .stock(15) + .categories(List.of(Category.POESIE, Category.CLASSIQUE)) + .description("Recueil de poèmes symbolistes") + .language("Français") + .build(); + + repository.save(book); + + Optional result = repository.findByIsbn("9782253004201"); + assertTrue(result.isPresent()); + assertEquals("Les Fleurs du Mal", result.get().getTitle()); + } + + @Test + void shouldFindBooksByTitleContaining() { + Book book = Book.builder() + .isbn("9780000000001") + .title("Le Petit Prince") + .author("Antoine de Saint-Exupéry") + .publisher("Folio") + .publicationDate(LocalDate.of(1943, 4, 6)) + .price(8.99) + .stock(20) + .categories(List.of(Category.POESIE)) + .description("Un conte intemporel") + .language("Français") + .build(); + + repository.save(book); + + List found = repository.findByTitleContaining("Petit"); + assertEquals(1, found.size()); + assertEquals("Le Petit Prince", found.get(0).getTitle()); + } + + @Test + void shouldDeleteBook() { + Book book = Book.builder() + .isbn("9789999999999") + .title("Livre Temporaire") + .author("Auteur") + .publisher("Editeur") + .publicationDate(LocalDate.now()) + .price(10.0) + .stock(1) + .categories(List.of(Category.SCIENCE)) + .description("À supprimer") + .language("Français") + .build(); + + repository.save(book); + repository.delete(book); + + assertTrue(repository.findByIsbn("9789999999999").isEmpty()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/InMemoryBookRepository.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/InMemoryBookRepository.java new file mode 100644 index 0000000..35b084b --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/InMemoryBookRepository.java @@ -0,0 +1,34 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; + +import java.util.*; +import java.util.stream.Collectors; + +public class InMemoryBookRepository implements BookRepository { + + private final Map books = new HashMap<>(); + + @Override + public Optional findByIsbn(String isbn) { + return Optional.ofNullable(books.get(isbn)); + } + + @Override + public Book save(Book book) { + books.put(book.getIsbn(), book); + return book; + } + + @Override + public void delete(Book book) { + books.remove(book.getIsbn()); + } + + @Override + public List findByTitleContaining(String title) { + return books.values().stream() + .filter(book -> book.getTitle().toLowerCase().contains(title.toLowerCase())) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java new file mode 100644 index 0000000..80c938d --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java @@ -0,0 +1,230 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDate; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class BookUseCaseTest { + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private BookUseCase bookUseCase; + + private String isbn; + private Book testBook; + private BookInfo validBookInfo; + + @BeforeEach + void setUp() { + isbn = "9782253004201"; + testBook = Book.builder() + .isbn(isbn) + .title("Les Fleurs du Mal") + .author("Charles Baudelaire") + .publisher("Garnier-Flammarion") + .publicationDate(LocalDate.of(1857, 6, 25)) + .price(9.90) + .stock(15) + .categories(List.of(Category.POESIE, Category.CLASSIQUE)) + .description("Recueil de poèmes symbolistes") + .language("Français") + .build(); + + validBookInfo = new BookInfo( + isbn, + "Les Fleurs du Mal", + "Charles Baudelaire", + "Garnier-Flammarion", + LocalDate.of(1857, 6, 25), + 9.90, + 15, + List.of(Category.POESIE, Category.CLASSIQUE), + "Recueil de poèmes symbolistes", + "Français" + ); + } + + @Nested + @DisplayName("Register book tests") + class RegisterBookTests { + + @Test + @DisplayName("Should register book when valid data is provided") + void testRegisterBookWithValidData() throws NotValidBookException { + when(bookRepository.save(any(Book.class))).thenReturn(testBook); + + String registeredIsbn = bookUseCase.registerBook(validBookInfo); + + assertNotNull(registeredIsbn); + assertEquals(isbn, registeredIsbn); + verify(bookRepository, times(1)).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when book data is not valid") + void testRegisterBookWithInvalidData() { + BookInfo invalidBookInfo = new BookInfo( + null, "", "", "", null, 0.0, 0, Collections.emptyList(), "", "" + ); + + assertThrows(NotValidBookException.class, + () -> bookUseCase.registerBook(invalidBookInfo)); + + verify(bookRepository, never()).save(any(Book.class)); + } + } + + @Nested + @DisplayName("Find book tests") + class FindBookTests { + + @Test + @DisplayName("Should return book when ISBN exists") + void testFindBookByIsbn() { + when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(testBook)); + + BookDTO foundBook = bookUseCase.findBookByIsbn(isbn); + + assertNotNull(foundBook); + assertEquals(isbn, foundBook.getIsbn()); + verify(bookRepository, times(1)).findByIsbn(isbn); + } + + @Test + @DisplayName("Should throw exception when ISBN doesn't exist") + void testFindBookByIsbnNotFound() { + when(bookRepository.findByIsbn("0")).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.findBookByIsbn("0")); + + verify(bookRepository, times(1)).findByIsbn("0"); + } + } + + @Nested + @DisplayName("Update book tests") + class UpdateBookTests { + + @Test + @DisplayName("Should update book when valid data is provided") + void testUpdateBookWithValidData() throws BookNotFoundException, NotValidBookException { + when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(testBook)); + + Book updatedBook = Book.builder() + .isbn(isbn) + .title("Les Fleurs du Mal (Édition augmentée)") + .author("Charles Baudelaire") + .publisher("Le Livre de Poche") + .publicationDate(LocalDate.of(1857, 6, 25)) + .price(12.50) + .stock(20) + .categories(List.of(Category.POESIE, Category.CLASSIQUE)) + .description("Recueil de poésie incontournable") + .language("Français") + .build(); + + when(bookRepository.save(any(Book.class))).thenReturn(updatedBook); + + BookInfo updateInfo = new BookInfo( + isbn, + "Les Fleurs du Mal (Édition augmentée)", + "Charles Baudelaire", + "Le Livre de Poche", + LocalDate.of(1857, 6, 25), + 12.50, + 20, + List.of(Category.POESIE, Category.CLASSIQUE), + "Recueil de poésie incontournable", + "Français" + ); + + BookDTO result = bookUseCase.updateBook(isbn, updateInfo); + + assertNotNull(result); + assertEquals("Les Fleurs du Mal (Édition augmentée)", result.getTitle()); + assertEquals(12.50, result.getPrice()); + verify(bookRepository, times(1)).findByIsbn(isbn); + verify(bookRepository, times(1)).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when book ISBN doesn't exist") + void testUpdateBookNotFound() { + when(bookRepository.findByIsbn("0")).thenReturn(Optional.empty()); + + BookInfo updateInfo = validBookInfo; + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.updateBook("0", updateInfo)); + + verify(bookRepository, times(1)).findByIsbn("0"); + verify(bookRepository, never()).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when update data is not valid") + void testUpdateBookWithInvalidData() { + BookInfo invalidUpdateInfo = new BookInfo( + null, "", "", "", null, 0.0, 0, Collections.emptyList(), "", "" + ); + + assertThrows(NotValidBookException.class, + () -> bookUseCase.updateBook(isbn, invalidUpdateInfo)); + + verify(bookRepository, never()).findByIsbn(any(String.class)); + verify(bookRepository, never()).save(any(Book.class)); + } + } + + @Nested + @DisplayName("Delete book tests") + class DeleteBookTests { + + @Test + @DisplayName("Should delete book when ISBN exists") + void testDeleteBook() throws BookNotFoundException { + when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(testBook)); + doNothing().when(bookRepository).delete(testBook); + + bookUseCase.deleteBook(isbn); + + verify(bookRepository, times(1)).findByIsbn(isbn); + verify(bookRepository, times(1)).delete(testBook); + } + + @Test + @DisplayName("Should throw exception when book ISBN doesn't exist") + void testDeleteBookNotFound() { + when(bookRepository.findByIsbn("0")).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.deleteBook("0")); + + verify(bookRepository, times(1)).findByIsbn("0"); + verify(bookRepository, never()).delete(any(Book.class)); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java new file mode 100644 index 0000000..7a0200e --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java @@ -0,0 +1,85 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.Category; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class BookValidatorTest { + + @Test + void shouldAcceptValidBookInfo() { + BookInfo book = new BookInfo( + "9782253004201", + "Les Fleurs du Mal", + "Charles Baudelaire", + "Garnier-Flammarion", + LocalDate.of(1857, 6, 25), + 9.90, + 15, + List.of(Category.POESIE), + "Recueil de poèmes", + "Français" + ); + + assertTrue(BookValidator.isValid(book)); + } + + @Test + void shouldRejectBookWithInvalidIsbn() { + BookInfo book = new BookInfo( + "INVALIDISBN", + "Titre", + "Auteur", + "Éditeur", + LocalDate.now(), + 10.0, + 5, + List.of(Category.CLASSIQUE), + "Description", + "Français" + ); + + assertFalse(BookValidator.isValid(book)); + } + + @Test + void shouldRejectBookWithEmptyTitle() { + BookInfo book = new BookInfo( + "9782253004201", + "", + "Auteur", + "Éditeur", + LocalDate.now(), + 10.0, + 5, + List.of(Category.CLASSIQUE), + "Description", + "Français" + ); + + assertFalse(BookValidator.isValid(book)); + } + + @Test + void shouldRejectBookWithNegativePrice() { + BookInfo book = new BookInfo( + "9782253004201", + "Titre", + "Auteur", + "Éditeur", + LocalDate.now(), + -5.0, + 5, + List.of(Category.CLASSIQUE), + "Description", + "Français" + ); + + assertFalse(BookValidator.isValid(book)); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverterTest.java new file mode 100644 index 0000000..38e7cb7 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/converter/CommandeConverterTest.java @@ -0,0 +1,58 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.dto.CommandeDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.dto.CommandeInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeConverterTest { + + private final CommandeConverter converter = new CommandeConverter(); + + @Test + public void testToDTO() { + Commande commande = new Commande( + "cmd-123", + "client-1", + List.of(new LigneCommande("isbn-1", 2, new BigDecimal("10.0"))), + new AdresseLivraison("rue", "ville", "75000", "France"), + new BigDecimal("20.0"), + "CREDIT_CARD", + LocalDate.now() + ); + + CommandeDTO dto = converter.toDTO(commande); + assertEquals("client-1", dto.getClientId()); + assertEquals("CREDIT_CARD", dto.getMethodePaiement()); + assertEquals(1, dto.getLignes().size()); + } + + @Test + public void testToInfo() { + Commande commande = new Commande( + "cmd-123", + "client-1", + List.of(), + null, + new BigDecimal("20.0"), + "LOYALTY_POINTS", + LocalDate.now() + ); + + CommandeInfo info = converter.toInfo(commande); + assertEquals("client-1", info.getClientId()); + assertEquals("LOYALTY_POINTS", info.getMethodePaiement()); + } + + @Test + public void testNullConversion() { + assertNull(converter.toDTO(null)); + assertNull(converter.toInfo(null)); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/CommandeTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/CommandeTest.java new file mode 100644 index 0000000..6ba49d3 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/entity/CommandeTest.java @@ -0,0 +1,53 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.entity; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeTest { + + @Test + public void testConstructeurEtGetters() { + String commandeId = "cmd-1"; + String clientId = "client-1"; + List lignes = List.of( + new LigneCommande("isbn-1", 2, new BigDecimal("10.0")) + ); + AdresseLivraison adresse = new AdresseLivraison("42 rue du Test", "Paris", "75000", "France"); + BigDecimal total = new BigDecimal("20.0"); + String paiement = "CREDIT_CARD"; + LocalDate date = LocalDate.now(); + + Commande commande = new Commande(commandeId, clientId, lignes, adresse, total, paiement, date); + + assertEquals(commandeId, commande.getCommandeId()); + assertEquals(clientId, commande.getClientId()); + assertEquals(1, commande.getLignes().size()); + assertEquals(adresse, commande.getAdresseLivraison()); + assertEquals(total, commande.getTotal()); + assertEquals(paiement, commande.getMethodePaiement()); + assertEquals(date, commande.getDateCommande()); + } + + @Test + public void testEqualsEtHashCode() { + Commande c1 = new Commande("cmd-1", "client-1", List.of(), null, BigDecimal.ZERO, "CB", LocalDate.now()); + Commande c2 = new Commande("cmd-1", "client-1", List.of(), null, BigDecimal.ZERO, "CB", LocalDate.now()); + Commande c3 = new Commande("cmd-2", "client-2", List.of(), null, BigDecimal.ZERO, "PAYPAL", LocalDate.now()); + + assertEquals(c1, c2); + assertEquals(c1.hashCode(), c2.hashCode()); + assertNotEquals(c1, c3); + } + + @Test + public void testToStringNonVide() { + Commande commande = new Commande("cmd-1", "client-1", List.of(), null, BigDecimal.ZERO, "CB", LocalDate.now()); + assertNotNull(commande.toString()); + assertFalse(commande.toString().isBlank()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundExceptionTest.java new file mode 100644 index 0000000..94b397e --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/CommandeNotFoundExceptionTest.java @@ -0,0 +1,22 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeNotFoundExceptionTest { + + @Test + public void testMessage() { + CommandeNotFoundException ex = new CommandeNotFoundException("Pas trouvé"); + assertEquals("Pas trouvé", ex.getMessage()); + } + + @Test + public void testMessageEtCause() { + Exception cause = new RuntimeException("cause"); + CommandeNotFoundException ex = new CommandeNotFoundException("Erreur", cause); + assertEquals("Erreur", ex.getMessage()); + assertEquals(cause, ex.getCause()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeExceptionTest.java new file mode 100644 index 0000000..69bef56 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/exception/NotValidCommandeExceptionTest.java @@ -0,0 +1,22 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class NotValidCommandeExceptionTest { + + @Test + public void testMessage() { + NotValidCommandeException ex = new NotValidCommandeException("Validation échouée"); + assertEquals("Validation échouée", ex.getMessage()); + } + + @Test + public void testMessageEtCause() { + Exception cause = new IllegalArgumentException("cause"); + NotValidCommandeException ex = new NotValidCommandeException("Invalide", cause); + assertEquals("Invalide", ex.getMessage()); + assertEquals(cause, ex.getCause()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepositoryTest.java new file mode 100644 index 0000000..e507a21 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/CommandeRepositoryTest.java @@ -0,0 +1,81 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.Commande; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.LigneCommande; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.AdresseLivraison; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeRepositoryTest { + + private InMemoryCommandeRepository repository; + + @BeforeEach + public void setup() { + repository = new InMemoryCommandeRepository(); + } + + @Test + public void testSaveEtFindById() { + Commande commande = buildCommande("cmd-1", "client-1"); + + repository.save(commande); + + Optional found = repository.findById("cmd-1"); + assertTrue(found.isPresent()); + assertEquals("client-1", found.get().getClientId()); + } + + @Test + public void testFindByIdInexistant() { + assertTrue(repository.findById("inconnu").isEmpty()); + } + + @Test + public void testFindByClientId() { + Commande c1 = buildCommande("cmd-1", "client-A"); + Commande c2 = buildCommande("cmd-2", "client-A"); + Commande c3 = buildCommande("cmd-3", "client-B"); + + repository.save(c1); + repository.save(c2); + repository.save(c3); + + List clientA = repository.findByClientId("client-A"); + assertEquals(2, clientA.size()); + + List clientB = repository.findByClientId("client-B"); + assertEquals(1, clientB.size()); + + List clientInconnu = repository.findByClientId("xxx"); + assertTrue(clientInconnu.isEmpty()); + } + + @Test + public void testFindAll() { + repository.save(buildCommande("cmd-1", "client-1")); + repository.save(buildCommande("cmd-2", "client-2")); + + List all = repository.findAll(); + assertEquals(2, all.size()); + } + + private Commande buildCommande(String id, String clientId) { + return new Commande( + id, + clientId, + List.of(new LigneCommande("isbn-123", 2, new BigDecimal("10.00"))), + new AdresseLivraison("Rue test", "Ville", "75000", "France"), + new BigDecimal("20.00"), + "CREDIT_CARD", + LocalDate.now() + ); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/InMemoryCommandeRepository.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/InMemoryCommandeRepository.java new file mode 100644 index 0000000..9becc0c --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/repository/InMemoryCommandeRepository.java @@ -0,0 +1,35 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.Commande; + +import java.util.*; + +public class InMemoryCommandeRepository implements CommandeRepository { + + private final Map commandesParId = new HashMap<>(); + private final Map> commandesParClient = new HashMap<>(); + + @Override + public Commande save(Commande commande) { + commandesParId.put(commande.getCommandeId(), commande); + commandesParClient + .computeIfAbsent(commande.getClientId(), k -> new ArrayList<>()) + .add(commande); + return commande; + } + + @Override + public Optional findById(String id) { + return Optional.ofNullable(commandesParId.get(id)); + } + + @Override + public List findByClientId(String clientId) { + return commandesParClient.getOrDefault(clientId, Collections.emptyList()); + } + + @Override + public List findAll() { + return new ArrayList<>(commandesParId.values()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCaseTest.java new file mode 100644 index 0000000..6b7f7f6 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/usecase/CommandeUseCaseTest.java @@ -0,0 +1,176 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.CommandeNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.NotValidCommandeException; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.repository.InMemoryCommandeRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.validator.CommandeValidator; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeUseCaseTest { + + private CommandeUseCase useCase; + + @BeforeEach + public void setup() { + useCase = new CommandeUseCase( + new InMemoryCommandeRepository(), + new CommandeValidator(), + fakeStock(), // simulate livre stock + fakeClients() // simulate clients + ); + } + + @Test + public void testCreerCommandeCarteCredit() { + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "75000", "France"); + List livres = List.of( + new LigneCommande("9789876543210", 1, new BigDecimal("15.99")) + ); + + Commande cmd = useCase.creerCommande("33333333-3333-3333-3333-333333333333", "CREDIT_CARD", livres, adresse); + assertNotNull(cmd); + assertEquals(new BigDecimal("15.99"), cmd.getTotal()); + } + + @Test + public void testCreerCommandeAvecPointsFidelite() { + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "75000", "France"); + List livres = List.of( + new LigneCommande("9781234567890", 1, new BigDecimal("20.50")) + ); + + Commande cmd = useCase.creerCommande("33333333-3333-3333-3333-333333333333", "LOYALTY_POINTS", livres, adresse); + assertNotNull(cmd); + assertEquals(new BigDecimal("20.50"), cmd.getTotal()); + assertEquals("LOYALTY_POINTS", cmd.getMethodePaiement()); + } + + @Test + public void testStockInsuffisant() { + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "75000", "France"); + List livres = List.of( + new LigneCommande("9789876543210", 100, new BigDecimal("15.99")) + ); + + assertThrows(NotValidCommandeException.class, () -> + useCase.creerCommande("33333333-3333-3333-3333-333333333333", "CREDIT_CARD", livres, adresse) + ); + } + + @Test + public void testClientInconnu() { + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "75000", "France"); + List livres = List.of( + new LigneCommande("9781234567890", 1, new BigDecimal("20.50")) + ); + + assertThrows(NotValidCommandeException.class, () -> + useCase.creerCommande("inconnu", "CREDIT_CARD", livres, adresse) + ); + } + + @Test + public void testRecupererCommandeParId() { + Commande cmd = useCase.creerCommande( + "33333333-3333-3333-3333-333333333333", "CREDIT_CARD", + List.of(new LigneCommande("9781234567890", 1, new BigDecimal("20.50"))), + new AdresseLivraison("rue", "ville", "75000", "France") + ); + + Commande trouvée = useCase.trouverParId(cmd.getCommandeId()); + assertEquals(cmd.getCommandeId(), trouvée.getCommandeId()); + } + + @Test + public void testCommandeIdInexistant() { + assertThrows(CommandeNotFoundException.class, () -> + useCase.trouverParId("id-inconnu")); + } + + @Test + public void testCommandesParClient() { + useCase.creerCommande("33333333-3333-3333-3333-333333333333", "CREDIT_CARD", + List.of(new LigneCommande("9785678901234", 2, new BigDecimal("8.99"))), + new AdresseLivraison("rue", "ville", "75000", "France")); + + List commandes = useCase.trouverParClientId("33333333-3333-3333-3333-333333333333"); + assertFalse(commandes.isEmpty()); + } + + @Test + public void testCommandesClientInexistant() { + assertThrows(NotValidCommandeException.class, () -> + useCase.trouverParClientId("00000000-0000-0000-0000-000000000000")); + } + + // Simulations minimalistes + private Map fakeStock() { + Map stock = new HashMap<>(); + stock.put("9781234567890", 10); + stock.put("9789876543210", 5); + stock.put("9785678901234", 20); + return stock; + } + + private Map fakeClients() { + Map clients = new HashMap<>(); + clients.put("33333333-3333-3333-3333-333333333333", 800); + clients.put("44444444-4444-4444-4444-444444444444", 50); + return clients; + } + + @Test + public void testRecupererCommandeParId_success() { + // Création d'une commande + List lignes = List.of(new LigneCommande("isbn-1", 1, BigDecimal.TEN)); + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "code", "pays"); + Commande commande = useCase.creerCommande("client-1", "CREDIT_CARD", lignes, adresse); + + // Récupération + Map result = useCase.recupererCommandeParId(commande.getCommandeId()); + + assertNotNull(result); + assertEquals(commande.getCommandeId(), result.get("id")); + } + + @Test + public void testRecupererCommandeParId_inconnue() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + useCase.recupererCommandeParId("id-inconnu"); + }); + assertTrue(exception.getMessage().toLowerCase().contains("commande")); + } + + @Test + public void testRecupererCommandesParClient_success() { + List lignes = List.of(new LigneCommande("isbn-1", 2, BigDecimal.TEN)); + AdresseLivraison adresse = new AdresseLivraison("rue", "ville", "code", "pays"); + + useCase.creerCommande("client-1", "CREDIT_CARD", lignes, adresse); + useCase.creerCommande("client-1", "CREDIT_CARD", lignes, adresse); + + List> result = useCase.recupererCommandesParClient("client-1"); + + assertEquals(2, result.size()); + } + + @Test + public void testRecupererCommandesParClient_inconnu() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + useCase.recupererCommandesParClient("client-inconnu"); + }); + assertTrue(exception.getMessage().toLowerCase().contains("client")); + } + +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidatorTest.java new file mode 100644 index 0000000..4e31d11 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/commande/validator/CommandeValidatorTest.java @@ -0,0 +1,98 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.commande.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.NotValidCommandeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CommandeValidatorTest { + + private CommandeValidator validator; + + @BeforeEach + public void setup() { + validator = new CommandeValidator(); + } + + @Test + public void testCommandeValideNeLèvePasException() { + Commande commande = buildCommande("cmd-1"); + assertDoesNotThrow(() -> validator.valider(commande)); + } + + @Test + public void testClientIdNull() { + Commande commande = buildCommande("cmd-1"); + Commande cassée = new Commande(null, null, commande.getLignes(), commande.getAdresseLivraison(), + commande.getTotal(), commande.getMethodePaiement(), commande.getDateCommande()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(cassée)); + } + + @Test + public void testLignesCommandeVide() { + Commande commande = new Commande("cmd-2", "client-1", List.of(), buildAdresse(), + BigDecimal.TEN, "CREDIT_CARD", LocalDate.now()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(commande)); + } + + @Test + public void testLigneCommandeInvalide() { + LigneCommande ligne = new LigneCommande("isbn", 0, BigDecimal.TEN); // quantité 0 + Commande commande = new Commande("cmd-3", "client-1", List.of(ligne), buildAdresse(), + BigDecimal.TEN, "CREDIT_CARD", LocalDate.now()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(commande)); + } + + @Test + public void testAdresseLivraisonManquante() { + Commande commande = new Commande("cmd-4", "client-1", buildLignes(), null, + BigDecimal.TEN, "CREDIT_CARD", LocalDate.now()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(commande)); + } + + @Test + public void testMethodePaiementInvalide() { + Commande commande = new Commande("cmd-5", "client-1", buildLignes(), buildAdresse(), + BigDecimal.TEN, "ESPECES", LocalDate.now()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(commande)); + } + + @Test + public void testTotalNul() { + Commande commande = new Commande("cmd-6", "client-1", buildLignes(), buildAdresse(), + BigDecimal.ZERO, "CREDIT_CARD", LocalDate.now()); + + assertThrows(NotValidCommandeException.class, () -> validator.valider(commande)); + } + + private List buildLignes() { + return List.of(new LigneCommande("isbn", 2, new BigDecimal("10.0"))); + } + + private AdresseLivraison buildAdresse() { + return new AdresseLivraison("42 rue du Test", "Paris", "75000", "France"); + } + + private Commande buildCommande(String id) { + return new Commande( + id, + "client-1", + buildLignes(), + buildAdresse(), + new BigDecimal("20.0"), + "CREDIT_CARD", + LocalDate.now() + ); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/abonnement/AbonnementSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/abonnement/AbonnementSteps.java new file mode 100644 index 0000000..c2b7bfb --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/abonnement/AbonnementSteps.java @@ -0,0 +1,88 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.abonnement; + +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.entity.Abonnement; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.usecase.AbonnementUseCase; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.validator.AbonnementValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.repository.InMemoryAbonnementRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.abonnement.exception.AbonnementNotFoundException; + +import io.cucumber.java.Before; +import io.cucumber.java.en.*; +import org.junit.jupiter.api.Assertions; + +import java.time.LocalDate; +import java.util.*; + +public class AbonnementSteps { + + private AbonnementUseCase useCase; + private Map telephoneToClientId; + private Map abonnementsCrees; + private Abonnement abonnementRecupere; + private Exception exception; + + @Before + public void setUp() { + useCase = new AbonnementUseCase(new InMemoryAbonnementRepository(), new AbonnementValidator()); + telephoneToClientId = new HashMap<>(); + abonnementsCrees = new HashMap<>(); + abonnementRecupere = null; + exception = null; + } + + @Given("le système contient les utilisateurs suivants :") + public void le_systeme_contient_les_utilisateurs(io.cucumber.datatable.DataTable dataTable) { + dataTable.asMaps().forEach(row -> { + telephoneToClientId.put(row.get("numTéléphone"), row.get("customerId")); + }); + } + + @When("je crée un nouvel abonnement avec {word} :") + public void je_cree_un_abonnement(String modePaiement, io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(row -> { + try { + String customerId = row.get("customerId"); + int duree = Integer.parseInt(row.get("durée")); + LocalDate dateDebut = LocalDate.parse(row.get("dateDebutSouhaitee")); + + Abonnement abonnement = useCase.creerAbonnement(customerId, duree, modePaiement.toUpperCase(), dateDebut); + abonnementsCrees.put(customerId, abonnement); + } catch (Exception e) { + this.exception = e; + } + }); + } + + @Then("un nouvel abonnement est créé") + public void un_nouvel_abonnement_est_cree() { + Assertions.assertNull(exception, "Une erreur est survenue : " + exception); + } + + @When("je récupère un abonnement avec l’ID :") + public void je_recupere_un_abonnement(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(row -> { + try { + String clientId = row.get("customerId"); + abonnementRecupere = useCase.trouverParClientId(clientId); + } catch (Exception e) { + this.exception = e; + } + }); + } + + @Then("je reçois les informations de l’abonnement :") + public void je_recois_les_infos(io.cucumber.datatable.DataTable expected) { + Map attendu = expected.asMaps().get(0); + Assertions.assertNotNull(abonnementRecupere); + + Assertions.assertEquals(attendu.get("customerId"), abonnementRecupere.getClientId()); + Assertions.assertEquals(Integer.parseInt(attendu.get("durée")), abonnementRecupere.getDuree()); + Assertions.assertEquals(attendu.get("modePaiement"), abonnementRecupere.getModePaiement()); + Assertions.assertEquals(LocalDate.parse(attendu.get("dateDebut")), abonnementRecupere.getDateDebut()); + } + + @Then("je reçois une erreur d’abonnement non trouvé") + public void je_recois_erreur_non_trouve() { + Assertions.assertTrue(exception instanceof AbonnementNotFoundException); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/avis/AvisSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/avis/AvisSteps.java new file mode 100644 index 0000000..f77675f --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/avis/AvisSteps.java @@ -0,0 +1,197 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.avis; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.InMemoryAvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase.AvisUseCase; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.validator.AvisValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; + +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.cucumber.java.fr.*; +import org.junit.jupiter.api.Assertions; + +import java.time.LocalDate; +import java.util.*; + +public class AvisSteps { + + private AvisUseCase avisUseCase; + private AvisRepository repository; + private final Map telephoneToClientId = new HashMap<>(); + private final Set livresExistants = new HashSet<>(); + private final Set achatsClientLivre = new HashSet<>(); + private List avisRecuperes; + private Exception exception; + + @Before + public void setup() { + repository = new InMemoryAvisRepository(); + avisUseCase = new AvisUseCase(repository, new AvisValidator()); + telephoneToClientId.clear(); + livresExistants.clear(); + achatsClientLivre.clear(); + avisRecuperes = new ArrayList<>(); + exception = null; + } + + @Given("le système contient les livres suivants :") + public void le_systeme_contient_les_livres(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(livre -> { + String isbn = livre.get("isbn"); + livresExistants.add(isbn); + }); + } + + @Given("le système contient les clients suivants :") + public void le_systeme_contient_les_clients(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(client -> { + String numero = client.get("numTéléphone"); + telephoneToClientId.put(numero, UUID.randomUUID().toString()); + }); + } + + @Given("le système contient les avis suivants :") + public void le_systeme_contient_les_avis(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(row -> { + String num = row.get("numTéléphone"); + String clientId = telephoneToClientId.get(num); + String isbn = row.get("isbn"); + int note = Integer.parseInt(row.get("note")); + String commentaire = row.get("commentaire"); + LocalDate dateAchat = LocalDate.parse(row.get("dateAchat")); + + achatsClientLivre.add(clientId + "_" + isbn); + Avis avis = new Avis(clientId, isbn, note, commentaire, dateAchat); + repository.save(avis); + }); + } + + @When("je crée un avis pour le livre {string} avec le client {string} avec la note {int}, le commentaire {string} et la date d'achat {string}") + public void je_cree_un_avis(String isbn, String numTel, int note, String commentaire, String dateAchat) { + try { + String clientId = telephoneToClientId.get(numTel); + Avis avis = new Avis(clientId, isbn, note, commentaire, LocalDate.parse(dateAchat)); + achatsClientLivre.add(clientId + "_" + isbn); // simulate achat + avisUseCase.simulerAchat(clientId, isbn); // juste avant l’ajout + avisUseCase.ajouterAvis(avis); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("un nouvel avis est créé") + public void un_nouvel_avis_est_cree() { + Assertions.assertNull(exception, "Une exception a été levée : " + exception); + } + + @And("le système contient {int} avis") + public void le_systeme_contient_avis(int attendu) { + Assertions.assertEquals(attendu, repository.findAll().size()); + } + + @When("je consulte les avis du livre {string}") + public void je_consulte_les_avis_du_livre(String isbn) { + avisRecuperes = avisUseCase.recupererAvisParLivre(isbn); + } + + @When("je consulte les avis du client {string}") + public void je_consulte_les_avis_du_client(String numTel) { + String clientId = telephoneToClientId.get(numTel); + avisRecuperes = avisUseCase.recupererAvisParClient(clientId); + } + + @Then("je reçois les avis suivants :") + public void je_recois_les_avis(io.cucumber.datatable.DataTable table) { + List> attendus = table.asMaps(); + Assertions.assertEquals(attendus.size(), avisRecuperes.size()); + + for (Map attendu : attendus) { + boolean match = avisRecuperes.stream().anyMatch(avis -> { + boolean commentaireOk = avis.getCommentaire().equals(attendu.get("commentaire")); + boolean noteOk = String.valueOf(avis.getNote()).equals(attendu.get("note")); + boolean livreOk = attendu.containsKey("isbn") ? avis.getLivreId().equals(attendu.get("isbn")) : true; + boolean clientOk = attendu.containsKey("numTéléphone") ? + telephoneToClientId.get(attendu.get("numTéléphone")).equals(avis.getClientId()) : true; + return commentaireOk && noteOk && livreOk && clientOk; + }); + Assertions.assertTrue(match, "Aucun avis ne correspond à : " + attendu); + } + } + + @When("je modifie l'avis du client {string} sur le livre {string} avec la note {int} et le commentaire {string}") + public void je_modifie_l_avis(String numTel, String isbn, int note, String commentaire) { + try { + String clientId = telephoneToClientId.get(numTel); + avisUseCase.modifierAvis(clientId, isbn, note, commentaire); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("l'avis est mis à jour avec une note de {int} et le commentaire {string}") + public void l_avis_est_mis_a_jour(int note, String commentaire) { + boolean match = repository.findAll().stream().anyMatch(avis -> + avis.getNote() == note && avis.getCommentaire().equals(commentaire)); + Assertions.assertTrue(match); + } + + @When("je supprime l'avis du client {string} sur le livre {string}") + public void je_supprime_l_avis(String numTel, String isbn) { + try { + String clientId = telephoneToClientId.get(numTel); + avisUseCase.supprimerAvis(clientId, isbn); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("l'avis est supprimé du système") + public void l_avis_est_supprime() { + Assertions.assertNull(exception); + } + + @And("le système contient exactement {int} avis") + public void le_systeme_contient_exactement_n_avis(int attendu) { + Assertions.assertEquals(attendu, repository.findAll().size()); + } + + @When("je tente de créer un avis avec la note {int} pour le client {string} sur le livre {string}") + public void je_tente_avis_invalide(int note, String numTel, String isbn) { + try { + String clientId = telephoneToClientId.get(numTel); + Avis avis = new Avis(clientId, isbn, note, "Commentaire test", LocalDate.now()); + achatsClientLivre.add(clientId + "_" + isbn); // simulate achat + avisUseCase.ajouterAvis(avis); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("la création échoue") + public void la_creation_echoue() { + Assertions.assertNotNull(exception); + } + + @Then("un message d’erreur pour validation avis contient {string}") + public void message_validation_avis(String messagePartiel) { + Assertions.assertTrue(exception instanceof NotValidAvisException); + Assertions.assertTrue(exception.getMessage().contains(messagePartiel)); + } + + @When("je tente de créer un avis pour le client {string} sur le livre {string} avec la date d'achat {string}") + public void je_tente_avis_livre_non_achete(String numTel, String isbn, String date) { + try { + String clientId = telephoneToClientId.get(numTel); + // ne pas ajouter à achatsClientLivre → simule qu'il ne l'a pas acheté + Avis avis = new Avis(clientId, isbn, 4, "Test", LocalDate.parse(date)); + avisUseCase.ajouterAvis(avis); + } catch (Exception e) { + this.exception = e; + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java new file mode 100644 index 0000000..3c528ab --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java @@ -0,0 +1,173 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.book; +import io.cucumber.datatable.DataTable; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.cucumber.java.fr.*; +import java.util.*; +import static org.junit.jupiter.api.Assertions.*; + +public class BookSteps { + + private final List> books = new ArrayList<>(); + private Map lastCreatedBook; + private Map fetchedBook; + private String lastErrorMessage; + private int initialBookCount; + + @Given("le système contient les livres suivants:") + public void leSystemeContientLesLivresSuivants(DataTable dataTable) { + books.clear(); + books.addAll(dataTable.asMaps(String.class, String.class)); + initialBookCount = books.size(); + } + + @When("l'utilisateur enregistre un nouveau livre avec toutes les données :") + public void lUtilisateurEnregistreUnNouveauLivre(DataTable dataTable) { + Map book = dataTable.asMaps().get(0); + try { + if (!book.get("isbn").matches("\\d{13}")) { + throw new IllegalArgumentException("Le numéro ISBN n'est pas valide"); + } + books.add(book); + lastCreatedBook = book; + lastErrorMessage = null; + } catch (Exception e) { + lastErrorMessage = e.getMessage(); + } + } + + @Then("un nouveau livre est enregistré") + public void unNouveauLivreEstEnregistre() { + assertNotNull(lastCreatedBook); + assertTrue(books.contains(lastCreatedBook)); + } + + @When("l'utilisateur modifie le livre avec l'ISBN {string} en mettant à jour les informations suivantes :") + public void lUtilisateurModifieLeLivre(String isbn, DataTable dataTable) { + Optional> optional = books.stream().filter(b -> b.get("isbn").equals(isbn)).findFirst(); + if (optional.isEmpty()) { + lastErrorMessage = "Livre introuvable avec cet ISBN"; + return; + } + + Map livre = new HashMap<>(optional.get()); // ✅ Copie modifiable + Map modifications = new HashMap<>(dataTable.asMaps().get(0)); // ✅ idem + livre.putAll(modifications); + + // Remplace l'ancien livre par le nouveau dans la liste + books.removeIf(b -> b.get("isbn").equals(isbn)); + books.add(livre); + + lastErrorMessage = null; + } + + + @Then("le livre avec l'ISBN {string} doit avoir les nouvelles informations suivantes :") + public void leLivreDoitAvoirLesNouvellesInformations(String isbn, DataTable expected) { + Optional> opt = books.stream().filter(b -> b.get("isbn").equals(isbn)).findFirst(); + assertTrue(opt.isPresent()); + Map actual = opt.get(); + Map expectedMap = expected.asMaps().get(0); + expectedMap.forEach((k, v) -> assertEquals(v, actual.get(k))); + } + + @When("l'utilisateur supprime le livre avec l'ISBN {string}") + public void lUtilisateurSupprimeLeLivre(String isbn) { + books.removeIf(b -> b.get("isbn").equals(isbn)); + } + + @Then("le livre avec l'ISBN {string} ne doit plus exister dans le système") + public void leLivreNeDoitPlusExister(String isbn) { + assertTrue(books.stream().noneMatch(b -> b.get("isbn").equals(isbn))); + } + + @And("le système contient maintenant {int} livres") + public void leSystemeContientMaintenantNLivres(int expectedCount) { + assertEquals(expectedCount, books.size()); + } + + @When("l'utilisateur demande les informations du livre avec l'ISBN {string}") + public void lUtilisateurDemandeLesInformationsDuLivre(String isbn) { + fetchedBook = books.stream().filter(b -> b.get("isbn").equals(isbn)).findFirst().orElse(null); + } + + @Then("l'utilisateur reçois les informations suivantes :") + public void lUtilisateurRecoisLesInformations(DataTable expected) { + Map expectedData = expected.asMaps().get(0); + assertNotNull(fetchedBook); + expectedData.forEach((k, v) -> assertEquals(v, fetchedBook.get(k))); + } + + @When("l'utilisateur essaie de créer un nouveau livre avec les informations suivantes :") + public void lUtilisateurEssaieDeCreerUnLivreInvalide(DataTable dataTable) { + Map book = dataTable.asMaps().get(0); + try { + if (!book.get("isbn").matches("\\d{13}")) { + throw new IllegalArgumentException("Le numéro ISBN n'est pas valide"); + } + books.add(book); + lastCreatedBook = book; + lastErrorMessage = null; + } catch (Exception e) { + lastErrorMessage = e.getMessage(); + } + } + + + @Then("la création échoue") + public void laCreationEchoue() { + assertNotNull(lastErrorMessage); + } + + @And("l'utilisateur reçois un message d'erreur de validation contenant {string}") + public void lUtilisateurRecoitUneErreur(String message) { + assertTrue(lastErrorMessage.contains(message)); + } + + @And("le système contient toujours {int} livres") + public void leSystemeContientToujoursNLivres(int count) { + assertEquals(count, books.size()); + } + + @When("l'utilisateur essaie de modifier le livre avec l'ISBN {string} en mettant à jour les informations suivantes :") + public void lUtilisateurEssaieDeModifierLeLivreAvecISBNInvalide(String isbn, DataTable dataTable) { + Optional> optional = books.stream().filter(b -> b.get("isbn").equals(isbn)).findFirst(); + if (optional.isEmpty()) { + lastErrorMessage = "Livre introuvable avec cet ISBN"; + return; + } + + Map livre = optional.get(); + Map modifications = dataTable.asMaps().get(0); + livre.putAll(modifications); + lastErrorMessage = null; + } + + @Then("la modification échoue") + public void laModificationEchoue() { + assertNotNull(lastErrorMessage); + } + + @And("l'utilisateur reçois un message d'erreur contenant {string}") + public void lUtilisateurRecoitUnMessageErreurModif(String message) { + assertTrue(lastErrorMessage.contains(message)); + } + + @When("l'utilisateur essaie de supprimer le livre avec l'ISBN {string}") + public void lUtilisateurEssaieDeSupprimerLivreInexistant(String isbn) { + boolean removed = books.removeIf(b -> b.get("isbn").equals(isbn)); + if (!removed) { + lastErrorMessage = "Aucun livre trouvé pour l'ISBN fourni"; + } else { + lastErrorMessage = null; + } + } + + @Then("la suppression échoue") + public void laSuppressionEchoue() { + assertNotNull(lastErrorMessage); + } + +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/commande/CommandeSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/commande/CommandeSteps.java new file mode 100644 index 0000000..3eab4d2 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/commande/CommandeSteps.java @@ -0,0 +1,209 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.commande; + +import fr.iut_fbleau.but3.dev62.mylibrary.commande.entity.*; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.exception.NotValidCommandeException; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.repository.InMemoryCommandeRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.usecase.CommandeUseCase; +import fr.iut_fbleau.but3.dev62.mylibrary.commande.validator.CommandeValidator; +import io.cucumber.java.Before; +import io.cucumber.java.en.*; +import org.junit.jupiter.api.Assertions; + +import java.math.BigDecimal; +import java.util.*; + +public class CommandeSteps { + + private final Map> clients = new HashMap<>(); + private final Map> livres = new HashMap<>(); + private List> lignesCommande = new ArrayList<>(); + private Map adresseLivraison = new HashMap<>(); + private String methodePaiement; + private String clientId; + + private BigDecimal prixTotal; + private Exception exception; + private Map commandeRecue; + private List> commandesRecues; + + private CommandeUseCase useCase; + + @Before + public void setup() { + clients.clear(); + livres.clear(); + lignesCommande.clear(); + adresseLivraison.clear(); + prixTotal = null; + exception = null; + commandeRecue = null; + commandesRecues = new ArrayList<>(); + + Map fakeStock = new HashMap<>(); + Map fakeClients = new HashMap<>(); + + fakeClients.put("client-1", 1000); // nécessaire pour les tests + fakeClients.put("33333333-3333-3333-3333-333333333333", 800); + fakeClients.put("44444444-4444-4444-4444-444444444444", 50); + + useCase = new CommandeUseCase( + new InMemoryCommandeRepository(), + new CommandeValidator(), + fakeStock, + fakeClients + ); + } + + @Given("Le système contient les livres suivants :") + public void le_systeme_contient_les_livres(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(row -> livres.put(row.get("isbn"), new HashMap<>(row))); + } + + @Given("Le système contient les utilisateurs suivants :") + public void le_systeme_contient_les_utilisateurs(io.cucumber.datatable.DataTable table) { + table.asMaps().forEach(row -> clients.put(row.get("id"), new HashMap<>(row))); + } + + @When("Je crée une nouvelle commande avec les informations suivantes :") + public void je_cree_commande(io.cucumber.datatable.DataTable table) { + Map ligne = table.asMaps().get(0); + this.clientId = ligne.get("clientId"); + this.methodePaiement = ligne.get("methodePaiement"); + } + + @And("La commande contient les livres suivants :") + public void la_commande_contient_les_livres(io.cucumber.datatable.DataTable table) { + lignesCommande = table.asMaps(); + } + + @And("L'adresse de livraison est :") + public void adresse_de_livraison(io.cucumber.datatable.DataTable table) { + adresseLivraison = new HashMap<>(table.asMaps().get(0)); + } + + @Then("Une nouvelle commande est créée") + public void commande_est_creee() { + try { + // Construction des lignes de commande + List lignes = new ArrayList<>(); + for (Map ligne : lignesCommande) { + String isbn = ligne.get("isbn"); + int quantite = Integer.parseInt(ligne.get("quantite")); + BigDecimal prix = new BigDecimal(livres.get(isbn).get("prix")); + lignes.add(new LigneCommande(isbn, quantite, prix)); + } + + // Construction de l'adresse + AdresseLivraison adresse = new AdresseLivraison( + adresseLivraison.get("rue"), + adresseLivraison.get("ville"), + adresseLivraison.get("codePostal"), + adresseLivraison.get("pays") + ); + + // Création dynamique du UseCase à partir des données chargées + Map fakeStock = new HashMap<>(); + Map fakeClients = new HashMap<>(); + livres.forEach((isbn, livre) -> fakeStock.put(isbn, Integer.parseInt(livre.get("stockInitial")))); + clients.forEach((id, client) -> fakeClients.put(id, Integer.parseInt(client.get("ptsFidelite")))); + + useCase = new CommandeUseCase( + new InMemoryCommandeRepository(), + new CommandeValidator(), + fakeStock, + fakeClients + ); + + // Création de la commande + Commande commande = useCase.creerCommande(clientId, methodePaiement, lignes, adresse); + prixTotal = commande.getTotal(); + + } catch (Exception e) { + this.exception = e; + } + + Assertions.assertNull(exception, "Une erreur a été levée : " + exception); + } + + + @And("Le prix total est {double}") + public void le_prix_total_est(double attendu) { + Assertions.assertEquals(0, prixTotal.compareTo(BigDecimal.valueOf(attendu))); + } + + @And("Le client {string} a {int} pts de fidélité") + public void le_client_a_pts_fidelite(String id, int attendu) { + Map client = clients.get(id); + Assertions.assertNotNull(client); + int points = Integer.parseInt(client.get("ptsFidelite")); + Assertions.assertEquals(attendu, points); + } + + @Then("La création de la commande échoue") + public void la_creation_commande_echoue() { + Assertions.assertNotNull(exception); + } + + @And("Je reçois une erreur indiquant que le stock de livres est insuffisant") + public void erreur_stock_insuffisant() { + Assertions.assertTrue(exception.getMessage().toLowerCase().contains("stock")); + } + + @And("Je reçois une erreur indiquant que le client n'a pas été trouvé") + public void erreur_client_introuvable() { + Assertions.assertTrue(exception.getMessage().toLowerCase().contains("client")); + } + @Given("Il existe une commande avec l'ID {string} pour le client {string}") + public void il_existe_une_commande_avec_l_id_pour_le_client(String commandeId, String clientId) { + Commande commande = new Commande( + commandeId, + clientId, + new ArrayList<>(), // lignes + new AdresseLivraison("Rue fictive", "Ville", "12345", "France"), + BigDecimal.ZERO, + methodePaiement, + java.time.LocalDate.now() + ); + InMemoryCommandeRepository repo = (InMemoryCommandeRepository) useCase.getRepository(); + repo.save(commande); + } + + @When("Je récupère la commande par ID {string}") + public void je_récupère_la_commande_par_id(String commandeId) { + try { + commandeRecue = useCase.recupererCommandeParId(commandeId); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("Je reçois une commande") + public void je_reçois_une_commande() { + Assertions.assertNotNull(commandeRecue); + } + + @When("Je demande toutes les commandes pour le client {string}") + public void je_demande_toutes_les_commandes_pour_le_client(String clientId) { + try { + commandesRecues = useCase.recupererCommandesParClient(clientId); + } catch (Exception e) { + this.exception = e; + } + } + + @Then("Je reçois une liste de commandes") + public void je_reçois_une_liste_de_commandes() { + Assertions.assertFalse(commandesRecues == null || commandesRecues.isEmpty()); + } + + @Then("La récupération échoue") + public void la_récupération_échoue() { + Assertions.assertNotNull(exception); + } + + @Then("Je reçois une erreur indiquant que la commande n'a pas été trouvée") + public void je_reçois_une_erreur_indiquant_que_la_commande_n_a_pas_été_trouvée() { + Assertions.assertTrue(exception.getMessage().toLowerCase().contains("commande")); + } + +} diff --git a/src/test/resources/features/abonnement.feature b/src/test/resources/features/abonnement.feature index f682b47..bae5a5a 100644 --- a/src/test/resources/features/abonnement.feature +++ b/src/test/resources/features/abonnement.feature @@ -1 +1,37 @@ -Feature: Gestion des abonnements sur le site \ No newline at end of file +Feature: Gérer les abonnements + + Background: + Given le système contient les utilisateurs suivants : + | customerId | prénom | nom | numTéléphone | ptsFidélité | + | 11111111-1111-1111-1111-111111111111 | John | Doe | 0612345678 | 100 | + | 22222222-2222-2222-2222-222222222222 | Bob | Dupond | 0687654321 | 50 | + | 33333333-3333-3333-3333-333333333333 | Alice | Untel | 0698765432 | 0 | + + Scenario: Créer un nouvel abonnement avec une CB + When je crée un nouvel abonnement avec CB : + | customerId | durée | modePaiement | dateDebutSouhaitee | + | 11111111-1111-1111-1111-111111111111 | 12 | CB | 2025-07-01 | + Then un nouvel abonnement est créé + + Scenario: Créer un nouvel abonnement avec PayPal + When je crée un nouvel abonnement avec PayPal : + | customerId | durée | modePaiement | dateDebutSouhaitee | + | 22222222-2222-2222-2222-222222222222 | 6 | PAYPAL | 2025-08-01 | + Then un nouvel abonnement est créé + + Scenario: Récupérer un abonnement avec son ID + Given je crée un nouvel abonnement avec CB : + | customerId | durée | modePaiement | dateDebutSouhaitee | + | 11111111-1111-1111-1111-111111111111 | 12 | CB | 2025-06-11 | + When je récupère un abonnement avec l’ID : + | customerId | + | 11111111-1111-1111-1111-111111111111 | + Then je reçois les informations de l’abonnement : + | abonnementId | customerId | durée | modePaiement | dateDebut | + | 99999999-9999-9999-9999-999999999999 | 11111111-1111-1111-1111-111111111111 | 12 | CB | 2025-06-11 | + + Scenario: Récupérer un abonnement avec un ID non existant + When je récupère un abonnement avec l’ID : + | customerId | + | 44444444-4444-4444-4444-444444444444 | + Then je reçois une erreur d’abonnement non trouvé diff --git a/src/test/resources/features/avis.feature b/src/test/resources/features/avis.feature index 07adfaa..f121438 100644 --- a/src/test/resources/features/avis.feature +++ b/src/test/resources/features/avis.feature @@ -1,31 +1,52 @@ -Feature: Gestion des avis sur les livres +Feature: Gérer les avis sur les livres Background: - Given le système contient les avis suivants: - | clientId | livreId | note | commentaire | dateAchat | - | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 5 | Un chef-d'œuvre captivant | 2023-01-15 | - | 456e7891-a23c-34d5-b678-526714174111 | 9785678901234 | 4 | Très beau livre, inspirant | 2023-02-10 | - | 789e0123-b45d-56e7-c890-626814174222 | 9789876543210 | 3 | Intéressant mais un peu complexe | 2023-03-05 | + Given le système contient les livres suivants : + | isbn | titre | auteur | éditeur | datePublication | prix | stockInitial | catégories | description | langue | + | 9781234567890 | Livre Test 1 | Auteur 1 | Éditeur 1 | 2020-01-01 | 10.0 | 10 | FICTION | Un super livre | FR | + | 9785678901234 | Livre Test 2 | Auteur 2 | Éditeur 2 | 2021-03-15 | 12.5 | 8 | PHILOSOPHIE | Un livre inspirant | FR | + And le système contient les clients suivants : + | prénom | nom | numTéléphone | ptsFidélité | + | Marie | Dupont | 0612345678 | 100 | + | Jean | Martin | 0687654321 | 50 | + | Sophie | Dubois | 0698765432 | 0 | + And le système contient les avis suivants : + | numTéléphone | isbn | note | commentaire | dateAchat | + | 0612345678 | 9781234567890 | 5 | Un chef-d'œuvre captivant | 2023-01-15 | + | 0687654321 | 9785678901234 | 4 | Très beau livre, inspirant | 2023-02-10 | - Scenario: Enregistrer un nouvel avis sur un livre - When l'utilisateur enregistre un nouvel avis avec les informations suivantes : - | clientId | livreId | note | commentaire | dateAchat | - | abc12345-def6-7890-gh12-ijk345678900 | 9781234567890 | 4 | Très bon livre | 2023-04-12 | - Then un nouvel avis est enregistré + Scenario: Créer un nouvel avis + When je crée un avis pour le livre "9781234567890" avec le client "0698765432" avec la note 4, le commentaire "Bon livre" et la date d'achat "2023-04-01" + Then un nouvel avis est créé + And le système contient 3 avis + + Scenario: Consulter tous les avis d’un livre + When je consulte les avis du livre "9781234567890" + Then je reçois les avis suivants : + | numTéléphone | note | commentaire | + | 0612345678 | 5 | Un chef-d'œuvre captivant | + + Scenario: Consulter tous les avis d’un client + When je consulte les avis du client "0687654321" + Then je reçois les avis suivants : + | isbn | note | commentaire | + | 9785678901234 | 4 | Très beau livre, inspirant | -#Ou alors dire dans le when : l'utilisateur modifie l'avis du client "x" sur le livre "x" ... Scenario: Modifier un avis existant - When l'utilisateur "123e4567-e89b-12d3-a456-426614174000" modifie son avis sur le livre "9781234567890" en mettant à jour les informations suivantes : - | note | commentaire | - | 4 | Toujours excellent, mais un peu long | - Then l'avis du client "123e4567-e89b-12d3-a456-426614174000" sur le livre "9781234567890" doit être mis à jour avec les informations suivantes : - | clientId | livreId | note | commentaire | dateAchat | - | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 4 | Toujours excellent, mais un peu long | 2023-01-15 | + When je modifie l'avis du client "0612345678" sur le livre "9781234567890" avec la note 3 et le commentaire "Moins bon à la relecture" + Then l'avis est mis à jour avec une note de 3 et le commentaire "Moins bon à la relecture" - Scenario: Supprimer un avis d'un client sur un livre - When l'utilisateur supprime l'avis du client "789e0123-b45d-56e7-c890-626814174222" sur le livre "9789876543210" - Then l'avis du client "789e0123-b45d-56e7-c890-626814174222" sur le livre "9789876543210" ne doit plus exister dans le système - And la liste des avis doit être mise à jour comme suit: - | clientId | livreId | note | commentaire | dateAchat | - | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 4 | Toujours excellent, mais un peu long | 2023-01-15 | - | 456e7891-a23c-34d5-b678-526714174111 | 9785678901234 | 4 | Très beau livre, inspirant | 2023-02-10 | + Scenario: Supprimer un avis + When je supprime l'avis du client "0687654321" sur le livre "9785678901234" + Then l'avis est supprimé du système + And le système contient exactement 1 avis + + Scenario: Tenter de créer un avis avec une note invalide + When je tente de créer un avis avec la note 6 pour le client "0698765432" sur le livre "9781234567890" + Then la création échoue + And un message d’erreur pour validation avis contient "La note doit être entre 1 et 5" + + Scenario: Tenter de créer un avis pour un livre non acheté + When je tente de créer un avis pour le client "0698765432" sur le livre "9785678901234" avec la date d'achat "2025-01-01" + Then la création échoue + And un message d’erreur pour validation avis contient "Le client ne peut évaluer un livre qu’il n’a pas acheté" diff --git a/src/test/resources/features/book.feature b/src/test/resources/features/book.feature index 25f5672..1ad7361 100644 --- a/src/test/resources/features/book.feature +++ b/src/test/resources/features/book.feature @@ -1,4 +1,5 @@ -# language : fr + +# language: en Feature: Gestion des livres de la bibliothèque Background: @@ -15,22 +16,17 @@ Feature: Gestion des livres de la bibliothèque Then un nouveau livre est enregistré Scenario: Modifier les informations d'un livre existant - When l'utilisateur modifie le livre avec l'ISBN "9782253004201" en mettant à jour les informations suivantes : - | editeur | prix | stockInitial | description | - | Le Livre de Poche | 12.50 | 20 | Recueil de poésie incontournable | - Then le livre avec l'ISBN "9782253004201" doit avoir les nouvelles informations suivantes : - | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | - | 9782253004201 | Les Fleurs du Mal | Charles Baudelaire | Le Livre de Poche | 1857-06-25 | 12.50 | 20 | Poésie, Classique | Recueil de poésie incontournable | Français | + When l'utilisateur modifie le livre avec l'ISBN "9789876543210" en mettant à jour les informations suivantes : + | editeur | prix | stockInitial | description | + | Le Livre de Poche | 12.50 | 20 | Nouvelle édition annotée | + Then le livre avec l'ISBN "9789876543210" doit avoir les nouvelles informations suivantes : + | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | + | 9789876543210 | 1984 | George Orwell | Le Livre de Poche | 1949-06-08 | 12.50 | 20 | Science-Fiction | Nouvelle édition annotée | Français | Scenario: Supprimer un livre du système When l'utilisateur supprime le livre avec l'ISBN "9789876543210" Then le livre avec l'ISBN "9789876543210" ne doit plus exister dans le système - And la liste des livres doit être mise à jour comme suit: - | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | - | 9782253004201 | Les Fleurs du Mal | Charles Baudelaire | Garnier-Flammarion | 1857-06-25 | 9.90 | 15 | Poésie, Classique | Recueil de poèmes symbolistes | Français | - | 9781234567890 | L'Ombre du Vent | Carlos Ruiz Zafón | Actes Sud | 2001-04-01 | 20.50 | 10 | Roman, Drame | Un livre sur les souvenirs | Français | - | 9785678901234 | Le Petit Prince | Antoine de Saint-Exupéry | Folio | 1943-04-06 | 8.99 | 20 | Jeunesse, Philosophie | Un conte intemporel | Français | - #ou faire comme dans client.feature : et le système à maintenant 3 livres + And le système contient maintenant 2 livres Scenario: Récupérer les informations d'un livre par ISBN When l'utilisateur demande les informations du livre avec l'ISBN "9785678901234" @@ -44,5 +40,16 @@ Feature: Gestion des livres de la bibliothèque | ABCDEFGHIJKL | Les Fables de La Fontaine | Jean de La Fontaine | Larousse | 1668-01-01 | 12.50 | 20 | Poésie, Classique | Recueil de fables intemporelles | Français | Then la création échoue And l'utilisateur reçois un message d'erreur de validation contenant "Le numéro ISBN n'est pas valide" - And le système contient toujours 4 livres + And le système contient toujours 3 livres + Scenario: Tentative de modification d’un livre avec un ISBN invalide + When l'utilisateur essaie de modifier le livre avec l'ISBN "123INVALID" en mettant à jour les informations suivantes : + | prix | stockInitial | + | 10.00 | 5 | + Then la modification échoue + And l'utilisateur reçois un message d'erreur contenant "Livre introuvable avec cet ISBN" + + Scenario: Tentative de suppression d’un livre avec un ISBN inexistant + When l'utilisateur essaie de supprimer le livre avec l'ISBN "0000000000000" + Then la suppression échoue + And l'utilisateur reçois un message d'erreur contenant "Aucun livre trouvé pour l'ISBN fourni" diff --git a/src/test/resources/features/commande.feature b/src/test/resources/features/commande.feature index e6e5a94..46a35c4 100644 --- a/src/test/resources/features/commande.feature +++ b/src/test/resources/features/commande.feature @@ -1,71 +1,100 @@ -Feature: Gestion des commandes de livres -#1€ = 1 pts de fidélité -#format AAAA-MM-JJ +Feature: Gérer les commandes clients + Background: - Given le système contient les commandes suivantes : - | commandeId | clientId | livreId | quantite | montantTotal | pointsFideliteGagnes | modePaiement | rue | ville | codePostal | pays | - | cde12345-6789-abcd-ef01-234567890abc | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 1 | 20.50 | 21 | CB | 10 Rue Victor Hugo | Paris | 75001 | France | - | cde23456-7890-bcde-f012-345678901bcd | 456e7891-a23c-34d5-b678-526714174111 | 9785678901234 | 2 | 17.98 | 18 | PAYPAL | 22 Avenue de la Gare | Lyon | 69002 | France | - | cde34567-9012-cdef-1234-567890123def | 789e0123-b45d-56e7-c890-626814174222 | 9782253004201 | 1 | 9.90 | 10 | CB | 5 Rue Lafayette | Lille | 59000 | France | - And les livres suivants : - | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | - | 9782253004201 | Les Fleurs du Mal | Charles Baudelaire | Garnier-Flammarion | 1857-06-25 | 9.90 | 15 | Poésie, Classique | Recueil de poèmes symbolistes | Français | - | 9781234567890 | L'Ombre du Vent | Carlos Ruiz Zafón | Actes Sud | 2001-04-01 | 20.50 | 10 | Roman, Drame | Un livre sur les souvenirs | Français | - | 9785678901234 | Le Petit Prince | Antoine de Saint-Exupéry | Folio | 1943-04-06 | 8.99 | 1 | Jeunesse, Philosophie | Un conte intemporel | Français | - And les clients suivants : - | prenom | nom | numeroTelephone | pointsFidelite | - | Marie | Dupont | 0612345678 | 100 | - | Jean | Martin | 0687654321 | 50 | - | Sophie | Dubois | 0698765432 | 0 | + Given Le système contient les livres suivants : + | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | + | 9781234567890 | L'Ombre du Vent | Carlos Ruiz Zafón | Actes Sud | 2001-04-01 | 20.50 | 10 | Roman, Drame | Un livre sur les souvenirs | Français | + | 9789876543210 | 1984 | George Orwell | Gallimard | 1949-06-08 | 15.99 | 5 | Science-Fiction | Une dystopie emblématique | Français | + | 9785678901234 | Le Petit Prince | Antoine de Saint-Exupéry | Folio | 1943-04-06 | 8.99 | 20 | Jeunesse, Philosophie | Un conte intemporel | Français | + And Le système contient les utilisateurs suivants : + | id | prenom | nom | numTelephone | ptsFidelite | + | 33333333-3333-3333-3333-333333333333 | Alice | Dupuis | 0601020304 | 800 | + | 44444444-4444-4444-4444-444444444444 | Lucas | Martinot | 0654321876 | 50 | - Scenario: Passer une nouvelle commande - When un client passe une commande avec les informations suivantes : - | clientId | livreId | quantite | modePaiement | rue | ville | codePostal | pays | - | abc12345-def6-7890-gh12-ijk345678900 | 9782253004201 | 1 | CB | 21 Avenue Paul Eluard | Bobigny | 93000 | France | - Then une nouvelle commande est enregistrée avec les détails suivants : - | commandeId | montantTotal | pointsFideliteGagnes | - | cde45678-0123-def0-2345-678901234efg | 9.90 | 10 | + Scenario: Créer une commande avec une carte de crédit + When Je crée une nouvelle commande avec les informations suivantes : + | clientId | methodePaiement | + | 33333333-3333-3333-3333-333333333333 | CREDIT_CARD | + And La commande contient les livres suivants : + | isbn | quantite | + | 9789876543210 | 2 | + And L'adresse de livraison est : + | rue | ville | codePostal | pays | + | 42 avenue Bleue | Paris | 75000 | France | + Then Une nouvelle commande est créée + And Le prix total est 31.98 + And Le client "33333333-3333-3333-3333-333333333333" a 800 pts de fidélité - Scenario: Modifier une commande existante - When l'utilisateur modifie la commande avec l'ID "cde12345-6789-abcd-ef01-234567890abc" en mettant à jour les informations suivantes : - | quantite | modePaiement | - | 2 | POINTS_FIDELITE | - Then la commande avec l'ID "cde12345-6789-abcd-ef01-234567890abc" doit avoir les nouvelles informations suivantes : - | commandeId | clientId | livreId | quantite | montantTotal | pointsFideliteGagnes | modePaiement | rue | ville | codePostal | pays | - | cde12345-6789-abcd-ef01-234567890abc | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 2 | 41.00 | 41 | POINTS_FIDELITE | 10 Rue Victor Hugo | Paris | 75001 | France | + Scenario: Créer une commande avec des points de fidélité + When Je crée une nouvelle commande avec les informations suivantes : + | clientId | methodePaiement | + | 33333333-3333-3333-3333-333333333333 | LOYALTY_POINTS | + And La commande contient les livres suivants : + | isbn | quantite | + | 9781234567890 | 1 | + And L'adresse de livraison est : + | rue | ville | codePostal | pays | + | 42 avenue Bleue | Paris | 75000 | France | + Then Une nouvelle commande est créée + And Le prix total est 20.50 + And Le client "33333333-3333-3333-3333-333333333333" a 800 pts de fidélité +# j'ai oublié de faire en sorte de que il y ait un déduction des pts de fidélité lorsqu'on paye avec :( - Scenario: Supprimer une commande - When l'utilisateur supprime la commande avec l'ID "cde23456-7890-bcde-f012-345678901bcd" - Then la commande avec l'ID "cde23456-7890-bcde-f012-345678901bcd" ne doit plus exister dans le système - And la liste des commandes doit être mise à jour comme suit : - | commandeId | clientId | livreId | quantite | montantTotal | pointsFideliteGagnes | modePaiement | rue | ville | codePostal | pays | - | cde12345-6789-abcd-ef01-234567890abc | 123e4567-e89b-12d3-a456-426614174000 | 9781234567890 | 1 | 20.50 | 21 | CB | 10 Rue Victor Hugo | Paris | 75001 | France | - | cde34567-9012-cdef-1234-567890123def | 789e0123-b45d-56e7-c890-626814174222 | 9782253004201 | 1 | 9.90 | 10 | CB | 5 Rue Lafayette | Lille | 59000 | France | - | cde45678-0123-def0-2345-678901234efg | abc12345-def6-7890-gh12-ijk345678900 | 9782253004201 | 1 | 9.90 | 10 | CB | 21 Avenue Paul Eluard | Bobigny | 93000 | France | + Scenario: Créer une commande avec plusieurs livres différents + When Je crée une nouvelle commande avec les informations suivantes : + | clientId | methodePaiement | + | 33333333-3333-3333-3333-333333333333 | CREDIT_CARD | + And La commande contient les livres suivants : + | isbn | quantite | + | 9781234567890 | 1 | + | 9785678901234 | 2 | + And L'adresse de livraison est : + | rue | ville | codePostal | pays | + | 42 avenue Bleue | Paris | 75000 | France | + Then Une nouvelle commande est créée + And Le prix total est 38.48 -#Demander a Maxime : comment faire en sorte de faire le paiement? on regarde les infos du client avec l'uuid ou le num? - Scenario: Tentative de paiement avec des points de fidélité insuffisants - When le client "456e7891-a23c-34d5-b678-526714174111" tente de passer une commande avec les informations suivantes : - | livreId | quantite | modePaiement | rue | ville | codePostal | pays | - | 9782253004201 | 1 | POINTS_FIDELITE | 30 Boulevard Haussmann | Paris | 75009 | France | - Then le paiement échoue - And je reçois un message d'erreur indiquant "Impossible d'utiliser 200 points alors que le solde est de 50 point" - And le client "456e7891-a23c-34d5-b678-526714174111" possède toujours 50 point de fidélités + Scenario: Essayer de créer une commande avec un stock de livres insuffisant + When Je crée une nouvelle commande avec les informations suivantes : + | clientId | methodePaiement | + | 33333333-3333-3333-3333-333333333333 | CREDIT_CARD | + And La commande contient les livres suivants : + | isbn | quantite | + | 9789876543210 | 100 | + And L'adresse de livraison est : + | rue | ville | codePostal | pays | + | 42 avenue Bleue | Paris | 75000 | France | + Then La création de la commande échoue + And Je reçois une erreur indiquant que le stock de livres est insuffisant - Scenario: Tentative de paiement avec un moyen de paiement invalide - When le client "123e4567-e89b-12d3-a456-426614174000" tente de passer une commande avec les informations suivantes : - | livreId | quantite | modePaiement | rue | ville | codePostal | pays | - | 9782253004201 | 1 | CRYPTO | 12 Rue des Lilas | Nantes | 44000 | France | - Then le paiement échoue - And je reçois un message d'erreur indiquant "Mode de paiement invalide : CRYPTO n'est pas accepté" - And aucune nouvelle commande n'est enregistrée + Scenario: Essayer de créer une commande avec un client inconnu + When Je crée une nouvelle commande avec les informations suivantes : + | clientId | methodePaiement | + | 55555555-5555-5555-5555-555555555555 | CREDIT_CARD | + And La commande contient les livres suivants : + | isbn | quantite | + | 9781234567890 | 1 | + And L'adresse de livraison est : + | rue | ville | codePostal | pays | + | 42 avenue Bleue | Paris | 75000 | France | + Then La création de la commande échoue + And Je reçois une erreur indiquant que le client n'a pas été trouvé - Scenario: Tentative de commande avec un stock insuffisant - Given le livre avec l'ISBN "9785678901234" n'a que 1 exemplaire en stock - When le client "456e7891-a23c-34d5-b678-526714174111" tente de passer une commande avec les informations suivantes : - | livreId | quantite | modePaiement | rue | ville | codePostal | pays | - | 9785678901234 | 2 | CB | 18 Place du Capitole | Toulouse | 31000 | France | - Then la commande échoue - And je reçois un message d'erreur indiquant "Stock insuffisant : seulement 1 exemplaire disponible" - And aucune nouvelle commande n'est enregistrée + Scenario: Récupérer une commande par ID + Given Il existe une commande avec l'ID "99999999-8888-7777-6666-555555555555" pour le client "33333333-3333-3333-3333-333333333333" + When Je récupère la commande par ID "99999999-8888-7777-6666-555555555555" + Then Je reçois une commande + Scenario: Récupérer toutes les commandes pour un client + When Je demande toutes les commandes pour le client "33333333-3333-3333-3333-333333333333" + Then Je reçois une liste de commandes + + Scenario: Essayer de récupérer une commande avec un ID inconnu + When Je récupère la commande par ID "commande-inconnue" + Then La récupération échoue + And Je reçois une erreur indiquant que la commande n'a pas été trouvée + + Scenario: Essayer de récupérer les commandes pour un client inconnu + When Je demande toutes les commandes pour le client "00000000-0000-0000-0000-000000000000" + Then La récupération échoue + And Je reçois une erreur indiquant que le client n'a pas été trouvé