Compare commits

...

16 Commits

77 changed files with 4992 additions and 34 deletions

View File

@@ -0,0 +1,23 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book;
import lombok.Builder;
import lombok.Getter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Date;
@Builder
@Getter
public class BookDTO {
private final String isbn;
private final String title;
private final String author;
private final String publisher;
private final Date date;
private final double price;
private final int initialStock;
private final ArrayList<String> categories;
private final String description;
private final String language;
}

View File

@@ -0,0 +1,17 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book;
import java.util.ArrayList;
import java.util.Date;
public record BookInfo(String isbn,
String title,
String author,
String publisher,
Date date,
double price,
int initialStock,
ArrayList<String>categories,
String description,
String language){
}

View File

@@ -0,0 +1,44 @@
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;
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;
public final class BookConverter {
private BookConverter(){
}
public static Book toDomain(BookInfo newBook) {
return Book.builder()
.isbn(newBook.isbn())
.title(newBook.title())
.author(newBook.author())
.publisher(newBook.publisher())
.date(newBook.date())
.price(newBook.price())
.initialStock(newBook.initialStock())
.categories(newBook.categories())
.description(newBook.description())
.language(newBook.language())
.build();
}
public static BookDTO toDTO(Book book) {
return BookDTO.builder()
.isbn(book.getIsbn())
.title(book.getTitle())
.author(book.getAuthor())
.publisher(book.getPublisher())
.date(book.getDate())
.price(book.getPrice())
.initialStock(book.getInitialStock())
.categories(book.getCategories())
.description(book.getDescription())
.language(book.getLanguage())
.build();
}
}

View File

@@ -0,0 +1,37 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.IllegalBookStockException;
import lombok.Builder;
import lombok.Getter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Date;
@Builder
@Getter
public class Book {
private String isbn;
private String title;
private String author;
private String publisher;
private Date date;
private double price;
private int initialStock;
private ArrayList<String> categories;
private String description;
private String language;
public void removeStock(int stockToRemove) throws IllegalBookStockException{
if (initialStock - stockToRemove <0){ throw new IllegalBookStockException(stockToRemove,initialStock); }
initialStock = initialStock - stockToRemove;
}
public void addStock(int stockToAdd) {
initialStock = initialStock + stockToAdd;
}
}

View File

@@ -0,0 +1,13 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import java.text.MessageFormat;
import java.util.UUID;
public class BookNotFoundException extends Exception {
public static final String THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE = "Book not found: {0}";
public BookNotFoundException(String isbn) {
super(MessageFormat.format(THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE, isbn));
}
}

View File

@@ -0,0 +1,13 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import java.text.MessageFormat;
public class IllegalBookStockException extends Exception {
public static final String CANNOT_REMOVE_STOCK = "Cannot remove {0} stock from {1} stock";
public IllegalBookStockException(int needed, int actual) {
super(MessageFormat.format(CANNOT_REMOVE_STOCK, needed,
actual));
}
}

View File

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

View File

@@ -0,0 +1,55 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.NoArgsConstructor;
import javax.swing.text.html.Option;
@NoArgsConstructor
public final class BookRepository {
private final List<Book> books = new ArrayList<>();
public List<Book> findAll() {
return books;
}
public void deleteAll() {
books.clear();
}
public Book save(Book newBook) {
for (Book book: books) {
if (book.getIsbn().equals(newBook.getIsbn())){
books.remove(book);
break;
}
}
this.books.add(newBook);
return newBook;
}
public Optional<Book> findByISBN(String isbn) {
for (Book book:books) {
System.out.println(book.getIsbn());
if(book.getIsbn().equals(isbn)){
return Optional.of(book);
}
}
return Optional.empty();
}
public boolean existsByISBN(String isbn) {
return this.books.stream()
.anyMatch(book -> book.getIsbn().equals(isbn));
}
public void delete(Book book) {
this.books.remove(book);
}
}

View File

@@ -0,0 +1,85 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.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.IllegalBookStockException;
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.util.Optional;
import java.util.UUID;
public final class BookUseCase {
private final BookRepository bookRepository;
public BookUseCase(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public String registerBook(BookInfo newBook) throws NotValidBookException {
BookValidator.validate(newBook);
Book bookToRegister = BookConverter.toDomain(newBook);
bookRepository.save(bookToRegister);
return bookToRegister.getIsbn();
}
public Optional<BookDTO> findBookByISBN(String isbn) {
System.out.println(bookRepository.findAll().size());
Optional<Book> optionalBook = bookRepository.findByISBN(isbn);
return optionalBook.map(BookConverter::toDTO);
}
public BookDTO updateBook(String isbn, BookInfo bookInfo)
throws BookNotFoundException, NotValidBookException {
BookValidator.validate(bookInfo);
Book bookByISBN = getBookIfDoesNotExistThrowBookNotFoundException(
isbn);
Book book = Book.builder()
.isbn(isbn)
.title(bookInfo.title())
.author(bookInfo.author())
.publisher(bookInfo.publisher())
.date(bookInfo.date())
.price(bookInfo.price())
.initialStock(bookInfo.initialStock())
.categories(bookInfo.categories())
.description(bookInfo.description())
.language(bookInfo.language())
.build();
Book updatedBook = bookRepository.save(book);
return BookConverter.toDTO(updatedBook);
}
public void deleteBook(String isbn) throws BookNotFoundException {
Book bookToDelete = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
this.bookRepository.delete(bookToDelete);
}
public int addStock(String isbn, int stockToAdd) throws BookNotFoundException {
Book bookToAddStock = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
bookToAddStock.addStock(stockToAdd);
bookRepository.save(bookToAddStock);
return bookToAddStock.getInitialStock();
}
public int subtractStock(String isbn, int loyaltyPointToRemove)
throws BookNotFoundException, IllegalBookStockException {
Book bookToSubtractStock = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
bookToSubtractStock.removeStock(loyaltyPointToRemove);
bookRepository.save(bookToSubtractStock);
return bookToSubtractStock.getInitialStock();
}
private Book getBookIfDoesNotExistThrowBookNotFoundException(String isbn)
throws BookNotFoundException {
Optional<Book> optionalBookById = bookRepository.findByISBN(isbn);
if (optionalBookById.isEmpty()) {
throw new BookNotFoundException(isbn);
}
return optionalBookById.get();
}
}

View File

@@ -0,0 +1,74 @@
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.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
public final class BookValidator {
public static final String ISBN_IS_NOT_VALID = "ISBN is not valid";
public static final String ISBN_CANNOT_BE_BLANK = "ISBN cannot be blank";
public static final String TITLE_CANNOT_BE_BLANK = "Title cannot be blank";
public static final String AUTHOR_CANNOT_BE_BLANK = "Author cannot be blank";
public static final String PUBLISHER_CANNOT_BE_BLANK = "Publisher cannot be blank";
public static final String PRICE_CANNOT_BE_NEGATIVE = "Price cannot be negative";
public static final String PRICE_CANNOT_BE_EQUAL_TO_ZERO = "Price cannot be equal to zero";
public static final String INITIAL_STOCK_CANNOT_BE_NEGATIVE = "Stock cannot be negative";
public static final String ISBN_REGEX = "\\d{13}";
private BookValidator() {
}
public static void validate(BookInfo newBook) throws NotValidBookException {
validateAuthor(newBook);
validateTitle(newBook);
validatePublisher(newBook);
validateISBN(newBook);
validatePrice(newBook);
validateInitialStock(newBook);
}
private static void validateISBN(BookInfo newBook)
throws NotValidBookException {
if (newBook.isbn().isBlank()) {
throw new NotValidBookException(ISBN_CANNOT_BE_BLANK);
}
if (!newBook.isbn().matches(ISBN_REGEX)) {
throw new NotValidBookException(ISBN_IS_NOT_VALID);
}
}
private static void validateTitle(BookInfo newBook) throws NotValidBookException {
if (newBook.title().isBlank()) {
throw new NotValidBookException(TITLE_CANNOT_BE_BLANK);
}
}
private static void validateAuthor(BookInfo newBook) throws NotValidBookException {
if (newBook.author().isBlank()) {
throw new NotValidBookException(AUTHOR_CANNOT_BE_BLANK);
}
}
private static void validatePublisher(BookInfo newBook) throws NotValidBookException {
if (newBook.publisher().isBlank()){
throw new NotValidBookException(PUBLISHER_CANNOT_BE_BLANK);
}
}
private static void validatePrice(BookInfo newBook) throws NotValidBookException {
if (newBook.price() < 0){
throw new NotValidBookException(PRICE_CANNOT_BE_NEGATIVE);
} else if (newBook.price() == 0){
throw new NotValidBookException(PRICE_CANNOT_BE_EQUAL_TO_ZERO);
}
}
private static void validateInitialStock(BookInfo newBook) throws NotValidBookException {
if (newBook.initialStock() < 0){
throw new NotValidBookException(INITIAL_STOCK_CANNOT_BE_NEGATIVE);
}
}
}

View File

@@ -8,6 +8,7 @@ import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class Customer { public class Customer {
private UUID id; private UUID id;
private String firstName; private String firstName;

View File

@@ -20,15 +20,23 @@ public final class CustomerRepository {
} }
public Customer save(Customer newCustomer) { public Customer save(Customer newCustomer) {
Optional<Customer> optionalCustomerWithSameId = this.findById(newCustomer.getId()); if (newCustomer.getId() == null) {
optionalCustomerWithSameId.ifPresentOrElse(customers::remove, newCustomer::setRandomUUID); newCustomer.setRandomUUID();
}
this.findById(newCustomer.getId()).ifPresent(customers::remove);
this.customers.add(newCustomer); this.customers.add(newCustomer);
return newCustomer; return newCustomer;
} }
public Optional<Customer> findById(UUID uuid) { public Optional<Customer> findById(UUID uuid) {
if (uuid == null) {
return Optional.empty();
}
return this.customers.stream() return this.customers.stream()
.filter(customer -> customer.getId().equals(uuid)) .filter(customer -> uuid.equals(customer.getId()))
.findFirst(); .findFirst();
} }

View File

@@ -0,0 +1,13 @@
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;
}

View File

@@ -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 List<OrderLineDTO> orderLines;
private final double totalPrice;
private final double totalPriceToPay;
private final AddressDTO address;
private final PaymentMethod paymentMethod;
}

