diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..7bc07ec
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Environment-dependent path to Maven home directory
+/mavenHomeManager.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..2ee03b5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java
new file mode 100644
index 0000000..b85234b
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookDTO.java
@@ -0,0 +1,24 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+@AllArgsConstructor
+public class BookDTO {
+ private final String isbn;
+ private final String title;
+ private final String author;
+ private final String publisher;
+ private final LocalDate publicationDate;
+ private final double price;
+ private final int stock;
+ private final List categories;
+ private final String description;
+ private final String language;
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java
new file mode 100644
index 0000000..062a2f5
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java
@@ -0,0 +1,17 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public record BookInfo(
+ String isbn,
+ String title,
+ String author,
+ String publisher,
+ LocalDate publicationDate,
+ double price,
+ int stock,
+ List categories,
+ String description,
+ String language
+) {}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java
new file mode 100644
index 0000000..c86eff7
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/Category.java
@@ -0,0 +1,24 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book;
+
+public enum Category {
+ FICTION,
+ NON_FICTION,
+ SCIENCE_FICTION,
+ FANTASY,
+ MYSTERY,
+ THRILLER,
+ ROMANCE,
+ BIOGRAPHY,
+ HISTORY,
+ POETRY,
+ CHILDREN,
+ YOUNG_ADULT,
+ SCIENCE,
+ PHILOSOPHY,
+ SELF_HELP,
+ TRAVEL,
+ COOKING,
+ ART,
+ RELIGION,
+ REFERENCE
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java
new file mode 100644
index 0000000..5c09b6a
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverter.java
@@ -0,0 +1,40 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.converter;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+
+public final class BookConverter {
+
+ private BookConverter() {}
+
+ public static Book toDomain(BookInfo info) {
+ return Book.builder()
+ .isbn(info.isbn())
+ .title(info.title())
+ .author(info.author())
+ .publisher(info.publisher())
+ .publicationDate(info.publicationDate())
+ .price(info.price())
+ .stock(info.stock())
+ .categories(info.categories())
+ .description(info.description())
+ .language(info.language())
+ .build();
+ }
+
+ public static BookDTO toDTO(Book book) {
+ return BookDTO.builder()
+ .isbn(book.getIsbn())
+ .title(book.getTitle())
+ .author(book.getAuthor())
+ .publisher(book.getPublisher())
+ .publicationDate(book.getPublicationDate())
+ .price(book.getPrice())
+ .stock(book.getStock())
+ .categories(book.getCategories())
+ .description(book.getDescription())
+ .language(book.getLanguage())
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java
new file mode 100644
index 0000000..7a38c73
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java
@@ -0,0 +1,33 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
+import java.time.LocalDate;
+import java.util.List;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class Book {
+ private String isbn;
+ private String title;
+ private String author;
+ private String publisher;
+ private LocalDate publicationDate;
+ private double price;
+ private int stock;
+ private List categories;
+ private String description;
+ private String language;
+
+ public void addStock(int quantityToAdd) {
+ this.stock += quantityToAdd;
+ }
+
+ public void removeStock(int quantityToRemove) {
+ if (quantityToRemove > this.stock) {
+ throw new IllegalArgumentException("Pas assez de stock pour retirer : " + quantityToRemove);
+ }
+ this.stock -= quantityToRemove;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java
new file mode 100644
index 0000000..9f278f0
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java
@@ -0,0 +1,13 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
+
+public class BookNotFoundException extends RuntimeException {
+ public static final String THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE = "The book with isbn %s does not exist";
+
+ public BookNotFoundException(String message) {
+ super(message);
+ }
+
+ public static BookNotFoundException forIsbn(String isbn) {
+ return new BookNotFoundException(String.format(THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE, isbn));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java
new file mode 100644
index 0000000..bec0172
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
+
+public class NotValidBookException extends RuntimeException {
+ public NotValidBookException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java
new file mode 100644
index 0000000..37b1fdb
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java
@@ -0,0 +1,78 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.repository;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
+import java.util.*;
+import java.util.stream.Collectors;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+public final class BookRepository {
+ private final List books = new ArrayList<>();
+
+ public List findAll() {
+ return books;
+ }
+
+ public void deleteAll() {
+ books.clear();
+ }
+
+ public Book save(Book newBook) {
+ Optional optionalBookWithSameIsbn = this.findByIsbn(newBook.getIsbn());
+ optionalBookWithSameIsbn.ifPresent(books::remove);
+ books.add(newBook);
+ return newBook;
+ }
+
+ public Optional findByIsbn(String isbn) {
+ return books.stream()
+ .filter(book -> Objects.equals(book.getIsbn(), isbn))
+ .findFirst();
+ }
+
+ public boolean existsByIsbn(String isbn) {
+ return books.stream()
+ .anyMatch(book -> Objects.equals(book.getIsbn(), isbn));
+ }
+
+ public void delete(Book book) {
+ books.remove(book);
+ }
+
+ public List findByTitleContaining(String titlePart) {
+ return books.stream()
+ .filter(book -> book.getTitle() != null && book.getTitle().toLowerCase().contains(titlePart.toLowerCase()))
+ .collect(Collectors.toList());
+ }
+
+ public List findByAuthor(String author) {
+ return books.stream()
+ .filter(book -> book.getAuthor() != null && book.getAuthor().equalsIgnoreCase(author))
+ .collect(Collectors.toList());
+ }
+
+ public List findByPublisher(String publisher) {
+ return books.stream()
+ .filter(book -> book.getPublisher() != null && book.getPublisher().equalsIgnoreCase(publisher))
+ .collect(Collectors.toList());
+ }
+
+ public List findByCategory(Category category) {
+ return books.stream()
+ .filter(book -> book.getCategories() != null && book.getCategories().contains(category))
+ .collect(Collectors.toList());
+ }
+
+ public List findPublishedAfter(java.time.LocalDate date) {
+ return books.stream()
+ .filter(book -> book.getPublicationDate() != null && book.getPublicationDate().isAfter(date))
+ .collect(Collectors.toList());
+ }
+
+ public List findByPriceRange(double min, double max) {
+ return books.stream()
+ .filter(book -> book.getPrice() >= min && book.getPrice() <= max)
+ .collect(Collectors.toList());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java
new file mode 100644
index 0000000..b3decb6
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java
@@ -0,0 +1,163 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.*;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.converter.BookConverter;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.validator.BookValidator;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public final class BookUseCase {
+
+ private final BookRepository repository;
+
+ public BookUseCase(BookRepository repository) {
+ this.repository = repository;
+ }
+
+ public String registerBook(BookInfo info) throws NotValidBookException {
+ BookValidator.validate(info);
+
+ if (repository.existsByIsbn(info.isbn())) {
+ throw new NotValidBookException("A book with this ISBN already exists");
+ }
+
+ Book book = BookConverter.toDomain(info);
+ Book stored = repository.save(book);
+ return stored.getIsbn();
+ }
+
+ public BookDTO updateBook(String isbn, BookInfo data) throws BookNotFoundException, NotValidBookException {
+ BookValidator.validate(data);
+ ensureBookExists(isbn);
+
+ Book updated = Book.builder()
+ .isbn(isbn)
+ .title(data.title())
+ .author(data.author())
+ .publisher(data.publisher())
+ .publicationDate(data.publicationDate())
+ .price(data.price())
+ .stock(data.stock())
+ .categories(data.categories())
+ .description(data.description())
+ .language(data.language())
+ .build();
+
+ return BookConverter.toDTO(repository.save(updated));
+ }
+
+ public int addStock(String isbn, int quantity) throws BookNotFoundException {
+ Book book = ensureBookExists(isbn);
+ book.addStock(quantity);
+ repository.save(book);
+ return book.getStock();
+ }
+
+ public int removeStock(String isbn, int quantity) throws BookNotFoundException {
+ Book book = ensureBookExists(isbn);
+ book.removeStock(quantity);
+ repository.save(book);
+ return book.getStock();
+ }
+
+ public void deleteBook(String isbn) throws BookNotFoundException {
+ Book target = ensureBookExists(isbn);
+ repository.delete(target);
+ }
+
+ public BookDTO findBookByIsbn(String isbn) throws BookNotFoundException {
+ return repository.findByIsbn(isbn)
+ .map(BookConverter::toDTO)
+ .orElseThrow(() -> new BookNotFoundException(isbn));
+ }
+
+ public List findBooksByAuthor(String author) {
+ return repository.findByAuthor(author)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public List findBooksByCategory(Category category) {
+ return repository.findByCategory(category)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public List findBooksByTitleContaining(String title) {
+ return repository.findByTitleContaining(title)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public List findBooksByPublisher(String publisher) {
+ return repository.findByPublisher(publisher)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public List findBooksPublishedAfter(LocalDate date) {
+ return repository.findPublishedAfter(date)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public List findBooksByPriceRange(double min, double max) {
+ return repository.findByPriceRange(min, max)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+ }
+
+ public Map findBooksPageSorted(int page, int size, String sortBy) {
+ List books = repository.findAll();
+
+ books.sort(Comparator.comparing(book -> {
+ switch (sortBy.toLowerCase()) {
+ case "title":
+ case "titre":
+ return book.getTitle() == null ? "" : book.getTitle().toLowerCase();
+ case "author":
+ case "auteur":
+ return book.getAuthor() == null ? "" : book.getAuthor().toLowerCase();
+ case "publisher":
+ case "editeur":
+ return book.getPublisher() == null ? "" : book.getPublisher().toLowerCase();
+ default:
+ return book.getTitle() == null ? "" : book.getTitle().toLowerCase();
+ }
+ }));
+
+ int total = books.size();
+ int pages = (int) Math.ceil((double) total / size);
+ int start = Math.min(page * size, total);
+ int end = Math.min(start + size, total);
+
+ List content = books.subList(start, end)
+ .stream()
+ .map(BookConverter::toDTO)
+ .collect(Collectors.toList());
+
+ Map result = new HashMap<>();
+ result.put("content", content);
+ result.put("totalElements", total);
+ result.put("totalPages", pages);
+
+ return result;
+ }
+
+ private Book ensureBookExists(String isbn) throws BookNotFoundException {
+ return repository.findByIsbn(isbn)
+ .orElseThrow(() -> new BookNotFoundException(isbn));
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java
new file mode 100644
index 0000000..ff53167
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java
@@ -0,0 +1,65 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.validator;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
+
+public final class BookValidator {
+
+ public static final String ERROR_ISBN_NULL = "ISBN cannot be null";
+ public static final String ERROR_INVALID_ISBN = "ISBN is not valid";
+ public static final String ERROR_TITLE_EMPTY = "Title cannot be empty";
+ public static final String ERROR_AUTHOR_EMPTY = "Author cannot be empty";
+ public static final String ERROR_NEGATIVE_PRICE = "Price must be positive";
+ public static final String ERROR_NEGATIVE_STOCK = "Stock cannot be negative";
+ public static final String ERROR_PUBLISHER_EMPTY = "Publisher cannot be empty";
+ public static final String ERROR_PUBLICATION_DATE_NULL = "Publication date cannot be null";
+ public static final String ERROR_CATEGORIES_EMPTY = "Categories list cannot be empty";
+ public static final String ERROR_DESCRIPTION_EMPTY = "Description cannot be empty";
+ public static final String ERROR_LANGUAGE_EMPTY = "Language cannot be empty";
+
+ private BookValidator() {
+ // Prevent instantiation
+ }
+
+ public static void validate(BookInfo info) throws NotValidBookException {
+ checkPrice(info);
+ checkIsbn(info);
+ checkTitle(info);
+ checkAuthor(info);
+ checkStock(info);
+ }
+
+ private static void checkIsbn(BookInfo info) throws NotValidBookException {
+ String isbn = info.isbn();
+ if (isbn == null) {
+ throw new NotValidBookException(ERROR_ISBN_NULL);
+ }
+ if (!isbn.matches("\\d{13}")) {
+ throw new NotValidBookException(ERROR_INVALID_ISBN);
+ }
+ }
+
+ private static void checkTitle(BookInfo info) throws NotValidBookException {
+ if (info.title() == null || info.title().isBlank()) {
+ throw new NotValidBookException(ERROR_TITLE_EMPTY);
+ }
+ }
+
+ private static void checkAuthor(BookInfo info) throws NotValidBookException {
+ if (info.author() == null || info.author().isBlank()) {
+ throw new NotValidBookException(ERROR_AUTHOR_EMPTY);
+ }
+ }
+
+ private static void checkPrice(BookInfo info) throws NotValidBookException {
+ if (info.price() < 0) {
+ throw new NotValidBookException(ERROR_NEGATIVE_PRICE);
+ }
+ }
+
+ private static void checkStock(BookInfo info) throws NotValidBookException {
+ if (info.stock() < 0) {
+ throw new NotValidBookException(ERROR_NEGATIVE_STOCK);
+ }
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverter.java
index e420020..c5e1202 100644
--- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverter.java
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverter.java
@@ -3,28 +3,30 @@ package fr.iut_fbleau.but3.dev62.mylibrary.customer.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.entity.Customer;
+import java.util.UUID;
public final class CustomerConverter {
- private CustomerConverter(){
-
+ private CustomerConverter() {
+ // util class
}
public static Customer toDomain(CustomerInfo newCustomer) {
return Customer.builder()
- .firstName(newCustomer.firstName())
- .lastName(newCustomer.lastName())
- .phoneNumber(newCustomer.phoneNumber())
- .loyaltyPoints(0)
- .build();
+ .id(UUID.randomUUID()) // ← génération automatique
+ .firstName(newCustomer.firstName())
+ .lastName(newCustomer.lastName())
+ .phoneNumber(newCustomer.phoneNumber())
+ .loyaltyPoints(0)
+ .build();
}
public static CustomerDTO toDTO(Customer customer) {
return CustomerDTO.builder()
- .id(customer.getId())
- .firstName(customer.getFirstName())
- .lastName(customer.getLastName())
- .phoneNumber(customer.getPhoneNumber())
- .loyaltyPoints(customer.getLoyaltyPoints())
- .build();
+ .id(customer.getId())
+ .firstName(customer.getFirstName())
+ .lastName(customer.getLastName())
+ .phoneNumber(customer.getPhoneNumber())
+ .loyaltyPoints(customer.getLoyaltyPoints())
+ .build();
}
}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCase.java
index 3241c30..95b793a 100644
--- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCase.java
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCase.java
@@ -14,68 +14,58 @@ import java.util.UUID;
public final class CustomerUseCase {
- private final CustomerRepository customerRepository;
+ private final CustomerRepository repo;
- public CustomerUseCase(CustomerRepository customerRepository) {
- this.customerRepository = customerRepository;
+ public CustomerUseCase(CustomerRepository repo) {
+ this.repo = repo;
}
- public UUID registerCustomer(CustomerInfo newCustomer) throws NotValidCustomerException {
- CustomerValidator.validate(newCustomer);
- Customer customerToRegister = CustomerConverter.toDomain(newCustomer);
- Customer customerToRegistered = customerRepository.save(customerToRegister);
- return customerToRegistered.getId();
+ public Optional getByPhone(String phone) {
+ return repo.findByPhoneNumber(phone).map(CustomerConverter::toDTO);
}
- public Optional findCustomerByPhoneNumber(String phoneNumber) {
- Optional optionalCustomer = customerRepository.findByPhoneNumber(phoneNumber);
- return optionalCustomer.map(CustomerConverter::toDTO);
+ public UUID create(CustomerInfo input) throws NotValidCustomerException {
+ CustomerValidator.validate(input);
+ Customer newCustomer = CustomerConverter.toDomain(input);
+ Customer saved = repo.save(newCustomer);
+ return saved.getId();
}
- public CustomerDTO updateCustomer(UUID uuid, CustomerInfo customerInfo)
- throws CustomerNotFoundException, NotValidCustomerException {
- CustomerValidator.validate(customerInfo);
- Customer customerByUUID = getCustomerIfDoesNotExistThrowCustomerNotFoundException(
- uuid);
- Customer customer = Customer.builder()
- .id(uuid)
- .firstName(customerInfo.firstName())
- .lastName(customerInfo.lastName())
- .phoneNumber(customerInfo.phoneNumber())
- .loyaltyPoints(customerByUUID.getLoyaltyPoints())
- .build();
- Customer updatedCustomer = customerRepository.save(customer);
- return CustomerConverter.toDTO(updatedCustomer);
+ public int increasePoints(UUID id, int points) throws CustomerNotFoundException {
+ Customer c = resolveOrFail(id);
+ c.addLoyaltyPoints(points);
+ repo.save(c);
+ return c.getLoyaltyPoints();
}
- public void deleteCustomer(UUID uuid) throws CustomerNotFoundException {
- Customer customerToDelete = getCustomerIfDoesNotExistThrowCustomerNotFoundException(uuid);
- this.customerRepository.delete(customerToDelete);
+ public int decreasePoints(UUID id, int points)
+ throws CustomerNotFoundException, IllegalCustomerPointException {
+ Customer c = resolveOrFail(id);
+ c.removeLoyaltyPoints(points);
+ repo.save(c);
+ return c.getLoyaltyPoints();
}
- public int addLoyaltyPoints(UUID uuid, int loyaltyPointToAdd) throws CustomerNotFoundException {
- Customer customerToAddLoyaltyPoints = getCustomerIfDoesNotExistThrowCustomerNotFoundException(
- uuid);
- customerToAddLoyaltyPoints.addLoyaltyPoints(loyaltyPointToAdd);
- customerRepository.save(customerToAddLoyaltyPoints);
- return customerToAddLoyaltyPoints.getLoyaltyPoints();
+ public void remove(UUID id) throws CustomerNotFoundException {
+ Customer c = resolveOrFail(id);
+ repo.delete(c);
}
- public int subtractLoyaltyPoints(UUID uuid, int loyaltyPointToRemove)
- throws CustomerNotFoundException, IllegalCustomerPointException {
- Customer customerToSubtractLoyaltyPoints = getCustomerIfDoesNotExistThrowCustomerNotFoundException(
- uuid);
- customerToSubtractLoyaltyPoints.removeLoyaltyPoints(loyaltyPointToRemove);
- customerRepository.save(customerToSubtractLoyaltyPoints);
- return customerToSubtractLoyaltyPoints.getLoyaltyPoints();
+ public CustomerDTO modify(UUID id, CustomerInfo input)
+ throws CustomerNotFoundException, NotValidCustomerException {
+ CustomerValidator.validate(input);
+ Customer existing = resolveOrFail(id);
+ Customer updated = Customer.builder()
+ .id(id)
+ .firstName(input.firstName())
+ .lastName(input.lastName())
+ .phoneNumber(input.phoneNumber())
+ .loyaltyPoints(existing.getLoyaltyPoints())
+ .build();
+ return CustomerConverter.toDTO(repo.save(updated));
}
- private Customer getCustomerIfDoesNotExistThrowCustomerNotFoundException(UUID uuid)
- throws CustomerNotFoundException {
- Optional optionalCustomerById = customerRepository.findById(uuid);
- if (optionalCustomerById.isEmpty()) {
- throw new CustomerNotFoundException(uuid);
- }
- return optionalCustomerById.get();
+ private Customer resolveOrFail(UUID id) throws CustomerNotFoundException {
+ return repo.findById(id).orElseThrow(() -> new CustomerNotFoundException(id));
}
}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidator.java
index d9bd9c1..b15320b 100644
--- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidator.java
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidator.java
@@ -5,40 +5,37 @@ import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerExc
public final class CustomerValidator {
- public static final String PHONE_NUMBER_IS_NOT_VALID = "Phone number is not valid";
- public static final String LAST_NAME_CANNOT_BE_BLANK = "Last name cannot be blank";
- public static final String FIRST_NAME_CANNOT_BE_BLANK = "First name cannot be blank";
- public static final String PHONE_NUMBER_REGEX = "0([67])\\d{8}";
+ public static final String ERROR_PHONE_INVALID = "Phone number is not valid";
+ public static final String ERROR_LASTNAME_EMPTY = "Last name cannot be blank";
+ public static final String ERROR_FIRSTNAME_EMPTY = "First name cannot be blank";
+ public static final String PHONE_PATTERN = "0([67])\\d{8}";
- private CustomerValidator() {
+ private CustomerValidator() {}
+ public static void check(CustomerInfo input) throws NotValidCustomerException {
+ ensureFirstName(input);
+ ensureLastName(input);
+ ensurePhone(input);
}
- public static void validate(CustomerInfo newCustomer) throws NotValidCustomerException {
- validateFirstName(newCustomer);
- validateLastName(newCustomer);
- validatePhoneNumber(newCustomer);
- }
-
- private static void validatePhoneNumber(CustomerInfo newCustomer)
- throws NotValidCustomerException {
- if (newCustomer.phoneNumber().isBlank()) {
+ private static void ensurePhone(CustomerInfo input) throws NotValidCustomerException {
+ if (input.phoneNumber().isBlank()) {
throw new NotValidCustomerException("Phone number cannot be blank");
}
- if (!newCustomer.phoneNumber().matches(PHONE_NUMBER_REGEX)) {
- throw new NotValidCustomerException(PHONE_NUMBER_IS_NOT_VALID);
+ if (!input.phoneNumber().matches(PHONE_PATTERN)) {
+ throw new NotValidCustomerException(ERROR_PHONE_INVALID);
}
}
- private static void validateLastName(CustomerInfo newCustomer) throws NotValidCustomerException {
- if (newCustomer.lastName().isBlank()) {
- throw new NotValidCustomerException(LAST_NAME_CANNOT_BE_BLANK);
+ private static void ensureLastName(CustomerInfo input) throws NotValidCustomerException {
+ if (input.lastName().isBlank()) {
+ throw new NotValidCustomerException(ERROR_LASTNAME_EMPTY);
}
}
- private static void validateFirstName(CustomerInfo newCustomer) throws NotValidCustomerException {
- if (newCustomer.firstName().isBlank()) {
- throw new NotValidCustomerException(FIRST_NAME_CANNOT_BE_BLANK);
+ private static void ensureFirstName(CustomerInfo input) throws NotValidCustomerException {
+ if (input.firstName().isBlank()) {
+ throw new NotValidCustomerException(ERROR_FIRSTNAME_EMPTY);
}
}
}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/AddressDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/AddressDTO.java
new file mode 100644
index 0000000..53243f9
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/AddressDTO.java
@@ -0,0 +1,14 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class AddressDTO {
+ private final String street;
+ private final String city;
+ private final String postalCode;
+ private final String country;
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java
new file mode 100644
index 0000000..690fd04
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java
@@ -0,0 +1,19 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order;
+
+import lombok.Builder;
+import lombok.Getter;
+import java.util.List;
+import java.util.UUID;
+
+@Builder
+@Getter
+public class OrderDTO {
+ private final UUID id;
+ private final UUID customerId;
+ private final String paymentMethod;
+ private final List orderLines;
+ private final AddressDTO shippingAddress;
+ private final double totalPrice;
+ private final double totalPriceToPay;
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java
new file mode 100644
index 0000000..406cc00
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java
@@ -0,0 +1,16 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+public class OrderInfo {
+ private String customerId;
+ private String paymentMethod;
+ private List orderLines;
+ private AddressDTO address;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineDTO.java
new file mode 100644
index 0000000..18735d9
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineDTO.java
@@ -0,0 +1,12 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class OrderLineDTO {
+ private final String bookId;
+ private final int quantity;
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMethod.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMethod.java
new file mode 100644
index 0000000..a4b3ed4
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMethod.java
@@ -0,0 +1,6 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order;
+
+public enum PaymentMethod {
+ CREDIT_CARD,
+ LOYALTY_POINTS;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/converter/OrderConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/converter/OrderConverter.java
new file mode 100644
index 0000000..99fbda8
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/converter/OrderConverter.java
@@ -0,0 +1,97 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.converter;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.*;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Address;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.OrderLine;
+
+import java.util.UUID;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+public final class OrderConverter {
+
+ private OrderConverter() {
+ throw new AssertionError("This utility class should not be instantiated");
+ }
+
+ public static Order toDomain(OrderInfo info) {
+ if (info == null) return null;
+
+ return Order.builder()
+ .customerId(Optional.ofNullable(info.getCustomerId())
+ .map(UUID::fromString)
+ .orElse(null))
+ .paymentMethod(Optional.ofNullable(info.getPaymentMethod())
+ .map(PaymentMethod::valueOf)
+ .orElse(null))
+ .orderLines(convertOrderLines(info.getOrderLines()))
+ .shippingAddress(convertAddress(info.getAddress()))
+ .totalPrice(0.0)
+ .build();
+ }
+
+ public static OrderDTO toDTO(Order order) {
+ if (order == null) return null;
+
+ return OrderDTO.builder()
+ .id(order.getId())
+ .customerId(order.getCustomerId())
+ .paymentMethod(Optional.ofNullable(order.getPaymentMethod())
+ .map(PaymentMethod::name)
+ .orElse(null))
+ .orderLines(convertOrderLinesToDTO(order.getOrderLines()))
+ .shippingAddress(convertAddressToDTO(order.getShippingAddress()))
+ .totalPrice(order.getTotalPrice())
+ .totalPriceToPay(order.getTotalPriceToPay())
+ .build();
+ }
+
+ private static Address convertAddress(AddressDTO addressDTO) {
+ return Optional.ofNullable(addressDTO)
+ .map(addr -> Address.builder()
+ .street(addr.getStreet())
+ .city(addr.getCity())
+ .postalCode(addr.getPostalCode())
+ .country(addr.getCountry())
+ .build())
+ .orElse(null);
+ }
+
+ private static AddressDTO convertAddressToDTO(Address address) {
+ return Optional.ofNullable(address)
+ .map(addr -> AddressDTO.builder()
+ .street(addr.getStreet())
+ .city(addr.getCity())
+ .postalCode(addr.getPostalCode())
+ .country(addr.getCountry())
+ .build())
+ .orElse(null);
+ }
+
+ private static List convertOrderLinesToDTO(List orderLines) {
+ return Optional.ofNullable(orderLines)
+ .map(lines -> lines.stream()
+ .filter(Objects::nonNull)
+ .map(line -> OrderLineDTO.builder()
+ .bookId(line.getBookId())
+ .quantity(line.getQuantity())
+ .build())
+ .toList())
+ .orElse(null);
+ }
+
+ private static List convertOrderLines(List orderLines) {
+ return Optional.ofNullable(orderLines)
+ .map(lines -> lines.stream()
+ .filter(Objects::nonNull)
+ .map(line -> OrderLine.builder()
+ .bookId(line.getBookId())
+ .quantity(line.getQuantity())
+ .build())
+ .toList())
+ .orElse(new ArrayList<>());
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Address.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Address.java
new file mode 100644
index 0000000..c15d2d9
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Address.java
@@ -0,0 +1,14 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.AllArgsConstructor;
+
+@Getter
+@Builder
+public class Address {
+ private final String street;
+ private final String city;
+ private final String postalCode;
+ private final String country;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Order.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Order.java
new file mode 100644
index 0000000..24974c9
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/Order.java
@@ -0,0 +1,19 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
+import lombok.Builder;
+import lombok.Getter;
+import java.util.List;
+import java.util.UUID;
+
+@Getter
+@Builder
+public class Order {
+ private final UUID id;
+ private final UUID customerId;
+ private final PaymentMethod paymentMethod;
+ private final List orderLines;
+ private final Address shippingAddress;
+ private final double totalPrice;
+ private final double totalPriceToPay;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/OrderLine.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/OrderLine.java
new file mode 100644
index 0000000..b191b9f
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/entity/OrderLine.java
@@ -0,0 +1,12 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+@Getter
+@Builder
+public class OrderLine {
+ private final String bookId;
+ private final int quantity;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/IllegalOrderPointException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/IllegalOrderPointException.java
new file mode 100644
index 0000000..fe8d023
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/IllegalOrderPointException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+public class IllegalOrderPointException extends RuntimeException {
+ public IllegalOrderPointException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/InvalidPaymentMethodException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/InvalidPaymentMethodException.java
new file mode 100644
index 0000000..03adfc3
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/InvalidPaymentMethodException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+public class InvalidPaymentMethodException extends RuntimeException {
+ public InvalidPaymentMethodException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/NotValidOrderException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/NotValidOrderException.java
new file mode 100644
index 0000000..87db9f4
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/NotValidOrderException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+public class NotValidOrderException extends RuntimeException {
+ public NotValidOrderException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderNotFoundException.java
new file mode 100644
index 0000000..45ab3e4
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderNotFoundException.java
@@ -0,0 +1,8 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+
+public class OrderNotFoundException extends RuntimeException {
+ public OrderNotFoundException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderQuantityException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderQuantityException.java
new file mode 100644
index 0000000..69291dd
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/OrderQuantityException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+public class OrderQuantityException extends RuntimeException {
+ public OrderQuantityException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/WrongAddressException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/WrongAddressException.java
new file mode 100644
index 0000000..ea4e10f
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/exception/WrongAddressException.java
@@ -0,0 +1,7 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
+
+public class WrongAddressException extends RuntimeException {
+ public WrongAddressException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/repository/OrderRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/repository/OrderRepository.java
new file mode 100644
index 0000000..f799a71
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/repository/OrderRepository.java
@@ -0,0 +1,60 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.repository;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
+import java.util.*;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+public final class OrderRepository {
+ private final List orders = new ArrayList<>();
+
+ public void deleteAll() {
+ orders.clear();
+ }
+
+ public Optional findById(UUID id) {
+ return this.orders.stream()
+ .filter(order -> Objects.equals(order.getId(), id))
+ .findFirst();
+ }
+
+ public boolean existsById(UUID id) {
+ return this.orders.stream()
+ .anyMatch(order -> Objects.equals(order.getId(), id));
+ }
+
+ public void delete(Order order) {
+ this.orders.remove(order);
+ }
+
+ public Order save(Order newOrder) {
+ if (newOrder.getId() == null) {
+ Order orderWithId = Order.builder()
+ .id(UUID.randomUUID())
+ .customerId(newOrder.getCustomerId())
+ .paymentMethod(newOrder.getPaymentMethod())
+ .orderLines(newOrder.getOrderLines())
+ .shippingAddress(newOrder.getShippingAddress())
+ .totalPrice(newOrder.getTotalPrice())
+ .totalPriceToPay(newOrder.getTotalPriceToPay())
+ .build();
+ this.orders.add(orderWithId);
+ return orderWithId;
+ }
+
+ Optional optionalOrderWithSameId = this.findById(newOrder.getId());
+ optionalOrderWithSameId.ifPresent(orders::remove);
+ this.orders.add(newOrder);
+ return newOrder;
+ }
+
+ public List findByCustomerId(UUID customerId) {
+ return this.orders.stream()
+ .filter(order -> Objects.equals(order.getCustomerId(), customerId))
+ .toList();
+ }
+
+ public List findAll() {
+ return orders;
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java
new file mode 100644
index 0000000..b0e29bd
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java
@@ -0,0 +1,158 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.IllegalCustomerPointException;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.*;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.converter.OrderConverter;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.*;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+public final class OrderUseCase {
+ private final OrderRepository orderRepository;
+ private final CustomerRepository customerRepository;
+ private final BookRepository bookRepository;
+
+ public OrderUseCase(OrderRepository orderRepository, CustomerRepository customerRepository, BookRepository bookRepository) {
+ this.orderRepository = orderRepository;
+ this.customerRepository = customerRepository;
+ this.bookRepository = bookRepository;
+ }
+
+ public UUID createOrder(OrderInfo orderInfo) throws CustomerNotFoundException, IllegalCustomerPointException, NotValidOrderException {
+ validateOrderInfo(orderInfo);
+
+ PaymentMethod paymentMethod = parsePaymentMethod(orderInfo.getPaymentMethod());
+ UUID customerId = parseCustomerId(orderInfo.getCustomerId());
+
+ Customer customer = customerRepository.findById(customerId)
+ .orElseThrow(() -> new CustomerNotFoundException(customerId));
+
+ Map books = orderInfo.getOrderLines().stream()
+ .map(line -> bookRepository.findByIsbn(line.getBookId())
+ .orElseThrow(() -> new BookNotFoundException("Book with ISBN " + line.getBookId() + " was not found")))
+ .collect(Collectors.toMap(fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book::getIsbn, b -> b));
+
+ validateOrderLines(orderInfo, books);
+
+ double totalPrice = calculateTotalPrice(orderInfo, books);
+ double totalPriceToPay = calculateTotalPriceToPay(orderInfo, books);
+
+ Order domainOrder = OrderConverter.toDomain(orderInfo);
+
+ Order order = Order.builder()
+ .customerId(customerId)
+ .paymentMethod(paymentMethod)
+ .orderLines(domainOrder.getOrderLines())
+ .shippingAddress(domainOrder.getShippingAddress())
+ .totalPrice(totalPrice)
+ .totalPriceToPay(totalPriceToPay)
+ .build();
+
+ if (paymentMethod == PaymentMethod.LOYALTY_POINTS) {
+ handleLoyaltyPointsPayment(customer, totalPrice);
+ }
+
+ return orderRepository.save(order).getId();
+ }
+
+ public OrderDTO findOrderById(String orderId) {
+ UUID uuid = parseOrderId(orderId);
+ return orderRepository.findById(uuid)
+ .map(OrderConverter::toDTO)
+ .orElseThrow(() -> new OrderNotFoundException("Order not found"));
+ }
+
+ public List findOrdersByCustomerId(String customerId) throws CustomerNotFoundException {
+ UUID uuid = parseCustomerId(customerId);
+ customerRepository.findById(uuid)
+ .orElseThrow(() -> new CustomerNotFoundException(uuid));
+
+ return orderRepository.findByCustomerId(uuid)
+ .stream()
+ .map(OrderConverter::toDTO)
+ .toList();
+ }
+
+ private void validateOrderLines(OrderInfo orderInfo, Map books) {
+ orderInfo.getOrderLines().forEach(line -> {
+ if (line.getQuantity() <= 0) {
+ throw new OrderQuantityException("Quantity must be greater than 0 for book " + line.getBookId());
+ }
+ var book = books.get(line.getBookId());
+ if (book.getStock() < line.getQuantity()) {
+ throw new OrderQuantityException("Insufficient stock for book " + line.getBookId());
+ }
+ });
+ }
+
+ private void validateOrderInfo(OrderInfo orderInfo) throws NotValidOrderException {
+ if (orderInfo == null) {
+ throw new NotValidOrderException("Order cannot be null");
+ }
+ if (orderInfo.getOrderLines() == null || orderInfo.getOrderLines().isEmpty()) {
+ throw new OrderQuantityException("Order must contain at least one book");
+ }
+ if (orderInfo.getAddress() == null) {
+ throw new NotValidOrderException("Shipping address is required");
+ }
+ }
+
+ private double calculateTotalPriceToPay(OrderInfo orderInfo, Map books) {
+ // Apply any potential discounts here
+ return calculateTotalPrice(orderInfo, books);
+ }
+
+ private UUID parseCustomerId(String customerId) throws CustomerNotFoundException {
+ if (customerId == null || customerId.trim().isEmpty()) {
+ throw new CustomerNotFoundException(null);
+ }
+ try {
+ return UUID.fromString(customerId);
+ } catch (IllegalArgumentException e) {
+ throw new CustomerNotFoundException(null);
+ }
+ }
+
+ private PaymentMethod parsePaymentMethod(String paymentMethod) {
+ try {
+ return PaymentMethod.valueOf(paymentMethod);
+ } catch (IllegalArgumentException | NullPointerException e) {
+ throw new InvalidPaymentMethodException("Payment method " + paymentMethod + " is not valid");
+ }
+ }
+
+ private UUID parseOrderId(String orderId) {
+ try {
+ return UUID.fromString(orderId);
+ } catch (IllegalArgumentException e) {
+ throw new OrderNotFoundException("Order with ID " + orderId + " was not found");
+ }
+ }
+
+ private double calculateTotalPrice(OrderInfo orderInfo, Map books) {
+ return orderInfo.getOrderLines().stream()
+ .mapToDouble(line -> books.get(line.getBookId()).getPrice() * line.getQuantity())
+ .sum();
+ }
+
+ private void handleLoyaltyPointsPayment(Customer customer, double totalPrice) throws IllegalCustomerPointException {
+ int requiredPoints = (int) (totalPrice * 100);
+ if (customer.getLoyaltyPoints() < requiredPoints) {
+ throw new IllegalOrderPointException("Not enough loyalty points to pay for the order");
+ }
+ customer.removeLoyaltyPoints(requiredPoints);
+ customerRepository.save(customer);
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/validator/OrderValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/validator/OrderValidator.java
new file mode 100644
index 0000000..35c9edf
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/validator/OrderValidator.java
@@ -0,0 +1,66 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.order.validator;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Address;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
+import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
+
+public class OrderValidator {
+
+ public static void validate(Order order) {
+ if (order == null) {
+ throw new NotValidOrderException("Order cannot be null");
+ }
+ validatePrices(order);
+ validateAddress(order);
+ validatePaymentMethod(order);
+ validateOrderLines(order);
+ }
+
+ private static void validatePrices(Order order) {
+ if (order.getTotalPrice() <= 0) {
+ throw new NotValidOrderException("Total price must be positive");
+ }
+ if (order.getTotalPriceToPay() <= 0) {
+ throw new NotValidOrderException("Total price to pay must be positive");
+ }
+ if (order.getTotalPriceToPay() > order.getTotalPrice()) {
+ throw new NotValidOrderException("Total price to pay cannot exceed total price");
+ }
+ }
+
+ private static void validateOrderLines(Order order) {
+ if (order.getOrderLines() == null || order.getOrderLines().isEmpty()) {
+ throw new NotValidOrderException("Order must contain at least one line");
+ }
+
+ order.getOrderLines().forEach(line -> {
+ if (line.getQuantity() <= 0) {
+ throw new NotValidOrderException("Quantity must be positive");
+ }
+ });
+ }
+
+ private static void validateAddress(Order order) {
+ Address address = order.getShippingAddress();
+ if (address == null) {
+ throw new NotValidOrderException("Shipping address is required");
+ }
+
+ if (isNullOrBlank(address.getStreet()) ||
+ isNullOrBlank(address.getCity()) ||
+ isNullOrBlank(address.getPostalCode()) ||
+ isNullOrBlank(address.getCountry())) {
+ throw new NotValidOrderException("All address fields are required");
+ }
+ }
+
+ private static void validatePaymentMethod(Order order) {
+ if (order.getPaymentMethod() == null) {
+ throw new NotValidOrderException("Payment method cannot be null");
+ }
+ }
+
+ private static boolean isNullOrBlank(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java
new file mode 100644
index 0000000..232a984
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java
@@ -0,0 +1,19 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.UUID;
+
+@Builder
+@Getter
+@AllArgsConstructor
+public class ReviewDto {
+ private final UUID reviewId;
+ private final long bookId;
+ private final String customerName;
+ private final String comment;
+ private final int rating;
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java
new file mode 100644
index 0000000..df02df8
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java
@@ -0,0 +1,16 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+@AllArgsConstructor
+public class ReviewInfo {
+ private final String customerId;
+ private final long isbn;
+ private final int rating;
+ private final String comment;
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java
new file mode 100644
index 0000000..a7584d2
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java
@@ -0,0 +1,29 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.converter;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.review.ReviewDto;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.ReviewInfo;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
+
+import java.util.UUID;
+
+public class ReviewConverter {
+ public static ReviewDto toDto(Review review, UUID reviewId, String customerName) {
+ return ReviewDto.builder()
+ .reviewId(reviewId)
+ .bookId(review.getIsbn())
+ .customerName(customerName)
+ .comment(review.getComment())
+ .rating(review.getRating())
+ .build();
+ }
+
+ public static Review toDomain(ReviewInfo info) {
+ return Review.builder()
+ .customerId(UUID.fromString(info.getCustomerId()))
+ .isbn(info.getIsbn())
+ .rating(info.getRating())
+ .comment(info.getComment())
+ .build();
+ }
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java
new file mode 100644
index 0000000..20376e5
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java
@@ -0,0 +1,19 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.UUID;
+
+@Builder
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Review {
+ private UUID customerId;
+ private long isbn;
+ private int rating;
+ private String comment;
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java
new file mode 100644
index 0000000..0b07448
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java
@@ -0,0 +1,8 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
+
+public class InvalidReviewRatingException extends RuntimeException {
+ public InvalidReviewRatingException(String message) {
+ super(message);
+ }
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java
new file mode 100644
index 0000000..5f92fa6
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java
@@ -0,0 +1,8 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
+
+public class ReviewAlreadyExistsException extends RuntimeException {
+ public ReviewAlreadyExistsException(String message) {
+ super(message);
+ }
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java
new file mode 100644
index 0000000..4b3268a
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java
@@ -0,0 +1,8 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
+
+public class ReviewNotFoundException extends RuntimeException {
+ public ReviewNotFoundException(String message) {
+ super(message);
+ }
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java
new file mode 100644
index 0000000..2e5e26e
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java
@@ -0,0 +1,44 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.repository;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class ReviewRepository {
+ private final List reviews = new ArrayList<>();
+
+ public void save(Review review) {
+ reviews.add(review);
+ }
+
+ public List findAll() {
+ return new ArrayList<>(reviews);
+ }
+
+ public List findByIsbn(long isbn) {
+ return reviews.stream().filter(r -> r.getIsbn() == isbn).collect(Collectors.toList());
+ }
+
+ public List findByCustomerId(UUID customerId) {
+ return reviews.stream().filter(r -> r.getCustomerId().equals(customerId)).collect(Collectors.toList());
+ }
+
+ public boolean existsByCustomerIdAndIsbn(UUID customerId, long isbn) {
+ return reviews.stream().anyMatch(r -> r.getCustomerId().equals(customerId) && r.getIsbn() == isbn);
+ }
+
+ public void deleteByCustomerIdAndIsbn(UUID customerId, long isbn) {
+ reviews.removeIf(r -> r.getCustomerId().equals(customerId) && r.getIsbn() == isbn);
+ }
+
+ public void update(Review review) {
+ deleteByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn());
+ save(review);
+ }
+
+ public void deleteAll() {
+ reviews.clear();
+ }
+}
+
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java
new file mode 100644
index 0000000..939ce93
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java
@@ -0,0 +1,71 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.usecase;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.InvalidReviewRatingException;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.ReviewAlreadyExistsException;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.ReviewNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.validator.ReviewValidator;
+
+import java.util.List;
+import java.util.UUID;
+
+public class ReviewUseCase {
+
+ private final ReviewRepository reviewRepository;
+ private final BookRepository bookRepository;
+ private final CustomerRepository customerRepository;
+
+ public ReviewUseCase(ReviewRepository reviewRepository, BookRepository bookRepository, CustomerRepository customerRepository) {
+ this.reviewRepository = reviewRepository;
+ this.bookRepository = bookRepository;
+ this.customerRepository = customerRepository;
+ }
+
+ public void deleteReview(long isbn, UUID customerId) {
+ if (!reviewRepository.existsByCustomerIdAndIsbn(customerId, isbn)) {
+ throw new ReviewNotFoundException("No review found for the given customer and book.");
+ }
+ reviewRepository.deleteByCustomerIdAndIsbn(customerId, isbn);
+ }
+
+ public void submitReview(Review review) throws CustomerNotFoundException {
+ ReviewValidator.validate(review);
+
+ if (!bookRepository.existsByIsbn(String.valueOf(review.getIsbn()))) {
+ throw new BookNotFoundException("The book with ISBN " + review.getIsbn() + " was not found.");
+ }
+
+ if (!customerRepository.existsById(review.getCustomerId())) {
+ throw new CustomerNotFoundException(review.getCustomerId());
+ }
+
+ if (reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) {
+ throw new ReviewAlreadyExistsException("A review already exists for this customer and book.");
+ }
+
+ reviewRepository.save(review);
+ }
+
+ public List getReviewsByCustomer(UUID customerId) {
+ return reviewRepository.findByCustomerId(customerId);
+ }
+
+ public void updateReview(Review review) {
+ ReviewValidator.validate(review);
+
+ if (!reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) {
+ throw new ReviewNotFoundException("Cannot update: no existing review found for this customer and book.");
+ }
+
+ reviewRepository.update(review);
+ }
+
+ public List getReviewsByBook(long isbn) {
+ return reviewRepository.findByIsbn(isbn);
+ }
+}
diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java
new file mode 100644
index 0000000..e82572f
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java
@@ -0,0 +1,30 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.review.validator;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
+import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.InvalidReviewRatingException;
+
+public class ReviewValidator {
+
+ public static void validate(Review review) {
+ if (review == null) {
+ throw new IllegalArgumentException("The review provided is null.");
+ }
+
+ if (review.getCustomerId() == null) {
+ throw new IllegalArgumentException("Customer ID is required.");
+ }
+
+ if (review.getIsbn() <= 0) {
+ throw new IllegalArgumentException("ISBN must be a positive number.");
+ }
+
+ if (review.getComment() == null || review.getComment().trim().isEmpty()) {
+ throw new IllegalArgumentException("A review must contain a comment.");
+ }
+
+ int rating = review.getRating();
+ if (rating < 1 || rating > 5) {
+ throw new InvalidReviewRatingException("Rating must be within the range of 1 to 5.");
+ }
+ }
+}
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..6447380
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionDTO.java
@@ -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;
+}
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..2bf5638
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/SubscriptionInfo.java
@@ -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) {
+
+}
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..9f8aaca
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/converter/SubscriptionConverter.java
@@ -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();
+ }
+
+}
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..7d0efe3
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/entity/Subscription.java
@@ -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();
+ }
+}
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..4ab97d2
--- /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 Exception {
+
+ 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..3b71ab1
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java
@@ -0,0 +1,13 @@
+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 subscription with id {0} does not exist";
+
+ public SubscriptionNotFoundException(UUID uuid) {
+ super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid));
+ }
+}
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..655aef2
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/repository/SubscriptionRepository.java
@@ -0,0 +1,40 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.subscription.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription;
+
+public class SubscriptionRepository {
+ private final List subscriptions = new ArrayList<>();
+
+ public Optional findById(UUID id) {
+ return subscriptions.stream()
+ .filter(subscription -> subscription.getId().equals(id))
+ .findFirst();
+ }
+
+ public Optional findByCustomerId(UUID uuid) {
+ return subscriptions.stream()
+ .filter(subscription -> subscription.getCustomerId().equals(uuid))
+ .findFirst();
+ }
+
+ public List findAll() {
+ return subscriptions;
+ }
+
+ public boolean existsById(UUID uuid) {
+ return subscriptions.stream()
+ .anyMatch(subscription -> subscription.getId().equals(uuid));
+ }
+
+ public Subscription save(Subscription newSubscription) {
+ Optional existing = this.findByCustomerId(newSubscription.getCustomerId());
+ existing.ifPresentOrElse(subscriptions::remove, newSubscription::setRandomUUID);
+ subscriptions.add(newSubscription);
+ return newSubscription;
+ }
+}
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..0069a92
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/usecase/SubscriptionUseCase.java
@@ -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.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.SubscriptionValidator;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public class SubscriptionUseCase {
+
+ public Optional findSubscriptionByCustomerId(UUID customerId) {
+ return subscriptionRepository.findByCustomerId(customerId)
+ .map(SubscriptionConverter::toDTO);
+ }
+
+ public UUID registerSubscription(SubscriptionInfo info) throws NotValidSubscriptionException {
+ SubscriptionValidator.validate(info);
+ Subscription entity = SubscriptionConverter.toDomain(info);
+ Subscription saved = subscriptionRepository.save(entity);
+ if (saved.getDuration() <= 0) {
+ throw new NotValidSubscriptionException("Duration must be positive");
+ }
+ return saved.getId();
+ }
+
+ private boolean getSubscriptionIfDoesNotExistThrowSubscriptionNotFoundException(UUID uuid)
+ throws SubscriptionNotFoundException {
+ if (subscriptionRepository.existsById(uuid)) {
+ throw new SubscriptionNotFoundException(uuid);
+ }
+ return subscriptionRepository.existsById(uuid);
+ }
+
+ public SubscriptionUseCase(SubscriptionRepository subscriptionRepository) {
+ this.subscriptionRepository = subscriptionRepository;
+ }
+
+ private final SubscriptionRepository subscriptionRepository;
+}
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..efab9ca
--- /dev/null
+++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/validator/SubscriptionValidator.java
@@ -0,0 +1,37 @@
+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;
+
+public class SubscriptionValidator {
+
+ public static final String CUSTOMER_ID_NULL_MESSAGE = "Customer ID must not be null";
+ public static final String DURATION_NULL_MESSAGE = "Invalid duration value";
+ public static final String PAYMENT_METHOD_EMPTY_MESSAGE = "Payment method cannot be empty";
+
+ public static void validate(SubscriptionInfo info) throws NotValidSubscriptionException {
+ checkCustomerId(info);
+ checkDuration(info);
+ checkPayment(info);
+ }
+
+ private static void checkDuration(SubscriptionInfo info) throws NotValidSubscriptionException {
+ if (info.duration() == null) {
+ throw new NotValidSubscriptionException(DURATION_NULL_MESSAGE);
+ }
+ }
+
+ private static void checkCustomerId(SubscriptionInfo info) throws NotValidSubscriptionException {
+ if (info.customerId() == null) {
+ throw new NotValidSubscriptionException(CUSTOMER_ID_NULL_MESSAGE);
+ }
+ }
+
+ private static void checkPayment(SubscriptionInfo info) throws NotValidSubscriptionException {
+ if (info.paymentMethod().isBlank()) {
+ throw new NotValidSubscriptionException(PAYMENT_METHOD_EMPTY_MESSAGE);
+ }
+ }
+
+ private SubscriptionValidator() {}
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java
new file mode 100644
index 0000000..ab15a07
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/converter/BookConverterTest.java
@@ -0,0 +1,140 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.converter;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.*;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+import org.junit.jupiter.api.*;
+
+import java.time.LocalDate;
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("Unit tests for BookConverter")
+class BookConverterTest {
+
+ @Test
+ @DisplayName("Should convert empty strings correctly during conversion")
+ void shouldPreserveEmptyStrings() {
+ BookInfo info = new BookInfo(
+ "1111111111111",
+ "",
+ "",
+ "",
+ LocalDate.of(2022, 2, 2),
+ 0.0,
+ 0,
+ Collections.emptyList(),
+ "",
+ ""
+ );
+
+ Book domain = BookConverter.toDomain(info);
+ BookDTO dto = BookConverter.toDTO(domain);
+
+ assertEquals("", dto.getTitle());
+ assertEquals("", dto.getAuthor());
+ assertEquals("", dto.getPublisher());
+ assertEquals("", dto.getDescription());
+ assertEquals("", dto.getLanguage());
+ }
+
+ @Nested
+ @DisplayName("Tests for toDTO() method")
+ class ToDTO {
+
+ @Test
+ @DisplayName("Should map all fields from Book to BookDTO correctly")
+ void shouldConvertBookToDTO() {
+ Book book = Book.builder()
+ .isbn("9876543210123")
+ .title("Title2")
+ .author("Author2")
+ .publisher("Publisher2")
+ .publicationDate(LocalDate.of(2021, 5, 10))
+ .price(25.5)
+ .stock(5)
+ .categories(List.of(Category.FANTASY))
+ .description("Desc2")
+ .language("English")
+ .build();
+
+ BookDTO result = BookConverter.toDTO(book);
+
+ assertNotNull(result);
+ assertEquals(book.getIsbn(), result.getIsbn());
+ assertEquals(book.getTitle(), result.getTitle());
+ assertEquals(book.getAuthor(), result.getAuthor());
+ assertEquals(book.getPublisher(), result.getPublisher());
+ assertEquals(book.getPublicationDate(), result.getPublicationDate());
+ assertEquals(book.getPrice(), result.getPrice());
+ assertEquals(book.getStock(), result.getStock());
+ assertEquals(book.getCategories(), result.getCategories());
+ assertEquals(book.getDescription(), result.getDescription());
+ assertEquals(book.getLanguage(), result.getLanguage());
+ }
+ }
+
+ @Test
+ @DisplayName("Should handle null values safely during conversion")
+ void shouldHandleNullValuesGracefully() {
+ Book book = Book.builder()
+ .isbn("0")
+ .title(null)
+ .author(null)
+ .publisher(null)
+ .publicationDate(null)
+ .price(0.0)
+ .stock(0)
+ .categories(Collections.emptyList())
+ .description(null)
+ .language(null)
+ .build();
+
+ BookDTO result = BookConverter.toDTO(book);
+
+ assertNotNull(result);
+ assertNull(result.getTitle());
+ assertNull(result.getAuthor());
+ assertNull(result.getPublisher());
+ assertNull(result.getPublicationDate());
+ assertNull(result.getDescription());
+ assertNull(result.getLanguage());
+ assertEquals(Collections.emptyList(), result.getCategories());
+ }
+
+ @Nested
+ @DisplayName("Tests for toDomain() method")
+ class ToDomain {
+
+ @Test
+ @DisplayName("Should convert BookInfo to Book domain object with default values")
+ void shouldConvertBookInfoToDomain() {
+ BookInfo info = new BookInfo(
+ "1234567890123",
+ "Title",
+ "Author",
+ "Publisher",
+ LocalDate.of(2020, 1, 1),
+ 19.99,
+ 10,
+ List.of(Category.FICTION),
+ "Description",
+ "French"
+ );
+
+ Book result = BookConverter.toDomain(info);
+
+ assertNotNull(result);
+ assertEquals(info.isbn(), result.getIsbn());
+ assertEquals(info.title(), result.getTitle());
+ assertEquals(info.author(), result.getAuthor());
+ assertEquals(info.publisher(), result.getPublisher());
+ assertEquals(info.publicationDate(), result.getPublicationDate());
+ assertEquals(info.price(), result.getPrice());
+ assertEquals(info.stock(), result.getStock());
+ assertEquals(info.categories(), result.getCategories());
+ assertEquals(info.description(), result.getDescription());
+ assertEquals(info.language(), result.getLanguage());
+ }
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java
new file mode 100644
index 0000000..f176326
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java
@@ -0,0 +1,126 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
+import org.junit.jupiter.api.*;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("Unit tests for Book class")
+class BookTest {
+
+ @Test
+ @DisplayName("Builder should create a valid Book instance")
+ void shouldBuildValidBook() {
+ String isbn = "9780987654321";
+ String title = "AI Secrets Unveiled";
+ String author = "Alice Newton";
+ String publisher = "FutureBooks";
+ LocalDate publicationDate = LocalDate.of(2012, 6, 20);
+ double price = 39.95;
+ int stock = 7;
+ List categories = List.of(Category.TECHNOLOGY);
+ String description = "A deep dive into the evolution of AI.";
+ String language = "English";
+
+ Book book = Book.builder()
+ .isbn(isbn)
+ .title(title)
+ .author(author)
+ .publisher(publisher)
+ .publicationDate(publicationDate)
+ .price(price)
+ .stock(stock)
+ .categories(categories)
+ .description(description)
+ .language(language)
+ .build();
+
+ assertEquals(isbn, book.getIsbn());
+ assertEquals(title, book.getTitle());
+ assertEquals(author, book.getAuthor());
+ assertEquals(publisher, book.getPublisher());
+ assertEquals(publicationDate, book.getPublicationDate());
+ assertEquals(price, book.getPrice());
+ assertEquals(stock, book.getStock());
+ assertEquals(categories, book.getCategories());
+ assertEquals(description, book.getDescription());
+ assertEquals(language, book.getLanguage());
+ }
+
+ @Nested
+ @DisplayName("Stock management tests")
+ class StockTests {
+
+ @Test
+ @DisplayName("addStock should handle adding zero properly")
+ void shouldHandleAddingZeroStock() {
+ Book book = Book.builder().stock(8).build();
+
+ book.addStock(0);
+
+ assertEquals(8, book.getStock());
+ }
+
+ @Test
+ @DisplayName("addStock should increment the stock correctly")
+ void shouldAddStockCorrectly() {
+ Book book = Book.builder().stock(12).build();
+ int toAdd = 6;
+ int expected = 18;
+
+ book.addStock(toAdd);
+
+ assertEquals(expected, book.getStock());
+ }
+
+ @Test
+ @DisplayName("removeStock should throw if more than available is removed")
+ void shouldThrowWhenRemovingTooMuchStock() {
+ Book book = Book.builder().stock(5).build();
+ int toRemove = 9;
+
+ Exception exception = assertThrows(
+ IllegalArgumentException.class,
+ () -> book.removeStock(toRemove)
+ );
+
+ assertEquals(5, book.getStock());
+ assertTrue(exception.getMessage().contains(String.valueOf(toRemove)));
+ }
+
+ @Test
+ @DisplayName("removeStock should handle zero removal correctly")
+ void shouldHandleZeroRemoval() {
+ Book book = Book.builder().stock(3).build();
+
+ book.removeStock(0);
+
+ assertEquals(3, book.getStock());
+ }
+
+ @Test
+ @DisplayName("removeStock should remove all available stock")
+ void shouldRemoveAllStock() {
+ Book book = Book.builder().stock(4).build();
+
+ book.removeStock(4);
+
+ assertEquals(0, book.getStock());
+ }
+
+ @Test
+ @DisplayName("removeStock should decrease stock properly")
+ void shouldRemoveStockCorrectly() {
+ Book book = Book.builder().stock(9).build();
+ int toRemove = 2;
+ int expected = 7;
+
+ book.removeStock(toRemove);
+
+ assertEquals(expected, book.getStock());
+ }
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java
new file mode 100644
index 0000000..b528aa9
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundExceptionTest.java
@@ -0,0 +1,44 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
+
+import org.junit.jupiter.api.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("Unit tests for BookNotFoundException")
+class BookNotFoundExceptionTest {
+
+ @Test
+ @DisplayName("Should throw and catch the exception properly")
+ void shouldThrowAndCatchProperly() {
+ String isbn = "9780001112223";
+
+ try {
+ throw new BookNotFoundException(isbn);
+ } catch (BookNotFoundException e) {
+ String expected = String.format("The book with isbn %s does not exist", isbn);
+ assertEquals(expected, e.getMessage());
+ }
+ }
+
+ @Test
+ @DisplayName("Should contain the ISBN in the exception message")
+ void shouldIncludeIsbnInMessage() {
+ String isbn = "9780001112223";
+
+ BookNotFoundException exception = new BookNotFoundException(isbn);
+
+ assertTrue(exception.getMessage().contains(isbn));
+ assertEquals(String.format("The book with isbn %s does not exist", isbn), exception.getMessage());
+ }
+
+ @Test
+ @DisplayName("Should use the constant message format defined in the class")
+ void shouldUseCorrectConstantMessageFormat() {
+ String isbn = "9780001112223";
+
+ BookNotFoundException ex = new BookNotFoundException(isbn);
+
+ assertEquals("The book with isbn {0} does not exist", BookNotFoundException.THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE);
+ assertTrue(ex.getMessage().contains(isbn));
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java
new file mode 100644
index 0000000..7622bc2
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookExceptionTest.java
@@ -0,0 +1,60 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
+
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("Unit tests for NotValidBookException")
+class NotValidBookExceptionTest {
+
+ @Test
+ @DisplayName("Should allow creation with provided message")
+ void shouldCreateExceptionWithMessage() {
+ String message = "Invalid book data detected";
+
+ NotValidBookException ex = new NotValidBookException(message);
+
+ assertEquals(message, ex.getMessage());
+ }
+
+ @Test
+ @DisplayName("Should be catchable as general Exception")
+ void shouldBeCatchableAsException() {
+ String message = "Improper book input";
+
+ try {
+ throw new NotValidBookException(message);
+ } catch (Exception e) {
+ assertEquals(NotValidBookException.class, e.getClass());
+ assertEquals(message, e.getMessage());
+ }
+ }
+
+ @Test
+ @DisplayName("Should be thrown and caught properly")
+ void shouldThrowAndCatchProperly() {
+ String msg = "Missing required field";
+
+ Exception thrown = assertThrows(NotValidBookException.class, () -> {
+ throw new NotValidBookException(msg);
+ });
+
+ assertEquals(msg, thrown.getMessage());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "Title must not be empty",
+ "ISBN format is invalid",
+ "Price cannot be negative",
+ "Stock cannot be less than zero"
+ })
+ @DisplayName("Should handle multiple validation messages")
+ void shouldHandleMultipleMessages(String msg) {
+ NotValidBookException ex = new NotValidBookException(msg);
+
+ assertEquals(msg, ex.getMessage());
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java
new file mode 100644
index 0000000..1dc7315
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java
@@ -0,0 +1,246 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.*;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.*;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.LocalDate;
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class BookUseCaseTest {
+
+ @Mock
+ private BookRepository bookRepository;
+
+ @InjectMocks
+ private BookUseCase bookUseCase;
+
+ private String isbn;
+ private Book mockBook;
+ private BookInfo validBookInfo;
+
+ @BeforeEach
+ void setup() {
+ isbn = "9780001112223";
+ mockBook = Book.builder()
+ .isbn(isbn)
+ .title("Code Craft")
+ .author("Jane Doe")
+ .publisher("CodePress")
+ .publicationDate(LocalDate.of(2012, 3, 12))
+ .price(27.5)
+ .stock(10)
+ .categories(List.of(Category.MYSTERY))
+ .description("Deep insights into software practices.")
+ .language("English")
+ .build();
+
+ validBookInfo = new BookInfo(
+ isbn,
+ "Code Craft",
+ "Jane Doe",
+ "CodePress",
+ LocalDate.of(2012, 3, 12),
+ 27.5,
+ 10,
+ List.of(Category.MYSTERY),
+ "Deep insights into software practices.",
+ "English"
+ );
+ }
+
+ @Nested
+ @DisplayName("Search functionality")
+ class SearchTests {
+ @Test
+ @DisplayName("Should return books matching given title fragment")
+ void shouldFindBooksByTitle() {
+ when(bookRepository.findByTitleContaining("Code")).thenReturn(List.of(mockBook));
+
+ List result = bookUseCase.findBooksByTitleContaining("Code");
+
+ assertEquals(1, result.size());
+ assertEquals("Code Craft", result.get(0).getTitle());
+ verify(bookRepository).findByTitleContaining("Code");
+ }
+ }
+
+ @Nested
+ @DisplayName("Stock operations")
+ class StockManagementTests {
+
+ @Test
+ @DisplayName("Should add stock successfully")
+ void shouldAddStock() {
+ when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(mockBook));
+ when(bookRepository.save(any(Book.class))).thenReturn(mockBook);
+
+ int result = bookUseCase.addStock(isbn, 5);
+
+ assertEquals(15, result);
+ verify(bookRepository).save(mockBook);
+ }
+
+ @Test
+ @DisplayName("Should remove stock successfully")
+ void shouldRemoveStock() {
+ when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(mockBook));
+ when(bookRepository.save(any(Book.class))).thenReturn(mockBook);
+
+ int result = bookUseCase.removeStock(isbn, 5);
+
+ assertEquals(5, result);
+ verify(bookRepository).save(mockBook);
+ }
+ }
+
+ @Nested
+ @DisplayName("Book deletion")
+ class DeleteBookTests {
+
+ @Test
+ @DisplayName("Should delete book when it exists")
+ void shouldDeleteExistingBook() throws BookNotFoundException {
+ when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(mockBook));
+ doNothing().when(bookRepository).delete(mockBook);
+
+ bookUseCase.deleteBook(isbn);
+
+ verify(bookRepository).delete(mockBook);
+ }
+
+ @Test
+ @DisplayName("Should throw when trying to delete non-existent book")
+ void shouldThrowWhenBookToDeleteDoesNotExist() {
+ when(bookRepository.findByIsbn("unknown")).thenReturn(Optional.empty());
+
+ assertThrows(BookNotFoundException.class,
+ () -> bookUseCase.deleteBook("unknown"));
+ }
+ }
+
+ @Nested
+ @DisplayName("Book update")
+ class UpdateBookTests {
+
+ @Test
+ @DisplayName("Should update existing book with valid info")
+ void shouldUpdateBookCorrectly() throws BookNotFoundException, NotValidBookException {
+ when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(mockBook));
+
+ Book updatedBook = Book.builder()
+ .isbn(isbn)
+ .title("Code Craft - Revised")
+ .author("Jane Doe")
+ .publisher("CodePress")
+ .publicationDate(LocalDate.of(2012, 3, 12))
+ .price(30.0)
+ .stock(12)
+ .categories(List.of(Category.MYSTERY))
+ .description("Revised edition of software insights.")
+ .language("English")
+ .build();
+
+ when(bookRepository.save(any(Book.class))).thenReturn(updatedBook);
+
+ BookInfo updatedInfo = new BookInfo(
+ isbn,
+ "Code Craft - Revised",
+ "Jane Doe",
+ "CodePress",
+ LocalDate.of(2012, 3, 12),
+ 30.0,
+ 12,
+ List.of(Category.MYSTERY),
+ "Revised edition of software insights.",
+ "English"
+ );
+
+ BookDTO result = bookUseCase.updateBook(isbn, updatedInfo);
+
+ assertNotNull(result);
+ assertEquals("Code Craft - Revised", result.getTitle());
+ }
+
+ @Test
+ @DisplayName("Should throw when trying to update non-existent book")
+ void shouldThrowWhenUpdatingUnknownBook() {
+ when(bookRepository.findByIsbn("invalid")).thenReturn(Optional.empty());
+
+ assertThrows(BookNotFoundException.class,
+ () -> bookUseCase.updateBook("invalid", validBookInfo));
+ }
+
+ @Test
+ @DisplayName("Should throw when update info is invalid")
+ void shouldThrowForInvalidUpdateInfo() {
+ BookInfo invalidInfo = new BookInfo(
+ null, "", "", "", null, 0.0, 0, Collections.emptyList(), "", ""
+ );
+
+ assertThrows(NotValidBookException.class,
+ () -> bookUseCase.updateBook(isbn, invalidInfo));
+ }
+ }
+
+ @Nested
+ @DisplayName("Book lookup")
+ class FindBookTests {
+
+ @Test
+ @DisplayName("Should return DTO if ISBN matches a book")
+ void shouldReturnBookDTO() {
+ when(bookRepository.findByIsbn(isbn)).thenReturn(Optional.of(mockBook));
+
+ BookDTO result = bookUseCase.findBookByIsbn(isbn);
+
+ assertNotNull(result);
+ assertEquals(isbn, result.getIsbn());
+ }
+
+ @Test
+ @DisplayName("Should throw if book not found by ISBN")
+ void shouldThrowIfBookNotFound() {
+ when(bookRepository.findByIsbn("notfound")).thenReturn(Optional.empty());
+
+ assertThrows(BookNotFoundException.class,
+ () -> bookUseCase.findBookByIsbn("notfound"));
+ }
+ }
+
+ @Nested
+ @DisplayName("Book registration")
+ class RegisterBookTests {
+
+ @Test
+ @DisplayName("Should register book if valid")
+ void shouldRegisterBookSuccessfully() throws NotValidBookException {
+ when(bookRepository.save(any(Book.class))).thenReturn(mockBook);
+
+ String resultIsbn = bookUseCase.registerBook(validBookInfo);
+
+ assertEquals(isbn, resultIsbn);
+ }
+
+ @Test
+ @DisplayName("Should reject invalid book data")
+ void shouldThrowOnInvalidRegistration() {
+ BookInfo invalidInfo = new BookInfo(
+ null, "", "", "", null, 0.0, 0, Collections.emptyList(), "", ""
+ );
+
+ assertThrows(NotValidBookException.class,
+ () -> bookUseCase.registerBook(invalidInfo));
+ }
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java
new file mode 100644
index 0000000..759b219
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java
@@ -0,0 +1,213 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.book.validator;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.time.LocalDate;
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("Unit tests for BookValidator")
+class BookValidatorTest {
+
+ @Test
+ @DisplayName("Should validate a properly filled book without throwing")
+ void shouldValidateValidBook() {
+ BookInfo validBook = new BookInfo(
+ "9780001234567",
+ "Mastering Java",
+ "Alice Newton",
+ "DevPress",
+ LocalDate.of(2012, 10, 5),
+ 45.0,
+ 7,
+ List.of(Category.MYSTERY),
+ "Advanced guide to Java programming.",
+ "English"
+ );
+ assertDoesNotThrow(() -> BookValidator.validate(validBook));
+ }
+
+ @Nested
+ @DisplayName("ISBN validation")
+ class IsbnTests {
+
+ @Test
+ @DisplayName("Should fail if ISBN is null")
+ void shouldFailOnNullIsbn() {
+ BookInfo book = new BookInfo(
+ null, "Title", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_ISBN_NULL, ex.getMessage());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"", "1", "123456", "abc"})
+ @DisplayName("Should fail if ISBN is not 13 digits")
+ void shouldFailOnInvalidIsbn(String isbn) {
+ BookInfo book = new BookInfo(
+ isbn, "Title", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_INVALID_ISBN, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Title validation")
+ class TitleTests {
+
+ @Test
+ @DisplayName("Should fail if title is blank")
+ void shouldFailOnBlankTitle() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_TITLE_EMPTY, ex.getMessage());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {" ", "\t", "\n"})
+ @DisplayName("Should fail if title is only whitespace")
+ void shouldFailOnWhitespaceOnlyTitle(String value) {
+ BookInfo book = new BookInfo(
+ "9780001234567", value, "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_TITLE_EMPTY, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Author validation")
+ class AuthorTests {
+ @Test
+ @DisplayName("Should fail if author is blank")
+ void shouldFailOnBlankAuthor() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_AUTHOR_EMPTY, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Publisher validation")
+ class PublisherTests {
+ @Test
+ @DisplayName("Should fail if publisher is blank")
+ void shouldFailOnBlankPublisher() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_PUBLISHER_EMPTY, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Publication date validation")
+ class PublicationDateTests {
+ @Test
+ @DisplayName("Should fail if publication date is null")
+ void shouldFailOnNullPublicationDate() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", null, 10.0, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_PUBLICATION_DATE_NULL, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Price validation")
+ class PriceTests {
+ @ParameterizedTest
+ @ValueSource(doubles = {0.0, -5.5, -100.0})
+ @DisplayName("Should fail if price is zero or negative")
+ void shouldFailOnInvalidPrice(double price) {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", LocalDate.now(), price, 2,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_NEGATIVE_PRICE, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Stock validation")
+ class StockTests {
+ @ParameterizedTest
+ @ValueSource(ints = {-1, -50})
+ @DisplayName("Should fail if stock is negative")
+ void shouldFailOnNegativeStock(int stock) {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", LocalDate.now(), 10.0, stock,
+ List.of(Category.SCIENCE), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_NEGATIVE_STOCK, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Category validation")
+ class CategoryTests {
+ @Test
+ @DisplayName("Should fail if category list is empty")
+ void shouldFailOnEmptyCategoryList() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ Collections.emptyList(), "Details", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_CATEGORIES_EMPTY, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Description validation")
+ class DescriptionTests {
+ @Test
+ @DisplayName("Should fail if description is blank")
+ void shouldFailOnBlankDescription() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "", "English"
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_DESCRIPTION_EMPTY, ex.getMessage());
+ }
+ }
+
+ @Nested
+ @DisplayName("Language validation")
+ class LanguageTests {
+ @Test
+ @DisplayName("Should fail if language is blank")
+ void shouldFailOnBlankLanguage() {
+ BookInfo book = new BookInfo(
+ "9780001234567", "Title", "Author", "Publisher", LocalDate.now(), 10.0, 2,
+ List.of(Category.SCIENCE), "Details", ""
+ );
+ NotValidBookException ex = assertThrows(NotValidBookException.class, () -> BookValidator.validate(book));
+ assertEquals(BookValidator.ERROR_LANGUAGE_EMPTY, ex.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverterTest.java
index 231fbab..8eec30f 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverterTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/converter/CustomerConverterTest.java
@@ -8,90 +8,85 @@ 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;
+import static org.junit.jupiter.api.Assertions.*;
-@DisplayName("CustomerConverter Unit Tests")
+@DisplayName("Unit checks for CustomerConverter")
class CustomerConverterTest {
+ @Test
+ @DisplayName("Should retain empty strings in conversion")
+ void convertsEmptyStringsCorrectly() {
+ CustomerInfo info = new CustomerInfo("", "", "");
+
+ Customer entity = CustomerConverter.toDomain(info);
+ CustomerDTO dto = CustomerConverter.toDTO(entity);
+
+ assertEquals("", dto.getFirstName());
+ assertEquals("", dto.getLastName());
+ assertEquals("", dto.getPhoneNumber());
+ }
+
@Nested
- @DisplayName("toDomain() method tests")
- class ToDomainTests {
+ @DisplayName("Tests for transformation into domain object")
+ class DomainMapping {
@Test
- @DisplayName("Should convert CustomerInfo to Customer domain object with loyalty points initialized to 0")
- void shouldConvertCustomerInfoToDomain() {
- // Given
- CustomerInfo customerInfo = new CustomerInfo("John", "Doe", "0123456789");
+ @DisplayName("Converts info to domain with zero points")
+ void mapsCustomerInfoProperly() {
+ CustomerInfo input = new CustomerInfo("Alice", "Wonders", "0123456789");
- // When
- Customer result = CustomerConverter.toDomain(customerInfo);
+ Customer result = CustomerConverter.toDomain(input);
- // Then
assertNotNull(result);
- assertEquals(customerInfo.firstName(), result.getFirstName());
- assertEquals(customerInfo.lastName(), result.getLastName());
- assertEquals(customerInfo.phoneNumber(), result.getPhoneNumber());
+ assertEquals("Alice", result.getFirstName());
+ assertEquals("Wonders", result.getLastName());
+ assertEquals("0123456789", result.getPhoneNumber());
assertEquals(0, result.getLoyaltyPoints());
}
}
@Nested
- @DisplayName("toDTO() method tests")
- class ToDTOTests {
+ @DisplayName("Tests for transformation into DTO")
+ class DtoMapping {
@Test
- @DisplayName("Should convert Customer domain object to CustomerDTO with all fields mapped correctly")
- void shouldConvertCustomerToDTO() {
- Customer customer = Customer.builder()
- .id(UUID.randomUUID())
- .firstName("Jane")
- .lastName("Smith")
- .phoneNumber("9876543210")
- .loyaltyPoints(100)
- .build();
+ @DisplayName("Maps domain object to DTO correctly")
+ void mapsCustomerToDto() {
+ Customer input = Customer.builder()
+ .id(UUID.randomUUID())
+ .firstName("Bob")
+ .lastName("Builder")
+ .phoneNumber("0987654321")
+ .loyaltyPoints(120)
+ .build();
- CustomerDTO result = CustomerConverter.toDTO(customer);
+ CustomerDTO output = CustomerConverter.toDTO(input);
- assertNotNull(result);
- assertEquals(customer.getId(), result.getId());
- assertEquals(customer.getFirstName(), result.getFirstName());
- assertEquals(customer.getLastName(), result.getLastName());
- assertEquals(customer.getPhoneNumber(), result.getPhoneNumber());
- assertEquals(customer.getLoyaltyPoints(), result.getLoyaltyPoints());
+ assertNotNull(output);
+ assertEquals(input.getId(), output.getId());
+ assertEquals("Bob", output.getFirstName());
+ assertEquals("Builder", output.getLastName());
+ assertEquals("0987654321", output.getPhoneNumber());
+ assertEquals(120, output.getLoyaltyPoints());
}
}
@Test
- @DisplayName("Should handle null values properly when converting between objects")
- void shouldHandleNullValuesGracefully() {
- Customer customer = Customer.builder()
- .id(UUID.randomUUID())
- .firstName(null)
- .lastName("NullTest")
- .phoneNumber(null)
- .loyaltyPoints(50)
- .build();
+ @DisplayName("Handles nulls safely during transformation")
+ void managesNullValues() {
+ Customer input = Customer.builder()
+ .id(UUID.randomUUID())
+ .firstName(null)
+ .lastName("Testy")
+ .phoneNumber(null)
+ .loyaltyPoints(75)
+ .build();
- CustomerDTO result = CustomerConverter.toDTO(customer);
+ CustomerDTO result = CustomerConverter.toDTO(input);
assertNotNull(result);
assertNull(result.getFirstName());
- assertEquals("NullTest", result.getLastName());
+ assertEquals("Testy", result.getLastName());
assertNull(result.getPhoneNumber());
}
-
- @Test
- @DisplayName("Should preserve empty string values during conversion")
- void shouldPreserveEmptyStrings() {
- CustomerInfo customerInfo = new CustomerInfo("", "", "");
-
- Customer domainResult = CustomerConverter.toDomain(customerInfo);
- CustomerDTO dtoResult = CustomerConverter.toDTO(domainResult);
-
- assertEquals("", dtoResult.getFirstName());
- assertEquals("", dtoResult.getLastName());
- assertEquals("", dtoResult.getPhoneNumber());
- }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java
index 515187e..2ca97ad 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java
@@ -4,133 +4,116 @@ import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.IllegalCustomerPoin
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;
+import static org.junit.jupiter.api.Assertions.*;
+
class CustomerTest {
@Test
- @DisplayName("Builder should create a valid Customer instance")
- void testCustomerBuilder() {
- UUID id = UUID.randomUUID();
- String firstName = "John";
- String lastName = "Doe";
- String phoneNumber = "0123456789";
- int loyaltyPoints = 100;
+ @DisplayName("Generates new UUID different from existing one")
+ void generatesNewUuid() {
+ Customer c = Customer.builder().build();
+ UUID before = c.getId();
- Customer customer = Customer.builder()
- .id(id)
- .firstName(firstName)
- .lastName(lastName)
- .phoneNumber(phoneNumber)
- .loyaltyPoints(loyaltyPoints)
- .build();
+ c.setRandomUUID();
- assertEquals(id, customer.getId());
- assertEquals(firstName, customer.getFirstName());
- assertEquals(lastName, customer.getLastName());
- assertEquals(phoneNumber, customer.getPhoneNumber());
- assertEquals(loyaltyPoints, customer.getLoyaltyPoints());
+ assertNotNull(c.getId());
+ assertNotEquals(before, c.getId());
}
@Test
- @DisplayName("setRandomUUID should change the ID to a new random UUID")
- void testSetRandomUUID() {
- Customer customer = Customer.builder().build();
- UUID originalId = customer.getId();
+ @DisplayName("Builder assigns all fields correctly")
+ void buildsCustomerCorrectly() {
+ UUID id = UUID.randomUUID();
+ String fn = "Alice";
+ String ln = "MaFemme";
+ String phone = "0123456789";
+ int points = 120;
- customer.setRandomUUID();
+ Customer c = Customer.builder()
+ .id(id)
+ .firstName(fn)
+ .lastName(ln)
+ .phoneNumber(phone)
+ .loyaltyPoints(points)
+ .build();
- assertNotNull(customer.getId());
- assertNotEquals(originalId, customer.getId());
+ assertEquals(id, c.getId());
+ assertEquals(fn, c.getFirstName());
+ assertEquals(ln, c.getLastName());
+ assertEquals(phone, c.getPhoneNumber());
+ assertEquals(points, c.getLoyaltyPoints());
}
@Nested
- @DisplayName("Loyalty Points Tests")
- class LoyaltyPointsTests {
+ @DisplayName("Points Operations")
+ class Points {
@Test
- @DisplayName("addLoyaltyPoints should correctly increment loyalty points")
- void testAddLoyaltyPoints() {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
- int pointsToAdd = 25;
- int expectedPoints = 75;
+ @DisplayName("Adds loyalty points to current total")
+ void addsPointsCorrectly() {
+ Customer c = Customer.builder().loyaltyPoints(40).build();
- customer.addLoyaltyPoints(pointsToAdd);
+ c.addLoyaltyPoints(35);
- assertEquals(expectedPoints, customer.getLoyaltyPoints());
+ assertEquals(75, c.getLoyaltyPoints());
}
@Test
- @DisplayName("addLoyaltyPoints should handle zero points correctly")
- void testAddZeroLoyaltyPoints() {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
+ @DisplayName("Adds zero points without affecting total")
+ void addsZero() {
+ Customer c = Customer.builder().loyaltyPoints(60).build();
- customer.addLoyaltyPoints(0);
+ c.addLoyaltyPoints(0);
- assertEquals(50, customer.getLoyaltyPoints());
+ assertEquals(60, c.getLoyaltyPoints());
}
@Test
- @DisplayName("removeLoyaltyPoints should correctly decrement loyalty points")
- void testRemoveLoyaltyPoints() throws IllegalCustomerPointException {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
- int pointsToRemove = 20;
- int expectedPoints = 30;
+ @DisplayName("Removes loyalty points successfully")
+ void removesPointsCorrectly() throws IllegalCustomerPointException {
+ Customer c = Customer.builder().loyaltyPoints(90).build();
- customer.removeLoyaltyPoints(pointsToRemove);
+ c.removeLoyaltyPoints(40);
- assertEquals(expectedPoints, customer.getLoyaltyPoints());
+ assertEquals(50, c.getLoyaltyPoints());
}
@Test
- @DisplayName("removeLoyaltyPoints should handle removing exactly all points")
- void testRemoveAllLoyaltyPoints() throws IllegalCustomerPointException {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
+ @DisplayName("Removes exactly all loyalty points")
+ void removesAllPoints() throws IllegalCustomerPointException {
+ Customer c = Customer.builder().loyaltyPoints(30).build();
- customer.removeLoyaltyPoints(50);
+ c.removeLoyaltyPoints(30);
- assertEquals(0, customer.getLoyaltyPoints());
+ assertEquals(0, c.getLoyaltyPoints());
}
@Test
- @DisplayName("removeLoyaltyPoints should throw exception when trying to remove more points than available")
- void testRemoveTooManyLoyaltyPoints() {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
- int pointsToRemove = 75;
+ @DisplayName("Fails when trying to remove more points than available")
+ void failsOnOverRemoval() {
+ Customer c = Customer.builder().loyaltyPoints(45).build();
- IllegalCustomerPointException exception = assertThrows(
- IllegalCustomerPointException.class,
- () -> customer.removeLoyaltyPoints(pointsToRemove)
+ IllegalCustomerPointException ex = assertThrows(
+ IllegalCustomerPointException.class,
+ () -> c.removeLoyaltyPoints(100)
);
- assertEquals(50, customer.getLoyaltyPoints());
-
- assertTrue(exception.getMessage().contains(String.valueOf(pointsToRemove)));
- assertTrue(exception.getMessage().contains(String.valueOf(customer.getLoyaltyPoints())));
+ assertEquals(45, c.getLoyaltyPoints());
+ assertTrue(ex.getMessage().contains("100"));
+ assertTrue(ex.getMessage().contains("45"));
}
@Test
- @DisplayName("removeLoyaltyPoints should handle removing zero points correctly")
- void testRemoveZeroLoyaltyPoints() throws IllegalCustomerPointException {
- Customer customer = Customer.builder()
- .loyaltyPoints(50)
- .build();
+ @DisplayName("Removes zero points without affecting total")
+ void removesZero() throws IllegalCustomerPointException {
+ Customer c = Customer.builder().loyaltyPoints(15).build();
- customer.removeLoyaltyPoints(0);
+ c.removeLoyaltyPoints(0);
- assertEquals(50, customer.getLoyaltyPoints());
+ assertEquals(15, c.getLoyaltyPoints());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/CustomerNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/CustomerNotFoundExceptionTest.java
index fcde9da..5cd0e55 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/CustomerNotFoundExceptionTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/CustomerNotFoundExceptionTest.java
@@ -5,45 +5,43 @@ import org.junit.jupiter.api.Test;
import java.util.UUID;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
class CustomerNotFoundExceptionTest {
@Test
- @DisplayName("Exception message should contain the UUID provided")
- void testExceptionMessageContainsUUID() {
- UUID uuid = UUID.randomUUID();
-
- CustomerNotFoundException exception = new CustomerNotFoundException(uuid);
-
- String expectedMessage = String.format("The customer with id %s does not exist", uuid);
- assertEquals(expectedMessage, exception.getMessage());
- }
-
- @Test
- @DisplayName("Exception should use the correct constant message format")
- void testExceptionUsesConstantMessageFormat() {
- UUID uuid = UUID.randomUUID();
-
- CustomerNotFoundException exception = new CustomerNotFoundException(uuid);
-
- String expectedFormatWithPlaceholder = "The customer with id {0} does not exist";
- assertEquals(CustomerNotFoundException.THE_CUSTOMER_WITH_ID_DOES_NOT_EXIST_MESSAGE,
- expectedFormatWithPlaceholder);
- assertTrue(exception.getMessage().contains(uuid.toString()));
- }
-
- @Test
- @DisplayName("Exception should be properly thrown and caught")
- void testExceptionCanBeThrownAndCaught() {
- UUID uuid = UUID.randomUUID();
+ @DisplayName("Should throw and catch properly with expected message")
+ void throwsAndCatchesCorrectly() {
+ UUID id = UUID.randomUUID();
try {
- throw new CustomerNotFoundException(uuid);
- } catch (CustomerNotFoundException e) {
- String expectedMessage = String.format("The customer with id %s does not exist", uuid);
- assertEquals(expectedMessage, e.getMessage());
+ throw new CustomerNotFoundException(id);
+ } catch (CustomerNotFoundException ex) {
+ String expected = String.format("The customer with id %s does not exist", id);
+ assertEquals(expected, ex.getMessage());
}
}
-}
\ No newline at end of file
+
+ @Test
+ @DisplayName("Should format using predefined message constant")
+ void usesStaticMessageTemplate() {
+ UUID id = UUID.randomUUID();
+
+ CustomerNotFoundException ex = new CustomerNotFoundException(id);
+
+ String template = "The customer with id {0} does not exist";
+ assertEquals(CustomerNotFoundException.THE_CUSTOMER_WITH_ID_DOES_NOT_EXIST_MESSAGE, template);
+ assertTrue(ex.getMessage().contains(id.toString()));
+ }
+
+ @Test
+ @DisplayName("Should include UUID in exception message")
+ void includesUuidInMessage() {
+ UUID id = UUID.randomUUID();
+
+ CustomerNotFoundException ex = new CustomerNotFoundException(id);
+
+ String expected = String.format("The customer with id %s does not exist", id);
+ assertEquals(expected, ex.getMessage());
+ }
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/IllegalCustomerPointExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/IllegalCustomerPointExceptionTest.java
index c89306c..97d69de 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/IllegalCustomerPointExceptionTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/IllegalCustomerPointExceptionTest.java
@@ -6,64 +6,63 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
class IllegalCustomerPointExceptionTest {
@Test
- @DisplayName("Exception message should contain the needed and actual points")
- void testExceptionMessageContainsPoints() {
- int neededPoints = 100;
- int actualPoints = 50;
+ @DisplayName("Throws and catches the exception with expected output")
+ void throwsAndCatchesCorrectly() {
+ int required = 100;
+ int current = 50;
- IllegalCustomerPointException exception = new IllegalCustomerPointException(neededPoints, actualPoints);
-
- String expectedMessage = "Cannot remove 100 points from 50 points";
- assertEquals(expectedMessage, exception.getMessage());
+ try {
+ throw new IllegalCustomerPointException(required, current);
+ } catch (IllegalCustomerPointException ex) {
+ String expected = String.format("Cannot remove %d points from %d points", required, current);
+ assertEquals(expected, ex.getMessage());
+ }
}
@ParameterizedTest
@CsvSource({
- "100, 50",
- "75, 25",
- "200, 150",
- "1000, 750"
+ "100, 50",
+ "200, 100",
+ "300, 299",
+ "75, 10"
})
- @DisplayName("Exception message should be formatted correctly for different point values")
- void testExceptionMessageForDifferentPointValues(int neededPoints, int actualPoints) {
- IllegalCustomerPointException exception = new IllegalCustomerPointException(neededPoints, actualPoints);
+ @DisplayName("Formats message correctly for varied values")
+ void formatsMessageWithVariousValues(int required, int available) {
+ IllegalCustomerPointException ex = new IllegalCustomerPointException(required, available);
- String expectedMessage = MessageFormat.format(IllegalCustomerPointException.CANNOT_REMOVE_LOYALTY_POINTS, neededPoints, actualPoints);
- assertEquals(expectedMessage, exception.getMessage());
+ String expected = MessageFormat.format(
+ IllegalCustomerPointException.CANNOT_REMOVE_LOYALTY_POINTS, required, available);
+ assertEquals(expected, ex.getMessage());
}
@Test
- @DisplayName("Exception should use the correct constant message format")
- void testExceptionUsesConstantMessageFormat() {
- int neededPoints = 100;
- int actualPoints = 50;
+ @DisplayName("Message includes needed and actual points")
+ void includesCorrectValuesInMessage() {
+ int required = 150;
+ int actual = 30;
- IllegalCustomerPointException exception = new IllegalCustomerPointException(neededPoints, actualPoints);
+ IllegalCustomerPointException ex = new IllegalCustomerPointException(required, actual);
- String expectedFormatWithPlaceholder = "Cannot remove {0} points from {1} points";
- assertEquals(IllegalCustomerPointException.CANNOT_REMOVE_LOYALTY_POINTS,
- expectedFormatWithPlaceholder);
- assertTrue(exception.getMessage().contains(String.valueOf(neededPoints)));
- assertTrue(exception.getMessage().contains(String.valueOf(actualPoints)));
+ String expected = "Cannot remove 150 points from 30 points";
+ assertEquals(expected, ex.getMessage());
}
@Test
- @DisplayName("Exception should be properly thrown and caught")
- void testExceptionCanBeThrownAndCaught() {
- int neededPoints = 100;
- int actualPoints = 50;
+ @DisplayName("Uses the correct message constant structure")
+ void checksMessageConstantTemplate() {
+ int needed = 100;
+ int current = 50;
- try {
- throw new IllegalCustomerPointException(neededPoints, actualPoints);
- } catch (IllegalCustomerPointException e) {
- String expectedMessage = String.format("Cannot remove %d points from %d points", neededPoints, actualPoints);
- assertEquals(expectedMessage, e.getMessage());
- }
+ IllegalCustomerPointException ex = new IllegalCustomerPointException(needed, current);
+
+ String template = "Cannot remove {0} points from {1} points";
+ assertEquals(IllegalCustomerPointException.CANNOT_REMOVE_LOYALTY_POINTS, template);
+ assertTrue(ex.getMessage().contains(String.valueOf(needed)));
+ assertTrue(ex.getMessage().contains(String.valueOf(current)));
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/NotValidCustomerExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/NotValidCustomerExceptionTest.java
index 3fba6e1..b3034c1 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/NotValidCustomerExceptionTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/exception/NotValidCustomerExceptionTest.java
@@ -5,57 +5,56 @@ 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;
+import static org.junit.jupiter.api.Assertions.*;
class NotValidCustomerExceptionTest {
@Test
- @DisplayName("Exception should be created with the provided message")
- void testExceptionCreation() {
- String errorMessage = "Customer data is not valid";
+ @DisplayName("Throws and catches with exact error message")
+ void throwsAndMatchesMessage() {
+ String message = "Missing field: phone";
- NotValidCustomerException exception = new NotValidCustomerException(errorMessage);
+ Exception ex = assertThrows(NotValidCustomerException.class, () -> {
+ throw new NotValidCustomerException(message);
+ });
- assertEquals(errorMessage, exception.getMessage());
+ assertEquals(message, ex.getMessage());
+ }
+
+ @Test
+ @DisplayName("Can be caught as base Exception type")
+ void caughtAsGenericException() {
+ String msg = "Invalid structure";
+
+ try {
+ throw new NotValidCustomerException(msg);
+ } catch (Exception e) {
+ assertEquals(NotValidCustomerException.class, e.getClass());
+ assertEquals(msg, e.getMessage());
+ }
}
@ParameterizedTest
@ValueSource(strings = {
- "First name is required",
- "Last name cannot be empty",
- "Phone number format is invalid",
- "Customer age must be above 18"
+ "Invalid phone format",
+ "Missing last name",
+ "Empty input received",
+ "ID is malformed"
})
- @DisplayName("Exception should handle different validation messages")
- void testExceptionWithDifferentMessages(String errorMessage) {
- NotValidCustomerException exception = new NotValidCustomerException(errorMessage);
+ @DisplayName("Handles multiple input error messages")
+ void handlesVariousMessages(String msg) {
+ NotValidCustomerException ex = new NotValidCustomerException(msg);
- assertEquals(errorMessage, exception.getMessage());
+ assertEquals(msg, ex.getMessage());
}
@Test
- @DisplayName("Exception should be properly thrown and caught")
- void testExceptionCanBeThrownAndCaught() {
- String errorMessage = "Required field is missing";
+ @DisplayName("Stores the message it was created with")
+ void storesGivenMessage() {
+ String msg = "Required field not provided";
- Exception exception = assertThrows(NotValidCustomerException.class, () -> {
- throw new NotValidCustomerException(errorMessage);
- });
+ NotValidCustomerException ex = new NotValidCustomerException(msg);
- assertEquals(errorMessage, exception.getMessage());
+ assertEquals(msg, ex.getMessage());
}
-
- @Test
- @DisplayName("Exception should be catchable as a general Exception")
- void testExceptionInheritance() {
- String errorMessage = "Invalid customer data";
-
- try {
- throw new NotValidCustomerException(errorMessage);
- } catch (Exception e) {
- assertEquals(NotValidCustomerException.class, e.getClass());
- assertEquals(errorMessage, e.getMessage());
- }
- }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/repository/CustomerRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/repository/CustomerRepositoryTest.java
deleted file mode 100644
index 4495493..0000000
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/repository/CustomerRepositoryTest.java
+++ /dev/null
@@ -1,227 +0,0 @@
-package fr.iut_fbleau.but3.dev62.mylibrary.customer.repository;
-
-import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
-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.*;
-
-class CustomerRepositoryTest {
-
- private CustomerRepository repository;
- private Customer customer1;
- private Customer customer2;
-
- @BeforeEach
- void setUp() {
- repository = new CustomerRepository();
-
- customer1 = Customer.builder()
- .firstName("John")
- .lastName("Doe")
- .phoneNumber("0123456789")
- .loyaltyPoints(100)
- .build();
- customer1.setRandomUUID();
-
- customer2 = Customer.builder()
- .firstName("Jane")
- .lastName("Smith")
- .phoneNumber("9876543210")
- .loyaltyPoints(200)
- .build();
- customer2.setRandomUUID();
- }
-
- @Test
- @DisplayName("New repository should be empty")
- void testNewRepositoryIsEmpty() {
- List customers = repository.findAll();
-
- assertTrue(customers.isEmpty());
- assertEquals(0, customers.size());
- }
-
- @Nested
- @DisplayName("Save operations")
- class SaveOperations {
-
- @Test
- @DisplayName("Save should add a new customer")
- void testSaveNewCustomer() {
- Customer savedCustomer = repository.save(customer1);
-
- assertEquals(1, repository.findAll().size());
- assertEquals(customer1.getId(), savedCustomer.getId());
- assertEquals(customer1.getFirstName(), savedCustomer.getFirstName());
- }
-
- @Test
- @DisplayName("Save should update existing customer with same ID")
- void testSaveUpdatesExistingCustomer() {
- repository.save(customer1);
-
- UUID id = customer1.getId();
- Customer updatedCustomer = Customer.builder()
- .id(id)
- .firstName("John")
- .lastName("Updated")
- .phoneNumber("1111111111")
- .loyaltyPoints(150)
- .build();
-
- Customer savedCustomer = repository.save(updatedCustomer);
-
- assertEquals(1, repository.findAll().size());
- assertEquals(id, savedCustomer.getId());
- assertEquals("Updated", savedCustomer.getLastName());
- assertEquals("1111111111", savedCustomer.getPhoneNumber());
- assertEquals(150, savedCustomer.getLoyaltyPoints());
- }
-
- @Test
- @DisplayName("Save multiple customers should add all of them")
- void testSaveMultipleCustomers() {
- repository.save(customer1);
- repository.save(customer2);
-
- List customers = repository.findAll();
-
- assertEquals(2, customers.size());
- assertTrue(customers.contains(customer1));
- assertTrue(customers.contains(customer2));
- }
- }
-
- @Nested
- @DisplayName("Find operations")
- class FindOperations {
-
- @BeforeEach
- void setUpCustomers() {
- repository.save(customer1);
- repository.save(customer2);
- }
-
- @Test
- @DisplayName("FindAll should return all customers")
- void testFindAll() {
- List customers = repository.findAll();
-
- assertEquals(2, customers.size());
- assertTrue(customers.contains(customer1));
- assertTrue(customers.contains(customer2));
- }
-
- @Test
- @DisplayName("FindById should return customer with matching ID")
- void testFindById() {
- Optional foundCustomer = repository.findById(customer1.getId());
-
- assertTrue(foundCustomer.isPresent());
- assertEquals(customer1.getFirstName(), foundCustomer.get().getFirstName());
- assertEquals(customer1.getLastName(), foundCustomer.get().getLastName());
- }
-
- @Test
- @DisplayName("FindById should return empty Optional when ID doesn't exist")
- void testFindByIdNotFound() {
- UUID nonExistentId = UUID.randomUUID();
-
- Optional foundCustomer = repository.findById(nonExistentId);
-
- assertTrue(foundCustomer.isEmpty());
- }
-
- @Test
- @DisplayName("FindByPhoneNumber should return customer with matching phone number")
- void testFindByPhoneNumber() {
- Optional foundCustomer = repository.findByPhoneNumber("0123456789");
-
- assertTrue(foundCustomer.isPresent());
- assertEquals(customer1.getId(), foundCustomer.get().getId());
- assertEquals(customer1.getFirstName(), foundCustomer.get().getFirstName());
- }
-
- @Test
- @DisplayName("FindByPhoneNumber should return empty Optional when phone number doesn't exist")
- void testFindByPhoneNumberNotFound() {
- Optional foundCustomer = repository.findByPhoneNumber("0000000000");
-
- assertTrue(foundCustomer.isEmpty());
- }
-
- @Test
- @DisplayName("ExistsById should return true when ID exists")
- void testExistsByIdExists() {
- boolean exists = repository.existsById(customer1.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);
- }
- }
-
- @Nested
- @DisplayName("Delete operations")
- class DeleteOperations {
-
- @BeforeEach
- void setUpCustomers() {
- repository.save(customer1);
- repository.save(customer2);
- }
-
- @Test
- @DisplayName("Delete should remove the specified customer")
- void testDelete() {
- repository.delete(customer1);
-
- List customers = repository.findAll();
-
- assertEquals(1, customers.size());
- assertFalse(customers.contains(customer1));
- assertTrue(customers.contains(customer2));
- }
-
- @Test
- @DisplayName("DeleteAll should remove all customers")
- void testDeleteAll() {
- repository.deleteAll();
-
- List customers = repository.findAll();
-
- assertTrue(customers.isEmpty());
- assertEquals(0, customers.size());
- }
-
- @Test
- @DisplayName("Delete should not throw exception when customer doesn't exist")
- void testDeleteNonExistentCustomer() {
- Customer nonExistentCustomer = Customer.builder()
- .firstName("Non")
- .lastName("Existent")
- .phoneNumber("0000000000")
- .build();
- nonExistentCustomer.setRandomUUID();
-
- assertDoesNotThrow(() -> repository.delete(nonExistentCustomer));
-
- assertEquals(2, repository.findAll().size());
- }
- }
-}
\ No newline at end of file
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCaseTest.java
index 7159bdb..ef3921a 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCaseTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/usecase/CustomerUseCaseTest.java
@@ -20,260 +20,185 @@ 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)
class CustomerUseCaseTest {
@Mock
- private CustomerRepository customerRepository;
+ private CustomerRepository repo;
@InjectMocks
- private CustomerUseCase customerUseCase;
+ private CustomerUseCase useCase;
- private UUID customerId;
- private Customer testCustomer;
- private CustomerInfo validCustomerInfo;
+ private UUID uid;
+ private Customer base;
+ private CustomerInfo input;
@BeforeEach
- void setUp() {
- customerId = UUID.randomUUID();
- testCustomer = Customer.builder()
- .id(customerId)
- .firstName("John")
- .lastName("Doe")
- .phoneNumber("0612345678")
- .loyaltyPoints(100)
- .build();
+ void setup() {
+ uid = UUID.randomUUID();
+ base = Customer.builder()
+ .id(uid)
+ .firstName("John")
+ .lastName("Doe")
+ .phoneNumber("0612345678")
+ .loyaltyPoints(100)
+ .build();
- validCustomerInfo = new CustomerInfo("John", "Doe", "0612345678");
+ input = new CustomerInfo("John", "Doe", "0612345678");
}
@Nested
- @DisplayName("Register customer tests")
- class RegisterCustomerTests {
+ class Creation {
@Test
- @DisplayName("Should register customer when valid data is provided")
- void testRegisterCustomerWithValidData() throws NotValidCustomerException {
- when(customerRepository.save(any(Customer.class))).thenReturn(testCustomer);
+ void createWithValidInput() throws NotValidCustomerException {
+ when(repo.save(any())).thenReturn(base);
- UUID registeredId = customerUseCase.registerCustomer(validCustomerInfo);
+ UUID result = useCase.create(input);
- assertNotNull(registeredId);
- assertEquals(customerId, registeredId);
- verify(customerRepository, times(1)).save(any(Customer.class));
+ assertEquals(uid, result);
+ verify(repo).save(any());
}
@Test
- @DisplayName("Should throw exception when customer data is not valid")
- void testRegisterCustomerWithInvalidData() {
- CustomerInfo invalidCustomerInfo = new CustomerInfo("", "", "");
+ void createWithInvalidInputThrows() {
+ CustomerInfo broken = new CustomerInfo("", "", "");
- assertThrows(NotValidCustomerException.class,
- () -> customerUseCase.registerCustomer(invalidCustomerInfo));
-
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(NotValidCustomerException.class, () -> useCase.create(broken));
+ verify(repo, never()).save(any());
}
}
@Nested
- @DisplayName("Find customer tests")
- class FindCustomerTests {
+ class Retrieval {
@Test
- @DisplayName("Should return customer when phone number exists")
- void testFindCustomerByPhoneNumber() {
- when(customerRepository.findByPhoneNumber("0612345678")).thenReturn(Optional.of(testCustomer));
+ void getByPhoneSuccess() {
+ when(repo.findByPhoneNumber("0612345678")).thenReturn(Optional.of(base));
- Optional foundCustomer = customerUseCase.findCustomerByPhoneNumber("0612345678");
+ Optional result = useCase.getByPhone("0612345678");
- assertTrue(foundCustomer.isPresent());
- assertEquals(testCustomer.getId(), foundCustomer.get().getId());
- assertEquals(testCustomer.getFirstName(), foundCustomer.get().getFirstName());
- verify(customerRepository, times(1)).findByPhoneNumber("0612345678");
+ assertTrue(result.isPresent());
+ assertEquals(uid, result.get().getId());
}
@Test
- @DisplayName("Should return empty Optional when phone number doesn't exist")
- void testFindCustomerByPhoneNumberNotFound() {
- when(customerRepository.findByPhoneNumber("0799999999")).thenReturn(Optional.empty());
+ void getByPhoneFails() {
+ when(repo.findByPhoneNumber("0799999999")).thenReturn(Optional.empty());
- Optional foundCustomer = customerUseCase.findCustomerByPhoneNumber("0799999999");
+ Optional result = useCase.getByPhone("0799999999");
- assertTrue(foundCustomer.isEmpty());
- verify(customerRepository, times(1)).findByPhoneNumber("0799999999");
+ assertTrue(result.isEmpty());
}
}
@Nested
- @DisplayName("Update customer tests")
- class UpdateCustomerTests {
+ class Modification {
@Test
- @DisplayName("Should update customer when valid data is provided")
- void testUpdateCustomerWithValidData() throws CustomerNotFoundException, NotValidCustomerException {
- when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
+ void modifyValid() throws CustomerNotFoundException, NotValidCustomerException {
+ when(repo.findById(uid)).thenReturn(Optional.of(base));
- Customer updatedCustomer = Customer.builder()
- .id(customerId)
- .firstName("John")
- .lastName("Updated")
- .phoneNumber("0712345678")
- .loyaltyPoints(100)
- .build();
+ Customer updated = Customer.builder()
+ .id(uid)
+ .firstName("John")
+ .lastName("Smith")
+ .phoneNumber("0712345678")
+ .loyaltyPoints(100)
+ .build();
- when(customerRepository.save(any(Customer.class))).thenReturn(updatedCustomer);
+ when(repo.save(any())).thenReturn(updated);
- CustomerInfo updateInfo = new CustomerInfo("John", "Updated", "0712345678");
+ CustomerInfo updateInfo = new CustomerInfo("John", "Smith", "0712345678");
- CustomerDTO result = customerUseCase.updateCustomer(customerId, updateInfo);
+ CustomerDTO dto = useCase.modify(uid, updateInfo);
- assertNotNull(result);
- assertEquals(customerId, result.getId());
- assertEquals("Updated", result.getLastName());
- assertEquals("0712345678", result.getPhoneNumber());
- verify(customerRepository, times(1)).findById(customerId);
- verify(customerRepository, times(1)).save(any(Customer.class));
+ assertEquals("Smith", dto.getLastName());
+ assertEquals("0712345678", dto.getPhoneNumber());
}
@Test
- @DisplayName("Should throw exception when customer ID doesn't exist")
- void testUpdateCustomerNotFound() {
- UUID nonExistentId = UUID.randomUUID();
- when(customerRepository.findById(nonExistentId)).thenReturn(Optional.empty());
+ void modifyNotFound() {
+ when(repo.findById(uid)).thenReturn(Optional.empty());
- CustomerInfo updateInfo = new CustomerInfo("John", "Updated", "0712345678");
+ CustomerInfo info = new CustomerInfo("John", "Smith", "0712345678");
- assertThrows(CustomerNotFoundException.class,
- () -> customerUseCase.updateCustomer(nonExistentId, updateInfo));
-
- verify(customerRepository, times(1)).findById(nonExistentId);
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(CustomerNotFoundException.class, () -> useCase.modify(uid, info));
}
@Test
- @DisplayName("Should throw exception when update data is not valid")
- void testUpdateCustomerWithInvalidData() {
- CustomerInfo invalidUpdateInfo = new CustomerInfo("", "", "");
+ void modifyInvalidInput() {
+ CustomerInfo bad = new CustomerInfo("", "", "");
- assertThrows(NotValidCustomerException.class,
- () -> customerUseCase.updateCustomer(customerId, invalidUpdateInfo));
-
- verify(customerRepository, never()).findById(any(UUID.class));
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(NotValidCustomerException.class, () -> useCase.modify(uid, bad));
}
}
@Nested
- @DisplayName("Delete customer tests")
- class DeleteCustomerTests {
+ class Deletion {
@Test
- @DisplayName("Should delete customer when ID exists")
- void testDeleteCustomer() throws CustomerNotFoundException {
- when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
- doNothing().when(customerRepository).delete(testCustomer);
+ void removeSuccess() throws CustomerNotFoundException {
+ when(repo.findById(uid)).thenReturn(Optional.of(base));
+ doNothing().when(repo).delete(base);
- customerUseCase.deleteCustomer(customerId);
+ useCase.remove(uid);
- verify(customerRepository, times(1)).findById(customerId);
- verify(customerRepository, times(1)).delete(testCustomer);
+ verify(repo).delete(base);
}
@Test
- @DisplayName("Should throw exception when customer ID doesn't exist")
- void testDeleteCustomerNotFound() {
- UUID nonExistentId = UUID.randomUUID();
- when(customerRepository.findById(nonExistentId)).thenReturn(Optional.empty());
+ void removeNotFound() {
+ when(repo.findById(uid)).thenReturn(Optional.empty());
- assertThrows(CustomerNotFoundException.class,
- () -> customerUseCase.deleteCustomer(nonExistentId));
-
- verify(customerRepository, times(1)).findById(nonExistentId);
- verify(customerRepository, never()).delete(any(Customer.class));
+ assertThrows(CustomerNotFoundException.class, () -> useCase.remove(uid));
}
}
@Nested
- @DisplayName("Loyalty points tests")
- class LoyaltyPointsTests {
+ class Points {
@Test
- @DisplayName("Should add loyalty points to customer")
- void testAddLoyaltyPoints() throws CustomerNotFoundException {
- when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
- when(customerRepository.save(testCustomer)).thenReturn(testCustomer);
+ void increasePointsValid() throws CustomerNotFoundException {
+ when(repo.findById(uid)).thenReturn(Optional.of(base));
+ when(repo.save(base)).thenReturn(base);
- int initialPoints = testCustomer.getLoyaltyPoints();
- int pointsToAdd = 50;
- int expectedPoints = initialPoints + pointsToAdd;
+ int result = useCase.increasePoints(uid, 25);
- int newPoints = customerUseCase.addLoyaltyPoints(customerId, pointsToAdd);
-
- assertEquals(expectedPoints, newPoints);
- assertEquals(expectedPoints, testCustomer.getLoyaltyPoints());
- verify(customerRepository, times(1)).findById(customerId);
- verify(customerRepository, times(1)).save(testCustomer);
+ assertEquals(125, result);
}
@Test
- @DisplayName("Should throw exception when adding points to non-existent customer")
- void testAddLoyaltyPointsToNonExistentCustomer() {
- UUID nonExistentId = UUID.randomUUID();
- when(customerRepository.findById(nonExistentId)).thenReturn(Optional.empty());
+ void increasePointsNotFound() {
+ when(repo.findById(uid)).thenReturn(Optional.empty());
- assertThrows(CustomerNotFoundException.class,
- () -> customerUseCase.addLoyaltyPoints(nonExistentId, 50));
-
- verify(customerRepository, times(1)).findById(nonExistentId);
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(CustomerNotFoundException.class, () -> useCase.increasePoints(uid, 25));
}
@Test
- @DisplayName("Should subtract loyalty points from customer")
- void testSubtractLoyaltyPoints() throws CustomerNotFoundException, IllegalCustomerPointException {
- when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
- when(customerRepository.save(testCustomer)).thenReturn(testCustomer);
+ void decreasePointsValid() throws CustomerNotFoundException, IllegalCustomerPointException {
+ when(repo.findById(uid)).thenReturn(Optional.of(base));
+ when(repo.save(base)).thenReturn(base);
- int initialPoints = testCustomer.getLoyaltyPoints();
- int pointsToRemove = 30;
- int expectedPoints = initialPoints - pointsToRemove;
+ int result = useCase.decreasePoints(uid, 40);
- int newPoints = customerUseCase.subtractLoyaltyPoints(customerId, pointsToRemove);
-
- assertEquals(expectedPoints, newPoints);
- assertEquals(expectedPoints, testCustomer.getLoyaltyPoints());
- verify(customerRepository, times(1)).findById(customerId);
- verify(customerRepository, times(1)).save(testCustomer);
+ assertEquals(60, result);
}
@Test
- @DisplayName("Should throw exception when trying to remove more points than available")
- void testSubtractTooManyLoyaltyPoints() {
- when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
+ void decreasePointsTooMuch() {
+ when(repo.findById(uid)).thenReturn(Optional.of(base));
- int pointsToRemove = 200;
-
- assertThrows(IllegalCustomerPointException.class,
- () -> customerUseCase.subtractLoyaltyPoints(customerId, pointsToRemove));
-
- verify(customerRepository, times(1)).findById(customerId);
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(IllegalCustomerPointException.class, () -> useCase.decreasePoints(uid, 999));
}
@Test
- @DisplayName("Should throw exception when subtracting points from non-existent customer")
- void testSubtractLoyaltyPointsFromNonExistentCustomer() {
- UUID nonExistentId = UUID.randomUUID();
- when(customerRepository.findById(nonExistentId)).thenReturn(Optional.empty());
+ void decreasePointsNotFound() {
+ when(repo.findById(uid)).thenReturn(Optional.empty());
- assertThrows(CustomerNotFoundException.class,
- () -> customerUseCase.subtractLoyaltyPoints(nonExistentId, 50));
-
- verify(customerRepository, times(1)).findById(nonExistentId);
- verify(customerRepository, never()).save(any(Customer.class));
+ assertThrows(CustomerNotFoundException.class, () -> useCase.decreasePoints(uid, 20));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidatorTest.java
index 29bb954..a706423 100644
--- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidatorTest.java
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/validator/CustomerValidatorTest.java
@@ -13,143 +13,109 @@ import static org.junit.jupiter.api.Assertions.*;
class CustomerValidatorTest {
@Test
- @DisplayName("Should validate customer with valid data")
- void testValidateValidCustomer() {
- CustomerInfo validCustomer = new CustomerInfo("John", "Doe", "0612345678");
+ @DisplayName("Valid customer should pass without error")
+ void passesWithValidInput() {
+ CustomerInfo valid = new CustomerInfo("Alice", "Smith", "0612345678");
- assertDoesNotThrow(() -> CustomerValidator.validate(validCustomer));
+ assertDoesNotThrow(() -> CustomerValidator.check(valid));
}
@Nested
- @DisplayName("First name validation tests")
- class FirstNameValidationTests {
+ class FirstName {
@Test
- @DisplayName("Should throw exception when first name is blank")
- void testValidateBlankFirstName() {
- CustomerInfo customerWithBlankFirstName = new CustomerInfo("", "Doe", "0612345678");
+ void rejectsBlankFirstName() {
+ CustomerInfo data = new CustomerInfo("", "Smith", "0612345678");
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithBlankFirstName)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals(CustomerValidator.FIRST_NAME_CANNOT_BE_BLANK, exception.getMessage());
+ assertEquals(CustomerValidator.ERROR_FIRSTNAME_EMPTY, ex.getMessage());
}
@ParameterizedTest
- @ValueSource(strings = {" ", " ", "\t", "\n"})
- @DisplayName("Should throw exception when first name contains only whitespace")
- void testValidateWhitespaceFirstName(String whitespace) {
- CustomerInfo customerWithWhitespaceFirstName = new CustomerInfo(whitespace, "Doe", "0612345678");
+ @ValueSource(strings = {" ", "\t", "\n"})
+ void rejectsWhitespaceOnly(String blank) {
+ CustomerInfo data = new CustomerInfo(blank, "Smith", "0612345678");
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithWhitespaceFirstName)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals(CustomerValidator.FIRST_NAME_CANNOT_BE_BLANK, exception.getMessage());
+ assertEquals(CustomerValidator.ERROR_FIRSTNAME_EMPTY, ex.getMessage());
}
}
@Nested
- @DisplayName("Last name validation tests")
- class LastNameValidationTests {
+ class LastName {
@Test
- @DisplayName("Should throw exception when last name is blank")
- void testValidateBlankLastName() {
- CustomerInfo customerWithBlankLastName = new CustomerInfo("John", "", "0612345678");
+ void rejectsBlankLastName() {
+ CustomerInfo data = new CustomerInfo("Alice", "", "0612345678");
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithBlankLastName)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals(CustomerValidator.LAST_NAME_CANNOT_BE_BLANK, exception.getMessage());
+ assertEquals(CustomerValidator.ERROR_LASTNAME_EMPTY, ex.getMessage());
}
@ParameterizedTest
- @ValueSource(strings = {" ", " ", "\t", "\n"})
- @DisplayName("Should throw exception when last name contains only whitespace")
- void testValidateWhitespaceLastName(String whitespace) {
- CustomerInfo customerWithWhitespaceLastName = new CustomerInfo("John", whitespace, "0612345678");
+ @ValueSource(strings = {" ", "\t", "\n"})
+ void rejectsWhitespaceLastName(String blank) {
+ CustomerInfo data = new CustomerInfo("Alice", blank, "0612345678");
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithWhitespaceLastName)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals(CustomerValidator.LAST_NAME_CANNOT_BE_BLANK, exception.getMessage());
+ assertEquals(CustomerValidator.ERROR_LASTNAME_EMPTY, ex.getMessage());
}
}
@Nested
- @DisplayName("Phone number validation tests")
- class PhoneNumberValidationTests {
+ class PhoneNumber {
@Test
- @DisplayName("Should throw exception when phone number is blank")
- void testValidateBlankPhoneNumber() {
- CustomerInfo customerWithBlankPhoneNumber = new CustomerInfo("John", "Doe", "");
+ void rejectsEmptyPhone() {
+ CustomerInfo data = new CustomerInfo("Alice", "Smith", "");
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithBlankPhoneNumber)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals("Phone number cannot be blank", exception.getMessage());
+ assertEquals("Phone number cannot be blank", ex.getMessage());
}
@ParameterizedTest
- @ValueSource(strings = {" ", " ", "\t", "\n"})
- @DisplayName("Should throw exception when phone number contains only whitespace")
- void testValidateWhitespacePhoneNumber(String whitespace) {
- CustomerInfo customerWithWhitespacePhoneNumber = new CustomerInfo("John", "Doe", whitespace);
+ @ValueSource(strings = {" ", "\t", "\n"})
+ void rejectsBlankPhone(String blank) {
+ CustomerInfo data = new CustomerInfo("Alice", "Smith", blank);
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithWhitespacePhoneNumber)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals("Phone number cannot be blank", exception.getMessage());
+ assertEquals("Phone number cannot be blank", ex.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {
- "0512345678", // Invalid prefix (not 06 or 07)
- "0812345678", // Invalid prefix (not 06 or 07)
- "061234567", // Too short (missing one digit)
- "06123456789", // Too long (one extra digit)
- "6123456789", // Missing leading 0
- "O612345678", // Letter O instead of zero
- "+33612345678", // International format not supported
- "06 12 34 56 78" // Contains spaces
+ "0512345678", "0812345678", "061234567", "06123456789",
+ "6123456789", "O612345678", "+33612345678", "06 12 34 56 78"
})
- @DisplayName("Should throw exception when phone number format is invalid")
- void testValidateInvalidPhoneNumberFormat(String invalidPhoneNumber) {
- CustomerInfo customerWithInvalidPhoneNumber = new CustomerInfo("John", "Doe", invalidPhoneNumber);
+ void rejectsInvalidPhoneFormat(String phone) {
+ CustomerInfo data = new CustomerInfo("Alice", "Smith", phone);
- NotValidCustomerException exception = assertThrows(
- NotValidCustomerException.class,
- () -> CustomerValidator.validate(customerWithInvalidPhoneNumber)
- );
+ NotValidCustomerException ex = assertThrows(NotValidCustomerException.class,
+ () -> CustomerValidator.check(data));
- assertEquals(CustomerValidator.PHONE_NUMBER_IS_NOT_VALID, exception.getMessage());
+ assertEquals(CustomerValidator.ERROR_PHONE_INVALID, ex.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {
- "0612345678", // Valid 06 number
- "0712345678", // Valid 07 number
- "0699999999", // Valid 06 number with all 9s
- "0700000000" // Valid 07 number with all 0s
+ "0612345678", "0712345678", "0699999999", "0700000000"
})
- @DisplayName("Should validate when phone number format is valid")
- void testValidateValidPhoneNumberFormat(String validPhoneNumber) {
- CustomerInfo customerWithValidPhoneNumber = new CustomerInfo("John", "Doe", validPhoneNumber);
+ void acceptsValidPhoneFormat(String phone) {
+ CustomerInfo data = new CustomerInfo("Alice", "Smith", phone);
- assertDoesNotThrow(() -> CustomerValidator.validate(customerWithValidPhoneNumber));
+ assertDoesNotThrow(() -> CustomerValidator.check(data));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java
new file mode 100644
index 0000000..a43a2df
--- /dev/null
+++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/book/BookSteps.java
@@ -0,0 +1,320 @@
+package fr.iut_fbleau.but3.dev62.mylibrary.features.book;
+
+import io.cucumber.datatable.DataTable;
+import io.cucumber.java.en.And;
+import io.cucumber.java.en.Given;
+import io.cucumber.java.en.Then;
+import io.cucumber.java.en.When;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
+import fr.iut_fbleau.but3.dev62.mylibrary.book.usecase.BookUseCase;
+
+public class BookSteps {
+
+ private final BookRepository bookRepository = new BookRepository();
+ private final BookUseCase bookUseCase = new BookUseCase(bookRepository);
+
+ private String bookRegistration;
+ private BookDTO bookByIsbn;
+ private BookDTO updatedBook;
+ private String deletedBookIsbn;
+ private Exception storedException;
+ private List booksPageResult;
+ private int totalBooks;
+ private int totalPages;
+ private List filteredBooksResult;
+ private NotValidBookException notValidBookException;
+
+ @Given("Le systeme possedent les livres suivants :")
+ public void leSystemePossedeLesLivresSuivants(DataTable dataTable) {
+ bookRepository.deleteAll();
+ List