diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/DesiredSubscriptionDuration.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/DesiredSubscriptionDuration.java new file mode 100644 index 0000000..f216e3e --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/DesiredSubscriptionDuration.java @@ -0,0 +1,17 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription; + +public enum DesiredSubscriptionDuration { + THREE(3), + SIX(6), + TWELVE(12); + + private final Integer value; + + DesiredSubscriptionDuration(Integer value) { + this.value = value; + } + + public Integer getValue() { + return value; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentMethodInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentMethodInfo.java new file mode 100644 index 0000000..23339a8 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentMethodInfo.java @@ -0,0 +1,4 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription; + +public record PaymentMethodInfo(String paymentType, Object details) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentType.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentType.java new file mode 100644 index 0000000..701fafc --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/PaymentType.java @@ -0,0 +1,6 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription; + +public enum PaymentType { + CB, + PAYPAL; +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionDTO.java new file mode 100644 index 0000000..cfb68a0 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionDTO.java @@ -0,0 +1,22 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; +import java.util.UUID; + +@Builder +@Getter +public class SubscriptionDTO { + + private UUID subscriptionId; + private UUID customerId; + private Integer desiredSubscriptionDuration; + private PaymentMethod paymentMethod; + private LocalDate desiredStartDate; + private LocalDate startDate; + private LocalDate endDate; + private double monthlyAmount; +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionInfo.java new file mode 100644 index 0000000..a780116 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionInfo.java @@ -0,0 +1,6 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription; + +import java.time.LocalDate; + +public record SubscriptionInfo(Integer desiredSubscriptionDuration, LocalDate desiredStartDate) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverter.java new file mode 100644 index 0000000..a7de3bf --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverter.java @@ -0,0 +1,43 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.customer.CustomerDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentMethodInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; + +public class SubscriptionConverter { + + private SubscriptionConverter(){ + + } + + public static Subscription toDomain(SubscriptionInfo newSubscription, PaymentMethodInfo newPaymentMethod) { + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(newPaymentMethod.paymentType()) + .details(newPaymentMethod.details()) + .build(); + return Subscription.builder() + .desiredSubscriptionDuration(newSubscription.desiredSubscriptionDuration()) + .paymentMethod(paymentMethod) + .desiredStartDate(newSubscription.desiredStartDate()) + .startDate(newSubscription.desiredStartDate()) + .endDate(newSubscription.desiredStartDate().plusMonths(newSubscription.desiredSubscriptionDuration())) + .monthlyAmount(0) + .build(); + } + + public static SubscriptionDTO toDTO(Subscription subscription) { + return SubscriptionDTO.builder() + .subscriptionId(subscription.getSubscriptionId()) + .customerId(subscription.getCustomerId()) + .desiredSubscriptionDuration(subscription.getDesiredSubscriptionDuration()) + .paymentMethod(subscription.getPaymentMethod()) + .desiredStartDate(subscription.getDesiredStartDate()) + .startDate(subscription.getStartDate()) + .endDate(subscription.getEndDate()) + .monthlyAmount(subscription.getMonthlyAmount()) + .build(); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethod.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethod.java new file mode 100644 index 0000000..3828ba6 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethod.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class PaymentMethod { + + private String paymentType; + private Object details; +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/Subscription.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/Subscription.java new file mode 100644 index 0000000..b802547 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/Subscription.java @@ -0,0 +1,44 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity; + +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; +import java.util.UUID; + +@Builder +@Getter +public class Subscription { + + private UUID subscriptionId; + private UUID customerId; + private Integer desiredSubscriptionDuration; + private PaymentMethod paymentMethod; + private LocalDate desiredStartDate; + private LocalDate startDate; + private LocalDate endDate; + private double monthlyAmount; + + public void setRandomSubscriptionUUID() { + + this.subscriptionId = UUID.randomUUID(); + } + + public void setRandomCustomerUUID() { + + this.customerId = UUID.randomUUID(); + } + + public void setStartDate(){ + this.startDate = this.desiredStartDate; + } + + public void setEndDate(){ + this.endDate = this.desiredStartDate.plusMonths(this.desiredSubscriptionDuration); + } + + public void setDateSubscription(){ + setStartDate(); + setEndDate(); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodException.java new file mode 100644 index 0000000..7304eb9 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +public class NotValidPaymentMethodException extends RuntimeException { + + public NotValidPaymentMethodException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionException.java new file mode 100644 index 0000000..27829f6 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +public class NotValidSubscriptionException extends RuntimeException { + + public NotValidSubscriptionException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java new file mode 100644 index 0000000..4f73c47 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java @@ -0,0 +1,21 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +import java.text.MessageFormat; +import java.util.Optional; +import java.util.UUID; + +public class SubscriptionNotFoundException extends RuntimeException { + public static final String THE_SUBSCRIPTION_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE = "The subscriptions with the customer id {0} does not exists"; + public static final String THE_SUBSCRIPTION_WITH_SUBSCRIPTION_ID_DOES_NOT_EXIST_MESSAGE = "The subscription with subscription id {0} does not exists"; + + public SubscriptionNotFoundException(Optional customerUUID, Optional subscriptionUUID) { + super(buildMessage(customerUUID, subscriptionUUID)); + } + + private static String buildMessage(Optional customerUUID, Optional subscriptionUUID) { + if (customerUUID.isPresent()) { + return MessageFormat.format(THE_SUBSCRIPTION_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE, customerUUID.get()); + } + return MessageFormat.format(THE_SUBSCRIPTION_WITH_SUBSCRIPTION_ID_DOES_NOT_EXIST_MESSAGE, subscriptionUUID.get()); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepository.java new file mode 100644 index 0000000..d3c16c5 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepository.java @@ -0,0 +1,62 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class SubscriptionRepository { + + private final List subscriptions = new ArrayList<>(); + + public List findAll() { + + return subscriptions; + } + + public void deleteAll() { + + subscriptions.clear(); + } + + public Subscription save(Subscription newSubscription) { + Optional optionalSubscriptionWithSameSubscriptionId = this.findBySubscriptionId(newSubscription.getSubscriptionId()); + optionalSubscriptionWithSameSubscriptionId.ifPresent(subscriptions::remove); + this.subscriptions.add(newSubscription); + return newSubscription; + } + + public List FindByCustomerId(UUID customerUUID) { + return this.subscriptions.stream() + .filter(subscription -> subscription.getCustomerId().equals(customerUUID)) + .toList(); + } + + public Optional findBySubscriptionId(UUID subscriptionUUID) { + return this.subscriptions.stream() + .filter(subscription -> subscription.getSubscriptionId().equals(subscriptionUUID)) + .findFirst(); + } + + public boolean existsByCustomerId(UUID customerUUID) { + return this.subscriptions.stream() + .anyMatch(review -> review.getCustomerId().equals(customerUUID)); + } + + public boolean existsBySubscriptionId(UUID subscriptionUUID) { + return this.subscriptions.stream() + .anyMatch(subscription -> subscription.getSubscriptionId().equals(subscriptionUUID)); + } + + public void deleteByCustomerId(UUID customerUUID) { + + this.subscriptions.removeIf(subscription -> subscription.getCustomerId().equals(customerUUID)); + } + + public void delete(Subscription subscription) { + + this.subscriptions.remove(subscription); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCase.java new file mode 100644 index 0000000..9aebcb7 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCase.java @@ -0,0 +1,110 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentMethodInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.converter.SubscriptionConverter; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.SubscriptionNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository.SubscriptionRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator.PaymentMethodValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator.SubscriptionValidator; + +import java.util.*; + +public class SubscriptionUseCase { + + private final SubscriptionRepository subscriptionRepository; + + public SubscriptionUseCase(SubscriptionRepository subscriptionRepository) { + + this.subscriptionRepository = subscriptionRepository; + } + + private Map Output(Subscription subscription){ + Map result = new HashMap<>(); + + result.put("subscriptionId", subscription.getSubscriptionId()); + result.put("startDate", subscription.getStartDate()); + result.put("endDate", subscription.getEndDate()); + result.put("monthlyAmount", subscription.getMonthlyAmount()); + + return result; + } + + public Map registerSubscription(SubscriptionInfo newSubscription, PaymentMethodInfo newPaymentMethod) + throws NotValidSubscriptionException { + SubscriptionValidator.validate(newSubscription); + PaymentMethodValidator.validate(newPaymentMethod); + Subscription subscriptionToRegister = SubscriptionConverter.toDomain(newSubscription, newPaymentMethod); + Subscription subscriptionToRegistered = subscriptionRepository.save(subscriptionToRegister); + return Output(subscriptionToRegistered); + } + + public List findSubscriptionByCustomerId(UUID customerId) { + List optionalSubscriptions = subscriptionRepository.FindByCustomerId(customerId); + return optionalSubscriptions.stream() + .map(SubscriptionConverter::toDTO) + .toList(); + } + + public Optional findSubscriptionBySubscriptionId(UUID subscriptionId) { + Optional optionalSubscription = subscriptionRepository.findBySubscriptionId(subscriptionId); + return optionalSubscription.map(SubscriptionConverter::toDTO); + } + + public SubscriptionDTO updateSubscription(UUID SubscriptionUUID, SubscriptionInfo subscriptionInfo, PaymentMethodInfo paymentMethodInfo) + throws SubscriptionNotFoundException, NotValidSubscriptionException { + SubscriptionValidator.validate(subscriptionInfo); + PaymentMethodValidator.validate(paymentMethodInfo); + Subscription subscriptionBySubscriptionUUID = getSubscriptionIfDoesNotExistThrowSubscriptionNotFoundException( + SubscriptionUUID); + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(paymentMethodInfo.paymentType()) + .details(paymentMethodInfo.details()) + .build(); + Subscription subscription = Subscription.builder() + .subscriptionId(SubscriptionUUID) + .customerId(subscriptionBySubscriptionUUID.getCustomerId()) + .desiredSubscriptionDuration(subscriptionInfo.desiredSubscriptionDuration()) + .paymentMethod(paymentMethod) + .desiredStartDate(subscriptionInfo.desiredStartDate()) + .monthlyAmount(subscriptionBySubscriptionUUID.getMonthlyAmount()) + .build(); + subscription.setDateSubscription(); + Subscription updatedSubscription = subscriptionRepository.save(subscription); + return SubscriptionConverter.toDTO(updatedSubscription); + } + + public void deleteSubscription(UUID subscriptionUUID) throws SubscriptionNotFoundException { + Subscription subscriptionToDelete = getSubscriptionIfDoesNotExistThrowSubscriptionNotFoundException(subscriptionUUID); + this.subscriptionRepository.delete(subscriptionToDelete); + } + + public void deleteSubscriptionsOfACustomer(UUID customerUUID) throws SubscriptionNotFoundException { + List subscriptionsToDelete = getSubscriptionByCustomerIdIfDoesNotExistThrowSubscriptionNotFoundException(customerUUID); + for (Subscription subscription : subscriptionsToDelete) { + subscriptionRepository.delete(subscription); + } + } + + private Subscription getSubscriptionIfDoesNotExistThrowSubscriptionNotFoundException(UUID subscriptionUUID) + throws SubscriptionNotFoundException { + Optional optionalSubscriptionBySubscriptionId = subscriptionRepository.findBySubscriptionId(subscriptionUUID); + if (optionalSubscriptionBySubscriptionId.isEmpty()) { + throw new SubscriptionNotFoundException(Optional.empty(),Optional.of(subscriptionUUID)); + } + return optionalSubscriptionBySubscriptionId.get(); + } + + private List getSubscriptionByCustomerIdIfDoesNotExistThrowSubscriptionNotFoundException(UUID customerUUID) + throws SubscriptionNotFoundException { + List optionalSubscriptionBySubscriptionId = subscriptionRepository.FindByCustomerId(customerUUID); + if (optionalSubscriptionBySubscriptionId.isEmpty()) { + throw new SubscriptionNotFoundException(Optional.of(customerUUID),Optional.empty()); + } + return optionalSubscriptionBySubscriptionId; + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidator.java new file mode 100644 index 0000000..a9c9590 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidator.java @@ -0,0 +1,27 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentMethodInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidPaymentMethodException; + +import java.util.Set; + +public class PaymentMethodValidator { + + public static final String MODE_PAIEMENT_IS_NOT_VALID = "paymentType is not valid"; + + private PaymentMethodValidator() { + + } + + public static void validate(PaymentMethodInfo newPaymentMethod) + throws NotValidPaymentMethodException { + validatePaymentType(newPaymentMethod); + } + + private static void validatePaymentType(PaymentMethodInfo newPaymentMethod) + throws NotValidPaymentMethodException { + Set Valid_Payment_Type = Set.of("CB", "PAYPAL"); + if (!Valid_Payment_Type.contains(newPaymentMethod.paymentType())) { + throw new NotValidPaymentMethodException(MODE_PAIEMENT_IS_NOT_VALID);} + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidator.java new file mode 100644 index 0000000..c03206d --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidator.java @@ -0,0 +1,36 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException; + +import java.time.LocalDate; +import java.util.Set; + +public class SubscriptionValidator { + + public static final String SUBSCRIPTION_DURATION_DESIRED_IS_NOT_VALID = "desiredSubscriptionDuration will be 3, 6 or 12 by the ENUM file SubscriptionDurationDesired"; + public static final String DESIRED_START_DATE_CANNOT_BE_BEFORE_TODAY = "desiredStartDate cannot be before today"; + + private SubscriptionValidator() { + + } + + public static void validate(SubscriptionInfo newSubscription) throws NotValidSubscriptionException { + validateDesiredStartDate(newSubscription); + validateSubscriptionDurationDesired(newSubscription); + } + + private static void validateSubscriptionDurationDesired(SubscriptionInfo newSubscription) + throws NotValidSubscriptionException { + Set VALID_DURATIONS = Set.of(3, 6, 12); + if (!VALID_DURATIONS.contains(newSubscription.desiredSubscriptionDuration())) { + throw new NotValidSubscriptionException(SUBSCRIPTION_DURATION_DESIRED_IS_NOT_VALID);} + } + + private static void validateDesiredStartDate(SubscriptionInfo newSubscription) + throws NotValidSubscriptionException { + if (newSubscription.desiredStartDate().isBefore(LocalDate.now())) { + throw new NotValidSubscriptionException(DESIRED_START_DATE_CANNOT_BE_BEFORE_TODAY); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverterTest.java new file mode 100644 index 0000000..5e0952d --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverterTest.java @@ -0,0 +1,125 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.*; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class SubscriptionConverterTest { + + @Nested + @DisplayName("toDomain() method tests") + class ToDomainTests { + + @Test + @DisplayName("Should convert SubscriptionInfo to Subscription domain object with monthly amount initialized to 0") + void shouldConvertSubscriptionInfoToDomain() { + // Given + PaymentMethodInfo paymentMethodInfo = new PaymentMethodInfo(PaymentType.CB.name(), "Maxime Lebreton"); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + SubscriptionInfo subscriptionInfo = new SubscriptionInfo(DesiredSubscriptionDuration.THREE.getValue(), desiredStartDate); + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + + // When + Subscription result = SubscriptionConverter.toDomain(subscriptionInfo, paymentMethodInfo); + + // Then + assertNotNull(result); + assertEquals(subscriptionInfo.desiredSubscriptionDuration(), result.getDesiredSubscriptionDuration()); + assertEquals(paymentMethodInfo.paymentType(), result.getPaymentMethod().getPaymentType()); + assertEquals(paymentMethodInfo.details(), result.getPaymentMethod().getDetails()); + assertEquals(subscriptionInfo.desiredStartDate(), result.getDesiredStartDate()); + assertEquals(subscriptionInfo.desiredStartDate(), result.getStartDate()); + assertEquals(estimateEndDate, result.getEndDate()); + assertEquals(0, result.getMonthlyAmount()); + } + } + + @Nested + @DisplayName("toDTO() method tests") + class ToDTOTests { + + @Test + @DisplayName("Should convert Subscription domain object to SubscriptionDTO with all fields mapped correctly") + void shouldConvertSubscriptionToDTO() { + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(PaymentType.CB.name()) + .details("Maxime Lebreton") + .build(); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + Subscription subscription = Subscription.builder() + .subscriptionId(UUID.randomUUID()) + .customerId(UUID.randomUUID()) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .startDate(desiredStartDate) + .endDate(estimateEndDate) + .monthlyAmount(12.03) + .build(); + + SubscriptionDTO result = SubscriptionConverter.toDTO(subscription); + + assertNotNull(result); + assertEquals(subscription.getSubscriptionId(), result.getSubscriptionId()); + assertEquals(subscription.getCustomerId(), result.getCustomerId()); + assertEquals(subscription.getDesiredSubscriptionDuration(), result.getDesiredSubscriptionDuration()); + assertEquals(subscription.getPaymentMethod().getPaymentType(), result.getPaymentMethod().getPaymentType()); + assertEquals(subscription.getPaymentMethod().getDetails(), result.getPaymentMethod().getDetails()); + assertEquals(subscription.getDesiredStartDate(), result.getDesiredStartDate()); + assertEquals(subscription.getStartDate(), result.getStartDate()); + assertEquals(subscription.getEndDate(), result.getEndDate()); + assertEquals(12.03, result.getMonthlyAmount()); + } + } + + @Test + @DisplayName("Should handle null values properly when converting between objects") + void shouldHandleNullValuesGracefully() { + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(PaymentType.CB.name()) + .details(null) + .build(); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + Subscription subscription = Subscription.builder() + .subscriptionId(UUID.randomUUID()) + .customerId(UUID.randomUUID()) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .startDate(desiredStartDate) + .endDate(estimateEndDate) + .monthlyAmount(12.03) + .build(); + + SubscriptionDTO result = SubscriptionConverter.toDTO(subscription); + + assertNotNull(result); + assertNull(result.getPaymentMethod().getDetails()); + assertEquals(desiredStartDate, result.getDesiredStartDate()); + } + + @Test + @DisplayName("Should preserve empty string values during conversion") + void shouldPreserveEmptyStrings() { + PaymentMethodInfo paymentMethodInfo = new PaymentMethodInfo(PaymentType.CB.name(), ""); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + SubscriptionInfo subscriptionInfo = new SubscriptionInfo(DesiredSubscriptionDuration.THREE.getValue(), desiredStartDate); + + Subscription domainResult = SubscriptionConverter.toDomain(subscriptionInfo, paymentMethodInfo); + SubscriptionDTO dtoResult = SubscriptionConverter.toDTO(domainResult); + + assertEquals("", dtoResult.getPaymentMethod().getDetails()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethodTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethodTest.java new file mode 100644 index 0000000..4f184f5 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/PaymentMethodTest.java @@ -0,0 +1,58 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentType; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PaymentMethodTest { + + @Test + @DisplayName("Builder should create a valid PaymentMethod instance") + void testPaymentMethodBuilder() { + String paymentType = PaymentType.CB.name(); + Object details = new Object(); + details = "Maxime Lebreton"; + + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(paymentType) + .details(details) + .build(); + + assertEquals(paymentType, paymentMethod.getPaymentType()); + assertEquals(details, paymentMethod.getDetails()); + } + + @Test + @DisplayName("Builder should create a valid PaymentMethod instance with details as an Integer") + void testPaymentMethodDetailsInteger() { + String paymentType = PaymentType.CB.name(); + Object details = new Object(); + details = 10; + + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(paymentType) + .details(details) + .build(); + + assertEquals(paymentType, paymentMethod.getPaymentType()); + assertEquals(details, paymentMethod.getDetails()); + } + + @Test + @DisplayName("Builder should create a valid PaymentMethod instance with details as an boolean") + void testPaymentMethodDetailsBoolean() { + String paymentType = PaymentType.CB.name(); + Object details = new Object(); + details = true; + + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(paymentType) + .details(details) + .build(); + + assertEquals(paymentType, paymentMethod.getPaymentType()); + assertEquals(details, paymentMethod.getDetails()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/SubscriptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/SubscriptionTest.java new file mode 100644 index 0000000..98a4678 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/SubscriptionTest.java @@ -0,0 +1,125 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentType; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.DesiredSubscriptionDuration; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SubscriptionTest { + + @Test + @DisplayName("Builder should create a valid Subscription instance") + void testSubscriptionBuilder() { + UUID subscriptionId = UUID.randomUUID(); + UUID customerId = UUID.randomUUID(); + Integer desiredSubscriptionDuration = DesiredSubscriptionDuration.THREE.getValue(); + String paymentType = PaymentType.CB.name(); + Object details = new Object(); + details = "Maxime Lebreton"; + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + LocalDate startDate = desiredStartDate; + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + double monthlyAmount = 17.99; + + PaymentMethod paymentMethod = PaymentMethod.builder() + .paymentType(paymentType) + .details(details) + .build(); + Subscription subscription = Subscription.builder() + .subscriptionId(subscriptionId) + .customerId(customerId) + .desiredSubscriptionDuration(desiredSubscriptionDuration) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .startDate(startDate) + .endDate(estimateEndDate) + .monthlyAmount(monthlyAmount) + .build(); + + assertEquals(subscriptionId, subscription.getSubscriptionId()); + assertEquals(customerId, subscription.getCustomerId()); + assertEquals(desiredSubscriptionDuration, subscription.getDesiredSubscriptionDuration()); + assertEquals(paymentType, paymentMethod.getPaymentType()); + assertEquals(details, paymentMethod.getDetails()); + assertEquals(desiredStartDate, subscription.getDesiredStartDate()); + assertEquals(startDate, subscription.getStartDate()); + assertEquals(estimateEndDate, subscription.getEndDate()); + assertEquals(monthlyAmount, subscription.getMonthlyAmount()); + } + + @Test + @DisplayName("setRandomSubscriptionUUID should change the ID to a new random UUID") + void testSetRandomSubscriptionUUID() { + Subscription subscription = Subscription.builder().build(); + UUID originalId = subscription.getSubscriptionId(); + + subscription.setRandomSubscriptionUUID(); + + assertNotNull(subscription.getSubscriptionId()); + assertNotEquals(originalId, subscription.getSubscriptionId()); + } + + @Test + @DisplayName("setRandomCustomerUUID should change the ID to a new random UUID") + void testSetRandomCustomerUUID() { + Subscription subscription = Subscription.builder().build(); + UUID originalId = subscription.getCustomerId(); + + subscription.setRandomCustomerUUID(); + + assertNotNull(subscription.getCustomerId()); + assertNotEquals(originalId, subscription.getCustomerId()); + } + + @Test + @DisplayName("setStartDate should instantiate StartDate as the same value as the variable desiredStartDate") + void testSetStartDate() { + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + Subscription subscription = Subscription.builder() + .desiredStartDate(desiredStartDate) + .build(); + + subscription.setStartDate(); + + assertNotNull(subscription.getStartDate()); + assertEquals(desiredStartDate, subscription.getStartDate()); + } + + @Test + @DisplayName("setEndDate should instantiate EndDate as the same value as the variable desiredStartDate + desiredSubscriptionDuration") + void testSetEndDate() { + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + Subscription subscription = Subscription.builder() + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .desiredStartDate(desiredStartDate) + .build(); + + subscription.setEndDate(); + + assertNotNull(subscription.getEndDate()); + assertEquals(estimateEndDate, subscription.getEndDate()); + } + + @Test + @DisplayName("setDateSubscription should instantiate StartDate and EndDate ") + void testSetDateSubscription() { + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + LocalDate estimateEndDate = LocalDate.of(2026, 9, 24); + Subscription subscription = Subscription.builder() + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .desiredStartDate(desiredStartDate) + .build(); + + subscription.setDateSubscription(); + + assertNotNull(subscription.getEndDate()); + assertEquals(estimateEndDate, subscription.getEndDate()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodEsceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodEsceptionTest.java new file mode 100644 index 0000000..7ae5af4 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidPaymentMethodEsceptionTest.java @@ -0,0 +1,58 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class NotValidPaymentMethodEsceptionTest { + + @Test + @DisplayName("Exception should be created with the provided message") + void testExceptionCreation() { + String errorMessage = "PaymentMethod data is not valid"; + + NotValidPaymentMethodException exception = new NotValidPaymentMethodException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = { + "paymentType is not valid" + }) + @DisplayName("Exception should handle different validation messages") + void testExceptionWithDifferentMessages(String errorMessage) { + NotValidPaymentMethodException exception = new NotValidPaymentMethodException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + String errorMessage = "paymentType is not valid"; + + Exception exception = assertThrows(NotValidPaymentMethodException.class, () -> { + throw new NotValidPaymentMethodException(errorMessage); + }); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be catchable as a general Exception") + void testExceptionInheritance() { + String errorMessage = "Invalid paymentMethod data"; + + try { + throw new NotValidPaymentMethodException(errorMessage); + } catch (Exception e) { + assertEquals(NotValidPaymentMethodException.class, e.getClass()); + assertEquals(errorMessage, e.getMessage()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionExceptionTest.java new file mode 100644 index 0000000..eebaaf5 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/NotValidSubscriptionExceptionTest.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class NotValidSubscriptionExceptionTest { + + @Test + @DisplayName("Exception should be created with the provided message") + void testExceptionCreation() { + String errorMessage = "Subscription data is not valid"; + + NotValidSubscriptionException exception = new NotValidSubscriptionException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = { + "desiredSubscriptionDuration will be 3, 6 or 12 by the ENUM file SubscriptionDurationDesired", + "desiredStartDate cannot be before today" + }) + @DisplayName("Exception should handle different validation messages") + void testExceptionWithDifferentMessages(String errorMessage) { + NotValidSubscriptionException exception = new NotValidSubscriptionException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + String errorMessage = "desiredStartDate cannot be before today"; + + Exception exception = assertThrows(NotValidSubscriptionException.class, () -> { + throw new NotValidSubscriptionException(errorMessage); + }); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be catchable as a general Exception") + void testExceptionInheritance() { + String errorMessage = "Invalid subscription data"; + + try { + throw new NotValidSubscriptionException(errorMessage); + } catch (Exception e) { + assertEquals(NotValidSubscriptionException.class, e.getClass()); + assertEquals(errorMessage, e.getMessage()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundExceptionTest.java new file mode 100644 index 0000000..b122ba8 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundExceptionTest.java @@ -0,0 +1,74 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SubscriptionNotFoundExceptionTest { + + @Test + @DisplayName("Exception message should contain the UUID provided for customer") + void testExceptionMessageContainsUUIDForCustomer() { + UUID customerUUID = UUID.randomUUID(); + + SubscriptionNotFoundException exception = new SubscriptionNotFoundException(Optional.of(customerUUID), Optional.empty()); + + String expectedMessage = String.format("The subscriptions with the customer id %s does not exists", customerUUID); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception message should contain the UUID provided for subscription") + void testExceptionMessageContainsUUIDForSubscription() { + UUID subscriptionUUID = UUID.randomUUID(); + + SubscriptionNotFoundException exception = new SubscriptionNotFoundException(Optional.empty(), Optional.of(subscriptionUUID)); + + String expectedMessage = String.format("The subscription with subscription id %s does not exists", subscriptionUUID); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should use the correct constant message format for customer") + void testExceptionUsesConstantMessageCustomerFormat() { + UUID customerUUID = UUID.randomUUID(); + + SubscriptionNotFoundException exception = new SubscriptionNotFoundException(Optional.of(customerUUID), Optional.empty()); + + String expectedFormatWithPlaceholder = "The subscriptions with the customer id {0} does not exists"; + assertEquals(SubscriptionNotFoundException.THE_SUBSCRIPTION_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE, + expectedFormatWithPlaceholder); + assertTrue(exception.getMessage().contains(customerUUID.toString())); + } + + @Test + @DisplayName("Exception should use the correct constant message format for subscription") + void testExceptionUsesConstantMessageSubscriptionFormat() { + UUID subscriptionUUID = UUID.randomUUID(); + + SubscriptionNotFoundException exception = new SubscriptionNotFoundException(Optional.empty(), Optional.of(subscriptionUUID)); + + String expectedFormatWithPlaceholder = "The subscription with subscription id {0} does not exists"; + assertEquals(SubscriptionNotFoundException.THE_SUBSCRIPTION_WITH_SUBSCRIPTION_ID_DOES_NOT_EXIST_MESSAGE, + expectedFormatWithPlaceholder); + assertTrue(exception.getMessage().contains(subscriptionUUID.toString())); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + UUID subscriptionUUID = UUID.randomUUID(); + + try { + throw new SubscriptionNotFoundException(Optional.empty(), Optional.of(subscriptionUUID)); + } catch (SubscriptionNotFoundException e) { + String expectedMessage = String.format("The subscription with subscription id %s does not exists", subscriptionUUID); + assertEquals(expectedMessage, e.getMessage()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepositoryTest.java new file mode 100644 index 0000000..1f3d4fd --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepositoryTest.java @@ -0,0 +1,300 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.DesiredSubscriptionDuration; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentType; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; +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 java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SubscriptionRepositoryTest { + + private SubscriptionRepository repository; + private PaymentMethod paymentMethod; + private Subscription subscription1; + private Subscription subscription2; + private Subscription subscription3; + + @BeforeEach + void setUp() { + repository = new SubscriptionRepository(); + + paymentMethod = PaymentMethod.builder() + .paymentType(PaymentType.CB.name()) + .details("Maxime Lebreton") + .build(); + + LocalDate desiredStartDate1 = LocalDate.of(2026, 6, 24); + subscription1 = Subscription.builder() + .customerId(UUID.randomUUID()) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate1) + .monthlyAmount(12.03) + .build(); + subscription1.setRandomSubscriptionUUID(); + subscription1.setDateSubscription(); + + UUID customCustomerId = UUID.randomUUID(); + + LocalDate desiredStartDate2 = LocalDate.of(2026, 7, 24); + subscription2 = Subscription.builder() + .customerId(customCustomerId) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.SIX.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate2) + .monthlyAmount(20) + .build(); + subscription2.setRandomSubscriptionUUID(); + subscription2.setDateSubscription(); + + LocalDate desiredStartDate3 = LocalDate.of(2026, 8, 24); + subscription3 = Subscription.builder() + .customerId(customCustomerId) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.TWELVE.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate3) + .monthlyAmount(30) + .build(); + subscription3.setRandomSubscriptionUUID(); + subscription3.setDateSubscription(); + } + + @Test + @DisplayName("New subecription should be empty") + void testNewRepositoryIsEmpty() { + List subscriptions = repository.findAll(); + + assertTrue(subscriptions.isEmpty()); + assertEquals(0, subscriptions.size()); + } + + @Nested + @DisplayName("Save operations") + class SaveOperations { + + @Test + @DisplayName("Save should add a new customer") + void testSaveNewSubscription() { + Subscription savedSubscription = repository.save(subscription1); + + assertEquals(1, repository.findAll().size()); + assertEquals(subscription1.getSubscriptionId(), savedSubscription.getSubscriptionId()); + assertEquals(subscription1.getMonthlyAmount(), savedSubscription.getMonthlyAmount()); + } + + @Test + @DisplayName("Save should update existing subscription with same ID") + void testSaveUpdatesExistingSubscription() { + repository.save(subscription1); + + UUID subscriptionId = subscription1.getSubscriptionId(); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + Subscription updatedSubscription = Subscription.builder() + .subscriptionId(subscriptionId) + .customerId(UUID.randomUUID()) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.SIX.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .monthlyAmount(20) + .build(); + + Subscription savedCustomer = repository.save(updatedSubscription); + + assertEquals(1, repository.findAll().size()); + assertEquals(subscriptionId, savedCustomer.getSubscriptionId()); + assertEquals(6, savedCustomer.getDesiredSubscriptionDuration()); + assertEquals(20, savedCustomer.getMonthlyAmount()); + } + + @Test + @DisplayName("Save multiple subscriptions should add all of them") + void testSaveMultipleSubscriptions() { + repository.save(subscription1); + repository.save(subscription2); + + List subscriptions = repository.findAll(); + + assertEquals(2, subscriptions.size()); + assertTrue(subscriptions.contains(subscription1)); + assertTrue(subscriptions.contains(subscription2)); + } + } + + @Nested + @DisplayName("Find operations") + class FindOperations { + + @BeforeEach + void setUpSubscriptions() { + repository.save(subscription1); + repository.save(subscription2); + repository.save(subscription3); + } + + @Test + @DisplayName("FindAll should return all subscriptions") + void testFindAll() { + List subscriptions = repository.findAll(); + + assertEquals(3, subscriptions.size()); + assertTrue(subscriptions.contains(subscription1)); + assertTrue(subscriptions.contains(subscription2)); + assertTrue(subscriptions.contains(subscription3)); + } + + @Test + @DisplayName("FindBySubscriptionId should return subscription with matching ID") + void testFindBySubscriptionId() { + Optional foundSubscription = repository.findBySubscriptionId(subscription1.getSubscriptionId()); + + assertTrue(foundSubscription.isPresent()); + assertEquals(subscription1.getStartDate(), foundSubscription.get().getStartDate()); + assertEquals(subscription1.getMonthlyAmount(), foundSubscription.get().getMonthlyAmount()); + } + + @Test + @DisplayName("FindBySubscriptionId should return empty Optional when ID doesn't exist") + void testFindBySubscriptionIdNotFound() { + UUID nonExistentSubscriptionId = UUID.randomUUID(); + + Optional foundSubscription = repository.findBySubscriptionId(nonExistentSubscriptionId); + + assertTrue(foundSubscription.isEmpty()); + } + + @Test + @DisplayName("FindByCustomerId should return subscription with matching ID") + void testFindByCustomerId() { + List foundSubscriptions = repository.FindByCustomerId(subscription2.getCustomerId()); + + assertFalse(foundSubscriptions.isEmpty()); + assertTrue(foundSubscriptions.contains(subscription2)); + assertTrue(foundSubscriptions.contains(subscription3)); + } + + @Test + @DisplayName("FindByCustomerId should return empty Optional when ID doesn't exist") + void testFindByCustomerIdNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + + List foundSubscription = repository.FindByCustomerId(nonExistentCustomerId); + + assertTrue(foundSubscription.isEmpty()); + } + + @Test + @DisplayName("ExistsBySubscriptionId should return true when ID exists") + void testExistsBySubscriptionIdExists() { + boolean exists = repository.existsBySubscriptionId(subscription1.getSubscriptionId()); + + assertTrue(exists); + } + + @Test + @DisplayName("ExistsBySubscriptionId should return false when ID doesn't exist") + void testExistsBySubscriptionIdNotExists() { + UUID nonExistentSubscriptionId = UUID.randomUUID(); + + boolean exists = repository.existsBySubscriptionId(nonExistentSubscriptionId); + + assertFalse(exists); + } + + @Test + @DisplayName("ExistsByCustomerId should return true when ID exists") + void testExistsByCustomerIdExists() { + boolean exists = repository.existsByCustomerId(subscription1.getCustomerId()); + + assertTrue(exists); + } + + @Test + @DisplayName("ExistsByCustomerId should return false when ID doesn't exist") + void testExistsByCustomerIdNotExists() { + UUID nonExistentCustomerId = UUID.randomUUID(); + + boolean exists = repository.existsByCustomerId(nonExistentCustomerId); + + assertFalse(exists); + } + } + + @Nested + @DisplayName("Delete operations") + class DeleteOperations { + + @BeforeEach + void setUpSubscriptions() { + repository.save(subscription1); + repository.save(subscription2); + repository.save(subscription3); + } + + @Test + @DisplayName("Delete should remove the specified subscription") + void testDelete() { + repository.delete(subscription1); + + List subscriptions = repository.findAll(); + + assertEquals(2, subscriptions.size()); + assertFalse(subscriptions.contains(subscription1)); + assertTrue(subscriptions.contains(subscription2)); + assertTrue(subscriptions.contains(subscription3)); + } + + @Test + @DisplayName("DeleteAll should remove all subscriptions of a customer") + void testDeleteAllSubscriptionOfACustomer() { + repository.deleteByCustomerId(subscription2.getCustomerId()); + + List subscriptions = repository.findAll(); + + assertEquals(1, subscriptions.size()); + assertTrue(subscriptions.contains(subscription1)); + } + + @Test + @DisplayName("DeleteAll should remove all subscriptions") + void testDeleteAll() { + repository.deleteAll(); + + List subscriptions = repository.findAll(); + + assertTrue(subscriptions.isEmpty()); + assertEquals(0, subscriptions.size()); + } + + @Test + @DisplayName("Delete should not throw exception when customer doesn't exist") + void testDeleteNonExistentCustomer() { + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + Subscription nonExistentsubscription = Subscription.builder() + .customerId(UUID.randomUUID()) + .desiredSubscriptionDuration(DesiredSubscriptionDuration.THREE.getValue()) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .monthlyAmount(12.03) + .build(); + nonExistentsubscription.setRandomSubscriptionUUID(); + nonExistentsubscription.setDateSubscription(); + + assertDoesNotThrow(() -> repository.delete(nonExistentsubscription)); + + assertEquals(3, repository.findAll().size()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCaseTest.java new file mode 100644 index 0000000..7fcf5b8 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCaseTest.java @@ -0,0 +1,273 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.NotValidReviewException; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.*; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.PaymentMethod; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.SubscriptionNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository.SubscriptionRepository; +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.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; + +@ExtendWith(MockitoExtension.class) +public class SubscriptionUseCaseTest { + + @Mock + private SubscriptionRepository subscriptionRepository; + + @InjectMocks + private SubscriptionUseCase subscriptionUseCase; + + private UUID subscriptionId; + private UUID customerId; + private Integer desiredSubscriptionDuration; + private PaymentMethod paymentMethod; + private LocalDate desiredStartDate; + private double monthlyAmount; + private Subscription testSubscription; + private SubscriptionInfo validSubscriptionInfo; + private PaymentMethodInfo validPaymentMethodInfo; + + @BeforeEach + void setUp() { + subscriptionId = UUID.randomUUID(); + customerId = UUID.randomUUID(); + desiredSubscriptionDuration = DesiredSubscriptionDuration.THREE.getValue(); + desiredStartDate = LocalDate.of(2026, 6, 24); + paymentMethod = PaymentMethod.builder() + .paymentType(PaymentType.CB.name()) + .details("Maxime Lebreton") + .build(); + monthlyAmount = 12.99; + + testSubscription = Subscription.builder() + .subscriptionId(subscriptionId) + .customerId(customerId) + .desiredSubscriptionDuration(desiredSubscriptionDuration) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .monthlyAmount(monthlyAmount) + .build(); + + validPaymentMethodInfo = new PaymentMethodInfo(PaymentType.PAYPAL.name(),""); + validSubscriptionInfo = new SubscriptionInfo(desiredSubscriptionDuration, desiredStartDate); + } + + @Nested + @DisplayName("Register subscription tests") + class RegisterSubscriptionTests { + + @Test + @DisplayName("Should register review when valid data is provided") + void testRegisterSubscriptionithValidData() throws NotValidSubscriptionException { + when(subscriptionRepository.save(any(Subscription.class))).thenReturn(testSubscription); + + Map registeredSubscription = subscriptionUseCase.registerSubscription(validSubscriptionInfo, validPaymentMethodInfo); + + assertNotNull(registeredSubscription); + assertEquals(subscriptionId, (UUID) registeredSubscription.get("subscriptionId")); + verify(subscriptionRepository, times(1)).save(any(Subscription.class)); + } + + @Test + @DisplayName("Should throw exception when review data is not valid") + void testRegisterSubscriptionWithInvalidData() { + PaymentMethodInfo invalidPaymentMethodInfo = new PaymentMethodInfo("carte",""); + SubscriptionInfo invalidSubscriptionInfo = new SubscriptionInfo(0, desiredStartDate); + + assertThrows(NotValidSubscriptionException.class, + () -> subscriptionUseCase.registerSubscription(invalidSubscriptionInfo, invalidPaymentMethodInfo)); + + verify(subscriptionRepository, never()).save(any(Subscription.class)); + } + } + + @Nested + @DisplayName("Find subscription tests") + class FindSubscriptionTests { + + @Test + @DisplayName("Should return reviews when customer ID exists") + void testFindSubscriptionByCustomerId() { + when(subscriptionRepository.FindByCustomerId(customerId)).thenReturn(List.of(testSubscription)); + + List foundSubscriptions = subscriptionUseCase.findSubscriptionByCustomerId(customerId); + + assertFalse(foundSubscriptions.isEmpty()); + boolean allSameCustomer = foundSubscriptions.stream() + .allMatch(review -> review.getCustomerId().equals(customerId)); + assertTrue(allSameCustomer); + verify(subscriptionRepository, times(1)).FindByCustomerId(customerId); + } + + @Test + @DisplayName("Should return empty Optional when customer ID doesn't exist") + void testFindSubscriptionByCustomerIdNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + when(subscriptionRepository.FindByCustomerId(nonExistentCustomerId)).thenReturn(List.of()); + + List foundSubscriptions = subscriptionUseCase.findSubscriptionByCustomerId(nonExistentCustomerId); + + assertTrue(foundSubscriptions.isEmpty()); + verify(subscriptionRepository, times(1)).FindByCustomerId(nonExistentCustomerId); + } + + @Test + @DisplayName("Should return subscription when Subscription ID exists") + void testFindSubscriptionBySubscriptionId() { + when(subscriptionRepository.findBySubscriptionId(subscriptionId)).thenReturn(Optional.of(testSubscription)); + + Optional foundSubscription = subscriptionUseCase.findSubscriptionBySubscriptionId(subscriptionId); + + assertTrue(foundSubscription.isPresent()); + assertEquals(testSubscription.getCustomerId(), foundSubscription.get().getCustomerId()); + assertEquals(testSubscription.getMonthlyAmount(), foundSubscription.get().getMonthlyAmount()); + verify(subscriptionRepository, times(1)).findBySubscriptionId(subscriptionId); + } + + @Test + @DisplayName("Should return empty Optional when subscription ID doesn't exist") + void testFindSubscriptionBySubscriptionIdNotFound() { + UUID nonExistentSubscriptionId = UUID.randomUUID(); + when(subscriptionRepository.findBySubscriptionId(nonExistentSubscriptionId)).thenReturn(Optional.empty()); + + Optional foundSubscription = subscriptionUseCase.findSubscriptionBySubscriptionId(nonExistentSubscriptionId); + + assertTrue(foundSubscription.isEmpty()); + verify(subscriptionRepository, times(1)).findBySubscriptionId(nonExistentSubscriptionId); + } + } + + @Nested + @DisplayName("Update subscription tests") + class UpdateSubscriptionTests { + + @Test + @DisplayName("Should update subscription when valid data is provided") + void testUpdateSubscriptionWithValidData() throws SubscriptionNotFoundException, NotValidReviewException { + when(subscriptionRepository.findBySubscriptionId(subscriptionId)).thenReturn(Optional.of(testSubscription)); + + LocalDate updateDdesiredStartDate = LocalDate.of(2026, 6, 24); + Subscription updatedSubscription = Subscription.builder() + .subscriptionId(subscriptionId) + .customerId(customerId) + .desiredSubscriptionDuration(desiredSubscriptionDuration) + .paymentMethod(paymentMethod) + .desiredStartDate(desiredStartDate) + .monthlyAmount(monthlyAmount) + .build(); + + when(subscriptionRepository.save(any(Subscription.class))).thenReturn(updatedSubscription); + + SubscriptionInfo updateInfo = new SubscriptionInfo(DesiredSubscriptionDuration.SIX.getValue(), updateDdesiredStartDate); + + SubscriptionDTO result = subscriptionUseCase.updateSubscription(subscriptionId, updateInfo, validPaymentMethodInfo); + + assertNotNull(result); + assertEquals(customerId, result.getCustomerId()); + assertEquals(monthlyAmount, result.getMonthlyAmount()); + verify(subscriptionRepository, times(1)).findBySubscriptionId(subscriptionId); + verify(subscriptionRepository, times(1)).save(any(Subscription.class)); + } + + @Test + @DisplayName("Should throw exception when subscription ID doesn't exist") + void testUpdateSubscriptionNotFound() { + UUID nonExistentSubscriptionId = UUID.randomUUID(); + when(subscriptionRepository.findBySubscriptionId(nonExistentSubscriptionId)).thenReturn(Optional.empty()); + + SubscriptionInfo updateInfo = new SubscriptionInfo(desiredSubscriptionDuration, desiredStartDate); + + assertThrows(SubscriptionNotFoundException.class, + () -> subscriptionUseCase.updateSubscription(nonExistentSubscriptionId, updateInfo, validPaymentMethodInfo)); + + verify(subscriptionRepository, times(1)).findBySubscriptionId(nonExistentSubscriptionId); + verify(subscriptionRepository, never()).save(any(Subscription.class)); + } + + @Test + @DisplayName("Should throw exception when update data is not valid") + void testUpdateSubscriptionWithInvalidData() { + SubscriptionInfo invalidUpdateInfo = new SubscriptionInfo(0, desiredStartDate); + + assertThrows(NotValidSubscriptionException.class, + () -> subscriptionUseCase.updateSubscription(subscriptionId, invalidUpdateInfo, validPaymentMethodInfo)); + + verify(subscriptionRepository, never()).findBySubscriptionId(any(UUID.class)); + verify(subscriptionRepository, never()).save(any(Subscription.class)); + } + } + + @Nested + @DisplayName("Delete subscription tests") + class DeleteSubscriptionTests { + + @Test + @DisplayName("Should delete subscriptions when customer ID exists") + void testDeleteSubscriptionsOfACustomer() throws SubscriptionNotFoundException { + when(subscriptionRepository.FindByCustomerId(customerId)).thenReturn(List.of(testSubscription)); + doNothing().when(subscriptionRepository).delete(testSubscription); + + subscriptionUseCase.deleteSubscriptionsOfACustomer(customerId); + + verify(subscriptionRepository, times(1)).FindByCustomerId(customerId); + verify(subscriptionRepository, times(1)).delete(testSubscription); + } + + @Test + @DisplayName("Should throw exception when customer ID doesn't exist") + void testDeleteSubscriptionsOfACustomerNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + when(subscriptionRepository.FindByCustomerId(nonExistentCustomerId)).thenReturn(List.of()); + + assertThrows(SubscriptionNotFoundException.class, + () -> subscriptionUseCase.deleteSubscriptionsOfACustomer(nonExistentCustomerId)); + + verify(subscriptionRepository, times(1)).FindByCustomerId(nonExistentCustomerId); + verify(subscriptionRepository, never()).delete(any(Subscription.class)); + } + + @Test + @DisplayName("Should delete subscription when subscription ID exist") + void testDeleteSubscription() throws SubscriptionNotFoundException { + when(subscriptionRepository.findBySubscriptionId(subscriptionId)).thenReturn(Optional.of(testSubscription)); + doNothing().when(subscriptionRepository).delete(testSubscription); + + subscriptionUseCase.deleteSubscription(subscriptionId); + + verify(subscriptionRepository, times(1)).findBySubscriptionId(subscriptionId); + verify(subscriptionRepository, times(1)).delete(testSubscription); + } + + @Test + @DisplayName("Should throw exception when subscription ID doesn't exist") + void testDeleteSubscriptionNotFound() { + UUID nonExistentSubscriptionId = UUID.randomUUID(); + when(subscriptionRepository.findBySubscriptionId(nonExistentSubscriptionId)).thenReturn(Optional.empty()); + + assertThrows(SubscriptionNotFoundException.class, + () -> subscriptionUseCase.deleteSubscription(nonExistentSubscriptionId)); + + verify(subscriptionRepository, times(1)).findBySubscriptionId(nonExistentSubscriptionId); + verify(subscriptionRepository, never()).delete(any(Subscription.class)); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidatorTest.java new file mode 100644 index 0000000..5dc10be --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/PaymentMethodValidatorTest.java @@ -0,0 +1,51 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentMethodInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.PaymentType; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidPaymentMethodException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +public class PaymentMethodValidatorTest { + + @Test + @DisplayName("Should validate payment method with valid data") + void testValidateValidPaymentMethod() { + PaymentMethodInfo validPaymentMethod = new PaymentMethodInfo(PaymentType.CB.name(), "Maxime Lebreton"); + + assertDoesNotThrow(() -> PaymentMethodValidator.validate(validPaymentMethod)); + } + + @Nested + @DisplayName("PaymentType validation tests") + class PaymentTypeValidationTests { + + @ParameterizedTest + @EnumSource(value = PaymentType.class) + void testValidatePaymentType(PaymentType paymentType) { + String validPaymentType = paymentType.toString(); + PaymentMethodInfo validPaymentMethod = new PaymentMethodInfo(validPaymentType, "Maxime Lebreton"); + + assertDoesNotThrow(() -> PaymentMethodValidator.validate(validPaymentMethod)); + } + + @ParameterizedTest + @ValueSource(strings = {"jambon", " ", ""}) + void testNotValidatePaymentType(String invalidPaymentType) { + PaymentMethodInfo invalidPaymentMethod = new PaymentMethodInfo(invalidPaymentType, "Maxime Lebreton"); + + NotValidPaymentMethodException exception = assertThrows( + NotValidPaymentMethodException.class, + () -> PaymentMethodValidator.validate(invalidPaymentMethod) + ); + + assertEquals(PaymentMethodValidator.MODE_PAIEMENT_IS_NOT_VALID, exception.getMessage()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidatorTest.java new file mode 100644 index 0000000..e062047 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidatorTest.java @@ -0,0 +1,85 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.DesiredSubscriptionDuration; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class SubscriptionValidatorTest { + + @Test + @DisplayName("Should validate subscription with valid data") + void testValidateValidSubscription() { + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + SubscriptionInfo validSubscription = new SubscriptionInfo(DesiredSubscriptionDuration.THREE.getValue(), desiredStartDate); + + assertDoesNotThrow(() -> SubscriptionValidator.validate(validSubscription)); + } + + @Nested + @DisplayName("SubscriptionDurationDesired validation tests") + class SubscriptionDurationDesiredValidationTests { + + @ParameterizedTest + @EnumSource(value = DesiredSubscriptionDuration.class) + void testValidateSubscriptionDurationDesired(DesiredSubscriptionDuration desiredSubscriptionDuration) { + Integer validSubscriptionDurationDesired = desiredSubscriptionDuration.getValue(); + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + SubscriptionInfo validSubscription = new SubscriptionInfo(validSubscriptionDurationDesired, desiredStartDate); + + assertDoesNotThrow(() -> SubscriptionValidator.validate(validSubscription)); + } + + @Test + @DisplayName("Should throw exception when desiredSubscriptionDuration is not 3, 6 or 12") + void testNotValidateSubscriptionDurationDesired() { + Integer notValidSubscriptionDurationDesired = 1 ; + LocalDate desiredStartDate = LocalDate.of(2026, 6, 24); + SubscriptionInfo invalidSubscription = new SubscriptionInfo(notValidSubscriptionDurationDesired, desiredStartDate); + + NotValidSubscriptionException exception = assertThrows( + NotValidSubscriptionException.class, + () -> SubscriptionValidator.validate(invalidSubscription) + ); + assertEquals(SubscriptionValidator.SUBSCRIPTION_DURATION_DESIRED_IS_NOT_VALID, exception.getMessage()); + } + } + + @Nested + @DisplayName("DesiredStartDate validation tests") + class DesiredStartDateValidationTests { + + @Test + @DisplayName("Should validate when desiredStartDate is before today") + void testValidateDesiredStartDate() { + LocalDate desiredStartDate = LocalDate.now(); + SubscriptionInfo validSubscription = new SubscriptionInfo(DesiredSubscriptionDuration.THREE.getValue(), desiredStartDate); + + assertDoesNotThrow(() -> SubscriptionValidator.validate(validSubscription)); + } + + @Test + @DisplayName("Should throw exception when desiredStartDate is before today") + void testNotValidateDesiredStartDate() { + LocalDate desiredStartDate = LocalDate.of(2026, 3, 24); + SubscriptionInfo validSubscription = new SubscriptionInfo(DesiredSubscriptionDuration.THREE.getValue(), desiredStartDate); + + NotValidSubscriptionException exception = assertThrows( + NotValidSubscriptionException.class, + () -> SubscriptionValidator.validate(validSubscription) + ); + + assertEquals(SubscriptionValidator.DESIRED_START_DATE_CANNOT_BE_BEFORE_TODAY, exception.getMessage()); + } + } +}