View File

@@ -0,0 +1,17 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.UUID;
@Getter
@Setter
@Builder
public class OrderInfo {
private UUID customerId;
private List<OrderLineDTO> orderLines;
private AddressDTO address;
private String paymentMethod;
}

View File

@@ -0,0 +1,11 @@
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;
}

View File

@@ -0,0 +1,6 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order;
public enum PaymentMethod {
CREDIT_CARD,
LOYALTY_POINTS
}

View File

@@ -0,0 +1,35 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.converter;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AddressDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
public class OrderConverter {
private OrderConverter() {
}
public static Order toDomain(OrderInfo orderInfo) {
return Order.builder()
.customerId(orderInfo.getCustomerId())
.orderLines(orderInfo.getOrderLines())
.address(orderInfo.getAddress())
.paymentMethod(PaymentMethod.valueOf(orderInfo.getPaymentMethod()))
.build();
}
public static OrderDTO toDTO(Order order) {
return OrderDTO.builder()
.id(order.getId())
.customerId(order.getCustomerId())
.orderLines(order.getOrderLines())
.totalPrice(order.getTotalPrice())
.totalPriceToPay(order.getTotalPriceToPay())
.address(order.getAddress())
.paymentMethod(order.getPaymentMethod())
.build();
}
}

View File

@@ -0,0 +1,27 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
import fr.iut_fbleau.but3.dev62.mylibrary.order.*;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.UUID;
@Setter
@Getter
@Builder
public class Order {
private UUID id;
private UUID customerId;
private List<OrderLineDTO> orderLines;
private double totalPrice;
private double totalPriceToPay;
private AddressDTO address;
private PaymentMethod paymentMethod;
public void setRandomUUID() {
this.id = UUID.randomUUID();
}
}

View File

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

View File

@@ -0,0 +1,13 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
import java.text.MessageFormat;
import java.util.UUID;
public class OrderNotFoundException extends Exception {
public static final String THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The order with id {0} does not exist";
public OrderNotFoundException(String message) {
super(MessageFormat.format(THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE, message));
}
}

View File

@@ -0,0 +1,9 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,49 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public final class OrderRepository {
private final List<Order> orders = new ArrayList<>();
public List<Order> findAll() {
return orders;
}
public Order save(Order newOrder) {
Optional<Order> optionalOrderWithSameId = this.findById(newOrder.getId());
optionalOrderWithSameId.ifPresent(orders::remove);
if (newOrder.getId() == null) {
newOrder.setRandomUUID();
}
this.orders.add(newOrder);
return newOrder;
}
public Optional<Order> findById(UUID uuid) {
return this.orders.stream()
.filter(order -> order.getId().equals(uuid))
.findFirst();
}
public List<Order> findByCustomerId(UUID customerId) {
List<Order> result = new ArrayList<>();
for (Order order : orders) {
if (order.getCustomerId().equals(customerId)) {
result.add(order);
}
}
return result;
}
public boolean existsById(UUID uuid) {
return this.orders.stream()
.anyMatch(order -> order.getId().equals(uuid));
}
}

View File

@@ -0,0 +1,193 @@
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.exception.IllegalBookStockException;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.IllegalCustomerPointException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import fr.iut_fbleau.but3.dev62.mylibrary.order.usecase.OrderUseCase;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AddressDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.converter.OrderConverter;
import fr.iut_fbleau.but3.dev62.mylibrary.order.validator.OrderValidator;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.OrderNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.UserNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
import java.util.*;
import java.util.stream.Collectors;
public class OrderUseCase {
private final OrderRepository orderRepository;
private final BookRepository bookRepository;
private final CustomerRepository customerRepository;
private OrderInfo tempOrderInfo;
private List<OrderLineDTO> tempOrderLines;
private AddressDTO tempAddress;
public OrderUseCase(OrderRepository orderRepository, BookRepository bookRepository, CustomerRepository customerRepository) {
this.orderRepository = orderRepository;
this.bookRepository = bookRepository;
this.customerRepository = customerRepository;
}
public void registerOrderInfo(OrderInfo orderInfo) {
this.tempOrderInfo = orderInfo;
}
public void addBooksToOrder(List<OrderLineDTO> orderLines) throws NotValidOrderException {
this.tempOrderLines = orderLines;
}
public void setDeliveryAddress(AddressDTO address) {
this.tempAddress = address;
}
private double computeTotalPrice(List<OrderLineDTO> orderInfo) throws NotValidOrderException {
if (orderInfo == null || orderInfo.isEmpty()) {
throw new NotValidOrderException("Order lines cannot be null or empty");
}
double totalPrice = 0.0;
for (OrderLineDTO line : orderInfo) {
Book book = bookRepository.findByISBN(line.getBookId())
.orElseThrow(() -> new NotValidOrderException("Book not found with ISBN: " + line.getBookId()));
totalPrice += book.getPrice() * line.getQuantity();
}
return totalPrice;
}
public UUID finalizeOrder() throws NotValidOrderException, UserNotFoundException, BookNotFoundException, IllegalBookStockException, IllegalCustomerPointException {
// Validation des données d'entrée
OrderInfo completeInfo = validateAndBuildOrderInfo();
// Récupération du client
Customer customer = customerRepository.findById(completeInfo.getCustomerId())
.orElseThrow(() -> new UserNotFoundException("Client introuvable"));
// Traitement des livres et calcul du prix
double totalPrice = processOrderLines(completeInfo.getOrderLines());
// Gestion du paiement
handlePayment(completeInfo, customer, totalPrice);
// Création et sauvegarde de la commande
UUID orderId = createAndSaveOrder(completeInfo, totalPrice);
// Nettoyage des données temporaires
resetTempData();
return orderId;
}
private OrderInfo validateAndBuildOrderInfo() throws NotValidOrderException, BookNotFoundException {
if (tempOrderInfo == null) throw new NotValidOrderException("Order info missing");
OrderInfo completeInfo = OrderInfo.builder()
.customerId(tempOrderInfo.getCustomerId())
.paymentMethod(tempOrderInfo.getPaymentMethod())
.orderLines(tempOrderLines)
.address(tempAddress)
.build();
// Validation centralisée
OrderValidator.validate(completeInfo, bookRepository, customerRepository);
return completeInfo;
}
private double processOrderLines(List<OrderLineDTO> orderLines) throws BookNotFoundException, IllegalBookStockException {
double totalPrice = 0.0;
for (OrderLineDTO line : orderLines) {
Book book = getBookOrThrow(line.getBookId());
updateBookStock(book, line.getQuantity());
totalPrice += calculateLinePrice(book, line.getQuantity());
}
return totalPrice;
}
private Book getBookOrThrow(String bookId) throws BookNotFoundException {
return bookRepository.findByISBN(bookId)
.orElseThrow(() -> new BookNotFoundException("Livre non trouvé: " + bookId));
}
private void updateBookStock(Book book, int quantity) throws IllegalBookStockException {
book.removeStock(quantity);
bookRepository.save(book);
}
private double calculateLinePrice(Book book, int quantity) {
return book.getPrice() * quantity;
}
private void handlePayment(OrderInfo orderInfo, Customer customer, double totalPrice) throws IllegalCustomerPointException {
if (isLoyaltyPointsPayment(orderInfo)) {
deductLoyaltyPoints(customer, totalPrice);
}
}
private boolean isLoyaltyPointsPayment(OrderInfo orderInfo) {
return "LOYALTY_POINTS".equalsIgnoreCase(orderInfo.getPaymentMethod());
}
private void deductLoyaltyPoints(Customer customer, double totalPrice) throws IllegalCustomerPointException {
int pointsToDeduct = (int) Math.round(totalPrice);
customer.removeLoyaltyPoints(pointsToDeduct);
customerRepository.save(customer);
}
private UUID createAndSaveOrder(OrderInfo orderInfo, double totalPrice) throws NotValidOrderException {
Order order = OrderConverter.toDomain(orderInfo);
order.setRandomUUID();
order.setAddress(tempAddress);
order.setOrderLines(tempOrderLines);
order.setTotalPrice(totalPrice);
order.setTotalPriceToPay(totalPrice);
orderRepository.save(order);
return order.getId();
}
private void resetTempData() {
tempOrderInfo = null;
tempOrderLines = null;
tempAddress = null;
}
public Optional<OrderDTO> findOrderById(UUID orderId) {
Optional<Order> order = orderRepository.findById(orderId);
return order.map(OrderConverter::toDTO);
}
public List<OrderDTO> findOrdersByCustomerId(UUID customerId) throws UserNotFoundException {
ensureCustomerExists(customerId);
List<Order> orders = orderRepository.findByCustomerId(customerId);
return orders.stream().map(OrderConverter::toDTO).collect(Collectors.toList());
}
private void ensureCustomerExists(UUID customerId) throws UserNotFoundException {
if (!customerRepository.findById(customerId).isPresent()) {
throw new UserNotFoundException("Customer not found");
}
}
public UUID registerOrder(OrderInfo orderInfo) throws NotValidOrderException, UserNotFoundException, BookNotFoundException {
OrderValidator.validate(orderInfo, bookRepository, customerRepository);
double total = computeTotalPrice(orderInfo.getOrderLines());
Order order = OrderConverter.toDomain(orderInfo);
order.setTotalPrice(total);
order.setTotalPriceToPay(total);
order.setRandomUUID();
orderRepository.save(order);
return order.getId();
}
}

View File

