This commit is contained in:
2025-06-10 22:50:11 +02:00
18 changed files with 916 additions and 1 deletions

5
.idea/.gitignore generated vendored
View File

@@ -1,3 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

2
.idea/misc.xml generated
View File

@@ -8,5 +8,5 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK" />
</project>

View File

@@ -0,0 +1,15 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription;
import lombok.Builder;
import lombok.Getter;
import java.util.UUID;
@Builder
@Getter
public class SubscriptionDTO {
private final UUID id;
private final UUID customerId;
private final Integer duration;
private final String paymentMethod;
private final String debutDate;
}

View File

@@ -0,0 +1,7 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription;
import java.util.UUID;
public record SubscriptionInfo(UUID customerId, Integer duration, String paymentMethod) {
}

View File

@@ -0,0 +1,31 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.converter;
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.Subscription;
public final class SubscriptionConverter {
private SubscriptionConverter() {
}
public static Subscription toDomain(SubscriptionInfo newSubscription) {
return Subscription.builder()
.customerId(newSubscription.customerId())
.duration(newSubscription.duration())
.paymentMethod(newSubscription.paymentMethod())
.build();
}
public static SubscriptionDTO toDTO(Subscription subscription) {
return SubscriptionDTO.builder()
.id(subscription.getId())
.customerId(subscription.getCustomerId())
.duration(subscription.getDuration())
.paymentMethod(subscription.getPaymentMethod())
.debutDate(subscription.getDebutDate())
.build();
}
}

View File

@@ -0,0 +1,24 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity;
import java.util.UUID;
import lombok.Builder;
import lombok.Getter;
import java.time.LocalDate;
@Builder
@Getter
public class Subscription {
private UUID id;
private UUID customerId;
private Integer duration;
private String paymentMethod;
private String debutDate;
public void setRandomUUID() {
this.id = UUID.randomUUID();
}
public void setDebutDate(String debutDate) {
this.debutDate = LocalDate.now().toString();
}
}

View File

@@ -0,0 +1,8 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception;
public class NotValidSubscriptionException extends Exception {
public NotValidSubscriptionException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,12 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception;
import java.text.MessageFormat;
import java.util.UUID;
public class SubscriptionNotFoundException extends Exception {
public static final String THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The customer with id {0} does not exist";
public SubscriptionNotFoundException(UUID uuid) {
super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid));
}
}

View File

@@ -0,0 +1,36 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
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;
import lombok.NoArgsConstructor;
public class SubscriptionRepository {
private final List<Subscription> subscriptions = new ArrayList<>();
public List<Subscription> findAll() {
return subscriptions;
}
public Subscription save(Subscription newSubscription) {
Optional<Subscription> optionalSubscriptionWithSameId = this.findByCustomerId(newSubscription.getCustomerId());
optionalSubscriptionWithSameId.ifPresentOrElse(subscriptions::remove, newSubscription::setRandomUUID);
this.subscriptions.add(newSubscription);
return newSubscription;
}
public Optional<Subscription> findByCustomerId(UUID uuid) {
return this.subscriptions.stream()
.filter(subscription -> subscription.getCustomerId().equals(uuid))
.findFirst();
}
public boolean existsById(UUID uuid) {
return this.subscriptions.stream()
.anyMatch(subscription -> subscription.getId().equals(uuid));
}
}

View File

