diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java new file mode 100644 index 0000000..d90e431 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/BookInfo.java @@ -0,0 +1,14 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book; + +import java.time.LocalDate; + +public record BookInfo( + String isbn, + String title, + String author, + String publisher, + LocalDate publicationDate, + double price, + int stockInitial +) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java new file mode 100644 index 0000000..35f9c18 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/Book.java @@ -0,0 +1,29 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.entity; + +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.IllegalCustomerPointException; + +import java.rmi.server.UID; +import java.time.LocalDate; +import java.util.UUID; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter + +public class Book { + //private UUID id; + private String isbn; + private String title; + private String author; + private String publisher; + private LocalDate publicationDate; + private double price; + private int stock; +} +/* +public void setRandomUUID() { + this.id = UUID.randomUUID(); +} +*/ \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java new file mode 100644 index 0000000..d62cb3d --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/BookNotFoundException.java @@ -0,0 +1,14 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +import java.text.MessageFormat; +import java.util.UUID; + +public class BookNotFoundException { + + public static final String THE_BOOK_WITH_ID_DOES_NOT_EXISTS = "The book with id {0} does not exist"; + + public BookNotFoundException(UUID uuid) { + super(); //super(MessageFormat.format(THE_BOOK_WITH_ID_DOES_NOT_EXISTS, uuid)); à corriger + } + +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java new file mode 100644 index 0000000..6eab151 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/exception/NotValidBookException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; + +public class NotValidBookException extends Exception { + + public NotValidBookException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java new file mode 100644 index 0000000..c5b1c05 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepository.java @@ -0,0 +1,32 @@ +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 lombok.NoArgsConstructor; + +@NoArgsConstructor +public final class BookRepository { + private final List books = new ArrayList<>(); + + public Book save(Book newBook) { + this.findByIsbn(newBook.getIsbn()).ifPresent(books::remove); + this.books.add(newBook); + return newBook; + } + + public Optional findByIsbn(String isbn) { + return this.books.stream() + .filter(book -> book.getIsbn().equals(isbn)) + .findFirst(); + } + + public List findAll() { + return books; + } + + public void deleteAll() { + books.clear(); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java new file mode 100644 index 0000000..5d9142e --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCase.java @@ -0,0 +1,31 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; + +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.NotValidBookException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.book.validator.BookValidator; + +public final class BookUseCase { + + private final BookRepository bookRepository; + + public BookUseCase(BookRepository bookRepository) { + this.bookRepository = bookRepository; + } + + public String registerNewBook(BookInfo newBook) throws NotValidBookException { + BookValidator.validate(newBook); + Book bookToSave = Book.builder() + .isbn(newBook.isbn()) + .title(newBook.title()) + .author(newBook.author()) + .publisher(newBook.publisher()) + .publicationDate(newBook.publicationDate()) + .price(newBook.price()) + .stock(newBook.stockInitial()) + .build(); + Book savedBook = bookRepository.save(bookToSave); + return savedBook.getIsbn(); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java new file mode 100644 index 0000000..4a342cf --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java @@ -0,0 +1,38 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; + +public final class BookValidator { + + private BookValidator() { + } + + public static void validate(BookInfo bookInfo) throws NotValidBookException { + if (bookInfo == null) { + throw new NotValidBookException("Book cannot be null"); + } + if (isBlank(bookInfo.isbn())) { + throw new NotValidBookException("ISBN is required"); + } + if (isBlank(bookInfo.title())) { + throw new NotValidBookException("Title is required"); + } + if (isBlank(bookInfo.author())) { + throw new NotValidBookException("Author is required"); + } + if (isBlank(bookInfo.publisher())) { + throw new NotValidBookException("Publisher is required"); + } + if (bookInfo.price() <= 0) { + throw new NotValidBookException("Price must be positive"); + } + if (bookInfo.stockInitial() < 0) { + throw new NotValidBookException("Stock must be greater or equal to 0"); + } + } + + private static boolean isBlank(String value) { + return value == null || value.isBlank(); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java new file mode 100644 index 0000000..2853d90 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java @@ -0,0 +1,87 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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.NotValidBookException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import java.time.LocalDate; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class BookUseCaseTest { + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private BookUseCase bookUseCase; + + @Nested + @DisplayName("Register new book tests") + class RegisterNewBookTests { + + @Test + @DisplayName("Should register a new book and return ISBN") + void shouldRegisterBookAndReturnIsbn() throws NotValidBookException { + BookInfo validBookInfo = new BookInfo( + "9783161484100", + "Clean Code", + "Robert C. Martin", + "Prentice Hall", + LocalDate.of(2008, 8, 1), + 42.50, + 10 + ); + + Book savedBook = Book.builder() + .isbn("9783161484100") + .title("Clean Code") + .author("Robert C. Martin") + .publisher("Prentice Hall") + .publicationDate(LocalDate.of(2008, 8, 1)) + .price(42.50) + .stock(10) + .build(); + + when(bookRepository.save(any(Book.class))).thenReturn(savedBook); + + String isbn = bookUseCase.registerNewBook(validBookInfo); + + assertNotNull(isbn); + assertEquals("9783161484100", isbn); + verify(bookRepository, times(1)).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw when required field is empty") + void shouldThrowWhenRequiredFieldIsEmpty() { + BookInfo invalidBookInfo = new BookInfo( + "9783161484100", + "", + "Robert C. Martin", + "Prentice Hall", + LocalDate.of(2008, 8, 1), + 42.50, + 10 + ); + + assertThrows(NotValidBookException.class, () -> bookUseCase.registerNewBook(invalidBookInfo)); + verify(bookRepository, never()).save(any(Book.class)); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java index 515187e..220c46f 100644 --- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/customer/entity/CustomerTest.java @@ -8,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.UUID; + class CustomerTest { @Test