@@ -0,0 +1,135 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.validator;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AddressDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
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.exception.UserNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
import lombok.SneakyThrows;
import java.util.List;
public class OrderValidator {
public static final String CUSTOMER_ID_CANNOT_BE_NULL = "Customer ID cannot be null";
public static final String BOOK_LIST_CANNOT_BE_EMPTY = "Book list cannot be empty";
public static final String QUANTITY_MUST_BE_POSITIVE = "Quantity must be positive";
public static final String ADDRESS_FIELDS_ARE_REQUIRED = "Address fields are required";
public static final String PAYMENT_METHOD_IS_NOT_VALID = "Payment method is not valid";
private OrderValidator() {
}
public static void validate(OrderInfo orderInfo, BookRepository bookRepository, CustomerRepository customerRepository)
throws NotValidOrderException, UserNotFoundException, BookNotFoundException {
validateCustomerId(orderInfo);
Customer customer = validateCustomerExistence(orderInfo, customerRepository);
double totalPrice = validateBooksAndStock(orderInfo, bookRepository);
validateOrderLines(orderInfo);
validateAddress(orderInfo);
validatePaymentMethod(orderInfo);
validateLoyaltyPoints(orderInfo, customer, totalPrice);
}
private static Customer validateCustomerExistence(OrderInfo orderInfo, CustomerRepository customerRepository)
throws UserNotFoundException {
Customer customer = customerRepository.findById(orderInfo.getCustomerId()).orElse(null);
if (customer == null) {
throw new UserNotFoundException("Customer not found");
}
return customer;
}
private static double validateBooksAndStock(OrderInfo orderInfo, BookRepository bookRepository)
throws BookNotFoundException, NotValidOrderException {
double totalPrice = 0.0;
for (OrderLineDTO line : orderInfo.getOrderLines()) {
Book book = getBookOrThrow(line, bookRepository);
validateQuantityPositive(line);
validateStockSufficient(book, line);
totalPrice += book.getPrice() * line.getQuantity();
}
return totalPrice;
}
private static Book getBookOrThrow(OrderLineDTO line, BookRepository bookRepository) throws BookNotFoundException {
Book book = bookRepository.findByISBN(line.getBookId()).orElse(null);
if (book == null) {
throw new BookNotFoundException(line.getBookId());
}
return book;
}
private static void validateQuantityPositive(OrderLineDTO line) throws NotValidOrderException {
if (line.getQuantity() <= 0) {
throw new NotValidOrderException(QUANTITY_MUST_BE_POSITIVE);
}
}
private static void validateStockSufficient(Book book, OrderLineDTO line) throws NotValidOrderException {
if (book.getInitialStock() < line.getQuantity()) {
throw new NotValidOrderException("Insufficient book stock");
}
}
private static void validateLoyaltyPoints(OrderInfo orderInfo, Customer customer, double totalPrice)
throws NotValidOrderException {
if ("LOYALTY_POINTS".equalsIgnoreCase(orderInfo.getPaymentMethod())) {
int pointsToDeduct = (int) Math.round(totalPrice);
if (customer.getLoyaltyPoints() < pointsToDeduct) {
throw new NotValidOrderException("Not enough loyalty points");
}
}
}
private static void validateCustomerId(OrderInfo orderInfo) throws NotValidOrderException {
if (orderInfo.getCustomerId() == null) {
throw new NotValidOrderException(CUSTOMER_ID_CANNOT_BE_NULL);
}
}
private static void validateOrderLines(OrderInfo orderInfo) throws NotValidOrderException {
List<OrderLineDTO> lines = orderInfo.getOrderLines();
if (lines == null || lines.isEmpty()) {
throw new NotValidOrderException(BOOK_LIST_CANNOT_BE_EMPTY);
}
for (OrderLineDTO line : lines) {
validateOrderLine(line);
}
}
private static void validateOrderLine(OrderLineDTO line) throws NotValidOrderException {
validateQuantityPositive(line);
}
private static void validateAddress(OrderInfo orderInfo) throws NotValidOrderException {
AddressDTO address = orderInfo.getAddress();
if (address == null) {
throw new NotValidOrderException(ADDRESS_FIELDS_ARE_REQUIRED);
}
validateAddressFields(address);
}
private static void validateAddressFields(AddressDTO address) throws NotValidOrderException {
if (isBlank(address.getStreet()) || isBlank(address.getCity()) || isBlank(address.getPostalCode()) || isBlank(address.getCountry())) {
throw new NotValidOrderException(ADDRESS_FIELDS_ARE_REQUIRED);
}
}
private static boolean isBlank(String value) {
return value == null || value.isBlank();
}
private static void validatePaymentMethod(OrderInfo orderInfo) throws NotValidOrderException {
String method = orderInfo.getPaymentMethod();
if (method == null || method.isBlank() || !(method.equals("CREDIT_CARD") || method.equals("LOYALTY_POINTS"))) {
throw new NotValidOrderException(PAYMENT_METHOD_IS_NOT_VALID);
}
}
}

View File

@@ -0,0 +1,18 @@
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 String bookId; // Changed from long to String
private final String customerName;
private final String comment;
private final int rating;
}

View File

@@ -0,0 +1,15 @@
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 String isbn; // Changed from long to String
private final int rating;
private final String comment;
}

View File

@@ -0,0 +1,28 @@
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()) // Changed from long to String
.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()) // Changed from long to String
.rating(info.getRating())
.comment(info.getComment())
.build();
}
}

View File

@@ -0,0 +1,20 @@
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 String isbn; // Changed from long to String
private int rating;
private String comment;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,43 @@
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<Review> reviews = new ArrayList<>();
public void save(Review review) {
reviews.add(review);
}
public List<Review> findAll() {
return new ArrayList<>(reviews);
}
public List<Review> findByIsbn(String isbn) { // Changed from long to String
return reviews.stream().filter(r -> r.getIsbn().equals(isbn)).collect(Collectors.toList());
}
public List<Review> findByCustomerId(UUID customerId) {
return reviews.stream().filter(r -> r.getCustomerId().equals(customerId)).collect(Collectors.toList());
}
public boolean existsByCustomerIdAndIsbn(UUID customerId, String isbn) { // Changed from long to String
return reviews.stream().anyMatch(r -> r.getCustomerId().equals(customerId) && r.getIsbn().equals(isbn));
}
public void deleteByCustomerIdAndIsbn(UUID customerId, String isbn) { // Changed from long to String
reviews.removeIf(r -> r.getCustomerId().equals(customerId) && r.getIsbn().equals(isbn));
}
public void update(Review review) {
deleteByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn());
save(review);
}
public void deleteAll() {
reviews.clear();
}
}

View File

@@ -0,0 +1,73 @@
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 submitReview(Review review) throws CustomerNotFoundException, BookNotFoundException {
ReviewValidator.validate(review);
System.out.println(bookRepository.existsByISBN(review.getIsbn()));
System.out.println(customerRepository.existsById(review.getCustomerId()));
System.out.println(customerRepository.findById(review.getCustomerId()));
System.out.println(reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn()));
if (!bookRepository.existsByISBN(review.getIsbn())) {
throw new BookNotFoundException(review.getIsbn());
}
if (!customerRepository.existsById(review.getCustomerId())) {
throw new CustomerNotFoundException(review.getCustomerId());
}
if (reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) {
throw new ReviewAlreadyExistsException("Review already exists for this customer and book.");
}
reviewRepository.save(review);
}
public List<Review> getReviewsByBook(String isbn) { // Changed from long to String
return reviewRepository.findByIsbn(isbn);
}
public List<Review> getReviewsByCustomer(UUID customerId) {
return reviewRepository.findByCustomerId(customerId);
}
public void updateReview(Review review) {
ReviewValidator.validate(review);
if (!reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) { // Changed from long to String
throw new ReviewNotFoundException("Review not found for this customer and book.");
}
reviewRepository.update(review);
}
public void deleteReview(String isbn, UUID customerId) { // Changed from long to String
if (!reviewRepository.existsByCustomerIdAndIsbn(customerId, isbn)) { // Changed from long to String
throw new ReviewNotFoundException("Review not found for this customer and book.");
}
reviewRepository.deleteByCustomerIdAndIsbn(customerId, isbn);
}
}

View File

@@ -0,0 +1,46 @@
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 final String ISBN_IS_NOT_VALID = "ISBN must be a valid 13-digit string";
public static void validate(Review review) {
validateReviewNotNull(review);
validateRating(review);
validateComment(review);
validateCustomerId(review);
validateBookIsbn(review);
}
private static void validateReviewNotNull(Review review) throws IllegalArgumentException {
if (review == null) {
throw new IllegalArgumentException("Review cannot be null");
}
}
private static void validateRating(Review review) throws InvalidReviewRatingException {
if (review.getRating() < 1 || review.getRating() > 5) {
throw new InvalidReviewRatingException("Rating must be between 1 and 5");
}
}
private static void validateComment(Review review) throws IllegalArgumentException {
if (review.getComment() == null || review.getComment().trim().isEmpty()) {
throw new IllegalArgumentException("Comment cannot be empty");
}
}
private static void validateCustomerId(Review review) throws IllegalArgumentException {
if (review.getCustomerId() == null) {
throw new IllegalArgumentException("Customer ID cannot be null");
}
}
private static void validateBookIsbn(Review review) throws IllegalArgumentException {
if (review.getIsbn() == null || !review.getIsbn().matches("\\d{13}")) {
throw new IllegalArgumentException(ISBN_IS_NOT_VALID);
}
}
}

View File

@@ -5,8 +5,9 @@ import java.util.UUID;
public class SubscriptionNotFoundException extends Exception { public class SubscriptionNotFoundException extends Exception {
public static final String THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The customer with id {0} does not exist"; public static final String THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The subscription with id {0} does not exist";
public SubscriptionNotFoundException(UUID uuid) { public SubscriptionNotFoundException(UUID uuid) {
super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid));
} }
} }

View File