@@ -0,0 +1,45 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase;
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.Subscription;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.SubscriptionNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository.SubscriptionRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator.SubscriptionValidator;
import java.util.Optional;
import java.util.UUID;
public class SubscriptionUseCase {
private final SubscriptionRepository subscriptionRepository;
public SubscriptionUseCase(SubscriptionRepository subscriptionRepository) {
this.subscriptionRepository = subscriptionRepository;
}
public UUID registerSubscription(SubscriptionInfo newSubscription) throws NotValidSubscriptionException {
SubscriptionValidator.validate(newSubscription);
Subscription subscriptionToRegister = SubscriptionConverter.toDomain(newSubscription);
Subscription subscriptionToRegistered = subscriptionRepository.save(subscriptionToRegister);
if (subscriptionToRegistered.getDuration() <= 0) {
throw new NotValidSubscriptionException("Duration must be positive");
}
return subscriptionToRegistered.getId();
}
public Optional<SubscriptionDTO> findSubscriptionByCustomerId(UUID customerId) {
Optional<Subscription> optionalSubscription = subscriptionRepository.findByCustomerId(customerId);
return optionalSubscription.map(SubscriptionConverter::toDTO);
}
private boolean getSubscriptionIfDoesNotExistThrowSubscriptionNotFoundException(UUID uuid)
throws SubscriptionNotFoundException {
if (subscriptionRepository.existsById(uuid)) {
throw new SubscriptionNotFoundException(uuid);
}
return subscriptionRepository.existsById(uuid);
}
}

View File

@@ -0,0 +1,38 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.validator;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.CustomerInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException;
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.exception.NotValidSubscriptionException;
public class SubscriptionValidator {
public static final String CUSTOMER_ID_CANNOT_BE_NULL = "Customer ID cannot be null";
public static final String DURATION_CANNOT_BE_NULL = "Duration is not valid";
public static final String PAYMENT_METHOD_CANNOT_BE_BLANK = "Payment Method cannot be blank";
private SubscriptionValidator() {
}
public static void validate(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException {
validateDuration(newSubscription);
validatePaymentMethod(newSubscription);
}
private static void validateDuration(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException {
if (newSubscription.duration() == null) {
throw new fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException(DURATION_CANNOT_BE_NULL);
}
}
private static void validatePaymentMethod(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException {
if (newSubscription.paymentMethod().isBlank()) {
throw new NotValidSubscriptionException(PAYMENT_METHOD_CANNOT_BE_BLANK);
}
}
}

View File

@@ -0,0 +1,129 @@
package fr.iut_fbleau.but3.dev62.mylibrary.features.subscription;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.usecase.CustomerUseCase;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo;
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.repository.SubscriptionRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase.SubscriptionUseCase;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class SubscriptionSteps {
private final SubscriptionRepository subscriptionRepository = new SubscriptionRepository();
private final SubscriptionUseCase subscriptionUseCase = new SubscriptionUseCase(subscriptionRepository);
private NotValidSubscriptionException notValidSubscriptionException;
private final CustomerRepository customerRepository = new CustomerRepository();
private UUID subscriptionRegistration;
private final Map<String, UUID> customerPhoneUUID = new HashMap<>();
@Given("the system has the following customers:")
public void theSystemHasTheFollowingCustomers(DataTable dataTable) {
int size = customerRepository.findAll().size();
if (size > 0) {
customerRepository.deleteAll();
}
List<Map<String, String>> customers = dataTable.asMaps(String.class, String.class);
for (Map<String, String> customer : customers) {
String numeroTelephone = customer.get("numeroTelephone");
Customer newCustomer = Customer.builder()
.firstName(customer.get("prenom"))
.lastName(customer.get("nom"))
.phoneNumber(numeroTelephone)
.loyaltyPoints(Integer.parseInt(customer.get("pointsFidelite")))
.build();
Customer save = customerRepository.save(newCustomer);
customerPhoneUUID.put(numeroTelephone, save.getId());
}
assertEquals(customers.size(), customerRepository.findAll().size());
}
@When("I create a new subscription with CB:")
public void iCreateANewSubscriptionWithCB(DataTable dataTable) throws NotValidSubscriptionException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
// Extract the first row of data
Map<String, String> subscriptionData = rows.getFirst();
// Create a new SubscriptionInfo object with the correct keys
SubscriptionInfo newSubscription = new SubscriptionInfo(
UUID.fromString(subscriptionData.get("customerId")),
Integer.parseInt(subscriptionData.get("duration")),
subscriptionData.get("paymentMethod")
);
// Register the subscription
subscriptionRegistration = subscriptionUseCase.registerSubscription(newSubscription);
}
@Then("a new subscription is created")
public void aNewSubscriptionIsCreated() {
}
@When("I create a new subscription with Paypal:")
public void iCreateANewSubscriptionWithPaypal(DataTable dataTable) throws NotValidSubscriptionException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
// Extract the first row of data
Map<String, String> subscriptionData = rows.getFirst();
// Create a new SubscriptionInfo object with the correct keys
SubscriptionInfo newSubscription = new SubscriptionInfo(
UUID.fromString(subscriptionData.get("customerId")),
Integer.parseInt(subscriptionData.get("duration")),
subscriptionData.get("paymentMethod")
);
// Register the subscription
subscriptionRegistration = subscriptionUseCase.registerSubscription(newSubscription);
}
@When("I try to create a new subscription with the following information:")
public void iTryToCreateANewSubscriptionWithTheFollowingInformation(DataTable dataTable) throws NotValidSubscriptionException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
Map<String, String> subscriptionData = rows.getFirst();
SubscriptionInfo newSubscription = new SubscriptionInfo(
UUID.fromString(subscriptionData.get("customerId")),
Integer.parseInt(subscriptionData.get("duration")),
subscriptionData.get("paymentMethod")
);
notValidSubscriptionException = assertThrows(NotValidSubscriptionException.class, () -> subscriptionUseCase.registerSubscription(newSubscription));
}
@Then("the subsription duration creation fails")
public void theSubsriptionDurationCreationFails() {assertNotNull(notValidSubscriptionException);}
@And("I receive an error for validation subscription message containing {string}")
public void iReceiveAnErrorForValidationSubscriptionMessageContaining(String errorMessage) {
assertEquals(errorMessage, notValidSubscriptionException.getMessage());
}
}

