diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java new file mode 100644 index 0000000..b687a13 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java @@ -0,0 +1,25 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +import java.text.MessageFormat; +import java.util.Optional; +import java.util.UUID; + +public class ReviewNotFoundException extends RuntimeException { + + public static final String THE_REVIEWS_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE = "The reviews with the customer id {0} does not exists"; + public static final String THE_REVIEWS_WITH_BOOK_ID_DOES_NOT_EXIST_MESSAGE = "The reviews with the book id {0} does not exists"; + public static final String THE_REVIEWS_WITH_AVIS_ID_DOES_NOT_EXIST_MESSAGE = "The review with avis id {0} does not exists"; + + public ReviewNotFoundException(Optional customerUUID, Optional bookUUID, Optional avisUUID) { + super(buildMessage(customerUUID, bookUUID, avisUUID)); + } + + private static String buildMessage(Optional customerUUID, Optional bookUUID, Optional avisUUID) { + if (customerUUID.isPresent()) { + return MessageFormat.format(THE_REVIEWS_WITH_CUSTOMER_ID_DOES_NOT_EXIST_MESSAGE, customerUUID.get()); + }else if (bookUUID.isPresent()) { + return MessageFormat.format(THE_REVIEWS_WITH_BOOK_ID_DOES_NOT_EXIST_MESSAGE, bookUUID.get()); + } + return MessageFormat.format(THE_REVIEWS_WITH_AVIS_ID_DOES_NOT_EXIST_MESSAGE, avisUUID.get()); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java new file mode 100644 index 0000000..aa63f16 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java @@ -0,0 +1,113 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.usecase; + +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.converter.ReviewConverter; +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.exception.ReviewNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.review.validator.ReviewValidator; + +import java.util.ArrayList; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReviewUseCase { + + private final ReviewRepository reviewRepository; + + public ReviewUseCase(ReviewRepository reviewRepository) { + this.reviewRepository = reviewRepository; + } + + public UUID registerReview(ReviewInfo newReview) throws NotValidReviewException { + ReviewValidator.validate(newReview); + Review reviewToRegister = ReviewConverter.toDomain(newReview); + Review reviewToRegistered = reviewRepository.save(reviewToRegister); + return reviewToRegistered.getAvisId(); + } + + public ArrayList findReviewByCustomerId(UUID customerId) { + ArrayList optionalReviews = reviewRepository.findByCustomerId(customerId); + return optionalReviews.stream() + .map(ReviewConverter::toDTO) + .collect(Collectors.toCollection(ArrayList::new)); + } + + public ArrayList findReviewByBookId(UUID bookId) { + ArrayList optionalReviews = reviewRepository.findByBookId(bookId); + return optionalReviews.stream() + .map(ReviewConverter::toDTO) + .collect(Collectors.toCollection(ArrayList::new)); + } + + public Optional findReviewByAvisId(UUID avisId) { + Optional optionalReview = reviewRepository.findByAvisId(avisId); + return optionalReview.map(ReviewConverter::toDTO); + } + + public ReviewDTO updateReview(UUID avisUUID, ReviewInfo reviewInfo) + throws ReviewNotFoundException, NotValidReviewException { + ReviewValidator.validate(reviewInfo); + Review reviewByAvisUUID = getReviewIfDoesNotExistThrowReviewNotFoundException( + avisUUID); + Review review = Review.builder() + .avisId(avisUUID) + .customerId(reviewByAvisUUID.getCustomerId()) + .bookId(reviewByAvisUUID.getBookId()) + .note(reviewByAvisUUID.getNote()) + .comment(reviewByAvisUUID.getComment()) + .purchaseDate(reviewByAvisUUID.getPurchaseDate()) + .build(); + Review updatedReview = reviewRepository.save(review); + return ReviewConverter.toDTO(updatedReview); + } + + public void deleteReview(UUID avisUUID) throws ReviewNotFoundException { + Review reviewToDelete = getReviewIfDoesNotExistThrowReviewNotFoundException(avisUUID); + this.reviewRepository.delete(reviewToDelete); + } + + public void deleteCustomerReviews(UUID customerUUID) throws ReviewNotFoundException { + ArrayList reviewsToDelete = getReviewByCustomerIdIfDoesNotExistThrowReviewNotFoundException(customerUUID); + for (Review review : reviewsToDelete) { + reviewRepository.delete(review); + } + } + + public void deleteBookReviews(UUID bookUUID) throws ReviewNotFoundException { + ArrayList reviewsToDelete = getReviewByBookIfDoesNotExistThrowReviewNotFoundException(bookUUID); + for (Review review : reviewsToDelete) { + reviewRepository.delete(review); + } + } + + private Review getReviewIfDoesNotExistThrowReviewNotFoundException(UUID avisUUID) + throws ReviewNotFoundException { + Optional optionalReviewByAvisId = reviewRepository.findByAvisId(avisUUID); + if (optionalReviewByAvisId.isEmpty()) { + throw new ReviewNotFoundException(Optional.empty(), Optional.empty(),Optional.of(avisUUID)); + } + return optionalReviewByAvisId.get(); + } + + private ArrayList getReviewByCustomerIdIfDoesNotExistThrowReviewNotFoundException(UUID customerUUID) + throws ReviewNotFoundException { + ArrayList optionalReviewByAvisId = reviewRepository.findByCustomerId(customerUUID); + if (optionalReviewByAvisId.isEmpty()) { + throw new ReviewNotFoundException(Optional.of(customerUUID), Optional.empty(),Optional.empty()); + } + return optionalReviewByAvisId; + } + + private ArrayList getReviewByBookIfDoesNotExistThrowReviewNotFoundException(UUID bookUUID) + throws ReviewNotFoundException { + ArrayList optionalReviewByAvisId = reviewRepository.findByBookId(bookUUID); + if (optionalReviewByAvisId.isEmpty()) { + throw new ReviewNotFoundException(Optional.empty(), Optional.empty(), Optional.of(bookUUID)); + } + return optionalReviewByAvisId; + } +} 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 index 34ec57b..f9c2951 100644 --- 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 @@ -29,7 +29,7 @@ public class ReviewNotFoundExceptionTest { ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.of(bookUUID), Optional.empty()); - String expectedMessage = String.format("The reviews with book id %s does not exists", bookUUID); + String expectedMessage = String.format("The reviews with the book id %s does not exists", bookUUID); assertEquals(expectedMessage, exception.getMessage()); } @@ -40,7 +40,7 @@ public class ReviewNotFoundExceptionTest { ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.empty(), Optional.of(avisUUID)); - String expectedMessage = String.format("The review with id %s does not exists", avisUUID); + String expectedMessage = String.format("The review with avis id %s does not exists", avisUUID); assertEquals(expectedMessage, exception.getMessage()); } @@ -59,7 +59,7 @@ public class ReviewNotFoundExceptionTest { @Test @DisplayName("Exception should use the correct constant message format for book") - void testExceptionUsesConstantMessageCustomerFormat() { + void testExceptionUsesConstantMessageBookFormat() { UUID bookUUID = UUID.randomUUID(); ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.of(bookUUID), Optional.empty()); @@ -71,14 +71,14 @@ public class ReviewNotFoundExceptionTest { } @Test - @DisplayName("Exception should use the correct constant message format for customer and book") - void testExceptionUsesConstantMessageCustomerFormat() { + @DisplayName("Exception should use the correct constant message format for review") + void testExceptionUsesConstantMessageReviewFormat() { UUID avisUUID = UUID.randomUUID(); - ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.empty(), Optional.empty(avisUUID)); + ReviewNotFoundException exception = new ReviewNotFoundException(Optional.empty(), Optional.empty(), Optional.of(avisUUID)); - String expectedFormatWithPlaceholder = "The reviews with id {0} does not exists"; - assertEquals(ReviewNotFoundException.THE_REVIEWS_WITH_CUSTOMER_ID_AND_BOOK_ID_DOES_NOT_EXIST_MESSAGE, + String expectedFormatWithPlaceholder = "The review with avis id {0} does not exists"; + assertEquals(ReviewNotFoundException.THE_REVIEWS_WITH_AVIS_ID_DOES_NOT_EXIST_MESSAGE, expectedFormatWithPlaceholder); assertTrue(exception.getMessage().contains(avisUUID.toString())); } @@ -89,9 +89,9 @@ public class ReviewNotFoundExceptionTest { UUID avisUUID = UUID.randomUUID(); try { - throw new ReviewNotFoundException(Optional.of(avisUUID), Optional.empty()); + throw new ReviewNotFoundException(Optional.empty(),Optional.empty(), Optional.of(avisUUID)); } catch (ReviewNotFoundException e) { - String expectedMessage = String.format("The reviews id %s does not exists", avisUUID); + String expectedMessage = String.format("The review with avis id %s does not exists", avisUUID); 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 index 149f496..d10098d 100644 --- 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 @@ -1,19 +1,23 @@ 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.exception.ReviewNotFoundException; 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.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -25,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.mockito.Mockito.never; +@ExtendWith(MockitoExtension.class) public class ReviewUseCaseTest { @Mock @@ -70,14 +75,14 @@ public class ReviewUseCaseTest { UUID registeredId = reviewUseCase.registerReview(validReviewInfo); assertNotNull(registeredId); - assertEquals(customerId, registeredId); + assertEquals(avisId, 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); + ReviewInfo invalidReviewInfo = new ReviewInfo(0, "plutôt mauvais", purchaseDate); assertThrows(NotValidReviewException.class, () -> reviewUseCase.registerReview(invalidReviewInfo)); @@ -91,15 +96,16 @@ public class ReviewUseCaseTest { class FindReviewTests { @Test - @DisplayName("Should return review when customer ID exists") + @DisplayName("Should return reviews when customer ID exists") void testFindReviewByCustomerId() { - when(reviewRepository.findByCustomerId(customerId)).thenReturn(Optional.of(testReview)); + when(reviewRepository.findByCustomerId(customerId)).thenReturn(new ArrayList(List.of(testReview))); - Optional foundReview = reviewUseCase.findReviewByCustomerId(customerId); + ArrayList foundReviews = reviewUseCase.findReviewByCustomerId(customerId); - assertTrue(foundReview.isPresent()); - assertEquals(testReview.getBookId(), foundReview.get().getBookId()); - assertEquals(testReview.getNote(), foundReview.get().getNote()); + assertTrue(!foundReviews.isEmpty()); + boolean allSameCustomer = foundReviews.stream() + .allMatch(review -> review.getCustomerId().equals(customerId)); + assertTrue(allSameCustomer); verify(reviewRepository, times(1)).findByCustomerId(customerId); } @@ -107,24 +113,25 @@ public class ReviewUseCaseTest { @DisplayName("Should return empty Optional when customer ID doesn't exist") void testFindReviewByCustomerIdNotFound() { UUID nonExistentCustomerId = UUID.randomUUID(); - when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(Optional.empty()); + when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(new ArrayList()); - Optional foundReview = reviewUseCase.findReviewByCustomerId(nonExistentCustomerId); + ArrayList foundReviews = reviewUseCase.findReviewByCustomerId(nonExistentCustomerId); - assertTrue(foundReview.isEmpty()); + assertTrue(foundReviews.isEmpty()); verify(reviewRepository, times(1)).findByCustomerId(nonExistentCustomerId); } @Test - @DisplayName("Should return review when book ID exists") + @DisplayName("Should return reviews when book ID exists") void testFindReviewByBookId() { - when(reviewRepository.findByBookId(bookId)).thenReturn(Optional.of(testReview)); + when(reviewRepository.findByBookId(bookId)).thenReturn(new ArrayList(List.of(testReview))); - Optional foundReview = reviewUseCase.findReviewByBookId(bookId); + ArrayList foundReviews = reviewUseCase.findReviewByBookId(bookId); - assertTrue(foundReview.isPresent()); - assertEquals(testReview.getCustomerId(), foundReview.get().getCustomerId()); - assertEquals(testReview.getNote(), foundReview.get().getNote()); + assertTrue(!foundReviews.isEmpty()); + boolean allSameCustomer = foundReviews.stream() + .allMatch(review -> review.getBookId().equals(bookId)); + assertTrue(allSameCustomer); verify(reviewRepository, times(1)).findByBookId(bookId); } @@ -132,11 +139,11 @@ public class ReviewUseCaseTest { @DisplayName("Should return empty Optional when book ID doesn't exist") void testFindReviewByBookIdNotFound() { UUID nonExistentBookId = UUID.randomUUID(); - when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(Optional.empty()); + when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(new ArrayList()); - Optional foundReview = reviewUseCase.findReviewByBookId(nonExistentBookId); + ArrayList foundReviews = reviewUseCase.findReviewByBookId(nonExistentBookId); - assertTrue(foundReview.isEmpty()); + assertTrue(foundReviews.isEmpty()); verify(reviewRepository, times(1)).findByBookId(nonExistentBookId); } @@ -145,17 +152,17 @@ public class ReviewUseCaseTest { void testFindReviewByAvisId() { when(reviewRepository.findByAvisId(avisId)).thenReturn(Optional.of(testReview)); - Optional foundReview = reviewUseCase.findReviewByAvisId(customerId, bookId); + Optional foundReview = reviewUseCase.findReviewByAvisId(avisId); assertTrue(foundReview.isPresent()); assertEquals(testReview.getBookId(), foundReview.get().getBookId()); assertEquals(testReview.getNote(), foundReview.get().getNote()); - verify(reviewRepository, times(1)).findByAvisId(customerId, bookId); + verify(reviewRepository, times(1)).findByAvisId(avisId); } @Test - @DisplayName("Should return empty Optional when customer ID doesn't exist") - void testFindReviewByCustomerIdNotFound() { + @DisplayName("Should return empty Optional when avis ID doesn't exist") + void testFindReviewByAvisIdNotFound() { UUID nonExistentAvisId = UUID.randomUUID(); when(reviewRepository.findByAvisId(nonExistentAvisId)).thenReturn(Optional.empty()); @@ -200,19 +207,18 @@ public class ReviewUseCaseTest { } @Test - @DisplayName("Should throw exception when customer and book ID doesn't exist") + @DisplayName("Should throw exception when avis ID doesn't exist") void testUpdateReviewNotFound() { - UUID nonExistentCustomerId = UUID.randomUUID(); - UUID nonExistentBookId = UUID.randomUUID(); - when(reviewRepository.findByAvisId(nonExistentCustomerId, nonExistentBookId)).thenReturn(Optional.empty()); + UUID nonExistentAvisId = UUID.randomUUID(); + when(reviewRepository.findByAvisId(nonExistentAvisId)).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)); + () -> reviewUseCase.updateReview(nonExistentAvisId, updateInfo)); - verify(reviewRepository, times(1)).findByAvisId(nonExistentCustomerId, nonExistentBookId); + verify(reviewRepository, times(1)).findByAvisId(nonExistentAvisId); verify(reviewRepository, never()).save(any(Review.class)); } @@ -222,7 +228,7 @@ public class ReviewUseCaseTest { LocalDate updatePurchaseDate = LocalDate.of(2026, 5, 24); ReviewInfo invalidUpdateInfo = new ReviewInfo(0, "éclaté au sol", updatePurchaseDate); - assertThrows(NotValidCustomerException.class, + assertThrows(NotValidReviewException.class, () -> reviewUseCase.updateReview(avisId, invalidUpdateInfo)); verify(reviewRepository, never()).findByAvisId(any(UUID.class)); @@ -237,7 +243,7 @@ public class ReviewUseCaseTest { @Test @DisplayName("Should delete reviews when customer ID exists") void testDeleteCustomerReviews() throws ReviewNotFoundException { - when(reviewRepository.findByCustomerId(customerId)).thenReturn(Optional.of(testReview)); + when(reviewRepository.findByCustomerId(customerId)).thenReturn(new ArrayList(List.of(testReview))); doNothing().when(reviewRepository).delete(testReview); reviewUseCase.deleteCustomerReviews(customerId); @@ -250,7 +256,7 @@ public class ReviewUseCaseTest { @DisplayName("Should throw exception when customer ID doesn't exist") void testDeleteCustomerReviewsNotFound() { UUID nonExistentCustomerId = UUID.randomUUID(); - when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(Optional.empty()); + when(reviewRepository.findByCustomerId(nonExistentCustomerId)).thenReturn(new ArrayList()); assertThrows(ReviewNotFoundException.class, () -> reviewUseCase.deleteCustomerReviews(nonExistentCustomerId)); @@ -262,7 +268,7 @@ public class ReviewUseCaseTest { @Test @DisplayName("Should delete reviews when book ID exists") void testDeleteBookReviews() throws ReviewNotFoundException { - when(reviewRepository.findByBookId(bookId)).thenReturn(Optional.of(testReview)); + when(reviewRepository.findByBookId(bookId)).thenReturn(new ArrayList(List.of(testReview))); doNothing().when(reviewRepository).delete(testReview); reviewUseCase.deleteBookReviews(bookId); @@ -275,7 +281,7 @@ public class ReviewUseCaseTest { @DisplayName("Should throw exception when book ID doesn't exist") void testDeleteBookReviewsNotFound() { UUID nonExistentBookId = UUID.randomUUID(); - when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(Optional.empty()); + when(reviewRepository.findByBookId(nonExistentBookId)).thenReturn(new ArrayList()); assertThrows(ReviewNotFoundException.class, () -> reviewUseCase.deleteBookReviews(nonExistentBookId)); @@ -285,7 +291,7 @@ public class ReviewUseCaseTest { } @Test - @DisplayName("Should delete review when customer and book ID exists") + @DisplayName("Should delete review when avis ID exists") void testDeleteReview() throws ReviewNotFoundException { when(reviewRepository.findByAvisId(avisId)).thenReturn(Optional.of(testReview)); doNothing().when(reviewRepository).delete(testReview); @@ -297,13 +303,13 @@ public class ReviewUseCaseTest { } @Test - @DisplayName("Should throw exception when customer and book ID doesn't exist") + @DisplayName("Should throw exception when avis ID doesn't exist") void testDeleteReviewNotFound() { UUID nonExistentAvisId = UUID.randomUUID(); when(reviewRepository.findByAvisId(nonExistentAvisId)).thenReturn(Optional.empty()); assertThrows(ReviewNotFoundException.class, - () -> reviewUseCase.deleteReviews(nonExistentAvisId)); + () -> reviewUseCase.deleteReview(nonExistentAvisId)); verify(reviewRepository, times(1)).findByAvisId(nonExistentAvisId); verify(reviewRepository, never()).delete(any(Review.class));