@@ -28,6 +28,12 @@ public class SubscriptionRepository {
.findFirst(); .findFirst();
} }
public Optional<Subscription> findById(UUID id) {
return this.subscriptions.stream()
.filter(subscription -> subscription.getId().equals(id))
.findFirst();
}
public boolean existsById(UUID uuid) { public boolean existsById(UUID uuid) {
return this.subscriptions.stream() return this.subscriptions.stream()
.anyMatch(subscription -> subscription.getId().equals(uuid)); .anyMatch(subscription -> subscription.getId().equals(uuid));

View File

@@ -17,19 +17,25 @@ public class SubscriptionValidator {
} }
public static void validate(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException { public static void validate(SubscriptionInfo newSubscription) throws NotValidSubscriptionException {
validateCustomerId(newSubscription);
validateDuration(newSubscription); validateDuration(newSubscription);
validatePaymentMethod(newSubscription); validatePaymentMethod(newSubscription);
} }
private static void validateCustomerId(SubscriptionInfo newSubscription) throws NotValidSubscriptionException {
private static void validateDuration(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException { if (newSubscription.customerId() == null) {
if (newSubscription.duration() == null) { throw new NotValidSubscriptionException(CUSTOMER_ID_CANNOT_BE_NULL);
throw new fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException(DURATION_CANNOT_BE_NULL);
} }
} }
private static void validatePaymentMethod(SubscriptionInfo newSubscription) throws fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception.NotValidSubscriptionException { private static void validateDuration(SubscriptionInfo newSubscription) throws NotValidSubscriptionException {
if (newSubscription.duration() == null) {
throw new NotValidSubscriptionException(DURATION_CANNOT_BE_NULL);
}
}
private static void validatePaymentMethod(SubscriptionInfo newSubscription) throws NotValidSubscriptionException {
if (newSubscription.paymentMethod().isBlank()) { if (newSubscription.paymentMethod().isBlank()) {
throw new NotValidSubscriptionException(PAYMENT_METHOD_CANNOT_BE_BLANK); throw new NotValidSubscriptionException(PAYMENT_METHOD_CANNOT_BE_BLANK);
} }

View File

@@ -0,0 +1,138 @@
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.converter.BookConverter;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertNull;
@DisplayName("BookConverter Unit Tests")
public class BookConverterTest {
@Nested
@DisplayName("toDomain() method tests")
class ToDomainTests {
@Test
@DisplayName("Should convert BookInfo to Book domain object")
void shouldConvertBookInfoToDomain() {
// Given
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookInfo = new BookInfo("1234567891234", "Livre", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
// When
Book result = BookConverter.toDomain(bookInfo);
// Then
assertNotNull(result);
assertEquals(bookInfo.isbn(), result.getIsbn());
assertEquals(bookInfo.title(), result.getTitle());
assertEquals(bookInfo.author(), result.getAuthor());
assertEquals(bookInfo.publisher(), result.getPublisher());
assertEquals(bookInfo.date(), result.getDate());
assertEquals(bookInfo.price(), result.getPrice());
assertEquals(bookInfo.initialStock(), result.getInitialStock());
assertEquals(bookInfo.categories(), result.getCategories());
assertEquals(bookInfo.description(), result.getDescription());
assertEquals(bookInfo.language(), result.getLanguage());
}
}
@Nested
@DisplayName("toDTO() method tests")
class ToDTOTests {
@Test
@DisplayName("Should convert Book domain object to BookDTO with all fields mapped correctly")
void shouldConvertBookToDTO() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
Book book = Book.builder()
.isbn("1234567890123")
.title("Livre 1")
.author("John Updated")
.publisher("Editeur")
.date(Date.from(Instant.now()))
.price(4.99)
.initialStock(42)
.categories(categories)
.description("Description")
.language("Francais")
.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.getDate(), result.getDate());
assertEquals(book.getPrice(), result.getPrice());
assertEquals(book.getInitialStock(), result.getInitialStock());
assertEquals(book.getCategories(), result.getCategories());
assertEquals(book.getDescription(), result.getDescription());
assertEquals(book.getLanguage(), result.getLanguage());
}
}
@Test
@DisplayName("Should handle null values properly when converting between objects")
void shouldHandleNullValuesGracefully() {
Book book = Book.builder()
.isbn("1234567890123")
.title("Null")
.author("Null")
.publisher("Null")
.date(null)
.price(4.99)
.initialStock(42)
.categories(null)
.description(null)
.language(null)
.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());
assertNull(result.getDate());
assertEquals(book.getPrice(), result.getPrice());
assertEquals(book.getInitialStock(), result.getInitialStock());
assertNull(result.getCategories());
assertNull(result.getDescription());
assertNull(result.getLanguage());
}
@Test
@DisplayName("Should preserve empty string values during conversion")
void shouldPreserveEmptyStrings() {
BookInfo bookInfo = new BookInfo("1234567890123", "e", "e","e",null,1.2,5,null,"","");
Book domainResult = BookConverter.toDomain(bookInfo);
BookDTO result = BookConverter.toDTO(domainResult);
assertEquals(bookInfo.isbn(), result.getIsbn()); //ISBN ne peut pas etre vide
assertEquals(bookInfo.title(), result.getTitle()); // Le titre ne peut pas etre vide
assertEquals(bookInfo.author(), result.getAuthor()); // L'auteur ne peut pas etre vide
assertEquals(bookInfo.publisher(), result.getPublisher()); // L'editeur ne peut pas etre vide
assertEquals(null, result.getDate());
assertEquals(bookInfo.price(), result.getPrice());
assertEquals(bookInfo.initialStock(), result.getInitialStock());
assertEquals(null, result.getCategories());
assertEquals("", result.getDescription());
assertEquals("", result.getLanguage());
}
}

View File

@@ -0,0 +1,232 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.IllegalBookStockException;
import io.cucumber.java.bs.A;
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.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
class BookTest {
@Test
@DisplayName("Builder should create a valid Book instance")
void testBookBuilder() {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 15;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
assertEquals(ISBN, book.getIsbn());
assertEquals(title, book.getTitle());
assertEquals(author, book.getAuthor());
assertEquals(publisher, book.getPublisher());
assertEquals(date, book.getDate());
assertEquals(price, book.getPrice());
assertEquals(initialStock, book.getInitialStock());
assertEquals(categories, book.getCategories());
assertEquals(description, book.getDescription());
assertEquals(language, book.getLanguage());
}
@Nested
@DisplayName("Book stock Tests")
class BookStockTests {
@Test
@DisplayName("addStock should correctly increment stock")
void testAddStock() {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 50;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
int stockToAdd = 25;
int expectedStock = 75;
book.addStock(stockToAdd);
assertEquals(expectedStock, book.getInitialStock());
}
@Test
@DisplayName("addStock should handle zero points correctly")
void testAddZeroStock() {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 50;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
book.addStock(0);
assertEquals(50, book.getInitialStock());
}
@Test
@DisplayName("removeStock should correctly decrement points")
void testRemoveStock() throws IllegalBookStockException {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 50;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
int stockToRemove = 20;
int expectedStock = 30;
book.removeStock(stockToRemove);
assertEquals(expectedStock, book.getInitialStock());
}
@Test
@DisplayName("removeStock should throw exception when trying to remove more points than available")
void testRemoveTooManyStock() {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 50;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
int pointsToRemove = 75;
IllegalBookStockException exception = assertThrows(
IllegalBookStockException.class,
() -> book.removeStock(pointsToRemove)
);
assertEquals(50, book.getInitialStock());
assertTrue(exception.getMessage().contains(String.valueOf(pointsToRemove)));
assertTrue(exception.getMessage().contains(String.valueOf(book.getInitialStock())));
}
@Test
@DisplayName("removeStock should handle removing zero points correctly")
void testRemoveZeroStock() throws IllegalBookStockException {
String ISBN = "1234567890123";
String title = "LivreRandom";
String author = "John Doe";
String publisher = "EditeurRandom";
Date date = Date.from(Instant.now());
double price = 5.99;
int initialStock = 50;
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
String description = "Je suis un livre qui contient des phrases composees de mots qui sont eux memes composes de lettres faits a partir d'encre sur du papier relie par une couverture cartonnee";
String language = "Francais";
Book book = Book.builder()
.isbn(ISBN)
.title(title)
.author(author)
.publisher(publisher)
.date(date)
.price(price)
.initialStock(initialStock)
.categories(categories)
.description(description)
.language(language)
.build();
book.removeStock(0);
assertEquals(50, book.getInitialStock());
}
}
}

View File

@@ -0,0 +1,60 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Random;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BookNotFoundExceptionTest {
private String randomISBN(){
Random r = new Random();
String ret = "";
for(int i=0;i<13;i++){
int e = r.nextInt()%10;
ret = ret + e;
}
return ret;
}
@Test
@DisplayName("Exception message should contain the UUID provided")
void testExceptionMessageContainsISBN() {
String ISBN = randomISBN();
BookNotFoundException exception = new BookNotFoundException(ISBN);
String expectedMessage = String.format("The book with ISBN %s does not exist", ISBN);
assertEquals(expectedMessage, exception.getMessage());
}
@Test
@DisplayName("Exception should use the correct constant message format")
void testExceptionUsesConstantMessageFormat() {
String ISBN = randomISBN();
BookNotFoundException exception = new BookNotFoundException(ISBN);
String expectedFormatWithPlaceholder = "The book with ISBN {0} does not exist";
assertEquals(BookNotFoundException.THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE,
expectedFormatWithPlaceholder);
assertTrue(exception.getMessage().contains(ISBN));
}
@Test
@DisplayName("Exception should be properly thrown and caught")
void testExceptionCanBeThrownAndCaught() {
String ISBN = randomISBN();
try {
throw new BookNotFoundException(ISBN);
} catch (BookNotFoundException e) {
String expectedMessage = String.format("The book with ISBN %s does not exist", ISBN);
assertEquals(expectedMessage, e.getMessage());
}
}
}

View File

@@ -0,0 +1,71 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import java.text.MessageFormat;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.IllegalBookStockException;
import org.junit.jupiter.api.DisplayName;
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;
class IllegalBookStockExceptionTest {
@Test
@DisplayName("Exception message should contain the needed and actual stock")
void testExceptionMessageContainsStock() {
int neededStock = 100;
int actualStock = 50;
IllegalBookStockException exception = new IllegalBookStockException(neededStock, actualStock);
String expectedMessage = "Cannot remove 100 stock from 50 stock";
assertEquals(expectedMessage, exception.getMessage());
}
@ParameterizedTest
@CsvSource({
"100, 50",
"75, 25",
"200, 150",
"1000, 750"
})
@DisplayName("Exception message should be formatted correctly for different stock values")
void testExceptionMessageForDifferentStockValues(int neededStock, int actualStock) {
IllegalBookStockException exception = new IllegalBookStockException(neededStock, actualStock);
String expectedMessage = MessageFormat.format(IllegalBookStockException.CANNOT_REMOVE_STOCK, neededStock, actualStock);
assertEquals(expectedMessage, exception.getMessage());
}
@Test
@DisplayName("Exception should use the correct constant message format")
void testExceptionUsesConstantMessageFormat() {
int neededStock = 100;
int actualStock = 50;
IllegalBookStockException exception = new IllegalBookStockException(neededStock, actualStock);
String expectedFormatWithPlaceholder = "Cannot remove {0} stock from {1} stock";
assertEquals(IllegalBookStockException.CANNOT_REMOVE_STOCK,
expectedFormatWithPlaceholder);
assertTrue(exception.getMessage().contains(String.valueOf(neededStock)));
assertTrue(exception.getMessage().contains(String.valueOf(actualStock)));
}
@Test
@DisplayName("Exception should be properly thrown and caught")
void testExceptionCanBeThrownAndCaught() {
int neededStock = 100;
int actualStock = 50;
try {
throw new IllegalBookStockException(neededStock, actualStock);
} catch (IllegalBookStockException e) {
String expectedMessage = String.format("Cannot remove %d stock from %d stock", neededStock, actualStock);
assertEquals(expectedMessage, e.getMessage());
}
}
}

View File

@@ -0,0 +1,63 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class NotValidBookExceptionTest {
@Test
@DisplayName("Exception should be created with the provided message")
void testExceptionCreation() {
String errorMessage = "Customer data is not valid";
NotValidBookException exception = new NotValidBookException(errorMessage);
assertEquals(errorMessage, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {
"ISBN format is invalid",
"Title cannot be empty",
"Author cannot be empty",
"Publisher cannot be empty",
"Price needs to be positive",
"Stock cannot go below 0",
})
@DisplayName("Exception should handle different validation messages")
void testExceptionWithDifferentMessages(String errorMessage) {
NotValidBookException exception = new NotValidBookException(errorMessage);
assertEquals(errorMessage, exception.getMessage());
}
@Test
@DisplayName("Exception should be properly thrown and caught")
void testExceptionCanBeThrownAndCaught() {
String errorMessage = "Required field is missing";
Exception exception = assertThrows(NotValidBookException.class, () -> {
throw new NotValidBookException(errorMessage);
});
assertEquals(errorMessage, exception.getMessage());
}
@Test
@DisplayName("Exception should be catchable as a general Exception")
void testExceptionInheritance() {
String errorMessage = "Invalid book data";
try {
throw new NotValidBookException(errorMessage);
} catch (Exception e) {
assertEquals(NotValidBookException.class, e.getClass());
assertEquals(errorMessage, e.getMessage());
}
}
}

View File

@@ -0,0 +1,262 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.time.Instant;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
class BookRepositoryTest {
private BookRepository repository;
private Book book1;
private Book book2;
@BeforeEach
void setUp() {
repository = new BookRepository();
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
book1 = Book.builder()
.isbn("1234567890123")
.title("Livre 1")
.author("John Doe")
.publisher("Editeur")
.date(Date.from(Instant.now()))
.price(5.99)
.initialStock(50)
.categories(categories)
.description("Description")
.language("Francais")
.build();
book2 = Book.builder()
.isbn("3210987654321")
.title("Livre 2")
.author("Jane Smith")
.publisher("Editeur")
.date(Date.from(Instant.now()))
.price(8.54)
.initialStock(42)
.categories(categories)
.description("Description")
.language("Francais")
.build();
}
@Test
@DisplayName("New repository should be empty")
void testNewRepositoryIsEmpty() {
List<Book> books = repository.findAll();
assertTrue(books.isEmpty());
assertEquals(0, books.size());
}
@Nested
@DisplayName("Save operations")
class SaveOperations {
@Test
@DisplayName("Save should add a new book")
void testSaveNewBook() {
Book savedBook = repository.save(book1);
assertEquals(1, repository.findAll().size());
assertEquals(book1.getIsbn(), savedBook.getIsbn());
assertEquals(book1.getTitle(), savedBook.getTitle());
assertEquals(book1.getAuthor(), savedBook.getAuthor());
assertEquals(book1.getPublisher(), savedBook.getPublisher());
assertEquals(book1.getDate(), savedBook.getDate());
assertEquals(book1.getPrice(), savedBook.getPrice());
assertEquals(book1.getInitialStock(), savedBook.getInitialStock());
assertEquals(book1.getCategories(), savedBook.getCategories());
assertEquals(book1.getDescription(), savedBook.getDescription());
assertEquals(book1.getLanguage(), savedBook.getLanguage());
}
@Test
@DisplayName("Save should update existing book with same ISBN")
void testSaveUpdatesExistingBook() {
repository.save(book1);
String isbn = book1.getIsbn();
ArrayList<String> categories = book1.getCategories();
Book updatedBook = Book.builder()
.isbn(isbn)
.title("Livre 1")
.author("John Updated")
.publisher("Editeur")
.date(Date.from(Instant.now()))
.price(4.99)
.initialStock(42)
.categories(categories)
.description("Description")
.language("Francais")
.build();
Book savedBook = repository.save(updatedBook);
assertEquals(1, repository.findAll().size());
assertEquals(updatedBook.getIsbn(), savedBook.getIsbn());
assertEquals(updatedBook.getTitle(), savedBook.getTitle());
assertEquals(updatedBook.getAuthor(), savedBook.getAuthor());
assertEquals(updatedBook.getPublisher(), savedBook.getPublisher());
assertEquals(updatedBook.getDate(), savedBook.getDate());
assertEquals(updatedBook.getPrice(), savedBook.getPrice());
assertEquals(updatedBook.getInitialStock(), savedBook.getInitialStock());
assertEquals(updatedBook.getCategories(), savedBook.getCategories());
assertEquals(updatedBook.getDescription(), savedBook.getDescription());
assertEquals(updatedBook.getLanguage(), savedBook.getLanguage());
}
@Test
@DisplayName("Save multiple books should add all of them")
void testSaveMultipleBooks() {
repository.save(book1);
repository.save(book2);
List<Book> books = repository.findAll();
assertEquals(2, books.size());
assertTrue(books.contains(book1));
assertTrue(books.contains(book2));
}
}
@Nested
@DisplayName("Find operations")
class FindOperations {
@BeforeEach
void setUpBooks() {
repository.save(book1);
repository.save(book2);
}
@Test
@DisplayName("FindAll should return all books")
void testFindAll() {
List<Book> books = repository.findAll();
assertEquals(2, books.size());
assertTrue(books.contains(book1));
assertTrue(books.contains(book2));
}
@Test
@DisplayName("FindById should return book with matching ID")
void testFindById() {
Optional<Book> foundBook = repository.findByISBN(book1.getIsbn());
assertTrue(foundBook.isPresent());
assertEquals(book1.getIsbn(), foundBook.get().getIsbn());
assertEquals(book1.getTitle(), foundBook.get().getTitle());
assertEquals(book1.getAuthor(), foundBook.get().getAuthor());
assertEquals(book1.getPublisher(), foundBook.get().getPublisher());
assertEquals(book1.getDate(), foundBook.get().getDate());
assertEquals(book1.getPrice(), foundBook.get().getPrice());
assertEquals(book1.getInitialStock(), foundBook.get().getInitialStock());
assertEquals(book1.getCategories(), foundBook.get().getCategories());
assertEquals(book1.getDescription(), foundBook.get().getDescription());
assertEquals(book1.getLanguage(), foundBook.get().getLanguage());
}
@Test
@DisplayName("FindById should return empty Optional when ID doesn't exist")
void testFindByIdNotFound() {
String nonExistentISBN = "1115553331112";
Optional<Book> foundBook = repository.findByISBN(nonExistentISBN);
assertTrue(foundBook.isEmpty());
}
@Test
@DisplayName("FindByISBN should return book with matching ISBN")
void testFindByISBN() {
Optional<Book> foundBook = repository.findByISBN("1234567890123");
assertTrue(foundBook.isPresent());
assertEquals(book1.getIsbn(), foundBook.get().getIsbn());
assertEquals(book1.getTitle(), foundBook.get().getTitle());
assertEquals(book1.getAuthor(), foundBook.get().getAuthor());
assertEquals(book1.getPublisher(), foundBook.get().getPublisher());
assertEquals(book1.getDate(), foundBook.get().getDate());
assertEquals(book1.getPrice(), foundBook.get().getPrice());
assertEquals(book1.getInitialStock(), foundBook.get().getInitialStock());
assertEquals(book1.getCategories(), foundBook.get().getCategories());
assertEquals(book1.getDescription(), foundBook.get().getDescription());
assertEquals(book1.getLanguage(), foundBook.get().getLanguage());
}
@Test
@DisplayName("FindByISBN should return empty Optional when ISBN doesn't exist")
void testFindByISBNNotFound() {
Optional<Book> foundBook = repository.findByISBN("0000000000000");
assertTrue(foundBook.isEmpty());
}
}
@Nested
@DisplayName("Delete operations")
class DeleteOperations {
@BeforeEach
void setUpBooks() {
repository.save(book1);
repository.save(book2);
}
@Test
@DisplayName("Delete should remove the specified book")
void testDelete() {
repository.delete(book1);
List<Book> books = repository.findAll();
assertEquals(1, books.size());
assertFalse(books.contains(book1));
assertTrue(books.contains(book2));
}
@Test
@DisplayName("DeleteAll should remove all books")
void testDeleteAll() {
repository.deleteAll();
List<Book> books = repository.findAll();
assertTrue(books.isEmpty());
assertEquals(0, books.size());
}
@Test
@DisplayName("Delete should not throw exception when book doesn't exist")
void testDeleteNonExistentBook() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
Book nonExistentBook = Book.builder()
.isbn("0000000000000")
.title("Livre Non existant")
.author("John Doe")
.publisher("Editeur")
.date(Date.from(Instant.now()))
.price(5.99)
.initialStock(50)
.categories(categories)
.description("Description")
.language("Francais")
.build();
assertDoesNotThrow(() -> repository.delete(nonExistentBook));
assertEquals(2, repository.findAll().size());
}
}
}

View File

@@ -1,5 +1,12 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.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 org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -9,6 +16,10 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import javax.swing.text.html.Option;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.Optional; import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@@ -32,21 +43,22 @@ public class BookUseCaseTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Histoire"); categories.add("Action");
Date date = Date.from(Instant.now());
testBook = Book.builder() testBook = Book.builder()
.isbn(bookISBN) .isbn("1234567890123")
.title("LivreRandom") .title("LivreRandom")
.author("John Doe") .author("John Doe")
.publisher("RandomPublisher") .publisher("RandomPublisher")
.publicationDate(date) .date(date)
.price(12.5) .price(12.5)
.initialStock(50) .initialStock(50)
.categories(cat) .categories(categories)
.description("Je suis un livre qui est composé de mots.") .description("Je suis un livre qui est composé de mots.")
.language("Francais") .language("Francais")
.build(); .build();
validBookInfo = new BookInfo("LivreRandom", "John Doe", "RandomPublisher", date, 12.5, 50, cat, "Je suis un livre qui est composé de mots.", "Francais"); validBookInfo = new BookInfo("1234567890123","LivreRandom", "John Doe", "RandomPublisher", date, 12.5, 50, categories, "Je suis un livre qui est composé de mots.", "Francais");
} }
@@ -58,9 +70,10 @@ public class BookUseCaseTest {
@Test @Test
@DisplayName("Should register book when valid data is provided") @DisplayName("Should register book when valid data is provided")
void testRegisterBookWithValidData() throws NotValidBookException { void testRegisterBookWithValidData() throws NotValidBookException {
when(BookRepository.save(any(Book.class))).thenReturn(testBook); bookISBN = "1234567890123";
when(bookRepository.save(any(Book.class))).thenReturn(testBook);
String registeredISBN = BookUseCase.registerBook(validBookInfo); String registeredISBN = bookUseCase.registerBook(validBookInfo);
assertNotNull(registeredISBN); assertNotNull(registeredISBN);
assertEquals(bookISBN, registeredISBN); assertEquals(bookISBN, registeredISBN);
@@ -70,7 +83,7 @@ public class BookUseCaseTest {
@Test @Test
@DisplayName("Should throw exception when book data is not valid") @DisplayName("Should throw exception when book data is not valid")
void testRegisterBookWithInvalidData() { void testRegisterBookWithInvalidData() {
BookInfo invalidBookInfo = new BookInfo("", "", ""); BookInfo invalidBookInfo = new BookInfo("", "", "", "", Date.from(Instant.now()),-78, -1, null, "", "");
assertThrows(NotValidBookException.class, assertThrows(NotValidBookException.class,
() -> bookUseCase.registerBook(invalidBookInfo)); () -> bookUseCase.registerBook(invalidBookInfo));
@@ -90,15 +103,17 @@ public class BookUseCaseTest {
@Test @Test
@DisplayName("Should return book when ISBN exists") @DisplayName("Should return book when ISBN exists")
void testFindBookByISBN() { void testFindBookByISBN() throws NotValidBookException {
when(BookRepository.findBookByISBN("1234567890123")).thenReturn(Optional.of(testISBN)); when(bookRepository.findByISBN("1234567890123")).thenReturn(Optional.of(testBook));
String registeredISBN = bookUseCase.registerBook(validBookInfo);
Optional<BookDTO> foundBook = bookUseCase.findBookByISBN("1234567890123"); Optional<BookDTO> foundBook = bookUseCase.findBookByISBN("1234567890123");
assertTrue(foundBook.isPresent()); assertTrue(foundBook.isPresent());
assertEquals(testBook.getISBN(), foundBook.get().getISBN()); assertEquals(testBook.getIsbn(), foundBook.get().getIsbn());
assertEquals(testBook.getName(), foundBook.get().getName()); assertEquals(testBook.getTitle(), foundBook.get().getTitle());
verify(bookRepository, times(1)).findBookByISBN("1234567890123"); verify(bookRepository, times(1)).findByISBN("1234567890123");
} }
@Test @Test
@@ -124,16 +139,16 @@ public class BookUseCaseTest {
when(bookRepository.findByISBN(bookISBN)).thenReturn(Optional.of(testBook)); when(bookRepository.findByISBN(bookISBN)).thenReturn(Optional.of(testBook));
doNothing().when(bookRepository).delete(testBook); doNothing().when(bookRepository).delete(testBook);
bookUseCase.deleteBook(bookId); bookUseCase.deleteBook(bookISBN);
verify(bookRepository, times(1)).findByISBN(bookId); verify(bookRepository, times(1)).findByISBN(bookISBN);
verify(bookRepository, times(1)).delete(testBook); verify(bookRepository, times(1)).delete(testBook);
} }
@Test @Test
@DisplayName("Should throw exception when book ISBN doesn't exist") @DisplayName("Should throw exception when book ISBN doesn't exist")
void testDeleteBookNotFound() { void testDeleteBookNotFound() {
ISBN nonExistentId = ISBN.randomISBN(); String nonExistentISBN = "0000000000001";
when(bookRepository.findByISBN(nonExistentISBN)).thenReturn(Optional.empty()); when(bookRepository.findByISBN(nonExistentISBN)).thenReturn(Optional.empty());
assertThrows(BookNotFoundException.class, assertThrows(BookNotFoundException.class,

View File

@@ -0,0 +1,244 @@
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;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.CustomerInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.*;
class BookValidatorTest {
@Test
@DisplayName("Should validate book with valid data")
void testValidateValidBook() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo validBook = new BookInfo("1234567891234", "Livre", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
assertDoesNotThrow(() -> BookValidator.validate(validBook));
}
@Nested
@DisplayName("ISBN validation tests")
class ISBNValidationTests {
@Test
@DisplayName("Should throw exception when ISBN is blank")
void testValidateBlankISBN() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankISBN = new BookInfo("", "Livre", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankISBN)
);
assertEquals(BookValidator.ISBN_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when ISBN contains only whitespace")
void testValidateWhitespaceISBN(String whitespace) {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithWhitespaceISBN = new BookInfo(whitespace, "Livre", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithWhitespaceISBN)
);
assertEquals(BookValidator.ISBN_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {"hfoahdiehfyui", "123456789 0123", "123", "12345678901234","123456789 123"})
@DisplayName("Should throw exception when ISBN is not a valid format")
void testValidateNotValidISBN(String testedISBN) {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithInvalidISBN = new BookInfo(testedISBN, "Livre", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithInvalidISBN)
);
assertEquals(BookValidator.ISBN_IS_NOT_VALID, exception.getMessage());
}
}
@Nested
@DisplayName("Title validation tests")
class TitleValidationTests {
@Test
@DisplayName("Should throw exception when Title is blank")
void testValidateBlankTitle() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankTitle = new BookInfo("1234567890123", "", "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankTitle)
);
assertEquals(BookValidator.TITLE_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when Title contains only whitespace")
void testValidateWhitespaceTitle(String whitespace) {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankTitle = new BookInfo("1234567890123", whitespace, "john doe","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankTitle)
);
assertEquals(BookValidator.TITLE_CANNOT_BE_BLANK, exception.getMessage());
}
}
@Nested
@DisplayName("Author validation tests")
class AuthorValidationTests {
@Test
@DisplayName("Should throw exception when Author is blank")
void testValidateBlankAuthor() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankAuthor = new BookInfo("1234567890123", "Livre", "","editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankAuthor)
);
assertEquals(BookValidator.AUTHOR_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when Author contains only whitespace")
void testValidateWhitespaceAuthor(String whitespace) {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankAuthor = new BookInfo("1234567890123", "Livre", whitespace,"editeur", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankAuthor)
);
assertEquals(BookValidator.AUTHOR_CANNOT_BE_BLANK, exception.getMessage());
}
}
@Nested
@DisplayName("Publisher validation tests")
class PublisherValidationTests {
@Test
@DisplayName("Should throw exception when Publisher is blank")
void testValidateBlankPublisher() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankPublisher = new BookInfo("1234567890123", "Livre", "Auteur","", Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankPublisher)
);
assertEquals(BookValidator.PUBLISHER_CANNOT_BE_BLANK, exception.getMessage());
}
@ParameterizedTest
@ValueSource(strings = {" ", " ", "\t", "\n"})
@DisplayName("Should throw exception when Publisher contains only whitespace")
void testValidateWhitespacePublisher(String whitespace) {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithBlankPublisher = new BookInfo("1234567890123", "Livre", "Auteur",whitespace, Date.from(Instant.now()),5.99,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithBlankPublisher)
);
assertEquals(BookValidator.PUBLISHER_CANNOT_BE_BLANK, exception.getMessage());
}
}
@Nested
@DisplayName("Price validation tests")
class PriceValidationTests {
@Test
@DisplayName("Should throw exception when Price is negative")
void testValidateNegativePrice() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithNegativePrice = new BookInfo("1234567890123", "Livre", "Auteur","Editeur", Date.from(Instant.now()),-4.98,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithNegativePrice)
);
assertEquals(BookValidator.PRICE_CANNOT_BE_NEGATIVE, exception.getMessage());
}
@Test
@DisplayName("Should throw exception when Price is equal to zero")
void testValidatePriceEqualToZero() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithPriceEqualToZero = new BookInfo("1234567890123", "Livre", "Auteur","Editeur", Date.from(Instant.now()),0,15,categories,"description","langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithPriceEqualToZero)
);
assertEquals(BookValidator.PRICE_CANNOT_BE_EQUAL_TO_ZERO, exception.getMessage());
}
}
@Nested
@DisplayName("Initial Stock validation tests")
class InitialStockValidationTests {
@Test
@DisplayName("Should throw exception when Initial Stock is negative")
void testValidateNegativeStock() {
ArrayList<String> categories = new ArrayList<>(); categories.add("Categorie1"); categories.add("Categorie2");
BookInfo bookWithNegativeInitialStock = new BookInfo("1234567890123", "Livre", "Auteur", "Editeur", Date.from(Instant.now()), 5.12, -15, categories, "description", "langue");
NotValidBookException exception = assertThrows(
NotValidBookException.class,
() -> BookValidator.validate(bookWithNegativeInitialStock)
);
assertEquals(BookValidator.INITIAL_STOCK_CANNOT_BE_NEGATIVE, exception.getMessage());
}
}
}

View File

@@ -220,4 +220,5 @@ public class CustomerSteps {
assertEquals(errorMessage, illegalCustomerPointException.getMessage()); assertEquals(errorMessage, illegalCustomerPointException.getMessage());
} }
} }

View File

@@ -0,0 +1,222 @@
package fr.iut_fbleau.but3.dev62.mylibrary.features.livre;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
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.BookNotFoundExceptionTest;
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;
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 fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.usecase.CustomerUseCase;
import io.cucumber.datatable.DataTable;
import io.cucumber.java.ParameterType;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;
public class BookSteps {
private final Map<String, String> bookISBN = new HashMap<>();
private final BookRepository bookRepository = new BookRepository();
private final BookUseCase bookUseCase = new BookUseCase(bookRepository);
private String bookRegistration;
private Book updatedBook;
private Optional<BookDTO> bookByISBN;
private NotValidBookException notValidBookException;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-mm-dd", Locale.ENGLISH);
private ArrayList<String> listOfStrings(String arg) {
return new ArrayList<String>(Arrays.asList(arg.split(",\\s")));
}
@Given("le systeme possedent les livres suivants :")
public void theSystemHasTheFollowingBooks(DataTable dataTable) throws ParseException {
int size = bookRepository.findAll().size();
if (size > 0) {
bookRepository.deleteAll();
}
List<Map<String, String>> books = dataTable.asMaps(String.class, String.class);
for (Map<String, String> book : books) {
String ISBN = book.get("ISBN");
Book newBook = Book.builder()
.isbn(ISBN)
.title(book.get("titre"))
.author(book.get("auteur"))
.publisher(book.get("editeur"))
.date(formatter.parse(book.get("datePublication")))
.price(Double.parseDouble(book.get("prix")))
.initialStock(Integer.parseInt(book.get("stockInitial")))
.categories(listOfStrings(book.get("categories")))
.description(book.get("description"))
.language(book.get("langue"))
.build();
Book save = bookRepository.save(newBook);
bookISBN.put(ISBN, save.getIsbn());
}
assertEquals(books.size(), bookRepository.findAll().size());
}
@When("Je cree un nouveau livre avec les informations suivantes :")
public void iCreateANewBookWithTheFollowingInformation(DataTable dataTable) throws NotValidBookException, ParseException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
Map<String, String> bookInfo = rows.getFirst();
BookInfo newBook = new BookInfo(
bookInfo.get("ISBN"),
bookInfo.get("titre"),
bookInfo.get("auteur"),
bookInfo.get("editeur"),
formatter.parse(bookInfo.get("datePublication")),
Double.parseDouble(bookInfo.get("prix")),
Integer.parseInt(bookInfo.get("stockInitial")),
listOfStrings(bookInfo.get("categories")),
bookInfo.get("description"),
bookInfo.get("langue")
);
bookRegistration = bookUseCase.registerBook(newBook);
}
@Then("Un nouveau livre est cree")
public void aNewBookIsCreated(){
assertNotNull(bookRegistration);
}
@When("Je modifie le livre avec l'ISBN {string} avec les informations suivantes:")
public void iUpdateABookWithTheFollowingInformation(String isbn, DataTable dataTable) throws BookNotFoundException, NotValidBookException, ParseException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
Map<String, String> bookData = rows.getFirst();
BookInfo bookInfo = new BookInfo(
bookData.get("ISBN"),
bookData.get("titre"),
bookData.get("auteur"),
bookData.get("editeur"),
formatter.parse(bookData.get("datePublication")),
Double.parseDouble(bookData.get("prix")),
Integer.parseInt(bookData.get("stockInitial")),
listOfStrings(bookData.get("categories")),
bookData.get("description"),
bookData.get("langue")
);
bookUseCase.updateBook(isbn, bookInfo);
}
@Then("Le livre {string} a les informations suivantes:")
public void theBookHasFollowingInformations(String isbn, DataTable dataTable) throws ParseException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
Map<String, String> updatedData = rows.getFirst();
updatedBook = bookRepository.findByISBN(isbn).orElseThrow();
assertEquals(updatedData.get("ISBN"), updatedBook.getIsbn());
assertEquals(updatedData.get("titre"), updatedBook.getTitle());
assertEquals(updatedData.get("auteur"), updatedBook.getAuthor());
assertEquals(updatedData.get("editeur"), updatedBook.getPublisher());
assertEquals(formatter.parse(updatedData.get("datePublication")), updatedBook.getDate());
assertEquals(Double.parseDouble(updatedData.get("prix")), updatedBook.getPrice());
assertEquals(Integer.parseInt(updatedData.get("stockInitial")), updatedBook.getInitialStock());
assertEquals(listOfStrings(updatedData.get("categories")), updatedBook.getCategories());
assertEquals(updatedData.get("description"), updatedBook.getDescription());
assertEquals(updatedData.get("langue"), updatedBook.getLanguage());
}
@When("Je supprime le livre avec l'ISBN {string}")
public void iDeleteTheFollowingBook(String isbn) throws BookNotFoundException {
bookUseCase.deleteBook(isbn);
}
@Then("Le livre {string} n'existe plus dans le systeme")
public void theBookDoesNotExistInTheSystem(String isbn){
assertFalse(bookRepository.existsByISBN(isbn));
}
@And("Le systeme contient {int} livre")
public void theSystemContainsThisMuchBooks(int nBooks){
assertEquals(nBooks,bookRepository.findAll().size());
}
@When("Je demande les informations du lirve avec l'ISBN {string}")
public void iAskForTheBookWithISBN(String isbn){
bookByISBN = bookUseCase.findBookByISBN(isbn);
}
@Then("Je recupere les informations suivantes:")
public void iGetTheFollowingInformation(DataTable dataTable) throws ParseException {
List<Map<String, String>> books = dataTable.asMaps(String.class, String.class);
Map<String, String> bookInfo = books.getFirst();
assertTrue(bookByISBN.isPresent());
BookDTO bookDTO = bookByISBN.get();
assertEquals(bookInfo.get("ISBN"), bookDTO.getIsbn());
assertEquals(bookInfo.get("titre"), bookDTO.getTitle());
assertEquals(bookInfo.get("auteur"), bookDTO.getAuthor());
assertEquals(bookInfo.get("editeur"), bookDTO.getPublisher());
assertEquals(formatter.parse(bookInfo.get("datePublication")), bookDTO.getDate());
assertEquals(Double.parseDouble(bookInfo.get("prix")), bookDTO.getPrice());
assertEquals(Integer.parseInt(bookInfo.get("stockInitial")), bookDTO.getInitialStock());
assertEquals(listOfStrings(bookInfo.get("categories")), bookDTO.getCategories());
assertEquals(bookInfo.get("description"), bookDTO.getDescription());
assertEquals(bookInfo.get("langue"), bookDTO.getLanguage());
}
@When("J'essaie de creer un nouveau livre avec les informations suivantes :")
public void iTryToCreateANewBookWithFollowingInformation(DataTable dataTable) throws ParseException {
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
Map<String, String> bookInfo = rows.getFirst();
BookInfo newBook = new BookInfo(
bookInfo.get("ISBN"),
bookInfo.get("titre"),
bookInfo.get("auteur"),
bookInfo.get("editeur"),
formatter.parse(bookInfo.get("datePublication")),
Double.parseDouble(bookInfo.get("prix")),
Integer.parseInt(bookInfo.get("stockInitial")),
listOfStrings(bookInfo.get("categories")),
bookInfo.get("description"),
bookInfo.get("langue")
);
notValidBookException = assertThrows(NotValidBookException.class, () -> bookUseCase.registerBook(newBook));
}
@Then("La creation echoue")
public void creationFailed(){
assertNotNull(notValidBookException);
}
}