View File

@@ -0,0 +1,103 @@
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.customer.CustomerInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.converter.CustomerConverter;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription;
import java.util.UUID;
import java.util.concurrent.Flow;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@DisplayName("SubscriptionConverter Unit Tests")
public class SubscriptionConverterTest {
@Nested
@DisplayName("toDomain() method tests")
public class toDomainTests {
@Test
@DisplayName("Should convert SubscriptionInfo to Subscription domain object")
void shouldConvertSubscriptionInfoToDomain() {
// Given
SubscriptionInfo subscriptionInfo = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, "CB");
// When
Subscription result = SubscriptionConverter.toDomain(subscriptionInfo);
// Then
assertNotNull(result);
assertEquals(subscriptionInfo.customerId(), result.getCustomerId());
assertEquals(subscriptionInfo.duration(), result.getDuration());
assertEquals(subscriptionInfo.paymentMethod(), result.getPaymentMethod());
}
}
@Nested
@DisplayName("toDTO() method tests")
public class toDTOTests {
@Test
@DisplayName("Should convert Subscriber domain object to SubscriberDTO with all fields mapped correctly")
void shouldConvertSubscriptionToDTO() {
UUID id = UUID.randomUUID();
Subscription subscription = Subscription.builder()
.id(UUID.randomUUID())
.customerId(id)
.duration(12)
.paymentMethod("CB")
.debutDate("2025-06-08")
.build();
SubscriptionDTO result = SubscriptionConverter.toDTO(subscription);
assertNotNull(result);
assertEquals(subscription.getId(), result.getId());
assertEquals(subscription.getCustomerId(), result.getCustomerId());
assertEquals(subscription.getDuration(), result.getDuration());
assertEquals(subscription.getPaymentMethod(), result.getPaymentMethod());
assertEquals(subscription.getDebutDate(), result.getDebutDate());
}
@Test
@DisplayName("Should handle null values properly when converting between objects")
void shouldHandleNullValuesGracefully() {
Subscription subscription = Subscription.builder()
.id(UUID.randomUUID())
.customerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"))
.duration(null)
.paymentMethod("NullTest")
.debutDate("2025-06-08")
.build();
SubscriptionDTO result = SubscriptionConverter.toDTO(subscription);
assertNotNull(result);
assertNull(result.getDuration());
assertEquals("NullTest", result.getPaymentMethod());
}
@Test
@DisplayName("Should preserve empty string values during conversion")
void shouldPreserveEmptyStrings() {
SubscriptionInfo subscriptionInfo = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, "");
Subscription domainResult = SubscriptionConverter.toDomain(subscriptionInfo);
SubscriptionDTO dtoResult = SubscriptionConverter.toDTO(domainResult);
assertEquals("", dtoResult.getPaymentMethod());
}
}
}

