diff --git a/.github/workflows/automationtest.yml b/.github/workflows/automationtest.yml new file mode 100644 index 00000000..4fdd2383 --- /dev/null +++ b/.github/workflows/automationtest.yml @@ -0,0 +1,17 @@ +on: + pull_request: + branches: + - main + - develop +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn package -Dmaven.test.skip=true diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7ddfa42d --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Maven +log/ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### VS Code ### +.vscode + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# Log file +*.log + + +# MacOS +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..8445f3fa --- /dev/null +++ b/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + + ironlibrary + 0.0.1-SNAPSHOT + + + 21 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.mysql + mysql-connector-j + runtime + + + + org.projectlombok + lombok + true + + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/com/ironhack/IronLibrary.java b/src/main/java/com/ironhack/IronLibrary.java new file mode 100644 index 00000000..5622c3a4 --- /dev/null +++ b/src/main/java/com/ironhack/IronLibrary.java @@ -0,0 +1,30 @@ +package com.ironhack; + +import com.ironhack.viewer.LibraryMenu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.core.env.Environment; + +import java.util.Arrays; + +@SpringBootApplication +public class IronLibrary implements CommandLineRunner { + @Autowired + private LibraryMenu libraryMenu; + + @Autowired + private Environment environment; + + public static void main(String[] args) { + SpringApplication.run(IronLibrary.class, args); + } + + @Override + public void run(String... args) throws Exception { + if(!Arrays.asList(environment.getActiveProfiles()).contains("test")){ + libraryMenu.displayMenu(); + } + } +} diff --git a/src/main/java/com/ironhack/model/Author.java b/src/main/java/com/ironhack/model/Author.java new file mode 100644 index 00000000..ad890128 --- /dev/null +++ b/src/main/java/com/ironhack/model/Author.java @@ -0,0 +1,39 @@ +package com.ironhack.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Objects; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "author") +public class Author { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int authorId; + private String name; + private String email; + + public Author(String name, String email) { + setName(name); + setEmail(email); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Author author = (Author) o; + return authorId == author.authorId && Objects.equals(name, author.name) && Objects.equals(email, author.email); + } + + @Override + public int hashCode() { + return Objects.hash(authorId, name, email); + } +} \ No newline at end of file diff --git a/src/main/java/com/ironhack/model/Book.java b/src/main/java/com/ironhack/model/Book.java new file mode 100644 index 00000000..d3e27ce0 --- /dev/null +++ b/src/main/java/com/ironhack/model/Book.java @@ -0,0 +1,65 @@ +package com.ironhack.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Objects; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "book") +public class Book { + @Id + @Column(name = "isbn") + private String isbn; + + private String title; + + @Enumerated(EnumType.STRING) + private Categories category; + + private int quantity; + + @ManyToOne(cascade = CascadeType.PERSIST) + @JoinColumn(name = "author_id") + private Author authorBook; + + public Book(String isbn, String title, Categories category, int quantity, Author author) { + this.isbn = isbn; + this.title = title; + this.category = category; + this.quantity = quantity; + this.authorBook = author; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Book book)) return false; + return quantity == book.quantity && Objects.equals(isbn, book.isbn) && + Objects.equals(title, book.title) && category == book.category && + authorBook.getAuthorId() == book.authorBook.getAuthorId() && Objects.equals(authorBook.getName(), book.authorBook.getName()) && + book.authorBook.getEmail().equals(authorBook.getEmail()); + } + + @Override + public int hashCode() { + return Objects.hash(isbn, title, category, quantity, authorBook); + } + + public void updateQuantity(int newQuantity) { + this.quantity += newQuantity; + } + + @Override + public String toString() { + return String.format("%nISBN: %s%n" + + "Title: %s%n" + + "Category: %s%n" + + "No of Books: %d%n", isbn, title, category, quantity); + } +} diff --git a/src/main/java/com/ironhack/model/Categories.java b/src/main/java/com/ironhack/model/Categories.java new file mode 100644 index 00000000..45ed7bb4 --- /dev/null +++ b/src/main/java/com/ironhack/model/Categories.java @@ -0,0 +1,14 @@ +package com.ironhack.model; + +public enum Categories { + HORROR, + SCIENCE, + ROMANCE, + FICTION, + FANTASY, + ADVENTURE, + BIOGRAPHY, + MISTERY, + OTHERS + +} diff --git a/src/main/java/com/ironhack/model/Issue.java b/src/main/java/com/ironhack/model/Issue.java new file mode 100644 index 00000000..6381f4be --- /dev/null +++ b/src/main/java/com/ironhack/model/Issue.java @@ -0,0 +1,31 @@ +package com.ironhack.model; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor // Generates a no-args constructor for JPA +public class Issue { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int issueId; + private String issueDate; + private String returnDate; + @ManyToOne + @JoinColumn(name="issue_student") + private Student issueStudent; + @OneToOne + @JoinColumn(name="issue_book") + private Book issueBook; + + public Issue(String issueDate, String returnDate) { + this.issueDate = issueDate; + this.returnDate = returnDate; + } +} + + + diff --git a/src/main/java/com/ironhack/model/Student.java b/src/main/java/com/ironhack/model/Student.java new file mode 100644 index 00000000..1eba5f47 --- /dev/null +++ b/src/main/java/com/ironhack/model/Student.java @@ -0,0 +1,55 @@ +package com.ironhack.model; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Getter +@Setter +@Entity +@Table(name = "student") +@Data +public class Student { + @Id + private String usn; + private String name; + + @OneToMany(mappedBy = "issueStudent", cascade = CascadeType.ALL) + private List issues; + + public Student() { + } + + public Student(String usn, String name) { + this.usn = usn; + this.name = name; + } + + public void addIssue(Issue issue) { + if (issues == null) { + issues = new ArrayList<>(); + } + issues.add(issue); + issue.setIssueStudent(this); + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Student student = (Student) o; + return Objects.equals(usn, student.usn) && Objects.equals(name, student.name); + } + + @Override + public int hashCode() { + return Objects.hash(usn, name); + } + +} diff --git a/src/main/java/com/ironhack/repository/AuthorRepository.java b/src/main/java/com/ironhack/repository/AuthorRepository.java new file mode 100644 index 00000000..e1bfaafe --- /dev/null +++ b/src/main/java/com/ironhack/repository/AuthorRepository.java @@ -0,0 +1,12 @@ +package com.ironhack.repository; + +import com.ironhack.model.Author; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface AuthorRepository extends JpaRepository { + Optional findByName(String authorName); +} diff --git a/src/main/java/com/ironhack/repository/BookRepository.java b/src/main/java/com/ironhack/repository/BookRepository.java new file mode 100644 index 00000000..bed56705 --- /dev/null +++ b/src/main/java/com/ironhack/repository/BookRepository.java @@ -0,0 +1,25 @@ +package com.ironhack.repository; + + +import com.ironhack.model.Book; +import com.ironhack.model.Categories; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; + +public interface BookRepository extends JpaRepository { + Optional findBookByTitle(String title); + + List findBookByCategory(Categories category); + + @Query("Select b FROM Book b JOIN b.authorBook a WHERE a.authorId = :authorId") + List findBookByAuthorId(int authorId); + + Optional findByIsbn(String isbn); + + @Query("SELECT b FROM Book b JOIN FETCH b.authorBook") + List findAllBooksWithAuthor(); + +} diff --git a/src/main/java/com/ironhack/repository/IssueRepository.java b/src/main/java/com/ironhack/repository/IssueRepository.java new file mode 100644 index 00000000..afab4859 --- /dev/null +++ b/src/main/java/com/ironhack/repository/IssueRepository.java @@ -0,0 +1,20 @@ +package com.ironhack.repository; + +import com.ironhack.model.Issue; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface IssueRepository extends JpaRepository { + Issue findByIssueId(int issueId); + + @Query("SELECT i FROM Issue i JOIN i.issueBook b WHERE b.isbn = ?1") + List findByIsbn(String isbn); + + @Query("SELECT i FROM Issue i JOIN i.issueStudent s WHERE s.usn = ?1") + List findByUsn(String usn); + +} diff --git a/src/main/java/com/ironhack/repository/StudentRepository.java b/src/main/java/com/ironhack/repository/StudentRepository.java new file mode 100644 index 00000000..51c05fef --- /dev/null +++ b/src/main/java/com/ironhack/repository/StudentRepository.java @@ -0,0 +1,20 @@ +package com.ironhack.repository; + + +import com.ironhack.model.Issue; +import com.ironhack.model.Student; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; + +public interface StudentRepository extends JpaRepository { + + Optional findByName(String name); + + Optional findByUsn(String usn); + + @Query("SELECT i FROM Issue i JOIN i.issueStudent s WHERE s.usn = ?1") + List searchBooksByStudent(String usn); +} diff --git a/src/main/java/com/ironhack/service/LibraryService.java b/src/main/java/com/ironhack/service/LibraryService.java new file mode 100644 index 00000000..65959bfa --- /dev/null +++ b/src/main/java/com/ironhack/service/LibraryService.java @@ -0,0 +1,225 @@ +package com.ironhack.service; + +import com.ironhack.model.*; +import com.ironhack.repository.AuthorRepository; +import com.ironhack.repository.BookRepository; +import com.ironhack.repository.IssueRepository; +import com.ironhack.repository.StudentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ironhack.utils.Utils; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.Scanner; + +@Service +public class LibraryService { + + @Autowired + BookRepository bookRepository; + + @Autowired + AuthorRepository authorRepository; + + @Autowired + IssueRepository issueRepository; + + @Autowired + StudentRepository studentRepository; + + public void addNewBook(Book book) { + Optional optionalBook = bookRepository.findByIsbn(book.getIsbn()); + if (optionalBook.isPresent()) { + optionalBook.get().updateQuantity(book.getQuantity()); + bookRepository.save(optionalBook.get()); + } else { + bookRepository.save(book); + } + } + + public Optional searchBookByTitle(String title) { + return bookRepository.findBookByTitle(title); + } + + public List searchBookByCategory(Categories category) { + return bookRepository.findBookByCategory(category); + } + + public List searchBookByAuthor(int author_id) { + return bookRepository.findBookByAuthorId(author_id); + } + + public List searchAllBooks() { + return bookRepository.findAll(); + } + + public String issueBook(String usn, String name, String isbn) { + LocalDateTime issueDate = LocalDateTime.now(); + LocalDateTime returnDate = issueDate.plusDays(7); + String issueDateString = Utils.formatter.format(issueDate); + String returnDateString = Utils.formatter.format(returnDate); + Issue issue = new Issue(issueDateString, returnDateString); + Optional student = studentRepository.findByUsn(usn); + //check if book is already issued + if (!isBookIssued(isbn)) { + issue.setIssueStudent(student.get()); + Optional book = bookRepository.findByIsbn(isbn); + issue.setIssueBook(book.get()); + issueRepository.save(issue); + //restar un ejemplar a libro + book.get().updateQuantity(-1); + bookRepository.save(book.get()); + return returnDateString; + } else { + return null; + } + } + + public boolean isBookIssued(String isbn) { + Optional book = bookRepository.findByIsbn(isbn); + return book.get().getQuantity() == 0; + } + + public List searchBooksByStudentString(String usn) { + return studentRepository.searchBooksByStudent(usn); + } + + public List findIssueByIsbn(String isbn) { + return issueRepository.findByIsbn(isbn); + } + + public List findIssueByUsn(String usn) { + return issueRepository.findByUsn(usn); + } + + public Optional findBookByIsbn(String isbn) { + return bookRepository.findByIsbn(isbn); + } + + public Optional findStudentByUsn(String usn) { + return studentRepository.findByUsn(usn); + } + + public List findAllBooksWithAuthors() { + return bookRepository.findAllBooksWithAuthor(); + } + + //añadido hoy + public Optional findAuthorByName(String name) { + return authorRepository.findByName(name); + } + + public void printBooks(List books) { + if (books.isEmpty()) { + System.out.println("No books found."); + } else { + System.out.println("Book ISBN Book Title Category No of Books Author name Author mail "); + for (Book book : books) { + System.out.printf("%-20s %-15s %-12s %-15s %-20s %s%n", + book.getIsbn(), + book.getTitle(), + book.getCategory(), + book.getQuantity(), + book.getAuthorBook().getName(), + book.getAuthorBook().getEmail()); + } + } + } + + public void printBooksByCategoryOrAuthor(List books) { + if (books.isEmpty()) { + System.out.println("No books found."); + } else { + System.out.println("Book ISBN Book Title Category No of Books"); + for (Book book : books) { + System.out.printf("%-20s %-15s %-12s %-15s%n", + book.getIsbn(), + book.getTitle(), + book.getCategory(), + book.getQuantity()); + } + } + } + + public String getIsbn(Scanner scanner) { + String isbn; + do { + System.out.print("Enter isbn: "); + isbn = scanner.nextLine(); + if (!Utils.isbnValidator(isbn)) { + System.out.println("Invalid ISBN. Please try again."); + } + } while (!Utils.isbnValidator(isbn)); + return isbn; + } + + public String getAuthorEmail(Scanner scanner) { + String email; + do { + System.out.print("Enter author email: "); + email = scanner.nextLine(); + if (!Utils.emailValidator(email)) { + System.out.println("Invalid author email. Please try again."); + } + } while (!Utils.emailValidator(email)); + return email; + } + + public String getString(Scanner scanner, String promptMessage, String errorMessage) { + String input; + do { + System.out.print(promptMessage); + input = scanner.nextLine(); + if (!Utils.stringValidator(input)) { + System.out.println(errorMessage); + } + } while (!Utils.stringValidator(input)); + return input; + } + + public Categories getCategory(Scanner scanner) { + Categories category = null; + while (true) { + System.out.print("Enter category (Available categories: HORROR, SCIENCE, ROMANCE, FICTION, FANTASY, ADVENTURE, BIOGRAPHY, MISTERY, OTHERS): "); + String categoryInput = scanner.nextLine().toUpperCase(); + for (Categories c : Categories.values()) { + if (c.name().equals(categoryInput)) { + category = c; + break; + } + } + if (category != null) { + break; + } else { + System.out.println("Invalid category. Please enter a valid category."); + } + } + return category; + } + + public String getUsn(Scanner scanner) { + String usn; + do { + System.out.print("Enter USN: "); + usn = scanner.nextLine(); + if (!Utils.usnValidator(usn)) { + System.out.println("Invalid USN. Please try again."); + } + } while (!Utils.usnValidator(usn)); + return usn; + } + + public int getNumber(Scanner scanner, String promptMessage, String errorMessage) { + String input; + do { + System.out.print(promptMessage); + input = scanner.nextLine(); + if (!Utils.numericValidator(input)) { + System.out.println(errorMessage); + } + } while (!Utils.numericValidator(input)); + return Integer.parseInt(input); + } +} diff --git a/src/main/java/com/ironhack/utils/Utils.java b/src/main/java/com/ironhack/utils/Utils.java new file mode 100644 index 00000000..7c006fa4 --- /dev/null +++ b/src/main/java/com/ironhack/utils/Utils.java @@ -0,0 +1,139 @@ +package com.ironhack.utils; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Utils { + + /** + * Validates if the provided string is not null and not empty. + */ + public static boolean stringValidator(String input) { + return input != null && !input.trim().isEmpty(); + } + + /** + * Validates if the given string is a valid email address. + */ + public static boolean emailValidator(String email) { + if (email == null) return false; + String emailRegex = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; + Pattern emailPattern = Pattern.compile(emailRegex); + Matcher matcher = emailPattern.matcher(email); + return matcher.matches(); + } + + /** + * Validates ISBNs (ISBN-10 and ISBN-13). + * ISBN-10 Examples: "0-306-40615-2", "0306406152" + * ISBN-13 Examples: "978-0-306-40615-7", "9780306406157" + * Note: + * - ISBN-10 is a 10-digit number with or without optional hyphens and might end with an 'X' representing 10. + * - ISBN-13 is a 13-digit number, prefixed by '978' or '979', with or without optional hyphens. + * + * @param isbn the ISBN string to validate. + * @return true if the isbn is valid according to ISBN-10 or ISBN-13 standards, false otherwise. + */ + public static boolean isbnValidator(String isbn) { + if (isbn == null) return false; + + // ISBN Regex that matches ISBN-10 and ISBN-13 formats, taking into account optional hyphens + String isbnRegex = "^(?:ISBN(?:-13)?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$"; + + Pattern isbnPattern = Pattern.compile(isbnRegex); + Matcher matcher = isbnPattern.matcher(isbn); + + // Matches ISBN against the regex pattern + return matcher.matches(); + } + + /** + * Updates the quantity of an item, ensuring it cannot go below zero. + */ + public static int addQuantityUpdate(int currentQuantity, int change) { + if (currentQuantity < 0 || change < 0) { + System.out.println("Both currentQuantity and change must be non-negative."); + return currentQuantity; // Return the original quantity unchanged as an error signal + } + return currentQuantity + change; + } + + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); + + /** + * Validates if the provided date string follows the "dd/MM/yyyy" format. + * + * @param date the date string to validate. + * @return true if the date is in the correct format, false otherwise. + */ + public static boolean validateDateFormat(String date) { + try { + LocalDate.parse(date, formatter); + return true; // Date was successfully parsed, indicating valid format + } catch (DateTimeParseException e) { + return false; // Parsing failed, indicating invalid format + } + } + + /** + * Calculates the difference in days between two dates provided in "dd/MM/yyyy" format. + * Assumes both dates have been validated and are in the correct format. + * + * @param startDate the start date in "dd/MM/yyyy" format. + * @param endDate the end date in "dd/MM/yyyy" format. + * @return an Optional containing the difference in days between the start and end dates, + * or an empty Optional if either date is in an invalid format. + */ + public static Optional dateDifferenceCalculator(String startDate, String endDate) { + if (!validateDateFormat(startDate) || !validateDateFormat(endDate)) { + // If either date is in invalid format, return an empty Optional + return Optional.empty(); + } + + LocalDate start = LocalDate.parse(startDate, formatter); + LocalDate end = LocalDate.parse(endDate, formatter); + long daysBetween = ChronoUnit.DAYS.between(start, end); + + return Optional.of(daysBetween); + } + + + /** + * Generates a unique identifier, for example, for use with entities that don't have an auto-generated ID. + */ + public static String uniqueIdGenerator() { + return UUID.randomUUID().toString(); + } + + public static boolean usnValidator(String usn) { + if (usn == null) return false; + + // USN Regex that matches exactly 13 numeric characters + String usnRegex = "^[0-9]{11}$"; + + Pattern usnPattern = Pattern.compile(usnRegex); + Matcher matcher = usnPattern.matcher(usn); + + // Matches USN against the regex pattern + return matcher.matches(); + } + + public static boolean numericValidator(String input) { + if (input == null) return false; + + // Numeric Regex that matches integer numbers + String numericRegex = "^[1-9]\\d*$"; + + Pattern numericPattern = Pattern.compile(numericRegex); + Matcher matcher = numericPattern.matcher(input); + + // Matches input against the regex pattern + return matcher.matches(); + } +} diff --git a/src/main/java/com/ironhack/viewer/LibraryMenu.java b/src/main/java/com/ironhack/viewer/LibraryMenu.java new file mode 100644 index 00000000..f3d266ae --- /dev/null +++ b/src/main/java/com/ironhack/viewer/LibraryMenu.java @@ -0,0 +1,161 @@ +package com.ironhack.viewer; + +import com.ironhack.model.*; +import com.ironhack.repository.AuthorRepository; +import com.ironhack.service.LibraryService; +import org.springframework.stereotype.Component; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Optional; +import java.util.Scanner; + +@Component +public class LibraryMenu { + private final LibraryService libraryService; + private final AuthorRepository authorRepository; + public LibraryMenu(LibraryService libraryService, AuthorRepository authorRepository) { + this.libraryService = libraryService; + this.authorRepository = authorRepository; + } + public void displayMenu() { + Scanner scanner = new Scanner(System.in); + int choice; + + do { + System.out.println("Library Management System"); + System.out.println("1. Add Book"); + System.out.println("2. Search Book By Title"); + System.out.println("3. Search Book By Category"); + System.out.println("4. Search Book By Author"); + System.out.println("5. Show All Books"); + System.out.println("6. Issue Book"); + System.out.println("7. Return Book"); + System.out.println("8. Search Books By Student"); + System.out.println("0. Exit"); + System.out.print("Enter your choice: "); + try { + choice = scanner.nextInt(); + scanner.nextLine(); // Consume newline + } catch (InputMismatchException ime) { + choice = 9; + scanner.nextLine(); + } + switch (choice) { + case 1: + // Add Book + String isbnBook = libraryService.getIsbn(scanner); + String titleBook = libraryService.getString(scanner, "Enter title: ", "Title can not be empty. Please try again."); + Categories categoryBook = libraryService.getCategory(scanner); + String authorName = libraryService.getString(scanner, "Enter author name: ", "Author name can not be empty. Please try again."); + String authorMail = libraryService.getAuthorEmail(scanner); + int quantity = libraryService.getNumber(scanner, "Enter number of books: ", "Invalid input. Please enter a positive quantity."); + Author author; + Optional optionalAuthor = libraryService.findAuthorByName(authorName); + if (optionalAuthor.isPresent()) { + author = optionalAuthor.get(); + } else { + author = new Author(authorName, authorMail); + authorRepository.save(author); + } + Book newBook = new Book(isbnBook, titleBook, categoryBook, quantity, author); + try { + libraryService.addNewBook(newBook); + } catch (IllegalArgumentException iae) { + System.out.println("Something went wrong" + iae.getMessage()); + } + System.out.println("Book was successfully added to library"); + break; + case 2: + String title = libraryService.getString(scanner, "Enter title: ", "Title can not be empty. Please try again."); + Optional requestedBook = libraryService.searchBookByTitle(title); + if (requestedBook.isPresent()) { + System.out.println(requestedBook.get()); + } else { + System.out.println("Book not found"); + } + break; + case 3: + String category = libraryService.getCategory(scanner).name(); + try { + List books = libraryService.searchBookByCategory(Categories.valueOf(category)); + libraryService.printBooksByCategoryOrAuthor(books); + } catch (InputMismatchException imm) { + System.out.print("Wrong Category "); + } +// catch (IllegalArgumentException iae) { +// System.out.println("Wrong Category"); +// } + + break; + case 4: + int author_id = libraryService.getNumber(scanner, "Enter Author ID: ", "Invalid input. Please enter a positive numeric value."); + List books = libraryService.searchBookByAuthor(author_id); + libraryService.printBooksByCategoryOrAuthor(books); + break; + case 5: + libraryService.printBooks(libraryService.searchAllBooks()); + break; + case 6: + String usn = libraryService.getUsn(scanner); + String name = libraryService.getString(scanner, "Enter student name: ", "Student name can not be empty. Please try again."); + String isbn = libraryService.getIsbn(scanner); + try { + //check if student and book exist. + Optional studentOptional = libraryService.findStudentByUsn(usn); + Optional bookOptional = libraryService.findBookByIsbn(isbn); + if (studentOptional.isPresent() && bookOptional.isPresent()) { + Book book = bookOptional.get(); + if (book.getQuantity() > 0) { + String returnDate = libraryService.issueBook(usn, name, isbn); + System.out.println("\n"); + System.out.println("Book issued. Return date : " + returnDate); + } else { + System.out.println("There aren't any copies left."); + } + } else { + System.out.println("Student or book does not exist."); + } + } catch (IllegalArgumentException iae) { + System.out.println("An exception occurred: " + iae.getMessage()); + } + break; + case 7: + // Return Book + break; + case 8: + // Search Books By Student + String usnSearch = libraryService.getUsn(scanner); + try { + Optional studentOptional = libraryService.findStudentByUsn(usnSearch); + if (studentOptional.isPresent()) { + List issueList = libraryService.searchBooksByStudentString(usnSearch); + if (issueList.isEmpty()) { + System.out.println("No books found for the specified student."); + break; + } + System.out.println("Book Title Student Name Return date"); + for (Issue issue : issueList) { + String bookTitle = issue.getIssueBook().getTitle(); + String studentName = issue.getIssueStudent().getName(); + String returnDate = issue.getReturnDate(); + System.out.printf("%-20s %-15s %s%n", bookTitle, studentName, returnDate); + } + } else { + System.out.println("Student does not exist"); + } + } catch (IllegalArgumentException iae) { + System.out.println("An exception occurred: " + iae.getMessage()); + } + break; + case 0: + System.out.println("Exiting..."); + break; + default: + System.out.println("Invalid choice. Please try again."); + break; + } + } while (choice != 0); + + scanner.close(); + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 00000000..a096c8ec --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.application.name=ironlibrary +spring.datasource.url=jdbc:mysql://localhost:3306/library?serverTimezone=UTC +spring.datasource.username=ironhack +spring.datasource.password=ironhack2024 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.hibernate.ddl-auto=validate +spring.jpa.show-sql=true \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 00000000..a2a97074 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,47 @@ +drop schema library; +create schema library; +use library; + + +create table author( + author_id int AUTO_INCREMENT not null, + name varchar(255) not null, + email varchar(100) not null, + primary key(author_id) +); + +create table book( + isbn varchar(17) not null, + title varchar(255) not null, + category enum('HORROR', + 'SCIENCE', + 'ROMANCE', + 'FICTION', + 'FANTASY', + 'ADVENTURE', + 'BIOGRAPHY', + 'MISTERY', + 'OTHERS'), + quantity int not null, + author_id int not null, + foreign key(author_id) references author(author_id), + primary key(isbn) +); + + +CREATE TABLE student( + usn varchar(11) not null, + name varchar(255) not null, + primary key(usn) +); + +CREATE TABLE issue( + issue_id INT AUTO_INCREMENT not null, + issue_date varchar(255) not null, + return_date varchar(255) not null, + issue_student varchar(255) not null, + issue_book varchar(17) not null, + primary key(issue_id), + foreign key(issue_student) references student(usn), + foreign key(issue_book) references book(isbn) +); diff --git a/src/test/java/com/ironhack/model/AuthorTests.java b/src/test/java/com/ironhack/model/AuthorTests.java new file mode 100644 index 00000000..0312b00f --- /dev/null +++ b/src/test/java/com/ironhack/model/AuthorTests.java @@ -0,0 +1,32 @@ +package com.ironhack.model; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class AuthorTests { + + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + public void testAuthorCreation() { + + Author author = new Author("Xavi", "Xavi@mail.com"); + + assertNotNull(author); + + assertEquals("Xavi", author.getName()); + + assertEquals("Xavi@mail.com", author.getEmail()); + } +} diff --git a/src/test/java/com/ironhack/model/BookTests.java b/src/test/java/com/ironhack/model/BookTests.java new file mode 100644 index 00000000..7a5b0140 --- /dev/null +++ b/src/test/java/com/ironhack/model/BookTests.java @@ -0,0 +1,29 @@ +package com.ironhack.model; + +import com.ironhack.repository.BookRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class BookTests { + + + @Test + public void testBookCreation(){ + Author sample_author = new Author("Jose Martinez","josep@gmail.com"); + Book book = new Book("123456789","Best Book Ever" ,Categories.ADVENTURE, 2, sample_author); + assertEquals(book.getAuthorBook(),sample_author); + assertEquals(book.getCategory(),Categories.ADVENTURE); + assertEquals(book.getIsbn(),"123456789"); + assertEquals(book.getTitle(),"Best Book Ever"); + assertEquals(book.getQuantity(),2); + + } + +} diff --git a/src/test/java/com/ironhack/model/IssueTest.java b/src/test/java/com/ironhack/model/IssueTest.java new file mode 100644 index 00000000..45b91e7a --- /dev/null +++ b/src/test/java/com/ironhack/model/IssueTest.java @@ -0,0 +1,36 @@ +package com.ironhack.model; + +import com.ironhack.model.Issue; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class IssueTest { + + @Test + void testConstructorAssignsValuesCorrectly() { + // Given + String expectedIssueDate = "2023-01-01"; + String expectedReturnDate = "2023-01-10"; + + // When + Issue issue = new Issue(expectedIssueDate, expectedReturnDate); + + // Then + assertEquals(expectedIssueDate, issue.getIssueDate(), "IssueDate should match the constructor input"); + assertEquals(expectedReturnDate, issue.getReturnDate(), "ReturnDate should match the constructor input"); + } + + @Test + void testInputValidation() { + // Given + Issue issue = new Issue("2023-01-01", "2023-01-10"); + + // When + boolean isValid = issue.input_validation(); + + // Then + assertTrue(isValid, "input_validation should return true"); + } +} diff --git a/src/test/java/com/ironhack/model/StudentTest.java b/src/test/java/com/ironhack/model/StudentTest.java new file mode 100644 index 00000000..866ee09a --- /dev/null +++ b/src/test/java/com/ironhack/model/StudentTest.java @@ -0,0 +1,38 @@ +package com.ironhack.model; +import com.ironhack.model.Student; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StudentTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + public void testStudentCreation() { + + Student student = new Student("12345678901", "Juan"); + + assertNotNull(student); + + assertEquals("12345678901", student.getUsn()); + + assertEquals("Juan", student.getName()); + } + @Test + void testAddIssue() { + Student student = new Student("12345678901", "John Doe"); + Issue issue = new Issue("2022-01-01", "2022-02-01"); + student.addIssue(issue); + assertTrue(student.getIssues().contains(issue)); + assertEquals(student, issue.getIssueStudent()); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/repository/AuthorRepositoryTest.java b/src/test/java/com/ironhack/repository/AuthorRepositoryTest.java new file mode 100644 index 00000000..3bd92311 --- /dev/null +++ b/src/test/java/com/ironhack/repository/AuthorRepositoryTest.java @@ -0,0 +1,37 @@ +package com.ironhack.repository; + +import com.ironhack.model.Author; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +@SpringBootTest +class AuthorRepositoryTest { + + @Autowired + private AuthorRepository authorRepository; + Author author; + + @AfterEach + void tearDown() { + authorRepository.deleteAll(); + } + + @Test + public void findAuthorByIdTest() { + author = new Author("Xavi", "xavi@mail.com"); + authorRepository.save(author); + + Optional authorFound = authorRepository.findById(author.getAuthorId()); + + assertTrue(authorFound.isPresent()); + assertEquals(author.getAuthorId(), authorFound.get().getAuthorId()); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/repository/BookRepositoryTest.java b/src/test/java/com/ironhack/repository/BookRepositoryTest.java new file mode 100644 index 00000000..5c7601ac --- /dev/null +++ b/src/test/java/com/ironhack/repository/BookRepositoryTest.java @@ -0,0 +1,60 @@ +package com.ironhack.repository; + +import com.ironhack.model.Author; +import com.ironhack.model.Book; +import com.ironhack.model.Categories; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest +public class BookRepositoryTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private AuthorRepository authorRepository; + Author author; + Book sample_book; + + @BeforeEach + void setUp() { + author = new Author("Xavi", "xavi@mail.com"); + sample_book = new Book("1234", "my awesome book", Categories.ADVENTURE, 3, author); + authorRepository.save(author); + bookRepository.save(sample_book); + } + + @AfterEach + void tearDown() { + bookRepository.deleteAll(); + } + + @Test + public void findBookByTitleTest() { + Optional db_book = bookRepository.findBookByTitle("my awesome book"); + assertTrue(db_book.isPresent()); + assertEquals(sample_book, db_book.get()); + } + @Test + void findAllBooksWithAuthor() { + Author author1 = new Author("JK Rowling", "jkrowling@mail.com"); + Author author2 = new Author("George Orwell", "georgeorwell@mail.com"); + authorRepository.save(author1); + authorRepository.save(author2); + Book book1 = new Book("978-3-16-148410-0", "Harry Potter", Categories.FANTASY, 1, author1); + Book book2 = new Book("978-3-16-148434-0", "1984", Categories.FICTION, 2, author2); + bookRepository.save(book1); + bookRepository.save(book2); + assertEquals(author1, book1.getAuthorBook()); + } + +} diff --git a/src/test/java/com/ironhack/repository/IssueRepositoryTest.java b/src/test/java/com/ironhack/repository/IssueRepositoryTest.java new file mode 100644 index 00000000..fe434a50 --- /dev/null +++ b/src/test/java/com/ironhack/repository/IssueRepositoryTest.java @@ -0,0 +1,43 @@ +package com.ironhack.repository; + +import com.ironhack.model.Issue; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +public class IssueRepositoryTest { + + @Autowired + private IssueRepository issueRepository; + + @Test + void testIssueCreationAndRetrieval() { + // Create and save an Issue + Issue savedIssue = issueRepository.save(new Issue("2023-01-01", "2023-01-10")); + + // Retrieve the saved Issue by ID + Optional retrievedIssue = issueRepository.findById(savedIssue.getIssueId()); + + // Verify the retrieval + assertTrue(retrievedIssue.isPresent(), "Issue should be found by ID"); + assertEquals("2023-01-01", retrievedIssue.get().getIssueDate(), "Issue dates should match"); + } + + @Test + void testFindByIssueId() { + // Create and save an Issue + Issue savedIssue = issueRepository.save(new Issue("2023-02-01", "2023-02-10")); + + // Use the custom findByIssueId method + Issue foundIssue = issueRepository.findByIssueId(savedIssue.getIssueId()); + + // Verify the result + assertNotNull(foundIssue, "Issue should be found with custom query"); + assertEquals("2023-02-01", foundIssue.getIssueDate(), "Issue dates should match in custom query"); + } +} diff --git a/src/test/java/com/ironhack/repository/StudentRepositoryTest.java b/src/test/java/com/ironhack/repository/StudentRepositoryTest.java new file mode 100644 index 00000000..2e556d37 --- /dev/null +++ b/src/test/java/com/ironhack/repository/StudentRepositoryTest.java @@ -0,0 +1,76 @@ +package com.ironhack.repository; + + +import com.ironhack.model.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class StudentRepositoryTest { + + @Autowired + private StudentRepository studentRepository; + + @Autowired + private IssueRepository issueRepository; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private AuthorRepository authorRepository; + + private Student student; + + @BeforeEach + void setUp() { + student = new Student("09003688800", "Juan"); + student = studentRepository.save(student); + } + + @AfterEach + void tearDown() { + studentRepository.deleteAll(); + studentRepository.flush(); + } + + @Test + void searchBooksByStudentString() { + Author author1 = new Author("JK Rowling", "jkrowling@mail.com"); + Author author2 = new Author("George Orwell", "georgeorwell@mail.com"); + authorRepository.save(author1); + authorRepository.save(author2); + + Book book1 = new Book("978-3-16-148410-0", "Harry Potter", Categories.FANTASY, 1, author1); + Book book2 = new Book("978-3-16-148434-0", "1984", Categories.FICTION, 2, author2); + bookRepository.save(book1); + bookRepository.save(book2); + + Issue issue1 = new Issue("2022-08-01 17:09:38", "2022-08-07 17:09:38"); + issue1.setIssueBook(book1); + issue1.setIssueStudent(student); + student.addIssue(issue1); + issueRepository.save(issue1); + + Issue issue2 = new Issue("2022-10-01 17:09:38", "2022-10-07 17:09:38"); + issue2.setIssueBook(book2); + issue2.setIssueStudent(student); + student.addIssue(issue2); + issueRepository.save(issue2); + + List results = studentRepository.searchBooksByStudent("09003688800"); + + assertNotNull(results); + assertEquals(2, results.size()); + assertEquals("Harry Potter", results.getFirst().getIssueBook().getTitle()); + assertEquals("2022-08-07 17:09:38", results.getFirst().getReturnDate()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/service/LibraryServiceTest.java b/src/test/java/com/ironhack/service/LibraryServiceTest.java new file mode 100644 index 00000000..0ebc798b --- /dev/null +++ b/src/test/java/com/ironhack/service/LibraryServiceTest.java @@ -0,0 +1,202 @@ +package com.ironhack.service; + +import com.ironhack.model.*; +import com.ironhack.repository.AuthorRepository; +import com.ironhack.repository.BookRepository; +import com.ironhack.repository.IssueRepository; +import com.ironhack.repository.StudentRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.LocalDate; +import java.util.List; +import static org.junit.jupiter.api.Assertions.*; +import java.util.Optional; + +@SpringBootTest +class LibraryServiceTest { + + @Autowired + private LibraryService libraryService; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private AuthorRepository authorRepository; + + @Autowired + private IssueRepository issueRepository; + + @Autowired + private StudentRepository studentRepository; + Author author1; + Author author2; + Book book1; + Book book2; + Student student1; + Student student2; + private Issue issue1; + private Issue issue2; + + @BeforeEach + void setUp() { + author1 = new Author("Corey Schafer","corey@mail.com"); + author2 = new Author("Antonio Gámez","antonio@mail.com"); + book1 = new Book("978-1-123456-12-7","Java is awesome", Categories.HORROR,8,author1); + book2 = new Book("978-1-123456-12-6","SLA Driven Governance of RESTful systems", Categories.SCIENCE,5,author2); + authorRepository.saveAll(List.of(author1, author2)); + bookRepository.saveAll(List.of(book1, book2)); + student1 = new Student("12345678901", "Mosh"); + student2 = new Student("12345678902", "John"); + studentRepository.saveAll(List.of(student1, student2)); + issue1 = new Issue(LocalDate.now().toString(), LocalDate.now().plusMonths(1).toString()); + issue1.setIssueBook(book1); + issue1.setIssueStudent(student1); + + issue2 = new Issue(LocalDate.now().toString(), LocalDate.now().plusMonths(1).toString()); + issue2.setIssueBook(book2); + issue2.setIssueStudent(student2); + + issueRepository.saveAll(List.of(issue1, issue2)); + } + @AfterEach + void tearDown() { + issueRepository.deleteAll(); + bookRepository.deleteAll(); + studentRepository.deleteAll(); + authorRepository.deleteAll(); + } + + @Test + void addNewBook() { + libraryService.addNewBook(book1); + Optional optionalBook = bookRepository.findByIsbn(book1.getIsbn()); + assertTrue(optionalBook.isPresent()); + assertEquals(book1.getIsbn(), optionalBook.get().getIsbn()); + } + + @Test + void searchBookByTitle() { + Optional optionalBook = libraryService.searchBookByTitle("Java is awesome"); + + assertTrue(optionalBook.isPresent()); + assertEquals("Java is awesome", optionalBook.get().getTitle()); + } + + @Test + void searchBookByCategory() { + // Use the searchBookByCategory method to retrieve the books + List books = libraryService.searchBookByCategory(Categories.HORROR); + + // Assert that the books returned by the method are the same as the books you saved + assertEquals(1, books.size()); + assertTrue(books.contains(book1)); + } + + @Test + void searchBookByAuthor() { + // Use the searchBookByAuthor method to retrieve the books + List booksByAuthor1 = libraryService.searchBookByAuthor(author1.getAuthorId()); + List booksByAuthor2 = libraryService.searchBookByAuthor(author2.getAuthorId()); + + // Assert that the books returned by the method are the same as the books you saved + assertEquals(1, booksByAuthor1.size()); + assertTrue(booksByAuthor1.contains(book1)); + + assertEquals(1, booksByAuthor2.size()); + assertTrue(booksByAuthor2.contains(book2)); + } + + @Test + void searchBooksByStudentStringTest() { + List foundIssues = libraryService.searchBooksByStudentString(student1.getUsn()); + + // Verify the correct book issues are retrieved + assertNotNull(foundIssues, "The returned list of issues should not be null"); + assertEquals(1, foundIssues.size(), "Expected one issue to be found for student1"); + + // Use getters in Issue for issueBook + assertEquals(book1.getIsbn(), foundIssues.get(0).getIssueBook().getIsbn(), + "The ISBN of the book in the found issue should match book1's ISBN"); + } + + @Test + void isBookIssuedTest(){ + Author author3 = new Author("original author", "newemail@mail.com"); + authorRepository.save(author3); + Book bookZeroQuantity = new Book("123-5-567890-00-0", "No books lefts", Categories.ADVENTURE, 0, author3); + bookRepository.save(bookZeroQuantity); + assertTrue(libraryService.isBookIssued(bookZeroQuantity.getIsbn())); + assertFalse(libraryService.isBookIssued(book1.getIsbn())); + } + + @Test + void issueBookTestValid(){ + Author author4 = new Author("another author", "newermail@mail.com"); + authorRepository.save(author4); + Book bookToIssue = new Book("123-5-567890-12-3", "Book to issue", Categories.ADVENTURE, 5, author4); + bookRepository.save(bookToIssue); + String returnDate = libraryService.issueBook("12345678901", "Book to issue", "123-5-567890-12-3"); + List results = libraryService.findIssueByIsbn("978-1-123456-12-7"); + assertNotNull(results); + assertEquals("Java is awesome", results.getFirst().getIssueBook().getTitle()); + assertEquals("12345678901", results.getFirst().getIssueStudent().getUsn()); + assertNotNull(returnDate); + } + + @Test + void issueBookTest_OutOfStock(){ + Author author5 = new Author("nuevo", "email@mail.com"); + authorRepository.save(author5); + Book outOfStockBook = new Book("978-1-123456-10-5","Libro agotado2", Categories.FANTASY,0,author5); + bookRepository.save(outOfStockBook); + String returnDate = libraryService.issueBook("12345678901", "Libro agotado2", "978-1-123456-10-5"); + assertNull(returnDate); + } + + @Test + void testFindBookByIsbn() { + // Use the findBookByIsbn method to retrieve the book + Optional optionalBook1 = libraryService.findBookByIsbn(book1.getIsbn()); + Optional optionalBook2 = libraryService.findBookByIsbn(book2.getIsbn()); + + // Assert that the book returned by the method is the same as the book you saved + assertTrue(optionalBook1.isPresent()); + assertEquals(book1.getIsbn(), optionalBook1.get().getIsbn()); + + assertTrue(optionalBook2.isPresent()); + assertEquals(book2.getIsbn(), optionalBook2.get().getIsbn()); + } + + @Test + void testFindStudentByUsn() { + // Use the findStudentByUsn method to retrieve the students + Optional optionalStudent1 = libraryService.findStudentByUsn(student1.getUsn()); + Optional optionalStudent2 = libraryService.findStudentByUsn(student2.getUsn()); + + // Assert that the student returned by the method is the same as the student you saved + assertTrue(optionalStudent1.isPresent()); + assertEquals(student1.getUsn(), optionalStudent1.get().getUsn()); + + assertTrue(optionalStudent2.isPresent()); + assertEquals(student2.getUsn(), optionalStudent2.get().getUsn()); + } + + @Test + void testFindAuthorByName() { + // Use the findAuthorByName method to retrieve the authors + Optional optionalAuthor1 = libraryService.findAuthorByName(author1.getName()); + Optional optionalAuthor2 = libraryService.findAuthorByName(author2.getName()); + + // Assert that the author returned by the method is the same as the author you saved + assertTrue(optionalAuthor1.isPresent()); + assertEquals(author1.getName(), optionalAuthor1.get().getName()); + + assertTrue(optionalAuthor2.isPresent()); + assertEquals(author2.getName(), optionalAuthor2.get().getName()); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/utils/UtilsTest.java b/src/test/java/com/ironhack/utils/UtilsTest.java new file mode 100644 index 00000000..58514e5c --- /dev/null +++ b/src/test/java/com/ironhack/utils/UtilsTest.java @@ -0,0 +1,97 @@ +package com.ironhack.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +class UtilsTest { + + @Test + void testStringValidator() { + assertTrue(Utils.stringValidator("Hello World")); + assertFalse(Utils.stringValidator("")); + assertFalse(Utils.stringValidator(null)); + } + @Test + void testEmailValidator() { + assertTrue(Utils.emailValidator("example@example.com")); + assertFalse(Utils.emailValidator("example@")); + assertFalse(Utils.emailValidator("example.com")); + assertFalse(Utils.emailValidator(null)); + } + + @Test + void testIsbnValidator() { + assertTrue(Utils.isbnValidator("978-3-16-148410-0")); + assertTrue(Utils.isbnValidator("0-306-40615-2")); + + assertFalse(Utils.isbnValidator("1234567890123")); + assertFalse(Utils.isbnValidator(null)); + } + + @Test + void testQuantityUpdate() { + // Test for successful quantity update + assertEquals(10, Utils.addQuantityUpdate(8, 2), "The sum should be 10 for valid inputs."); + + // Test for unsuccessful quantity update + assertEquals(5, Utils.addQuantityUpdate(5, -10), "Negative changes should result in no update."); + assertEquals(-5, Utils.addQuantityUpdate(-5, 10), "Initial negative quantities should behave normally."); + } + + @Test + void testValidateDateFormat() { + // Test valid date formats + assertTrue(Utils.validateDateFormat("01/01/2023"), "Date should be considered valid"); + assertTrue(Utils.validateDateFormat("31/12/2023"), "Date should be considered valid"); + + // Test invalid date formats + assertFalse(Utils.validateDateFormat("2023-01-01"), "Date should be considered invalid"); + assertFalse(Utils.validateDateFormat("01/2023"), "Date should be considered invalid"); + assertFalse(Utils.validateDateFormat("test"), "Date should be considered invalid"); + } + + @Test + void testDateDifferenceCalculator() { + // Test valid date inputs + assertEquals(Optional.of(1L), Utils.dateDifferenceCalculator("01/01/2023", "02/01/2023"), + "The difference should be 1 day for valid date inputs"); + assertEquals(Optional.of(-1L), Utils.dateDifferenceCalculator("02/01/2023", "01/01/2023"), + "The difference should be -1 days for valid date inputs"); + + // Test invalid date inputs + assertEquals(Optional.empty(), Utils.dateDifferenceCalculator("2023-01-01", "01/01/2023"), + "Should return Optional.empty() for invalid date format"); + assertEquals(Optional.empty(), Utils.dateDifferenceCalculator("01/01/2023", "2023-01-02"), + "Should return Optional.empty() for invalid date format"); + } + + + @Test + void testUniqueIdGenerator() { + String uniqueId1 = Utils.uniqueIdGenerator(); + String uniqueId2 = Utils.uniqueIdGenerator(); + Assertions.assertNotEquals(uniqueId1, uniqueId2); + } + + @Test + void usnValidator(){ + assertTrue(Utils.usnValidator("12345678901")); + assertTrue(Utils.usnValidator("98765432101")); + assertFalse(Utils.usnValidator("123")); + assertFalse(Utils.usnValidator(null)); + } + + @Test + void numericValidator(){ + assertTrue(Utils.numericValidator("123")); + assertTrue(Utils.numericValidator("54")); + assertFalse(Utils.numericValidator("0")); + assertFalse(Utils.numericValidator(null)); + assertFalse(Utils.numericValidator("-2")); + assertFalse(Utils.numericValidator("2.5")); + } +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 00000000..30f6c7b9 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,8 @@ +spring.datasource.url=jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC&createDatabaseIfNotExist=true +spring.datasource.username=ironhack +spring.datasource.password=ironhack2024 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.profiles.active=test +spring.jpa.hibernate.ddl-auto=create-drop + +spring.jpa.show-sql=true \ No newline at end of file