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 index 9a517e5..6739236 100644 --- 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 @@ -5,7 +5,7 @@ import java.util.UUID; public class BookNotFoundException extends Exception { - public static final String THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE = "The book with ISBN {0} does not exist"; + 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)); diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java new file mode 100644 index 0000000..4f671cb --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewDto.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java new file mode 100644 index 0000000..eddd257 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/ReviewInfo.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java new file mode 100644 index 0000000..5c006a7 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverter.java @@ -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(); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java new file mode 100644 index 0000000..fe920db --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/Review.java @@ -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; + +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java new file mode 100644 index 0000000..0b07448 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +public class InvalidReviewRatingException extends RuntimeException { + public InvalidReviewRatingException(String message) { + super(message); + } +} + diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/NotValidReviewException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/NotValidReviewException.java new file mode 100644 index 0000000..99a3af8 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/NotValidReviewException.java @@ -0,0 +1,7 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +public class NotValidReviewException extends Exception { + public NotValidReviewException(String message) { + super(message); + } +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java new file mode 100644 index 0000000..5f92fa6 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +public class ReviewAlreadyExistsException extends RuntimeException { + public ReviewAlreadyExistsException(String message) { + super(message); + } +} + diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java new file mode 100644 index 0000000..4b3268a --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +public class ReviewNotFoundException extends RuntimeException { + public ReviewNotFoundException(String message) { + super(message); + } +} + diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java new file mode 100644 index 0000000..62bd97c --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepository.java @@ -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 reviews = new ArrayList<>(); + + public void save(Review review) { + reviews.add(review); + } + + public List findAll() { + return new ArrayList<>(reviews); + } + + public List findByIsbn(String isbn) { // Changed from long to String + return reviews.stream().filter(r -> r.getIsbn().equals(isbn)).collect(Collectors.toList()); + } + + public List findByCustomerId(UUID customerId) { + return reviews.stream().filter(r -> r.getCustomerId().equals(customerId)).collect(Collectors.toList()); + } + + public boolean existsByCustomerIdAndIsbn(UUID customerId, 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(); + } +} \ No newline at end of file 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..8156209 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCase.java @@ -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 getReviewsByBook(String isbn) { // Changed from long to String + return reviewRepository.findByIsbn(isbn); + } + + public List 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); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java new file mode 100644 index 0000000..83280c5 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidator.java @@ -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); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java index 26f1e1b..3b71ab1 100644 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/subscription/exception/SubscriptionNotFoundException.java @@ -5,8 +5,9 @@ import java.util.UUID; 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) { - super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); + super(MessageFormat.format(THE_SUBSCRIPTION_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); } } diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/review/ReviewSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/review/ReviewSteps.java new file mode 100644 index 0000000..68ee3c9 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/review/ReviewSteps.java @@ -0,0 +1,250 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.review; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +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.review.entity.Review; +import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.review.usecase.ReviewUseCase; +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.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ReviewSteps { + private final BookRepository bookRepository = new BookRepository(); + private final CustomerRepository customerRepository = new CustomerRepository(); + private final ReviewRepository reviewRepository = new ReviewRepository(); + private String errorMessage; + + @Given("the system contains the following books:") + public void theSystemContainsTheFollowingBooks(DataTable dataTable) { + bookRepository.deleteAll(); + List> books = dataTable.asMaps(String.class, String.class); + for (Map book : books) { + Book bookEntity = Book.builder() + .isbn(book.get("isbn")) + .title(book.get("title")) + .author(book.get("author")) + .publisher(book.get("publisher")) + .date(new Date()) + .price(Double.parseDouble(book.get("price"))) + .initialStock(Integer.parseInt(book.get("initialStock"))) + .categories(new ArrayList<>(Arrays.asList(book.get("categories").split(",")))) + .description(book.get("description")) + .language(book.get("language")) + .build(); + bookRepository.save(bookEntity); + } + } + + @And("the system contains the following users:") + public void theSystemContainsTheFollowingUsers(DataTable dataTable) { + customerRepository.deleteAll(); + List> users = dataTable.asMaps(String.class, String.class); + for (Map user : users) { + Customer customer = Customer.builder() + .id(UUID.fromString(user.get("customerId"))) + .firstName(user.get("firstName")) + .lastName(user.get("lastName")) + .phoneNumber(user.get("phoneNumber")) + .loyaltyPoints(Integer.parseInt(user.get("loyaltyPoints"))) + .build(); + customerRepository.save(customer); + } + } + + @And("the system contains the following reviews:") + public void theSystemContainsTheFollowingReviews(DataTable dataTable) { + reviewRepository.deleteAll(); + List> reviews = dataTable.asMaps(String.class, String.class); + for (Map reviewData : reviews) { + Review review = Review.builder() + .customerId(UUID.fromString(reviewData.get("customerId"))) + .isbn(reviewData.get("isbn")) + .rating(Integer.parseInt(reviewData.get("rating"))) + .comment(reviewData.get("comment")) + .build(); + reviewRepository.save(review); + } + } + + @When("I create a review for the book:") + public void iCreateAReviewForTheBook(DataTable dataTable) { + Map reviewData = dataTable.asMaps(String.class, String.class).get(0); + Review review = Review.builder() + .customerId(UUID.fromString(reviewData.get("customerId"))) + .isbn(reviewData.get("isbn")) + .rating(Integer.parseInt(reviewData.get("rating"))) + .comment(reviewData.get("comment")) + .build(); + reviewRepository.save(review); + } + + @Then("a new review is created") + public void aNewReviewIsCreated() { + // Verify that the review was successfully added to the repository + assertEquals(4, reviewRepository.findAll().size()); + } + + @When("I retrieve all reviews for the book:") + public void iRetrieveAllReviewsForTheBook(DataTable dataTable) { + String isbn = dataTable.asMaps(String.class, String.class).get(0).get("isbn"); + List reviews = reviewRepository.findByIsbn(isbn); + assertNotNull(reviews, "No reviews found for the book with ISBN: " + isbn); + } + + @Then("I receive the following reviews:") + public void iReceiveTheFollowingReviews(DataTable dataTable) { + List> expectedReviews = dataTable.asMaps(String.class, String.class); + String isbn = expectedReviews.get(0).get("isbn"); // Extract ISBN from the expected data + List actualReviews = reviewRepository.findByIsbn(isbn); // Filter reviews by ISBN + + assertEquals(expectedReviews.size(), actualReviews.size(), "Mismatch in the number of reviews."); + + for (int i = 0; i < expectedReviews.size(); i++) { + Map expected = expectedReviews.get(i); + Review actual = actualReviews.get(i); + + assertEquals(UUID.fromString(expected.get("customerId")), actual.getCustomerId(), "Customer ID mismatch."); + assertEquals(expected.get("isbn"), actual.getIsbn(), "ISBN mismatch."); + assertEquals(Integer.parseInt(expected.get("rating")), actual.getRating(), "Rating mismatch."); + assertEquals(expected.get("comment"), actual.getComment(), "Comment mismatch."); + } + } + + @When("I retrieve all reviews for the user:") + public void iRetrieveAllReviewsForTheUser(DataTable dataTable) { + String customerId = dataTable.asMaps(String.class, String.class).get(0).get("customerId"); + List reviews = reviewRepository.findByCustomerId(UUID.fromString(customerId)); + assertNotNull(reviews, "No reviews found for the user with ID: " + customerId); + } + + @When("I update the review for the book:") + public void iUpdateTheReviewForTheBook(DataTable dataTable) { + Map reviewData = dataTable.asMaps(String.class, String.class).get(0); + Review updatedReview = Review.builder() + .customerId(UUID.fromString(reviewData.get("customerId"))) + .isbn(reviewData.get("isbn")) + .rating(Integer.parseInt(reviewData.get("rating"))) + .comment(reviewData.get("comment")) + .build(); + reviewRepository.update(updatedReview); + } + + @Then("the review is updated with the following details:") + public void theReviewIsUpdatedWithTheFollowingDetails(DataTable dataTable) { + List> expectedReviews = dataTable.asMaps(String.class, String.class); + for (Map expected : expectedReviews) { + String isbn = expected.get("isbn"); + UUID customerId = UUID.fromString(expected.get("customerId")); + Review actualReview = reviewRepository.findByCustomerId(customerId) + .stream() + .filter(r -> r.getIsbn().equals(isbn)) + .findFirst() + .orElseThrow(() -> new AssertionError("Review not found for customer ID: " + customerId + " and ISBN: " + isbn)); + + assertEquals(Integer.parseInt(expected.get("rating")), actualReview.getRating(), "Rating mismatch."); + assertEquals(expected.get("comment"), actualReview.getComment(), "Comment mismatch."); + } + } + + @When("I delete the review for the book:") + public void iDeleteTheReviewForTheBook(DataTable dataTable) { + Map reviewData = dataTable.asMaps(String.class, String.class).get(0); + String isbn = reviewData.get("isbn"); + UUID customerId = UUID.fromString(reviewData.get("customerId")); + reviewRepository.deleteByCustomerIdAndIsbn(customerId, isbn); + } + + @Then("the review is removed from the system") + public void theReviewIsRemovedFromTheSystem() { + // Verify that the specific review targeted for deletion no longer exists + boolean exists = reviewRepository.existsByCustomerIdAndIsbn(UUID.fromString("33333333-3333-3333-3333-333333333333"), "9789876543210"); + assertEquals(false, exists, "Review still exists for customer ID: 33333333-3333-3333-3333-333333333333 and ISBN: 9789876543210"); + } + + @When("I attempt to submit a review for the book:") + public void iAttemptToSubmitAReviewForTheBook(DataTable dataTable) { + Map reviewData = dataTable.asMaps(String.class, String.class).get(0); + Review review = Review.builder() + .customerId(UUID.fromString(reviewData.get("customerId"))) + .isbn(reviewData.get("isbn")) + .rating(Integer.parseInt(reviewData.get("rating"))) + .comment(reviewData.get("comment")) + .build(); + try { + ReviewUseCase reviewUseCase = new ReviewUseCase(reviewRepository, bookRepository, customerRepository); + reviewUseCase.submitReview(review); + } catch (Exception e) { + errorMessage = e.getMessage(); // Capture the error message + } + } + + @Then("the review is not created") + public void theReviewIsNotCreated() { + assertEquals(3, reviewRepository.findAll().size(), "Unexpected number of reviews in the system."); + assertNotNull(errorMessage, "Expected an error message indicating why the review was not created."); + } + + @And("I receive an error indicating that the review already exists") + public void iReceiveAnErrorIndicatingThatTheReviewAlreadyExists() { + // Verify error handling logic (e.g., check logs or error messages) + assertNotNull(errorMessage, "Expected error message indicating duplicate review."); + } + + @And("I receive an error indicating that the rating is invalid") + public void iReceiveAnErrorIndicatingThatTheRatingIsInvalid() { + assertNotNull(errorMessage, "Expected error message indicating invalid rating."); + assertEquals("Rating must be between 1 and 5", errorMessage, "Unexpected error message."); + } + + @And("I receive an error indicating that the book does not exist") + public void iReceiveAnErrorIndicatingThatTheBookDoesNotExist() { + assertNotNull(errorMessage, "Expected error message indicating that the book does not exist."); + assertEquals("Book not found: 9780000000000", errorMessage, "Unexpected error message."); + } + + @And("I receive an error indicating that the user does not exist") + public void iReceiveAnErrorIndicatingThatTheUserDoesNotExist() { + assertNotNull(errorMessage, "Expected error message indicating that the user does not exist."); + assertEquals("The customer with id 99999999-9999-9999-9999-999999999999 does not exist", errorMessage, "Unexpected error message."); + } + + @When("I attempt to delete the review for the book:") + public void iAttemptToDeleteTheReviewForTheBook(DataTable dataTable) { + Map reviewData = dataTable.asMaps(String.class, String.class).get(0); + String isbn = reviewData.get("isbn"); + UUID customerId = UUID.fromString(reviewData.get("customerId")); + try { + ReviewUseCase reviewUseCase = new ReviewUseCase(reviewRepository, bookRepository, customerRepository); + reviewUseCase.deleteReview(isbn, customerId); + } catch (Exception e) { + errorMessage = e.getMessage(); // Capture the error message + } + } + + @Then("the review is not deleted") + public void theReviewIsNotDeleted() { + assertEquals(3, reviewRepository.findAll().size(), "Unexpected number of reviews in the system."); + assertNotNull(errorMessage, "Expected an error message indicating why the review was not deleted."); + } + + @And("I receive an error indicating that the review does not exist") + public void iReceiveAnErrorIndicatingThatTheReviewDoesNotExist() { + assertNotNull(errorMessage, "Expected error message indicating that the review does not exist."); + assertEquals("Review not found for this customer and book.", errorMessage, "Unexpected error message."); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverterTest.java new file mode 100644 index 0000000..910ab86 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/converter/ReviewConverterTest.java @@ -0,0 +1,45 @@ +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 org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +public class ReviewConverterTest { + @Test + void testToDto() { + Review review = Review.builder() + .customerId(UUID.fromString("11111111-1111-1111-1111-111111111111")) + .isbn("9781234567890") // Changed from long to String + .rating(5) + .comment("Excellent book!") + .build(); + UUID reviewId = UUID.randomUUID(); + String customerName = "Marie Dupont"; + ReviewDto dto = ReviewConverter.toDto(review, reviewId, customerName); + assertEquals(reviewId, dto.getReviewId()); + assertEquals("9781234567890", dto.getBookId()); // Changed from long to String + assertEquals("Marie Dupont", dto.getCustomerName()); + assertEquals("Excellent book!", dto.getComment()); + assertEquals(5, dto.getRating()); + } + + @Test + void testToDomain() { + ReviewInfo info = ReviewInfo.builder() + .customerId("11111111-1111-1111-1111-111111111111") + .isbn("9781234567890") // Changed from long to String + .rating(4) + .comment("Bon livre") + .build(); + Review review = ReviewConverter.toDomain(info); + assertEquals(UUID.fromString("11111111-1111-1111-1111-111111111111"), review.getCustomerId()); + assertEquals("9781234567890", review.getIsbn()); // Changed from long to String + assertEquals(4, review.getRating()); + assertEquals("Bon livre", review.getComment()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/ReviewTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/ReviewTest.java new file mode 100644 index 0000000..7d97752 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/entity/ReviewTest.java @@ -0,0 +1,68 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.entity; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Review Entity Tests") +class ReviewTest { + + @Test + @DisplayName("Should create a Review object with valid data") + void testReviewCreation() { + UUID customerId = UUID.randomUUID(); + String isbn = "9781234567890"; + int rating = 5; + String comment = "Excellent book!"; + + Review review = Review.builder() + .customerId(customerId) + .isbn(isbn) + .rating(rating) + .comment(comment) + .build(); + + assertNotNull(review); + assertEquals(customerId, review.getCustomerId()); + assertEquals(isbn, review.getIsbn()); + assertEquals(rating, review.getRating()); + assertEquals(comment, review.getComment()); + } + + @Test + @DisplayName("Should handle null values gracefully") + void testReviewWithNullValues() { + Review review = Review.builder() + .customerId(null) + .isbn(null) + .rating(1) // Use a valid rating within the range + .comment(null) + .build(); + + assertNotNull(review); + assertNull(review.getCustomerId()); + assertNull(review.getIsbn()); + assertEquals(1, review.getRating()); // Adjusted expected value + assertNull(review.getComment()); + } + + @Test + @DisplayName("Should throw exception for invalid rating") + void testInvalidRating() { + int invalidRating = -1; + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + Review.builder() + .customerId(UUID.randomUUID()) + .isbn("9781234567890") + .rating(invalidRating) + .comment("Invalid rating") + .build(); + }); + + assertTrue(exception.getMessage().contains("Rating must be between 1 and 5")); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingExceptionTest.java new file mode 100644 index 0000000..be4752a --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/InvalidReviewRatingExceptionTest.java @@ -0,0 +1,14 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class InvalidReviewRatingExceptionTest { + @Test + void testMessage() { + String msg = "Invalid review rating!"; + InvalidReviewRatingException ex = new InvalidReviewRatingException(msg); + assertEquals(msg, ex.getMessage()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsExceptionTest.java new file mode 100644 index 0000000..bc7f804 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewAlreadyExistsExceptionTest.java @@ -0,0 +1,14 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ReviewAlreadyExistsExceptionTest { + @Test + void testMessage() { + String msg = "Review already exists!"; + ReviewAlreadyExistsException ex = new ReviewAlreadyExistsException(msg); + assertEquals(msg, ex.getMessage()); + } +} 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..ded7356 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/exception/ReviewNotFoundExceptionTest.java @@ -0,0 +1,14 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ReviewNotFoundExceptionTest { + @Test + void testMessage() { + String msg = "Review not found!"; + ReviewNotFoundException ex = new ReviewNotFoundException(msg); + assertEquals(msg, ex.getMessage()); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepositoryTest.java new file mode 100644 index 0000000..0fe544e --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/repository/ReviewRepositoryTest.java @@ -0,0 +1,69 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Review Repository Tests") +class ReviewRepositoryTest { + + private final ReviewRepository reviewRepository = new ReviewRepository(); + + @Test + @DisplayName("Should save and retrieve reviews") + void testSaveAndRetrieveReviews() { + Review review = Review.builder() + .customerId(UUID.randomUUID()) + .isbn("9781234567890") + .rating(5) + .comment("Excellent book!") + .build(); + + reviewRepository.save(review); + List reviews = reviewRepository.findAll(); + + assertEquals(1, reviews.size()); + assertEquals(review, reviews.get(0)); + } + + @Test + @DisplayName("Should find reviews by ISBN") + void testFindByIsbn() { + String isbn = "9781234567890"; + Review review = Review.builder() + .customerId(UUID.randomUUID()) + .isbn(isbn) + .rating(4) + .comment("Good book") + .build(); + + reviewRepository.save(review); + List reviews = reviewRepository.findByIsbn(isbn); + + assertEquals(1, reviews.size()); + assertEquals(review, reviews.get(0)); + } + + @Test + @DisplayName("Should delete reviews by customer ID and ISBN") + void testDeleteByCustomerIdAndIsbn() { + UUID customerId = UUID.randomUUID(); + String isbn = "9781234567890"; + Review review = Review.builder() + .customerId(customerId) + .isbn(isbn) + .rating(3) + .comment("Average book") + .build(); + + reviewRepository.save(review); + reviewRepository.deleteByCustomerIdAndIsbn(customerId, isbn); + + assertTrue(reviewRepository.findByIsbn(isbn).isEmpty()); + } +} \ No newline at end of file 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..1a62e56 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/usecase/ReviewUseCaseTest.java @@ -0,0 +1,124 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.review.usecase; + +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.book.repository.BookRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +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.repository.CustomerRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review; +import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.*; +import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.review.ReviewInfo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +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.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@DisplayName("Review Use Case Tests") +class ReviewUseCaseTest { + + private final ReviewRepository reviewRepository = new ReviewRepository(); + private final BookRepository bookRepository = new BookRepository(); + private final CustomerRepository customerRepository = new CustomerRepository(); + private final ReviewUseCase reviewUseCase = new ReviewUseCase(reviewRepository, bookRepository, customerRepository); + private Customer testCustomer; + private CustomerInfo validCustomerInfo; + private String bookISBN; + private Book testBook; + private BookInfo validBookInfo; + + String isbn = "9781234567890"; + UUID customerId = UUID.fromString("3826b7a7-1163-4f7e-bda4-19ec0d571656"); + + @BeforeEach + void setUp() { + testCustomer = Customer.builder() + .id(customerId) + .firstName("John") + .lastName("Doe") + .phoneNumber("0612345678") + .loyaltyPoints(100) + .build(); + + validCustomerInfo = new CustomerInfo("John", "Doe", "0612345678"); + + ArrayList categories = new ArrayList<>(); + categories.add("Histoire"); + categories.add("Action"); + Date date = Date.from(Instant.now()); + testBook = Book.builder() + .isbn(isbn) + .title("LivreRandom") + .author("John Doe") + .publisher("RandomPublisher") + .date(date) + .price(12.5) + .initialStock(50) + .categories(categories) + .description("Je suis un livre qui est composé de mots.") + .language("Francais") + .build(); + + validBookInfo = new BookInfo("bookISBN", "LivreRandom", "John Doe", "RandomPublisher", date, 12.5, 50, categories, "Je suis un livre qui est composé de mots.", "Francais"); + + bookRepository.save(testBook); + customerRepository.save(testCustomer); + + System.out.println("Customers in repository:"); + customerRepository.findAll().forEach(customer -> System.out.println("ID: " + customer.getId())); + + // Debug: Print the ID being searched + System.out.println("Searching for customer with ID: " + customerId); + + // Find the customer + Customer customerFound = customerRepository.findById(customerId) + .orElseThrow(() -> new RuntimeException("Customer not found")); + + System.out.println("Customer found: " + customerFound.getId()); + } + + + @Test + @DisplayName("Should submit a valid review") + void testSubmitReview() { + Review review = Review.builder() + .customerId(UUID.fromString("3826b7a7-1163-4f7e-bda4-19ec0d571656")) + .isbn("9781234567890") + .rating(4) + .comment("Great book!") + .build(); + + assertDoesNotThrow(() -> reviewUseCase.submitReview(review), "La soumission de la revue a échoué."); + } + + + @Test + @DisplayName("Should throw exception for duplicate review") + void testDuplicateReview() { + // Create the review + Review review = Review.builder() + .customerId(customerId) + .isbn(isbn) + .rating(5) + .comment("Great book!") + .build(); + + // Submit the first review + assertDoesNotThrow(() -> reviewUseCase.submitReview(review), "La soumission de la première revue a échoué."); + + // Attempt to submit a duplicate review + Exception exception = assertThrows(ReviewAlreadyExistsException.class, () -> reviewUseCase.submitReview(review)); + assertEquals("Review already exists for this customer and book.", exception.getMessage(), "Le message d'erreur est incorrect."); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidatorTest.java new file mode 100644 index 0000000..4232a61 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/review/validator/ReviewValidatorTest.java @@ -0,0 +1,55 @@ +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; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Review Validator Tests") +class ReviewValidatorTest { + + @Test + @DisplayName("Should validate a valid review") + void testValidReview() { + Review review = Review.builder() + .customerId(UUID.randomUUID()) + .isbn("9781234567890") + .rating(5) + .comment("Great book!") + .build(); + + assertDoesNotThrow(() -> ReviewValidator.validate(review)); + } + + @Test + @DisplayName("Should throw exception for invalid rating") + void testInvalidRating() { + Review review = Review.builder() + .customerId(UUID.randomUUID()) + .isbn("9781234567890") + .rating(6) // Invalid rating + .comment("Interesting book") + .build(); + + Exception exception = assertThrows(InvalidReviewRatingException.class, () -> ReviewValidator.validate(review)); + assertEquals("Rating must be between 1 and 5", exception.getMessage()); + } + + @Test + @DisplayName("Should throw exception for invalid ISBN") + void testInvalidISBN() { + Review review = Review.builder() + .customerId(UUID.randomUUID()) + .isbn("123") + .rating(4) + .comment("Interesting book") + .build(); + + Exception exception = assertThrows(IllegalArgumentException.class, () -> ReviewValidator.validate(review)); + assertEquals("ISBN must be a valid 13-digit string", exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/resources/ReviewSteps.kt b/src/test/resources/ReviewSteps.kt new file mode 100644 index 0000000..8fd91d3 --- /dev/null +++ b/src/test/resources/ReviewSteps.kt @@ -0,0 +1,8 @@ +import io.cucumber.java.en.Given + +class ReviewSteps { + + @Given("the system contains the following books:") + fun theSystemContainsTheFollowingBooks() { + } +} \ No newline at end of file diff --git a/src/test/resources/features/review.feature b/src/test/resources/features/review.feature new file mode 100644 index 0000000..5b3b094 --- /dev/null +++ b/src/test/resources/features/review.feature @@ -0,0 +1,102 @@ +# language: en + +Feature: Manage Reviews + + Background: + Given the system contains the following books: + | isbn | title | author | publisher | publicationDate | price | initialStock | categories | description | language | + | 9781234567890 | Test Book 1 | Author 1 | Publisher 1 | 2020-01-01 | 10.0 | 10 | FICTION | A great book | EN | + | 9789876543210 | Test Book 2 | Author 2 | Publisher 2 | 2021-05-10 | 15.0 | 5 | SCIENCE_FICTION | A sci-fi book | EN | + And the system contains the following users: + | customerId | firstName | lastName | phoneNumber | loyaltyPoints | + | 11111111-1111-1111-1111-111111111111 | Marie | Dupont | 0612345678 | 100 | + | 22222222-2222-2222-2222-222222222222 | Jean | Martin | 0687654321 | 50 | + | 33333333-3333-3333-3333-333333333333 | Sophie | Dubois | 0698765432 | 0 | + | 44444444-4444-4444-4444-444444444444 | Pierre | Lambert | 0611223344 | 0 | + And the system contains the following reviews: + | customerId | isbn | rating | comment | + | 11111111-1111-1111-1111-111111111111 | 9781234567890 | 5 | Excellent book! | + | 22222222-2222-2222-2222-222222222222 | 9781234567890 | 3 | Average, but readable. | + | 33333333-3333-3333-3333-333333333333 | 9789876543210 | 4 | Very interesting. | + + Scenario: Create a review for a book + When I create a review for the book: + | isbn | customerId | rating | comment | + | 9781234567890 | 44444444-4444-4444-4444-444444444444 | 4 | cool | + Then a new review is created + And the system contains the following reviews: + | customerId | isbn | rating | comment | + | 11111111-1111-1111-1111-111111111111 | 9781234567890 | 5 | Excellent book! | + | 22222222-2222-2222-2222-222222222222 | 9781234567890 | 3 | Average, but readable. | + | 33333333-3333-3333-3333-333333333333 | 9789876543210 | 4 | Very interesting. | + | 44444444-4444-4444-4444-444444444444 | 9781234567890 | 4 | cool | + + Scenario: Retrieve all reviews for a book + When I retrieve all reviews for the book: + | isbn | + | 9781234567890 | + Then I receive the following reviews: + | customerId | isbn | rating | comment | + | 11111111-1111-1111-1111-111111111111 | 9781234567890 | 5 | Excellent book! | + | 22222222-2222-2222-2222-222222222222 | 9781234567890 | 3 | Average, but readable. | + + Scenario: Retrieve all reviews for a user + When I retrieve all reviews for the user: + | customerId | + | 33333333-3333-3333-3333-333333333333 | + Then I receive the following reviews: + | customerId | isbn | rating | comment | + | 33333333-3333-3333-3333-333333333333 | 9789876543210 | 4 | Very interesting. | + + Scenario: Update a review + When I update the review for the book: + | isbn | customerId | rating | comment | + | 9781234567890 | 22222222-2222-2222-2222-222222222222 | 4 | cool2 | + Then the review is updated with the following details: + | isbn | customerId | rating | comment | + | 9781234567890 | 22222222-2222-2222-2222-222222222222 | 4 | cool2 | + + Scenario: Delete a review + When I delete the review for the book: + | isbn | customerId | + | 9789876543210 | 33333333-3333-3333-3333-333333333333 | + Then the review is removed from the system + And the system contains the following reviews: + | customerId | isbn | rating | comment | + | 11111111-1111-1111-1111-111111111111 | 9781234567890 | 5 | Excellent book! | + | 22222222-2222-2222-2222-222222222222 | 9781234567890 | 3 | Average, but readable. | + + Scenario: Attempt to submit a duplicate review + When I attempt to submit a review for the book: + | isbn | customerId | rating | comment | + | 9781234567890 | 11111111-1111-1111-1111-111111111111 | 2 | Changed my mind. | + Then the review is not created + And I receive an error indicating that the review already exists + + Scenario: Attempt to submit a review with an invalid rating + When I attempt to submit a review for the book: + | isbn | customerId | rating | comment | + | 9781234567890 | 11111111-1111-1111-1111-111111111111 | 6 | Too good! | + Then the review is not created + And I receive an error indicating that the rating is invalid + + Scenario: Attempt to submit a review for a non-existent book + When I attempt to submit a review for the book: + | isbn | customerId | rating | comment | + | 9780000000000 | 11111111-1111-1111-1111-111111111111 | 3 | Not found | + Then the review is not created + And I receive an error indicating that the book does not exist + + Scenario: Attempt to submit a review for a non-existent user + When I attempt to submit a review for the book: + | isbn | customerId | rating | comment | + | 9781234567890 | 99999999-9999-9999-9999-999999999999 | 3 | Who am I? | + Then the review is not created + And I receive an error indicating that the user does not exist + + Scenario: Attempt to delete a non-existent review + When I attempt to delete the review for the book: + | isbn | customerId | + | 9781234567890 | 99999999-9999-9999-9999-999999999999 | + Then the review is not deleted + And I receive an error indicating that the review does not exist \ No newline at end of file