View File

@@ -0,0 +1,49 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import static org.junit.jupiter.api.Assertions.*;
import java.util.UUID;
public class SubscriptionTest {
@Test
@DisplayName("Builder should create a valid Subscription instance")
void testSubscriptionBuilder() {
UUID id = UUID.randomUUID();
UUID customerId = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
int duration = 12;
String paymentMethod = "CB";
String debutDate = "2025-06-08";
Subscription subscription = Subscription.builder()
.id(id)
.customerId(customerId)
.duration(duration)
.paymentMethod(paymentMethod)
.debutDate(debutDate)
.build();
assertEquals(id, subscription.getId());
assertEquals(customerId, subscription.getCustomerId());
assertEquals(duration, subscription.getDuration());
assertEquals(paymentMethod, subscription.getPaymentMethod());
assertEquals(debutDate, subscription.getDebutDate());
}
@Test
@DisplayName("setRandomUUID should change the ID to a new random UUID")
void testSetRandomUUID() {
Subscription subscription = Subscription.builder().build();
UUID originalId = subscription.getId();
subscription.setRandomUUID();
assertNotNull(subscription.getId());
assertNotEquals(originalId, subscription.getId());
}
}

View File

@@ -0,0 +1,155 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription;
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 java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
public class SubscriptionRepositoryTest {
private SubscriptionRepository repository;
private Subscription Subscription1;
private Subscription Subscription2;
@BeforeEach
void setUp() {
repository = new SubscriptionRepository();
Subscription1 = Subscription.builder()
.customerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"))
.duration(12)
.paymentMethod("CB")
.build();
Subscription1.setRandomUUID();
Subscription2 = Subscription.builder()
.customerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"))
.duration(24)
.paymentMethod("Paypal")
.build();
Subscription2.setRandomUUID();
}
@Test
@DisplayName("New repository should be empty")
void testNewRepositoryIsEmpty() {
List<Subscription> subscriptions = repository.findAll();
assertTrue(subscriptions.isEmpty());
assertEquals(0, subscriptions.size());
}
@Nested
@DisplayName("Save operations")
class SaveOperations {
@Test
@DisplayName("Save should add a new subsciption")
void testSaveNewSubscription() {
Subscription savedSubscription = repository.save(Subscription1);
assertEquals(1, repository.findAll().size());
assertEquals(Subscription1.getId(), savedSubscription.getId());
assertEquals(Subscription1.getDebutDate(), savedSubscription.getDebutDate());
}
@Test
@DisplayName("Save multiple Subscriptions should add all of them")
void testSaveMultipleSubscriptions() {
repository.save(Subscription1);
repository.save(Subscription2);
List<Subscription> 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);
}
@Test
@DisplayName("FindAll should return all subscriptions")
void testFindAll() {
List<Subscription> subscriptions = repository.findAll();
assertEquals(2, subscriptions.size());
assertTrue(subscriptions.contains(Subscription1));
assertTrue(subscriptions.contains(Subscription2));
}
@Test
@DisplayName("FindById should return subscriptions with matching ID")
void testFindById() {
Optional<Subscription> foundSubscription = repository.findByCustomerId(Subscription1.getId());
assertTrue(foundSubscription.isPresent());
assertEquals(Subscription1.getId(), foundSubscription.get().getId());
assertEquals(Subscription1.getCustomerId(), foundSubscription.get().getCustomerId());
}
@Test
@DisplayName("FindById should return empty Optional when ID doesn't exist")
void testFindByIdNotFound() {
UUID nonExistentId = UUID.randomUUID();
Optional<Subscription> foundSubscription = repository.findByCustomerId(nonExistentId);
assertTrue(foundSubscription.isEmpty());
}
@Test
@DisplayName("FindByCustomerId should return customer with matching customer id")
void testFindByCustomerId() {
Optional<Subscription> foundSubscription = repository.findByCustomerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"));
assertTrue(foundSubscription.isPresent());
assertEquals(Subscription1.getId(), foundSubscription.get().getId());
assertEquals(Subscription1.getDebutDate(), foundSubscription.get().getDebutDate());
}
@Test
@DisplayName("FindByCustomerId should return empty Optional when phone number doesn't exist")
void testFindByPhoneNumberNotFound() {
Optional<Subscription> foundSubscription = repository.findByCustomerId(UUID.fromString("0000000-0000-0000-0000-000000000000"));
assertTrue(foundSubscription.isEmpty());
}
@Test
@DisplayName("ExistsById should return true when ID exists")
void testExistsByIdExists() {
boolean exists = repository.existsById(Subscription1.getId());
assertTrue(exists);
}
@Test
@DisplayName("ExistsById should return false when ID doesn't exist")
void testExistsByIdNotExists() {
UUID nonExistentId = UUID.randomUUID();
boolean exists = repository.existsById(nonExistentId);
assertFalse(exists);
}
}
}

