diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundExceptionTest.java new file mode 100644 index 0000000..116fcc0 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundExceptionTest.java @@ -0,0 +1,100 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ReviewNotFoundExceptionTest { + + @Test + @DisplayName("Exception message should contain the UUID provided for customer") + void testExceptionMessageContainsUUIDForCustomer() { + UUID customerUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.of(customerUUID), Optional.empty()); + + String expectedMessage = String.format("The reviews with the customer id %s does not exists", customerUUID); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception message should contain the UUID provided for book") + void testExceptionMessageContainsUUIDForBook() { + UUID bookUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.of(bookUUID)); + + String expectedMessage = String.format("The reviews with book id %s does not exists", bookUUID); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception message should contain the UUID provided for customer and book") + void testExceptionMessageContainsUUIDForCustomerAndBook() { + UUID customerUUID = UUID.randomUUID(); + UUID bookUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.of(customerUUID), Optional.of(bookUUID)); + + String expectedMessage = String.format("The review with customer id %s and book id %s does not exists", customerUUID, bookUUID); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should use the correct constant message format for customer") + void testExceptionUsesConstantMessageCustomerFormat() { + UUID customerUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.of(customerUUID), Optional.empty()); + + String expectedFormatWithPlaceholder = "The reviews with the customer id {0} does not exists"; + assertEquals(ReviewNotFoundException.THE_REVIEWS_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE, + expectedFormatWithPlaceholder); + assertTrue(exception.getMessage().contains(customerUUID.toString())); + } + + @Test + @DisplayName("Exception should use the correct constant message format for book") + void testExceptionUsesConstantMessageCustomerFormat() { + UUID bookUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.of(bookUUID)); + + String expectedFormatWithPlaceholder = "The reviews with the book id {0} does not exists"; + assertEquals(ReviewNotFoundException.THE_REVIEWS_WITH_BOOK_ID_DOES_NOT_EXIST_MESSAGE, + expectedFormatWithPlaceholder); + assertTrue(exception.getMessage().contains(bookUUID.toString())); + } + + @Test + @DisplayName("Exception should use the correct constant message format for customer and book") + void testExceptionUsesConstantMessageCustomerFormat() { + UUID customerUUID = UUID.randomUUID(); + UUID bookUUID = UUID.randomUUID(); + + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.of(customerUUID), Optional.of(bookUUID)); + + String expectedFormatWithPlaceholder = "The reviews with the customer id {0} and the book id {1} does not exists"; + assertEquals(ReviewNotFoundException.THE_REVIEWS_WITH_CUSTOMER_ID_AND_BOOK_ID_DOES_NOT_EXIST_MESSAGE, + expectedFormatWithPlaceholder); + assertTrue(exception.getMessage().contains(customerUUID.toString())); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + UUID customerUUID = UUID.randomUUID(); + + try { + throw new ReviewNotFoundException(Optional.of(customerUUID), Optional.empty()); + } catch (ReviewNotFoundException e) { + String expectedMessage = String.format("The reviews with the customer id %s does not exists", customerUUID); + assertEquals(expectedMessage, e.getMessage()); + } + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCaseTest.java new file mode 100644 index 0000000..91bde51 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCaseTest.java @@ -0,0 +1,310 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException; +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 fr.iut_fbleau.but3.dev62.mylibrary.review.exception.NotValidReviewException; +import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.UUID; + +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.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; + +public class ReviewUseCaseTest { + + @Mock + private ReviewRepository reviewRepository; + + @InjectMocks + private ReviewUseCase reviewUseCase; + + private UUID customerId; + private UUID bookId; + private LocalDate purchaseDate; + private Review testReview; + private ReviewInfo validReviewInfo; + + @BeforeEach + void setUp() { + customerId = UUID.randomUUID(); + bookId = UUID.randomUUID(); + purchaseDate = LocalDate.of(2026, 5, 24); + testReview = Review.builder() + .customerId(customerId) + .bookId(bookId) + .note(2) + .comment("plutôt mauvais") + .purchaseDate(purchaseDate) + .build(); + + validReviewInfo = new ReviewInfo(2, "plutôt mauvais", purchaseDate); + } + + @Nested + @DisplayName("Register review tests") + class RegisterReviewTests { + + @Test + @DisplayName("Should register review when valid data is provided") + void testRegisterReviewWithValidData() throws NotValidReviewException { + when(reviewRepository.save(any(Review.class))).thenReturn(testReview); + + UUID registeredId = reviewUseCase.registerReview(validReviewInfo); + + assertNotNull(registeredId); + assertEquals(customerId, registeredId); + verify(reviewRepository, times(1)).save(any(Review.class)); + } + + @Test + @DisplayName("Should throw exception when review data is not valid") + void testRegisterReviewWithInvalidData() { + ReviewInfo invalidReviewInfo = new ReviewInfo(2, "plutôt mauvais", purchaseDate); + + assertThrows(NotValidReviewException.class, + () -> reviewUseCase.registerCustomer(invalidReviewInfo)); + + verify(reviewRepository, never()).save(any(Review.class)); + } + } + + @Nested + @DisplayName("Find review tests") + class FindReviewTests { + + @Test + @DisplayName("Should return review when customer ID exists") + void testFindReviewByCustomerId() { + when(reviewRepository.findByCustomerId(customerId)).thenReturn(Optional.of(testReview)); + + Optional foundReview = reviewUseCase.findReviewByCustomerId(customerId); + + assertTrue(foundReview.isPresent()); + assertEquals(testReview.getBookId(), foundReview.get().getBookId()); + assertEquals(testReview.getNote(), foundReview.get().getNote()); + verify(reviewRepository, times(1)).findByCustomerId(customerId); + } + + @Test + @DisplayName("Should return empty Optional when customer ID doesn't exist") + void testFindReviewByCustomerIdNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(Optional.empty()); + + Optional foundReview = reviewUseCase.findReviewByCustomerId(nonExistentCustomerId); + + assertTrue(foundReview.isEmpty()); + verify(reviewRepository, times(1)).findByCustomerId(nonExistentCustomerId); + } + + @Test + @DisplayName("Should return review when book ID exists") + void testFindReviewByBookId() { + when(reviewRepository.findByBookId(bookId)).thenReturn(Optional.of(testReview)); + + Optional foundReview = reviewUseCase.findReviewByBookId(bookId); + + assertTrue(foundReview.isPresent()); + assertEquals(testReview.getCustomerId(), foundReview.get().getCustomerId()); + assertEquals(testReview.getNote(), foundReview.get().getNote()); + verify(reviewRepository, times(1)).findByBookId(bookId); + } + + @Test + @DisplayName("Should return empty Optional when book ID doesn't exist") + void testFindReviewByBookIdNotFound() { + UUID nonExistentBookId = UUID.randomUUID(); + when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(Optional.empty()); + + Optional foundReview = reviewUseCase.findReviewByBookId(nonExistentBookId); + + assertTrue(foundReview.isEmpty()); + verify(reviewRepository, times(1)).findByBookId(nonExistentBookId); + } + + @Test + @DisplayName("Should return review when customer and book ID exists") + void testFindReviewByCustomerAndBookId() { + when(reviewRepository.findByCustomerAndBookId(customerId, bookId)).thenReturn(Optional.of(testReview)); + + Optional foundReview = reviewUseCase.findReviewByCustomerAndBookId(customerId, bookId); + + assertTrue(foundReview.isPresent()); + assertEquals(testReview.getBookId(), foundReview.get().getBookId()); + assertEquals(testReview.getNote(), foundReview.get().getNote()); + verify(reviewRepository, times(1)).findByCustomerAndBookId(customerId, bookId); + } + + @Test + @DisplayName("Should return empty Optional when customer ID doesn't exist") + void testFindReviewByCustomerIdNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + UUID nonExistentBookId = UUID.randomUUID(); + when(reviewRepository.findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId)).thenReturn(Optional.empty()); + + Optional foundReview = reviewUseCase.findReviewByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId); + + assertTrue(foundReview.isEmpty()); + verify(reviewRepository, times(1)).findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId); + } + } + + @Nested + @DisplayName("Update review tests") + class UpdateReviewTests { + + @Test + @DisplayName("Should update review when valid data is provided") + void testUpdateReviewWithValidData() throws ReviewNotFoundException, NotValidReviewException { + when(reviewRepository.findByCustomerAndBookId(customerId, bookId)).thenReturn(Optional.of(testReview)); + + LocalDate updatePurchaseDate = LocalDate.of(2026, 5, 30); + Review updatedReview = Review.builder() + .customerId(customerId) + .bookId(bookId) + .note(4) + .comment("en fait c'est bien") + .purchaseDate(updatePurchaseDate) + .build(); + + when(reviewRepository.save(any(Review.class))).thenReturn(updatedReview); + + ReviewInfo updateInfo = new ReviewInfo(4, "en fait c'est bien", updatePurchaseDate); + + ReviewDTO result = reviewUseCase.updateReview(customerId, bookId, updateInfo); + + assertNotNull(result); + assertEquals(customerId, result.getCustomerId()); + assertEquals(4, result.getNote()); + assertEquals("en fait c'est bien", result.getComment()); + verify(reviewRepository, times(1)).findByCustomerAndBookId(customerId, bookId); + verify(reviewRepository, times(1)).save(any(Review.class)); + } + + @Test + @DisplayName("Should throw exception when customer and book ID doesn't exist") + void testUpdateReviewNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + UUID nonExistentBookId = UUID.randomUUID(); + when(reviewRepository.findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId)).thenReturn(Optional.empty()); + + LocalDate updatePurchaseDate = LocalDate.of(2026, 5, 24); + ReviewInfo updateInfo = new ReviewInfo(3, "moyen", updatePurchaseDate); + + assertThrows(ReviewNotFoundException.class, + () -> reviewUseCase.updateReview(nonExistentCustomerId, nonExistentBookId, updateInfo)); + + verify(reviewRepository, times(1)).findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId); + verify(reviewRepository, never()).save(any(Review.class)); + } + + @Test + @DisplayName("Should throw exception when update data is not valid") + void testUpdateReviewWithInvalidData() { + LocalDate updatePurchaseDate = LocalDate.of(2026, 5, 24); + ReviewInfo invalidUpdateInfo = new ReviewInfo(0, "éclaté au sol", updatePurchaseDate); + + assertThrows(NotValidCustomerException.class, + () -> reviewUseCase.updateCustomer(customerId, invalidUpdateInfo)); + + verify(reviewRepository, never()).findByCustomerAndBookId(any(UUID.class), any(UUID.class)); + verify(reviewRepository, never()).save(any(Review.class)); + } + } + + @Nested + @DisplayName("Delete review tests") + class DeleteReviewTests { + + @Test + @DisplayName("Should delete reviews when customer ID exists") + void testDeleteCustomerReviews() throws ReviewNotFoundException { + when(reviewRepository.findByCustomerId(customerId)).thenReturn(Optional.of(testReview)); + doNothing().when(reviewRepository).delete(testReview); + + reviewUseCase.deleteCustomerReviews(customerId); + + verify(reviewRepository, times(1)).findByCustomerId(customerId); + verify(reviewRepository, times(1)).delete(testReview); + } + + @Test + @DisplayName("Should throw exception when customer ID doesn't exist") + void testDeleteCustomerReviewsNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(Optional.empty()); + + assertThrows(ReviewNotFoundException.class, + () -> reviewUseCase.deleteCustomerReviews(nonExistentCustomerId)); + + verify(reviewRepository, times(1)).findByCustomerId(nonExistentCustomerId); + verify(reviewRepository, never()).delete(any(Review.class)); + } + + @Test + @DisplayName("Should delete reviews when book ID exists") + void testDeleteBookReviews() throws ReviewNotFoundException { + when(reviewRepository.findByBookId(bookId)).thenReturn(Optional.of(testReview)); + doNothing().when(reviewRepository).delete(testReview); + + reviewUseCase.deleteBookReviews(bookId); + + verify(reviewRepository, times(1)).findByBookId(bookId); + verify(reviewRepository, times(1)).delete(testReview); + } + + @Test + @DisplayName("Should throw exception when book ID doesn't exist") + void testDeleteBookReviewsNotFound() { + UUID nonExistentBookId = UUID.randomUUID(); + when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(Optional.empty()); + + assertThrows(ReviewNotFoundException.class, + () -> reviewUseCase.deleteBookReviews(nonExistentBookId)); + + verify(reviewRepository, times(1)).findByBookId(nonExistentBookId); + verify(reviewRepository, never()).delete(any(Review.class)); + } + + @Test + @DisplayName("Should delete review when customer and book ID exists") + void testDeleteReview() throws ReviewNotFoundException { + when(reviewRepository.findByCustomerAndBookId(customerId, bookId)).thenReturn(Optional.of(testReview)); + doNothing().when(reviewRepository).delete(testReview); + + reviewUseCase.deleteReview(customerId, bookId); + + verify(reviewRepository, times(1)).findByCustomerAndBookId(customerId, bookId); + verify(reviewRepository, times(1)).delete(testReview); + } + + @Test + @DisplayName("Should throw exception when customer and book ID doesn't exist") + void testDeleteReviewNotFound() { + UUID nonExistentCustomerId = UUID.randomUUID(); + UUID nonExistentBookId = UUID.randomUUID(); + when(reviewRepository.findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId)).thenReturn(Optional.empty()); + + assertThrows(ReviewNotFoundException.class, + () -> reviewUseCase.deleteReviews(nonExistentCustomerId, nonExistentBookId)); + + verify(reviewRepository, times(1)).findByCustomerAndBookId(nonExistentCustomerId, nonExistentBookId); + verify(reviewRepository, never()).delete(any(Review.class)); + } + } +}