View File

@@ -0,0 +1,339 @@
package fr.iut_fbleau.but3.dev62.mylibrary.features.order;
import static org.junit.jupiter.api.Assertions.*;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import fr.iut_fbleau.but3.dev62.mylibrary.order.usecase.OrderUseCase;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AddressDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.OrderNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.UserNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
import io.cucumber.datatable.DataTable;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import java.util.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class OrderSteps {
private final OrderRepository orderRepository = new OrderRepository();
private final BookRepository bookRepository = new BookRepository();
private final CustomerRepository customerRepository = new CustomerRepository();
private final OrderUseCase orderUseCase = new OrderUseCase(orderRepository, bookRepository, customerRepository);
private final Map<String, UUID> customerPhoneUUID = new HashMap<>();
private final Map<String, String> bookISBN = new HashMap<>();
private UUID orderId;
private Optional<OrderDTO> orderByUUID;
private List<OrderDTO> orders;
private Exception exception;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-mm-dd", Locale.ENGLISH);
private ArrayList<String> listOfStrings(String arg) {
return new ArrayList<String>(Arrays.asList(arg.split(",\\s")));
}
@Given("the system has the following books in stock:")
public void theSystemHasTheFollowingBooksInStock(DataTable dataTable) throws ParseException {
int size = bookRepository.findAll().size();
if (size > 0) {
bookRepository.deleteAll();
}
List<Map<String, String>> books = dataTable.asMaps(String.class, String.class);
for (Map<String, String> book : books) {
String ISBN = book.get("isbn");
Book newBook = Book.builder()
.isbn(ISBN)
.title(book.get("titre"))
.author(book.get("auteur"))
.publisher(book.get("editeur"))
.date(formatter.parse(book.get("datePublication")))
.price(Double.parseDouble(book.get("prix")))
.initialStock(Integer.parseInt(book.get("stockInitial")))
.categories(listOfStrings(book.get("categories")))
.description(book.get("description"))
.language(book.get("langue"))
.build();
Book save = bookRepository.save(newBook);
bookISBN.put(ISBN, save.getIsbn());
}
assertEquals(books.size(), bookRepository.findAll().size());
}
@And("the system has the following customers in the database:")
public void theSystemHasTheFollowingCustomers(DataTable dataTable) {
int size = customerRepository.findAll().size();
if (size > 0) {
customerRepository.deleteAll();
}
List<Map<String, String>> customers = dataTable.asMaps(String.class, String.class);
for (Map<String, String> customer : customers) {
String numeroTelephone = customer.get("phoneNumber");
String idStr = customer.get("id");
UUID id = (idStr != null && !idStr.isBlank()) ? UUID.fromString(idStr) : UUID.randomUUID();
Customer newCustomer = Customer.builder()
.id(id)
.firstName(customer.get("firstName"))
.lastName(customer.get("lastName"))
.phoneNumber(numeroTelephone)
.loyaltyPoints(Integer.parseInt(customer.get("loyaltyPoints")))
.build();
Customer save = customerRepository.save(newCustomer);
customerPhoneUUID.put(numeroTelephone, save.getId());
}
assertEquals(customers.size(), customerRepository.findAll().size());
}
@When("I create a new order with the following information:")
public void iCreateANewOrderWithTheFollowingInformation(DataTable dataTable) {
Map<String, String> orderData = dataTable.asMaps(String.class, String.class).getFirst();
OrderInfo newOrder = OrderInfo.builder()
.customerId(UUID.fromString(orderData.get("customerId")))
.paymentMethod(orderData.get("paymentMethod"))
.build();
try{
orderUseCase.registerOrderInfo(newOrder);
exception = null;
} catch (Exception e) {
exception = e;
}
}
@And("the order includes the following books:")
public void theOrderIncludesTheFollowingBooks(DataTable dataTable) {
if (exception != null) return;
List<Map<String, String>> books = dataTable.asMaps(String.class, String.class);
List<OrderLineDTO> orderLines = new ArrayList<>();
for (Map<String, String> book : books) {
String bookId = book.get("bookId");
int quantity = Integer.parseInt(book.get("quantity"));
orderLines.add(OrderLineDTO.builder()
.bookId(bookId)
.quantity(quantity)
.build());
}
try {
orderUseCase.addBooksToOrder(orderLines);
exception = null;
} catch (Exception e) {
exception = e;
}
}
@And("the delivery address is:")
public void theDeliveryAddressIs(DataTable dataTable) {
if (exception != null) return;
Map<String, String> addressData = dataTable.asMaps(String.class, String.class).getFirst();
AddressDTO address = AddressDTO.builder()
.street(addressData.get("street"))
.city(addressData.get("city"))
.postalCode(addressData.get("postalCode"))
.country(addressData.get("country"))
.build();
try {
orderUseCase.setDeliveryAddress(address);
exception = null;
} catch (Exception e) {
exception = e;
}
}
@Then("a new order is created")
public void aNewOrderIsCreated() {
if (exception != null) {
fail("An exception should not have been thrown during order creation: " + exception.getMessage());
}
try {
orderId = orderUseCase.finalizeOrder();
exception = null;
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new Exception("Order not found"));
} catch (Exception e) {
exception = e;
}
assertNull(exception, "No exception should be thrown during order creation");
assertNotNull(orderId);
}
@Then("the order creation fails")
public void theCreationFails() {
// Toujours tenter de finaliser la commande si ce n'est pas déjà fait
if (exception == null) {
try {
orderUseCase.finalizeOrder();
} catch (Exception e) {
exception = e;
}
}
assertNotNull(exception, "An exception should have been thrown during order creation");
}
@And("the total price is {double}")
public void theTotalPriceIs(double expectedPrice) throws Exception {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new Exception("Order not found"));
double totalPrice = order.getTotalPrice();
assertEquals(expectedPrice, totalPrice, "The total price of the order should match the expected price");
}
@And("The customer {string} now has {int} loyalty points")
public void theCustomerNowHasLoyaltyPoints(String clientId, int actualPoints) throws Exception {
Customer customer = customerRepository.findById(UUID.fromString(clientId))
.orElseThrow(() -> new Exception("Customer not found"));
assertEquals(actualPoints, customer.getLoyaltyPoints(), "The customer's loyalty points should match the expected points");
}
@And("I receive an error for validation order message containing {string}")
public void iReceiveAnErrorForValidationOrderMessageContaining(String errorMessage) {
assertNotNull(exception, "An exception should be thrown during order creation");
assertInstanceOf(NotValidOrderException.class, exception, "The exception should be of type NotValidOrderException");
assertEquals(errorMessage, exception.getMessage(), "The error message should match the expected message");
}
@And("I receive an error for not found exception message containing {string}")
public void iReceiveAnErrorForNotFoundExceptionMessageContaining(String errorMessage) {
assertNotNull(exception, "An exception should be thrown during order retrieval");
String exceptionName = exception.getClass().getSimpleName();
boolean isOrderOrBookNotFound =
exception instanceof OrderNotFoundException || "BookNotFoundException".equals(exceptionName);
assertTrue(isOrderOrBookNotFound,
"The exception should be of type OrderNotFoundException or BookNotFoundException. Exception réelle : " + exception.getClass().getName());
String actualMessage = exception.getMessage();
boolean match = false;
if (actualMessage != null) {
match = actualMessage.contains(errorMessage);
if (!match) {
String lowerMsg = actualMessage.toLowerCase();
match = lowerMsg.contains("book") && lowerMsg.contains("does not exist");
}
}
assertTrue(match,
"Le message d'erreur réel était : '" + actualMessage + "', attendu : '" + errorMessage + "' ou un message contenant 'book' et 'does not exist'");
}
@And("I receive an error for not found user exception message containing {string}")
public void iReceiveAnErrorForIllegalOrderExceptionMessageContaining(String errorMessage) {
assertNotNull(exception, "An exception should be thrown during user processing");
assertInstanceOf(UserNotFoundException.class, exception, "The exception should be of type UserNotFoundException");
assertEquals(errorMessage, exception.getMessage(), "The error message should match the expected message");
}
@And("the order includes no books")
public void theOrderIncludesNoBooks() {
if (exception != null) return;
List<OrderLineDTO> orderLines = new ArrayList<>();
try {
orderUseCase.addBooksToOrder(orderLines);
exception = null;
} catch (Exception e) {
exception = e;
}
}
@Given("an order with ID {string} exists for customer {string}")
public void anOrderWithIDExistsForCustomer(String orderId, String customerId) {
UUID orderUUID = UUID.fromString(orderId);
UUID customerUUID = UUID.fromString(customerId);
Order order = Order.builder()
.id(orderUUID)
.customerId(customerUUID)
.orderLines(new ArrayList<OrderLineDTO>() {{
add(OrderLineDTO.builder()
.bookId("1234567890123")
.quantity(2)
.build());
add(OrderLineDTO.builder()
.bookId("9876543210987")
.quantity(1)
.build());
}})
.totalPrice(60.0)
.totalPriceToPay(60.0)
.address(AddressDTO.builder()
.street("123 Main St")
.city("Springfield")
.postalCode("12345")
.country("USA")
.build())
.paymentMethod(PaymentMethod.CREDIT_CARD)
.build();
orderRepository.save(order);
}
@When("I retrieve the order by ID {string}")
public void iRetrieveTheOrderByID(String orderId) {
try {
UUID orderUUID = UUID.fromString(orderId);
orderByUUID = orderUseCase.findOrderById(orderUUID);
exception = null;
} catch (IllegalArgumentException e) {
exception = new OrderNotFoundException("Order not found");
orderByUUID = Optional.empty();
} catch (Exception e) {
exception = e;
orderByUUID = Optional.empty();
}
}
@Then("I receive the order details")
public void iReceiveTheOrderDetails() {
assertTrue(orderByUUID.isPresent(), "The order should be found by ID");
OrderDTO order = orderByUUID.get();
assertNotNull(order, "The retrieved order should not be null");
if (orderId != null) {
assertEquals(orderId, order.getId(), "The retrieved order ID should match the expected ID");
}
}
@When("I request all orders for customer {string}")
public void iRequestAllOrdersForCustomer(String customerId) {
UUID customerUUID = UUID.fromString(customerId);
try {
orders = orderUseCase.findOrdersByCustomerId(customerUUID);
exception = null;
} catch (Exception e) {
exception = e;
orders = Collections.emptyList();
}
}
@Then("I receive a list of orders")
public void iReceiveAListOfOrders() {
assertNull(exception, "No exception should be thrown during order retrieval");
assertNotNull(orders, "The list of orders should not be null");
}
@Then("the retrieval fails")
public void theRetrievalFails() {
assertNotNull(exception, "An exception should be thrown during order retrieval");
}
}

Some files were not shown because too many files have changed in this diff Show More