View File

@@ -0,0 +1,109 @@
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase;
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.Subscription;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.SubscriptionNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository.SubscriptionRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.usecase.SubscriptionUseCase;
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.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class SubscribeUseCaseTest {
@Mock
private SubscriptionRepository subscriptionRepository;
@InjectMocks
private SubscriptionUseCase subscriptionUseCase;
private UUID subscriptionId;
private Subscription testSubscription;
private SubscriptionInfo validSubscriptionInfo;
@BeforeEach
void setUp() {
subscriptionId = UUID.randomUUID();
testSubscription = Subscription.builder()
.id(subscriptionId)
.customerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"))
.duration(12)
.paymentMethod("CB")
.build();
validSubscriptionInfo = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, "CB");
}
@Nested
@DisplayName("Register subscription tests")
class RegisterSubscriptionTests {
@Test
@DisplayName("Should register subscription when valid data is provided")
void testRegisterSubscriptionWithValidData() throws NotValidSubscriptionException {
when(subscriptionRepository.save(any(Subscription.class))).thenReturn(testSubscription);
UUID registeredId = subscriptionUseCase.registerSubscription(validSubscriptionInfo);
assertNotNull(registeredId);
assertEquals(subscriptionId, registeredId);
verify(subscriptionRepository, times(1)).save(any(Subscription.class));
}
@Test
@DisplayName("Should throw exception when subscription data is not valid")
void testRegisterSubscriptionWithInvalidData() {
SubscriptionInfo invalidSubscriptionInfo = new SubscriptionInfo(null, null, "");
assertThrows(NotValidSubscriptionException.class,
() -> subscriptionUseCase.registerSubscription(invalidSubscriptionInfo));
verify(subscriptionRepository, never()).save(any(Subscription.class));
}
}
@Nested
@DisplayName("Find subscription tests")
class FindSubscriptionTests {
@Test
@DisplayName("Should return subscription when phone number exists")
void testFindSubscriptionByCustomerId() {
when(subscriptionRepository.findByCustomerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"))).thenReturn(Optional.of(testSubscription));
Optional<SubscriptionDTO> foundSubscription = subscriptionUseCase.findSubscriptionByCustomerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"));
assertTrue(foundSubscription.isPresent());
assertEquals(testSubscription.getId(), foundSubscription.get().getId());
assertEquals(testSubscription.getDebutDate(), foundSubscription.get().getDebutDate());
verify(subscriptionRepository, times(1)).findByCustomerId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"));
}
@Test
@DisplayName("Should return empty Optional when phone number doesn't exist")
void testFindSubscriptionByPhoneNumberNotFound() {
when(subscriptionRepository.findByCustomerId(UUID.fromString("0000000-0000-0000-0000-000000000000"))).thenReturn(Optional.empty());
Optional<SubscriptionDTO> foundSubscription = subscriptionUseCase.findSubscriptionByCustomerId(UUID.fromString("0000000-0000-0000-0000-000000000000"));
assertTrue(foundSubscription.isEmpty());
verify(subscriptionRepository, times(1)).findByCustomerId(UUID.fromString("0000000-0000-0000-0000-000000000000"));
}
}
}

