diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java new file mode 100644 index 0000000..e838cad --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidatorTest.java @@ -0,0 +1,352 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDetails; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookSalesInfo; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class BookValidatorTest { + + @Test + @DisplayName("Should validate book with valid data") + void testValidateValidCustomer() { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo validBook = new BookInfo("0000000000000","La vie de Maxime", "Marvin Aubert", "Kioon", date); + + assertDoesNotThrow(() -> BookValidator.validate(validBook)); + } + + @Nested + @DisplayName("ISBN validation tests") + class ISBNValidationTests { + + @Test + @DisplayName("Should throw exception when isbn is blank") + void testValidateBlankTitle() { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithBlankTitle = new BookInfo("", "La vie de Maxime", "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithBlankTitle) + ); + + assertEquals(BookValidator.ISBN_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when title contains only whitespace") + void testValidateWhitespaceISBN(String whitespace) { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithWhitespaceTitle = new BookInfo(whitespace, "La vie de Maxime", "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceTitle) + ); + + assertEquals(BookValidator.TITLE_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {"00000", "0000000000", "0000000000000000"}) + @DisplayName("Should throw exception when isbn contains only thriteen character") + void testValidateThirteenCharacterISBN(String number) { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithWhitespaceTitle = new BookInfo(number, "La vie de Maxime", "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceTitle) + ); + + assertEquals(BookValidator.ISBN_CANNOT_CONTAIN_MORE_OR_LESS_THIRTEEN_CHARACTER, exception.getMessage()); + } + } + + @Nested + @DisplayName("Title validation tests") + class TitleValidationTests { + + @Test + @DisplayName("Should throw exception when title is blank") + void testValidateBlankTitle() { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithBlankTitle = new BookInfo("0000000000000","", "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithBlankTitle) + ); + + assertEquals(BookValidator.TITLE_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when title contains only whitespace") + void testValidateWhitespaceFirstName(String whitespace) { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithWhitespaceTitle = new BookInfo("0000000000000",whitespace, "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceTitle) + ); + + assertEquals(BookValidator.TITLE_CANNOT_BE_BLANK, exception.getMessage()); + } + } + + @Nested + @DisplayName("author validation tests") + class AuthorValidationTests { + + @Test + @DisplayName("Should throw exception when author is blank") + void testValidateBlankAuthor() { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithBlankAuthor = new BookInfo("0000000000000","La vie de Maxime", "", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithBlankAuthor) + ); + + assertEquals(BookValidator.AUTHOR_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when author contains only whitespace") + void testValidateWhitespaceAuthor(String whitespace) { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithWhitespaceAuthor = new BookInfo("0000000000000","La vie de Maxime", whitespace, "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceAuthor) + ); + + assertEquals(BookValidator.AUTHOR_CANNOT_BE_BLANK, exception.getMessage()); + } + } + + @Nested + @DisplayName("editor validation tests") + class EditorValidationTests { + + @Test + @DisplayName("Should throw exception when editor is blank") + void testValidateBlankEditor() { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithBlankEditor = new BookInfo("0000000000000","La vie de Maxime", "Marvin Aubert", "", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithBlankEditor) + ); + + assertEquals(BookValidator.EDITOR_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when editor contains only whitespace") + void testValidateWhitespaceEditor(String whitespace) { + LocalDate date = LocalDate.of(2026, 3, 24); + BookInfo bookWithWhitespaceEditor = new BookInfo("0000000000000","La vie de Maxime", "Marvin Aubert", whitespace, date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceEditor) + ); + + assertEquals(BookValidator.EDITOR_CANNOT_BE_BLANK, exception.getMessage()); + } + } + + @Nested + @DisplayName("date validation tests") + class DateValidationTests { + + @Test + @DisplayName("Should throw exception when date is after the actual date") + void testValidateFuturDate() { + LocalDate date = LocalDate.of(2026, 5, 24); + BookInfo bookWithFuturDate = new BookInfo("0000000000000","La vie de Maxime", "Marvin Aubert", "Kioon", date); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithFuturDate) + ); + + assertEquals(BookValidator.DATE_CANNOT_BE_AFTER_TODAY, exception.getMessage()); + } + } + + @Nested + @DisplayName("price validation tests") + class PriceValidationTests { + + @ParameterizedTest + @ValueSource(doubles = {-3, -15, 0}) + @DisplayName("Should throw exception when price is negative or equal to zero") + void testValidateNegativePrice(double invalidprice) { + BookSalesInfo bookWithNegativePrice = BookSalesInfo.builder() + .price(invalidprice) + .stock(10) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithNegativePrice) + ); + + assertEquals(BookValidator.PRICE_CANNOT_BE_NEGATIVE_OR_EQUAL_ZERO, exception.getMessage()); + } + } + + @Nested + @DisplayName("stock validation tests") + class StockValidationTests { + + @Test + @DisplayName("Should throw exception when stock is negative") + void testValidateNegativeSTock() { + BookSalesInfo bookWithNegativeStock = BookSalesInfo.builder() + .price(3) + .stock(-3) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithNegativeStock) + ); + + assertEquals(BookValidator.STOCK_CANNOT_BE_NEGATIVE, exception.getMessage()); + } + } + + @Nested + @DisplayName("categories validation tests") + class CategoriesValidationTests { + + @Test + @DisplayName("Should throw exception when categories is empty") + void testValidateBlankCategories() { + ArrayList categories = new ArrayList<>(); + String description = "C'était un brave partit trop tôt"; + String language = "Français"; + BookDetails bookWithEmptyCategories = BookDetails.builder() + .categories(categories) + .description(description) + .language(language) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithEmptyCategories) + ); + + assertEquals(BookValidator.Categories_CANNOT_BE_EMPTY, exception.getMessage()); + } + + @ParameterizedTest + @MethodSource("provideLists") + @DisplayName("Should throw exception when categories contains an whitespace") + void testValidateWhitespaceCategories(ArrayList invalidlist) { + String description = "C'était un brave partit trop tôt"; + String language = "Français"; + BookDetails bookWithWhitespaceCategories = BookDetails.builder() + .categories(invalidlist) + .description(description) + .language(language) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceCategories) + ); + + assertEquals(BookValidator.Categories_CANNOT_CONTAIN_BLANK, exception.getMessage()); + } + + static Stream> provideLists() { + return Stream.of( + new ArrayList(java.util.List.of("")), + new ArrayList(java.util.List.of(" ")), + new ArrayList(java.util.List.of(" ")), + new ArrayList(java.util.List.of("\t")), + new ArrayList(java.util.List.of("\n")), + new ArrayList(java.util.List.of("A", "", "C")) + ); + } + } + + @Nested + @DisplayName("language validation tests") + class LanguageValidationTests { + + @Test + @DisplayName("Should throw exception when language is blank") + void testValidateNegativeLanguage() { + ArrayList categories = new ArrayList<>(); + categories.add("Thriller"); + categories.add("Biographie"); + String description = "C'était un brave partit trop tôt"; + String language = ""; + + BookDetails bookWithBlankLanguage = BookDetails.builder() + .categories(categories) + .description(description) + .language(language) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithBlankLanguage) + ); + + assertEquals(BookValidator.LANGUAGE_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when language contains only whitespace") + void testValidateWhitespaceLanguage(String whitespace) { + ArrayList categories = new ArrayList<>(); + categories.add("Thriller"); + categories.add("Biographie"); + String description = "C'était un brave partit trop tôt"; + + BookDetails bookWithWhitespaceLanguage = BookDetails.builder() + .categories(categories) + .description(description) + .language(whitespace) + .build(); + + NotValidBookException exception = assertThrows( + NotValidBookException.class, + () -> BookValidator.validate(bookWithWhitespaceLanguage) + ); + + assertEquals(BookValidator.LANGUAGE_CANNOT_BE_BLANK, exception.getMessage()); + } + } +}