View File

@@ -0,0 +1,121 @@
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 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.ValueSource;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
public class SubscriptionValidatorTest {
@Test
@DisplayName("Should validate subscription with valid data")
void testValidateValidSubscription() {
SubscriptionInfo validSubscription = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, "CB");
assertDoesNotThrow(() -> SubscriptionValidator.validate(validSubscription));
}
@Nested
@DisplayName("customer id validation tests")
class CustomerIdValidationTests {
@Test
@DisplayName("Should throw exception when customer id is blank")
void testValidateBlankCustomerId() {
SubscriptionInfo subscriptionWithBlankCustomerId = new SubscriptionInfo(null, 12, "CB");
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithBlankCustomerId)
);
assertEquals(SubscriptionValidator.CUSTOMER_ID_CANNOT_BE_NULL,
exception.getMessage());
}
/**@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when customer id contains only whitespace")
void testValidateWhitespaceCustomerId(String whitespace) {
SubscriptionInfo subscriptionWithWhitespaceFirstName = new SubscriptionInfo(whitespace, 12, "CB");
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithWhitespaceCustomerId)
);
assertEquals(SubscriptionValidator.CUSTOMER_ID_CANNOT_BE_BLANK, exception.getMessage());
}**/
}
@Nested
@DisplayName("Duration validation tests")
class DurationValidationTests {
@Test
@DisplayName("Should throw exception when duration is blank")
void testValidateBlankDuration() {
SubscriptionInfo subscriptionWithBlankDuration = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), null, "CB");
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithBlankDuration)
);
assertEquals(SubscriptionValidator.DURATION_CANNOT_BE_NULL, exception.getMessage());
}
/**@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when last name contains only whitespace")
void testValidateWhitespaceDuration(String whitespace) {
SubscriptionInfo subscriptionWithWhitespaceDuration = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), whitespace, "CB");
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithWhitespaceDuration)
);
assertEquals(SubscriptionValidator.DURATION_CANNOT_BE_BLANK, exception.getMessage());
}**/
}
@Nested
@DisplayName("Payment method validation tests")
class PaymentMethodValidationTests {
@Test
@DisplayName("Should throw exception when payment method is blank")
void testValidateBlankPaymentMethod() {
SubscriptionInfo subscriptionWithBlankPaymentMethod = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, "");
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithBlankPaymentMethod)
);
assertEquals(SubscriptionValidator.PAYMENT_METHOD_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when payment method contains only whitespace")
void testValidateWhitespacePhoneNumber(String whitespace) {
SubscriptionInfo subscriptionWithWhitespacePaymentMethod = new SubscriptionInfo(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), 12, whitespace);
NotValidSubscriptionException exception = assertThrows(
NotValidSubscriptionException.class,
() -> SubscriptionValidator.validate(subscriptionWithWhitespacePaymentMethod)
);
assertEquals(SubscriptionValidator.PAYMENT_METHOD_CANNOT_BE_BLANK, exception.getMessage());
}
}
}

View File

@@ -0,0 +1,28 @@
# language: en
Feature: Manage customer subscription
Background:
Given the system has the following customers:
| customerId | firstName | lastName | phoneNumer | pointsFidelite |
| 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: Create a new subscription
When I create a new subscription with CB:
| customerId | duration | paymentMethod |
| 11111111-1111-1111-1111-111111111111 | 12 | CB |
Then a new subscription is created
Scenario: Create a new subscription
When I create a new subscription with Paypal:
| customerId | duration | paymentMethod |
| 22222222-2222-2222-2222-222222222222 | 24 | Paypal |
Then a new subscription is created
Scenario: Attempt to create a subscription with invalid duration:
When I try to create a new subscription with the following information:
| customerId | duration | paymentMethod |
| 33333333-3333-3333-3333-333333333333 | 0 | CB |
Then the subsription duration creation fails
And I receive an error for validation subscription message containing "Duration must be positive"