diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000..5d36283c --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,57 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + pull_request: + branches: + - main + - develop + +jobs: + build: + runs-on: ubuntu-latest + env: + MYSQL_DATABASE: library_test + MYSQL_USERNAME: root + MYSQL_PASSWORD: root + + #services: + #mysql: + #image: mysql:latest + #env: + #MYSQL_ROOT_PASSWORD: root + #MYSQL_DATABASE: ${{ secrets.MYSQL_DATABASE }} + #MYSQL_USERNAME: ${{ secrets.MYSQL_USERNAME }} + #MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }} + #ports: + #- 3306:3306 + #options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + steps: + - name: Set up MySQL + run: | + sudo /etc/init.d/mysql start + mysql -e 'CREATE DATABASE ${{ env.MYSQL_DATABASE }};' -u${{ env.MYSQL_USERNAME }} -p${{ env.MYSQL_PASSWORD }} + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + #- name: Debug MySQL connection + #run: mysql -h localhost -u $MYSQL_USERNAME --password=$MYSQL_PASSWORD -e 'SHOW DATABASES;' + - name: Build with Maven + run: mvn -B clean package --file pom.xml + + - name: Run unit tests + run : mvn test --file pom.xml \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..690b83d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Env +.env \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..cb28b0e3 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..5f0536eb --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/README_library.md b/README_library.md new file mode 100644 index 00000000..11c918db --- /dev/null +++ b/README_library.md @@ -0,0 +1,317 @@ +# IronLibrary Application + +## Models + +#### Author Class +The Author class represents the details of an author associated with a book in the library. +Attributes: + - authorId: Integer - Unique identifier for the author (generated automatically). + - name: String - Name of the author. + - email: String - Email address of the author. + +#### Book Class +The Book class represents the details of a book in the library. +Attributes: + - isbn: String - Unique identifier for the book. + - title: String - Title of the book. + - category: String - Category of the book. + - quantity: Integer - Number of copies available in the library. + +#### Issue Class +The Issue class represents the details of a book issued to a student from the library. +Attributes: + - issueId: Integer - Unique identifier for the issue (generated automatically). + - issueDate: LocalDateTime - Date and time when the book was issued. + - returnDate: LocalDateTime - Date and time when the book is expected to be returned. + - issueStudent: Student - Student who issued the book. + - issueBook: Book - Book issued. + +#### Student Class +The Student class represents the details of a student. +Attributes: + - usn: String - Unique student number. + - name: String - Student's name. + + +## Repositories + +#### AuthorRepository +Custom methods: + - findBookByAuthor(String authorName): Find a book by author's name. + - findAllBooksWithAuthors(): Find all books with authors. + - findByAuthorBook(Book book): Find an author by a specific book. + +#### BookRepository +Custom methods: + - findAllByCategory(String Category): Find all books by category. + - findOneByTitle(String Title): Find a book by title. + - findByIsbn(String isbn): Find a book by ISBN. + +#### IssueRepository +Custom methods: + - findAllBooksByUsn(String Usn): Find all books issued by a student number. + - findAllBooksAndIssuesByUsn(String usn): Find all books and issues by a student number. + +#### StudentRepository +Custom methods: + - findByUsnAndName(String usn, String name): Find a student by number and name. + - findByUsn(String usn): Find a student by number. + + +## Services + +#### AuthorServiceImpl +Methods: + - save(Author author): Saves an author. + - findBookByAuthor(String authorName): Find a book by author's name. + - findAllBooksWithAuthors(): Find all books with authors. + - findByAuthorBook(Book book): Findsan author by a specific book. + +#### BookServiceImpl +The BookServiceImpl class implements the service for book-related operations. +Methods: + - save(Book book): Save a book. + - findByIsbn(String isbn): Find a book by its ISBN. + - findAllByCategory(String category): Find all books by category. + - findOneByTitle(String title): Find a book by title. + - findAllByTitle(String title): Find all books by title. + +#### StudentServiceImpl +The class StudentServiceImpl implements the service for operations related to students in the application. +Methods: + - findStudentByUsnAndName(String usn, String name): Finds a student by unique number and name. + - save(String usn, String name): Saves a new student with the specified number and name. + - findStudentByUsn(String usn): Finds a student by their unique number. + +#### IssueServiceImpl +The class IssueServiceImpl implements the service for operations related to book lending in the application. +These methods allow performing specific operations related to book lending in the IronLibrary application. +Methods: + - save(Student student, Book book): Saves a book lending for a student. + - findAllBooksAndIssuesByUsn(String usn): Finds all books and lendings by student number. + - findAllBooksIssuedByUsn(String usn): Finds all books lent by student number. + - findIssueByIsbn(String isbn): Finds a lending by the ISBN number of a book. + +#### MenuServiceImpl +The MenuServiceImpl class provides methods for managing the menu and related operations in the IronLibrary application. +Methods: + - getNewBookInformation(): Get the information necessary to add a new book. + - getNewIssueInformation(): Get the information necessary to perform a new book issuance. + - addBook(List bookAndAuthorInformation): Add a new book with the provided information. + - searchBookByAuthor(String authorName): Find all books by author. + - searchBookByCategory(String category): Find all books by category. + - searchBookByTitle(String title): Find all books by title. + - issueBookToStudent(List issueData): Create a new issue. + - searchBooksByUsn(String usn): Find all books that are issued by a student with specific usn. + - searchBooksAlongAuthors(): Find all books and their author. + - mainMenu(): Manage the menu of the application. + +#### IAuthorService +AuthorService interface defines the contract for author-related operations in the IronLibrary application. + +#### IBookService +BookService interface defines service operations related to books. + +#### IStudentService +StudentService interface defines service operations related to students. + +#### IIssueService +IssueService interface defines service operations related to book issuance. + +#### IMenuService +MenuService interface defines service operations related to menu management in the application. + + +## Utils +These classes and methods provide a way to handle exceptions and format dates properly in the IronLibrary application. + +#### DataOutput +The DataOutput class provides static methods for formatting and generating data outputs related to books, authors, and loans. +These methods provide a visually appealing way to present information related to books, authors, and loans in the IronLibrary application. +Methods: + - oneBookTable(Book book): Creates an ASCII table to display a single book with its information. + - listBookTable(List books): Creates an ASCII table to display a list of books with their information. + - listBookTableWithAuthor(List lstObjects): Creates an ASCII table to display a list of books along with their respective authors. + - bookIssuedDate(Issue issue): Gets the expected return date of a loaned book. + - listBookTableByUsn(List lstObjects, Student student): Creates an ASCII table to display a list of books loaned by a student with their return information. + +#### DateFormatter +The DateFormatter class provides static methods for formatting dates and times in different formats. +Methods: + - simpleDateFormat(LocalDateTime returnDate): Formats the date and time into a simple "yyyy-MM-dd HH:mm:ss" format. + - largeDateFormat(LocalDateTime returnDate): Formats the date and time into a more detailed format with time zone and day and month abbreviations. + +#### BookWithActiveIssueException +The BookWithActiveIssueException class is an exception used to represent the situation where a book has an active loan. +This could occur when attempting to loan a book that is already on loan. + +#### InvalidBookInformationException +The InvalidBookInformationException class is an exception used to represent the situation where incorrect or invalid information is provided when trying to perform operations with books. + +#### NoBookFoundException +The NoBookFoundException class is an exception used to represent the situation where a book is not found in the application. + +#### NoStudentFoundException +The NoStudentFoundException class is an exception used to represent the situation where a student is not found in the application. + + +### Validator +The Validator class provides various static methods for validating and securely obtaining user input, ensuring that the entered data complies with certain patterns and formats. +Methods: + - checkUsnFormat(String usn): Verifies if the format of the student number (USN) is correct. + - checkISBNFormat(String maybeISBN): Verifies if the format of the ISBN number is correct. + - checkEmailFormat(String email): Verifies if the format of the email address is correct. + - patternMatches(String inputString, String regexPattern): Checks if the regular expression pattern matches the given input. + - validateInteger(String input): Validates if the input is an integer number. + - notBlankValidatorBooks(String input): Verifies if the input is not blank. + - validateStringGeneralFormat(String input): Verifies if the string complies with a general string format, containing only letters and spaces. +Additionally, the userInput method handles obtaining user input and validating it according to a specific format, providing feedback and suggestions to the user. +These methods and the Validator class as a whole offer a secure and consistent mechanism for validating user input in the IronLibrary application. + +## Run +The IronLibraryApplication class is the main class of the IronLibrary application. +It implements the CommandLineRunner interface of Spring Boot to execute additional actions before the application starts completely. + +#### Attributes: + - isMenuEnabled: A boolean attribute indicating whether the application menu is enabled. + - menuService: An instance of the IMenuService service that will be used to interact with the application menu. + +#### Methods: +- main(String[] args): The main method that starts the Spring Boot application. +- run(String... args): The method that executes at the start of the application. If the menu is enabled, it calls the mainMenu() method of the IMenuService service. + +#### Annotations: +@SpringBootApplication: An annotation that combines several annotations, including @Configuration, to enable auto-configuration of the application and scan components, configurations, and services. + +#### Usage: +The IronLibraryApplication class starts the Spring Boot application and controls whether the menu should be displayed at startup, based on the value of the isMenuEnabled attribute. + +### Properties +The application.properties file contains the configuration of the IronLibrary application: + +#### Application Properties: + spring.application.name=ironLibrary: Defines the name of the Spring Boot application as "ironLibrary". + spring.datasource.url: Specifies the URL of the MySQL database that the application connects to. + spring.datasource.username: Provides the username for the database connection. + spring.datasource.password: Provides the password for the database connection. + +#### JPA Configuration: + spring.jpa.properties.hibernate.hbm2ddl.auto=update: Configures the automatic database schema update strategy to the JPA entity model. + spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver: Specifies the name of the MySQL database driver class. + spring.jpa.properties.hibernate.dialect: Defines the Hibernate dialect to interact with the database. + +#### Other Configurations: + app.menu.enabled=true: Enables or disables the application menu. + +## TEST + +### Model tests +These unit tests validate the behavior and functionality of the model classes in the IronLibrary application. + +#### AuthorTest + - createAuthor(): Verifies the creation of an author and its association with a book. + +#### BookTest +Various tests to ensure that the getters and setters of the Book class work correctly. + - Tests to validate the default constructor and proper property initialization. + - Tests to verify object equality and hash codes. + - Tests to update the quantity, category, and title of a book. + - Tests to validate the format of the ISBN and ensure that the title is not null. + - +#### IssueTest + - createIssue(): Tests the creation of a book loan and verifies its properties, such as the date, student, and associated book. + - +#### StudentTest + - createStudent(): Verifies the correct creation of a student and its initialization. + + +### Repository Tests +These unit tests validate that the repositories of the IronLibrary application interact correctly with the database layer and manage business logic effectively. + +#### AuthorRepositoryTest + - Tests to check the retrieval of a book by author. + - Tests to ensure that an empty list is received if the author has no books. + - Tests to retrieve all books with their authors. + - Tests to verify that the associations between books and authors are correct. + - +#### BookRepositoryTest + - Tests to ensure the retrieval of a book by its ISBN, checking that the expected book is retrieved correctly. + - Tests to validate the quantity of books of a certain category. + - Tests to retrieve a book by its title. + - Tests to validate that no book is found for an unregistered ISBN. + - +#### IssueRepositoryTest + - Tests to verify the retrieval of books loaned by student number. + - Tests to confirm the absence of books loaned by a student who has not made loans. + - Tests to retrieve all loaned books with their respective details. + - Tests to ensure the deletion of a loan. + +#### StudentRepositoryTest + - Test to confirm that students are saved correctly in the database. + - Test to check the retrieval of a student by their unique number and name. + + +### Services Tests +These unit tests validate that the services of the IronLibrary application meet their requirements and behave properly in different scenarios. + +#### AuthorServiceImplTest + - Test to validate that the behavior is the same using the repository directly and using the service, confirming that different results are obtained. + +#### BookServiceImplTest + - Test to validate that the behavior is the same using the repository directly and using the service, confirming that different results are obtained. + +#### IssueServiceImplTest +Unit tests to verify if: + - All books issued by a student number are returned correctly. + - The expected behavior is obtained when lending a book to a student. + - It behaves correctly when trying to lend a book to a student with unavailable quantity. + - It behaves properly when searching for books around a student. + +#### MenuServiceImplTest +Tests to validate that: + - Books are added with valid and invalid information, verifying that the appropriate exception is thrown. + - Book searches by author are performed, confirming that they are found and that the correct exception is thrown if they are not found. + - Book searches by category are performed, ensuring they work correctly and that exceptions are thrown in incorrect cases. + - Books are issued to students correctly and that the search for loaned books is correct. + +### Utils Tests +These unit tests validate that the utilities of the IronLibrary application work correctly and comply with the defined format and validation rules. + +#### DataOutputTest + - Tests to validate the generation of ASCII tables for data visualization. + - The tests verify that the expected table is obtained for a single book, a list of books, an empty list of books, a list of books with authors, the issuance of a book, and the return of a book by student number. + +#### DateFormatterTest + - Tests to validate the date formats used in the application. Simple and long date formats are verified. + +#### ValidatorTest +Tests to validate: + - The format of the ISBN. + - The format of the email. + - The format of the student number (USN). + +#### ValidatorTestInteger + - Tests to validate if input numbers are valid integers. + +#### ValidatorTestStrings +Tests to validate: + - The presence of non-empty strings. + - The general format of strings, such as names. + - It also verifies behavior with null or empty strings. + +#### ValidatorUserInputTest + - Tests to verify if user input complies with the defined validation rules. + It uses a console input simulator to test the validation of an ISBN input. + +### Resources +Configuration of resources for IronLibrary tests: + - spring.application.name=ironLibrary: Defines the name of the Spring Boot application. This name can be used in various parts of the application. + - spring.datasource.url=jdbc:mysql://localhost:3306/library_test?createDatabaseIfNotExist=TRUE: Defines the URL of the MySQL database that the application will connect to. It also indicates that if the database does not exist, it will be created. + - spring.datasource.username=root: Username of the MySQL database. + - spring.datasource.password=root: Password of the MySQL database. + - spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop: Configures the creation and deletion of the database schema each time the application starts. + - spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver: Class of the database driver for MySQL connection. + - spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect: Indicates the dialect of the MySQL database that the application will use to map JPA queries to specific SQL queries of the database. + - spring.jpa.show-sql=true: Enables the display of SQL statements generated by Hibernate in the console. Useful for debugging and understanding the queries sent to the database. + - spring.jpa.open-in-view=true: Configures whether to enable open session in view. This property is discouraged as it may cause unexpected database queries. + - app.menu.enabled=false: A specific property of the application that can enable or disable a menu in the application's user interface. diff --git a/mvnw b/mvnw new file mode 100755 index 00000000..66df2854 --- /dev/null +++ b/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..95ba6f54 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..37ff52e7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + com.ironhack + ironLibrary + 0.0.1-SNAPSHOT + ironLibrary + Demo project for Spring Boot + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + com.mysql + mysql-connector-j + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.10.2 + test + + + de.vandermeer + asciitable + 0.3.2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + -Dspring.main.runOnce=true + + + + org.projectlombok + lombok + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + + prepare-agent + + + + report + test + + report + + + + + + + diff --git a/src/main/java/com/ironhack/ironLibrary/IronLibraryApplication.java b/src/main/java/com/ironhack/ironLibrary/IronLibraryApplication.java new file mode 100644 index 00000000..cc420cfa --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/IronLibraryApplication.java @@ -0,0 +1,33 @@ +package com.ironhack.ironLibrary; + +import com.ironhack.ironLibrary.service.IMenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class IronLibraryApplication implements CommandLineRunner { + + @Value("${app.menu.enabled}") + private boolean isMenuEnabled; + @Autowired + IMenuService menuService; + + public static void main(String[] args) { + SpringApplication.run(IronLibraryApplication.class, args + ); + } + + @Override + public void run(String... args) throws Exception { + if (isMenuEnabled) { + menuService.mainManu(); + } + } +} + + + + diff --git a/src/main/java/com/ironhack/ironLibrary/model/Author.java b/src/main/java/com/ironhack/ironLibrary/model/Author.java new file mode 100644 index 00000000..18ff3e81 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/model/Author.java @@ -0,0 +1,26 @@ +package com.ironhack.ironLibrary.model; + +import jakarta.persistence.*; +import lombok.*; + +@Data +@NoArgsConstructor +@Entity +@Table(name = "authors") +public class Author { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Setter(AccessLevel.NONE) + private Integer authorId; + private String name; + private String email; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "isbn") + private Book authorBook; + + public Author(String name, String email, Book authorBook){ + this.name = name; + this.email = email; + this.authorBook = authorBook; + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/model/Book.java b/src/main/java/com/ironhack/ironLibrary/model/Book.java new file mode 100644 index 00000000..7d00969e --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/model/Book.java @@ -0,0 +1,20 @@ +package com.ironhack.ironLibrary.model; + +import jakarta.persistence.Entity; +import lombok.*; +import jakarta.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "books") +public class Book { + @Id + @Setter(AccessLevel.NONE) + private String isbn; + private String title; + private String category; + private Integer quantity; + +} diff --git a/src/main/java/com/ironhack/ironLibrary/model/Issue.java b/src/main/java/com/ironhack/ironLibrary/model/Issue.java new file mode 100644 index 00000000..c0d6bc2d --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/model/Issue.java @@ -0,0 +1,40 @@ +package com.ironhack.ironLibrary.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Entity +@Table(name = "issue") +@Data +@NoArgsConstructor +public class Issue { + @Setter(AccessLevel.NONE) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer issueId; + + @Setter(AccessLevel.NONE) + private LocalDateTime issueDate; + + @Setter(AccessLevel.NONE) + private LocalDateTime returnDate; + + @OneToOne + @JoinColumn(name = "usn") + private Student issueStudent; + @OneToOne + @JoinColumn(name = "isbn") + private Book issueBook; + + public Issue(Student issueStudent, Book issueBook) { + this.issueDate = LocalDateTime.now(); + this.returnDate = issueDate.plusDays(7); + setIssueStudent(issueStudent); + setIssueBook(issueBook); + } + +} diff --git a/src/main/java/com/ironhack/ironLibrary/model/Student.java b/src/main/java/com/ironhack/ironLibrary/model/Student.java new file mode 100644 index 00000000..6c581f62 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/model/Student.java @@ -0,0 +1,31 @@ +package com.ironhack.ironLibrary.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "student") +@Data +public class Student { + + @Setter(AccessLevel.NONE) + @Id +// @GeneratedValue(strategy = GenerationType.UUID) + private String usn; + + private String name; + + public Student() { + + } + public Student(String usn, String name) { + this.usn = usn; + this.name = name; + } + + public Student(String name){ + setName(name); + } + +} diff --git a/src/main/java/com/ironhack/ironLibrary/repository/AuthorRepository.java b/src/main/java/com/ironhack/ironLibrary/repository/AuthorRepository.java new file mode 100644 index 00000000..82a05332 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/repository/AuthorRepository.java @@ -0,0 +1,26 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import javax.swing.text.html.Option; +import java.util.List; +import java.util.Optional; + +@Repository +public interface AuthorRepository extends JpaRepository { + + @Query("SELECT b From Author a JOIN a.authorBook b WHERE a.name = ?1") + Optional findBookByAuthor(String authorName); + + @Query("SELECT b,a FROM Author a JOIN Book b ON a.authorBook = b") + Optional > findAllBooksWithAuthors(); + + Optional findByAuthorBook(Book book); + + +} + diff --git a/src/main/java/com/ironhack/ironLibrary/repository/BookRepository.java b/src/main/java/com/ironhack/ironLibrary/repository/BookRepository.java new file mode 100644 index 00000000..5de8ff57 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/repository/BookRepository.java @@ -0,0 +1,17 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Book; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface BookRepository extends JpaRepository { + Optional> findAllByCategory(String Category); + Optional findOneByTitle(String Title); + Optional findByIsbn(String isbn); + Optional> findAllByTitle(String title); + +} diff --git a/src/main/java/com/ironhack/ironLibrary/repository/IssueRepository.java b/src/main/java/com/ironhack/ironLibrary/repository/IssueRepository.java new file mode 100644 index 00000000..523493db --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/repository/IssueRepository.java @@ -0,0 +1,19 @@ +package com.ironhack.ironLibrary.repository; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; + +public interface IssueRepository extends JpaRepository { + @Query("SELECT b FROM Issue i JOIN i.issueStudent c JOIN i.issueBook b WHERE c.usn = ?1") + Optional> findAllBooksByUsn(String usn); + + @Query("SELECT b, i FROM Issue i JOIN i.issueStudent c JOIN i.issueBook b WHERE c.usn = ?1") + Optional> findAllBooksAndIssuesByUsn(String usn); + + @Query("SELECT i FROM Issue i WHERE i.issueBook.isbn = ?1") + Optional findIssueByIsbn(String isbn); +} diff --git a/src/main/java/com/ironhack/ironLibrary/repository/StudentRepository.java b/src/main/java/com/ironhack/ironLibrary/repository/StudentRepository.java new file mode 100644 index 00000000..40632c5d --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/repository/StudentRepository.java @@ -0,0 +1,13 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Student; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; + +@Repository +public interface StudentRepository extends JpaRepository { + + Optional findByUsnAndName(String usn, String name); + Optional findByUsn(String usn); +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/AuthorServiceImpl.java b/src/main/java/com/ironhack/ironLibrary/service/AuthorServiceImpl.java new file mode 100644 index 00000000..7a92bf4b --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/AuthorServiceImpl.java @@ -0,0 +1,37 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.repository.AuthorRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class AuthorServiceImpl implements IAuthorService{ + + @Autowired + private AuthorRepository authorRepository; + + @Override + public Author save(Author author) { + return authorRepository.save(author); + } + + @Override + public Optional findBookByAuthor(String authorName) { + return authorRepository.findBookByAuthor(authorName); + } + + @Override + public Optional> findAllBooksWithAuthors() { + return authorRepository.findAllBooksWithAuthors(); + } + + @Override + public Optional findByAuthorBook(Book book) { + return authorRepository.findByAuthorBook(book); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/BookServiceImpl.java b/src/main/java/com/ironhack/ironLibrary/service/BookServiceImpl.java new file mode 100644 index 00000000..c70336e0 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/BookServiceImpl.java @@ -0,0 +1,40 @@ +package com.ironhack.ironLibrary.service; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.repository.BookRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class BookServiceImpl implements IBookService{ + + @Autowired + private BookRepository bookRepository; + + @Override + public Book save(Book book) { + return bookRepository.save(book); + } + + @Override + public Optional findByIsbn(String isbn) { + return bookRepository.findByIsbn(isbn); + } + + @Override + public Optional> findAllByCategory(String category) { + return bookRepository.findAllByCategory(category); + } + + @Override + public Optional findOneByTitle(String title) { + return bookRepository.findOneByTitle(title); + } + + @Override + public Optional> findAllByTitle(String title) { + return bookRepository.findAllByTitle(title); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IAuthorService.java b/src/main/java/com/ironhack/ironLibrary/service/IAuthorService.java new file mode 100644 index 00000000..fec9fc70 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IAuthorService.java @@ -0,0 +1,14 @@ +package com.ironhack.ironLibrary.service; +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; + +import java.util.List; +import java.util.Optional; + +public interface IAuthorService { + Author save (Author author); + Optional findBookByAuthor(String authorName); + Optional > findAllBooksWithAuthors(); + + Optional findByAuthorBook(Book book); +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IBookService.java b/src/main/java/com/ironhack/ironLibrary/service/IBookService.java new file mode 100644 index 00000000..732b5890 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IBookService.java @@ -0,0 +1,13 @@ +package com.ironhack.ironLibrary.service; +import com.ironhack.ironLibrary.model.Book; + +import java.util.List; +import java.util.Optional; +public interface IBookService { + Book save (Book book); + Optional findByIsbn(String isbn); + Optional> findAllByCategory(String Category); + Optional findOneByTitle(String Title); + Optional> findAllByTitle(String title); + +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IIssueService.java b/src/main/java/com/ironhack/ironLibrary/service/IIssueService.java new file mode 100644 index 00000000..03b822be --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IIssueService.java @@ -0,0 +1,16 @@ +package com.ironhack.ironLibrary.service; + + +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import java.util.List; +import java.util.Optional; + +public interface IIssueService { + + Issue save(Student student, Book book); + Optional> findAllBooksIssuedByUsn(String usn); + public Optional> findAllBooksAndIssuesByUsn(String usn); + public Optional findIssueByIsbn(String isbn); +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IMenuService.java b/src/main/java/com/ironhack/ironLibrary/service/IMenuService.java new file mode 100644 index 00000000..903b24e9 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IMenuService.java @@ -0,0 +1,27 @@ +package com.ironhack.ironLibrary.service; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.utils.NoBookFoundException; + +import java.util.List; +public interface IMenuService { + + void mainManu() throws Exception; + + List getNewBookInformation(); + + public List getNewIssueInformation(); + + void addBook (List bookAndAuthorInformation); + + Book searchBookByAuthor(String authorName) throws NoBookFoundException; + + List searchBookByCategory(String Category) throws NoBookFoundException; + + Issue issueBookToStudent(List issueInformation) throws NoBookFoundException; + + List searchBooksByUsn(String usn) throws Exception; + + List searchBooksAlongAuthors() throws NoBookFoundException; + +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IStudentService.java b/src/main/java/com/ironhack/ironLibrary/service/IStudentService.java new file mode 100644 index 00000000..18f93bc7 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IStudentService.java @@ -0,0 +1,12 @@ +package com.ironhack.ironLibrary.service; +import com.ironhack.ironLibrary.model.Student; +import org.springframework.stereotype.Service; +import java.util.Optional; + + +public interface IStudentService { + + Optional findStudentByUsnAndName(String usn, String name); + Student save(String usn, String name); + Optional findStudentByUsn(String usn); +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/IssueServiceImpl.java b/src/main/java/com/ironhack/ironLibrary/service/IssueServiceImpl.java new file mode 100644 index 00000000..7e3024a3 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/IssueServiceImpl.java @@ -0,0 +1,41 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import com.ironhack.ironLibrary.repository.IssueRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; +import java.util.Optional; + +@Service +public class IssueServiceImpl implements IIssueService{ + + @Autowired + private IssueRepository issueRepository; + + @Override + public Issue save(Student student, Book book) { + return issueRepository.save(new Issue(student, book)); + } + + @Override + public Optional> findAllBooksAndIssuesByUsn(String usn){ + return issueRepository.findAllBooksAndIssuesByUsn(usn); + } + + @Override + public Optional> findAllBooksIssuedByUsn(String usn) { + return issueRepository.findAllBooksByUsn(usn); + } + + @Override + public Optional findIssueByIsbn(String isbn) { + return issueRepository.findIssueByIsbn(isbn); + } + +} diff --git a/src/main/java/com/ironhack/ironLibrary/service/MenuServiceImpl.java b/src/main/java/com/ironhack/ironLibrary/service/MenuServiceImpl.java new file mode 100644 index 00000000..dd7c92bd --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/MenuServiceImpl.java @@ -0,0 +1,338 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.IronLibraryApplication; +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import com.ironhack.ironLibrary.utils.*; +import jakarta.persistence.criteria.CriteriaBuilder; +import org.springframework.beans.factory.annotation.Autowired; + + +import java.sql.SQLOutput; +import java.util.*; + +import org.springframework.stereotype.Service; + + +@Service +public class MenuServiceImpl implements IMenuService{ + + @Autowired + private IAuthorService authorService; + @Autowired + private IBookService bookService; + + @Autowired + private IStudentService studentService; + + @Autowired + private IIssueService issueService; + + /** + * TODO Testing + * @return + */ + public List getNewBookInformation(){ + + List bookAndAuthorDetails = new ArrayList<>(); + + String isbn = Validator.userInput("Enter isbn: ",true, "checkISBNFormat", + "The ISBN must follow the next format: 978-92-95055-02-5"); + bookAndAuthorDetails.add(isbn); + String title = Validator.userInput("Enter title: ", false, "NULL", "NULL"); + bookAndAuthorDetails.add(title); + String category = Validator.userInput("Enter category: ", true, "validateStringGeneralFormat", + "The category only accepts letters"); + bookAndAuthorDetails.add(category); + String authorName = Validator.userInput("Enter author name: ", true, "validateStringGeneralFormat", + "The author name only accepts letters"); + bookAndAuthorDetails.add(authorName); + String email = Validator.userInput("Enter author email: ", true, "checkEmailFormat", + "The email must contains an @ and a . "); + bookAndAuthorDetails.add(email); + String quantity = Validator.userInput("Enter number of books: ", true, "validateInteger", + "The quantity only accepts numbers"); + bookAndAuthorDetails.add(quantity); + + return bookAndAuthorDetails; + } + + public List getNewIssueInformation(){ + + List issueDetails = new ArrayList<>(); + String usn = Validator.userInput("Enter usn: ", true, "validateUsnFormat", + "USN must have 11 digits"); + issueDetails.add(usn); + String studentName = Validator.userInput("Enter name: ", true, "validateStringGeneralFormat", + "The author name only accepts letters"); + issueDetails.add(studentName); + String isbn = Validator.userInput("Enter book ISBN: ",true, "checkISBNFormat", + "The ISBN must follow the next format: 978-92-95055-02-5"); + issueDetails.add(isbn); + return issueDetails; + } + + public void addBook(List bookAndAuthorInformation) throws InvalidBookInformationException{ + + if (bookAndAuthorInformation.size() != 6) { + throw new InvalidBookInformationException( + "The book and author information must be a six-element string list."); + } + String isbn = bookAndAuthorInformation.get(0); + String title = bookAndAuthorInformation.get(1); + String category = bookAndAuthorInformation.get(2); + String authorName = bookAndAuthorInformation.get(3); + String email = bookAndAuthorInformation.get(4); + String quantityStr = bookAndAuthorInformation.get(5); + + if (!Validator.checkISBNFormat(isbn) || + !Validator.validateStringGeneralFormat(category) || + !Validator.validateStringGeneralFormat(authorName) || + !Validator.checkEmailFormat(email) || + !Validator.validateInteger(quantityStr)) { + throw new InvalidBookInformationException("The provided information is invalid. Please check the format"); + } + + int quantity = Integer.parseInt(quantityStr); + + Book newBook = new Book(isbn, title, category, quantity); + Author author = new Author(authorName, email, newBook); + + Optional optionalBook = bookService.findByIsbn(isbn); + + if(optionalBook.isPresent()){ + Book book = optionalBook.get(); + book.setCategory(category); + book.setQuantity(quantity); + book.setTitle(title); + bookService.save(book); + }else{ + authorService.save(author); + bookService.save(newBook); + } + } + + public Book searchBookByAuthor(String authorName) throws NoBookFoundException, InvalidBookInformationException { + if (!Validator.validateStringGeneralFormat(authorName)) { + throw new InvalidBookInformationException("The provided information is invalid. Please check the format"); + } + Optional optionalBook = authorService.findBookByAuthor(authorName); + if (optionalBook.isPresent()) { + return optionalBook.get(); + } else { + throw new NoBookFoundException("No book found for author: " + authorName); + } + } + + public List searchBookByCategory(String category) throws NoBookFoundException, + InvalidBookInformationException { + if(!Validator.validateStringGeneralFormat(category)) + throw new InvalidBookInformationException("The provided information is invalid. Please check the format"); + Optional> optionalBookList = bookService.findAllByCategory(category); + if(optionalBookList.isPresent() && !optionalBookList.get().isEmpty()){ + return optionalBookList.get(); + }else{ + throw new NoBookFoundException("No books found for this category: " + category); + } + } + + public List searchBookByTitle(String title) throws NoBookFoundException, InvalidBookInformationException { + if(!Validator.validateStringGeneralFormat(title)) throw new InvalidBookInformationException("The provided information is invalid. Please check the format"); + Optional> optionalBookList = bookService.findAllByTitle(title); + if(optionalBookList.isPresent() && !optionalBookList.get().isEmpty()){ + return optionalBookList.get(); + }else{ + throw new NoBookFoundException("No books found with this title: " + title); + } + } + + public Issue issueBookToStudent(List issueData) throws InvalidBookInformationException, + NoBookFoundException, BookWithActiveIssueException { + String usn = issueData.get(0); + String name = issueData.get(1); + String isbn = issueData.get(2); + if (!Validator.checkISBNFormat(isbn) + || !Validator.validateStringGeneralFormat(name) + || !Validator.checkUsnFormat(usn) + ) { + throw new InvalidBookInformationException("The provided information is invalid. Please check the format"); + } + Optional optionalStudent = studentService.findStudentByUsnAndName(usn,name); + if (optionalStudent.isEmpty()){ + studentService.save(usn, name); + optionalStudent = studentService.findStudentByUsnAndName(usn,name); + } + Student student = optionalStudent.get(); + Book book = bookService.findByIsbn(isbn).orElseThrow(() -> new NoBookFoundException("No books are found with that ISBN")); + Issue issue; + if (book.getQuantity() < 1) { + throw new NoBookFoundException("Quantity unavailable"); + } else if (issueService.findIssueByIsbn(book.getIsbn()).isPresent()) { + throw new BookWithActiveIssueException("The book has an active issue"); + } else { + book.setQuantity(book.getQuantity() - 1); + bookService.save(book); + issue = issueService.save(student, book); + // Update book quantity + } + return issue; + } + + public List searchBooksByUsn(String usn) throws NoBookFoundException, NoStudentFoundException { + Optional optionalStudent = studentService.findStudentByUsn(usn); + if(optionalStudent.isPresent()){ + Student student = optionalStudent.get(); + Optional> optionalObjects = issueService.findAllBooksAndIssuesByUsn(student.getUsn()); + if (optionalObjects.isPresent()){ + return optionalObjects.get(); + }else{ + throw new NoBookFoundException("No books found for this usn: " + usn); + } + }else{ + throw new NoStudentFoundException("No student found for this usn: " + usn); + } + } + + @Override + public List searchBooksAlongAuthors() throws NoBookFoundException { + return authorService.findAllBooksWithAuthors().orElseThrow(()-> new NoBookFoundException("No Books are found")); + } + + @Override + public void mainManu() throws Exception { + System.out.println("Welcome to Iron Library book management system!!"); + System.out.println("Please access one of the following options"); + Scanner scanner = new Scanner(System.in); + int userInput = 0; + boolean errorHandling = false; + printMenuOptions(); + + do{ + while (!scanner.hasNextInt()) { + System.out.println("Invalid input. Please enter a number from 1 to 8."); + scanner.next(); + } + userInput = scanner.nextInt(); + + if (userInput < 1 || userInput > 8) { + System.out.println("Invalid input. Please enter a number from 1 to 8."); + } else { + errorHandling = executeMenuOption(userInput); + if (userInput != 8) { + printMenuOptions(); + } + } + }while(userInput != 8 || !errorHandling); + + } + + private void printMenuOptions(){ + System.out.println(""" + Menu: + 1 - Add a book + 2 - Search book by title + 3 - Search book by category + 4 - Search book by Author + 5 - List all books along with author + 6 - Issue book to student + 7 - List books by usn + 8 - Exit + only digits between 1-8 are available"""); + } + + private boolean executeMenuOption(int userInput) { + boolean isError = false; + switch (userInput){ + case 1: + try { + List bookAndAuthorInformation = getNewBookInformation(); + addBook(bookAndAuthorInformation); + return isError; + } catch (InvalidBookInformationException e){ + System.out.println(e.getMessage()); + return true; + } + case 2: + String title = Validator.userInput("Enter title: ", false, "NULL", "NULL"); + List booksByTitle = null; + try { + booksByTitle = searchBookByTitle(title); + System.out.println(DataOutput.listBookTable(booksByTitle)); + return isError; + } catch (NoBookFoundException | InvalidBookInformationException e) { + System.out.println(e.getMessage()); + return true; + } + case 3: + String category = Validator.userInput("Enter category: ", true, "validateStringGeneralFormat", + "The category only accepts letters"); + List books = null; + try { + books = searchBookByCategory(category); + System.out.println(DataOutput.listBookTable(books)); + return isError; + } catch (NoBookFoundException | InvalidBookInformationException e) { + System.out.println(e.getMessage()); + return true; + } + case 4: + String authorName = Validator.userInput("Enter author name: ", true, "validateStringGeneralFormat", + "The author name only accepts letters"); + Book book = null; + try { + book = searchBookByAuthor(authorName); + System.out.println(DataOutput.oneBookTable(book)); + return isError; + } catch (NoBookFoundException | InvalidBookInformationException e) { + System.out.println(e.getMessage()); + return true; + } + case 5: + List objects = null; + try { + objects = searchBooksAlongAuthors(); + System.out.println(DataOutput.listBookTableWithAuthor(objects)); + return isError; + } catch (NoBookFoundException e) { + System.out.println(e.getMessage()); + return true; + } + case 6: + List issueData = getNewIssueInformation(); + try { + Issue issue = issueBookToStudent(issueData); + System.out.println(DataOutput.bookIssuedDate(issue)); + return isError; + } catch (NoBookFoundException | BookWithActiveIssueException e) { + System.out.println(e.getMessage()); + return true; + } + case 7: + String usn = Validator.userInput("Enter usn: ", true, "validateUsnFormat", + "USN must have 11 digits"); + try { + List info = searchBooksByUsn(usn); + Object[] firstElement = info.get(0); + Issue issue = (Issue) firstElement[1]; + Student student = issue.getIssueStudent(); + System.out.println(DataOutput.listBookTableByUsn(info, student)); + return isError; + } catch (NoBookFoundException | NoStudentFoundException e){ + System.out.println(e.getMessage()); + return true; + } + case 8: + System.out.println("Thanks for use our application :)"); + System.exit(0); + break; + default: + System.out.println("Invalid input. Please enter a number from 1 to 8."); + } + return isError; + } +} + + + diff --git a/src/main/java/com/ironhack/ironLibrary/service/StudentServiceImpl.java b/src/main/java/com/ironhack/ironLibrary/service/StudentServiceImpl.java new file mode 100644 index 00000000..51613d3b --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/service/StudentServiceImpl.java @@ -0,0 +1,29 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Student; +import com.ironhack.ironLibrary.repository.StudentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class StudentServiceImpl implements IStudentService{ + + @Autowired + private StudentRepository studentRepository; + + @Override + public Optional findStudentByUsnAndName(String usn, String name) { + return studentRepository.findByUsnAndName(usn, name); + } + @Override + public Student save(String usn, String name) { + return studentRepository.save(new Student(usn, name)); + } + @Override + public Optional findStudentByUsn(String usn) { + return studentRepository.findByUsn(usn); + } + +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/BookWithActiveIssueException.java b/src/main/java/com/ironhack/ironLibrary/utils/BookWithActiveIssueException.java new file mode 100644 index 00000000..3e83a6a6 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/BookWithActiveIssueException.java @@ -0,0 +1,7 @@ +package com.ironhack.ironLibrary.utils; + +public class BookWithActiveIssueException extends RuntimeException { + public BookWithActiveIssueException(String s) { + super(s); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/DataOutput.java b/src/main/java/com/ironhack/ironLibrary/utils/DataOutput.java new file mode 100644 index 00000000..e1cc4131 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/DataOutput.java @@ -0,0 +1,65 @@ +package com.ironhack.ironLibrary.utils; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import de.vandermeer.asciithemes.TA_GridThemes; +import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment; +import de.vandermeer.asciitable.AsciiTable; + +import java.util.List; + +public class DataOutput { + + private static AsciiTable createAsciiTable(){ + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + return asciiTable; + } + public static String oneBookTable(Book book){ + AsciiTable asciiTable = createAsciiTable(); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books"); + asciiTable.addRow(book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity()); + return asciiTable.render(); + } + + public static String listBookTable(List books){ + AsciiTable asciiTable = createAsciiTable(); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books"); + for (Book book : books){ + asciiTable.addRow(book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity()); + } + return asciiTable.render(); + } + + public static String listBookTableWithAuthor(List lstObjects){ + AsciiTable asciiTable = createAsciiTable(); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books", + "Author name", "Author mail"); + for (Object[] obj : lstObjects){ + Book book = (Book) obj[0]; + Author author = (Author) obj[1]; + asciiTable.addRow(book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity(), + author.getName(), author.getEmail()); + } + return asciiTable.render(); + } + + public static String bookIssuedDate(Issue issue){ + return "Book issued. Return date : " + DateFormatter.largeDateFormat(issue.getReturnDate()); + } + + public static String listBookTableByUsn(List lstObjects, Student student){ + AsciiTable asciiTable = createAsciiTable(); + asciiTable.addRow("Book Title", "Student Name", "Return date"); + for (Object[] obj : lstObjects){ + Book book = (Book) obj[0]; + Issue issue = (Issue) obj[1]; + asciiTable.addRow(book.getTitle(), student.getName(), + DateFormatter.simpleDateFormat(issue.getReturnDate())); + } + return asciiTable.render(); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/DateFormatter.java b/src/main/java/com/ironhack/ironLibrary/utils/DateFormatter.java new file mode 100644 index 00000000..02bc8039 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/DateFormatter.java @@ -0,0 +1,22 @@ +package com.ironhack.ironLibrary.utils; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +public class DateFormatter { + + public static String simpleDateFormat(LocalDateTime returnDate){ + DateTimeFormatter formatDate1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return returnDate.format(formatDate1); + } + + public static String largeDateFormat(LocalDateTime returnDate){ + DateTimeFormatter formatDate2 = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", + Locale.ENGLISH); + ZonedDateTime zonedDateTime = returnDate.atZone(ZoneId.of("Europe/Helsinki")); + return zonedDateTime.format(formatDate2); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/InvalidBookInformationException.java b/src/main/java/com/ironhack/ironLibrary/utils/InvalidBookInformationException.java new file mode 100644 index 00000000..cd27770a --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/InvalidBookInformationException.java @@ -0,0 +1,8 @@ +package com.ironhack.ironLibrary.utils; + +public class InvalidBookInformationException extends RuntimeException{ + public InvalidBookInformationException(String message) { + super(message); + } + +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/NoBookFoundException.java b/src/main/java/com/ironhack/ironLibrary/utils/NoBookFoundException.java new file mode 100644 index 00000000..8f62a1f8 --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/NoBookFoundException.java @@ -0,0 +1,7 @@ +package com.ironhack.ironLibrary.utils; + +public class NoBookFoundException extends InstantiationException{ + public NoBookFoundException(String s) { + super(s); + } +} diff --git a/src/main/java/com/ironhack/ironLibrary/utils/NoStudentFoundException.java b/src/main/java/com/ironhack/ironLibrary/utils/NoStudentFoundException.java new file mode 100644 index 00000000..f9690dcb --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/NoStudentFoundException.java @@ -0,0 +1,7 @@ +package com.ironhack.ironLibrary.utils; + +public class NoStudentFoundException extends InstantiationException{ + public NoStudentFoundException(String s) { + super(s); + } +} \ No newline at end of file diff --git a/src/main/java/com/ironhack/ironLibrary/utils/Validator.java b/src/main/java/com/ironhack/ironLibrary/utils/Validator.java new file mode 100644 index 00000000..b16c1ebc --- /dev/null +++ b/src/main/java/com/ironhack/ironLibrary/utils/Validator.java @@ -0,0 +1,99 @@ +package com.ironhack.ironLibrary.utils; + + +import java.util.Scanner; +import java.util.regex.Pattern; + +public class Validator { + + public static boolean checkUsnFormat(String usn){ + return patternMatches(usn, "^\\d{11}$"); + } + + public static boolean checkISBNFormat(String maybeISBN){ + return patternMatches(maybeISBN, "^(?=(?:\\D*\\d){10}(?:(?:\\D*\\d){3})?$)[\\d-]+$"); + } + + public static boolean checkEmailFormat(String email){ + return patternMatches(email, "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"); + } + + private static boolean patternMatches(String inputString, String regexPattern) { + return Pattern.compile(regexPattern) + .matcher(inputString) + .matches(); + } + + public static boolean validateInteger(String input) { + try { + if (input == null || input.trim().isEmpty()) { + return false; + } + Integer.parseInt(input); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + public static boolean notBlankValidatorBooks(String input) { + return input != null && !input.trim().isEmpty(); + } + + public static boolean validateStringGeneralFormat(String input) { + return input != null && !input.isEmpty() && patternMatches(input, "^[a-zA-ZÀ-ÿ\\s]*$"); + } + + /** + * TODO Testing + * @param printText + * @param validTheNextInput + * @param methodName + * @param suggestedInputFormat + * @return + */ + public static String userInput(String printText, boolean validTheNextInput, String methodName, String suggestedInputFormat){ + String userInputText; + boolean result = false; + do{ + System.out.print(printText); + Scanner scanner = new Scanner(System.in); + userInputText = scanner.nextLine(); + if(validTheNextInput){ + try{ + switch(methodName){ + case "checkISBNFormat": + result = Validator.checkISBNFormat(userInputText); + break; + case "validateStringGeneralFormat": + result = Validator.validateStringGeneralFormat(userInputText); + break; + case "checkEmailFormat": + result = Validator.checkEmailFormat(userInputText); + break; + case "validateInteger": + result = Validator.validateInteger(userInputText); + break; + case "notBlankValidatorBooks": + result = Validator.notBlankValidatorBooks(userInputText); + break; + case "validateUsnFormat": + result = Validator.checkUsnFormat(userInputText); + break; + } + if(!result){ + System.out.println("Sorry, but the input format it's incorrect. Please try again: "); + System.out.println(suggestedInputFormat); + } + }catch (Exception e) { + e.printStackTrace(); + } + }else{ + result = true; + } + }while(!result); + return userInputText; + }; +} + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 00000000..8c2ad29d --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,13 @@ +spring.application.name=ironLibrary +spring.datasource.url=jdbc:mysql://localhost:3306/${MYSQL_DATABASE}?createDatabaseIfNotExist=TRUE +spring.datasource.username=${MYSQL_USERNAME} +spring.datasource.password=${MYSQL_PASSWORD} + +spring.jpa.properties.hibernate.hbm2ddl.auto=update +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect +##spring.jpa.hibernate.ddl-auto=validate + +#spring.jpa.show-sql=true +#spring.jpa.open-in-view=true +app.menu.enabled=true \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/IronLibraryApplicationTests.java b/src/test/java/com/ironhack/ironLibrary/IronLibraryApplicationTests.java new file mode 100644 index 00000000..2388e935 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/IronLibraryApplicationTests.java @@ -0,0 +1,14 @@ +package com.ironhack.ironLibrary; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + + +@SpringBootTest +class IronLibraryApplicationTests { + + @Test + void contextLoads() { + + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/model/AuthorTest.java b/src/test/java/com/ironhack/ironLibrary/model/AuthorTest.java new file mode 100644 index 00000000..d6d69ef4 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/model/AuthorTest.java @@ -0,0 +1,21 @@ +package com.ironhack.ironLibrary.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class AuthorTest { + + @Test + void createAuthor(){ + Author authorOne = new Author(); + Book book = new Book("978-3-16-148410-0", "Test book", "Tester", 2); + Author authorTwo = new Author("Carlos Diaz","carlosdiaz@mail.com", book); + + assertNotNull(authorOne); + assertNotNull(authorTwo); + assertEquals("Carlos Diaz", authorTwo.getName()); + assertEquals("Test book", authorTwo.getAuthorBook().getTitle()); + } +} diff --git a/src/test/java/com/ironhack/ironLibrary/model/BookTest.java b/src/test/java/com/ironhack/ironLibrary/model/BookTest.java new file mode 100644 index 00000000..5b7e9c5b --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/model/BookTest.java @@ -0,0 +1,94 @@ +package com.ironhack.ironLibrary.model; + +import com.ironhack.ironLibrary.repository.BookRepository; +import com.ironhack.ironLibrary.utils.Validator; +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 static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +public class BookTest { + static Book book; + private Book dummyBook; + private Book dummyBook2; + + @BeforeEach + void setUp() { + book = new Book("978-0-670-82162-0", "title", "Romance", 12); + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + dummyBook2 = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + } + + @Test + public void BookSetterAndGetterTitleTest() { + book.setTitle("newTitle"); + assertEquals("newTitle", "newTitle"); + } + + @Test + public void BookSetterAndGetterCategoryTest() { + book.setCategory("terror"); + assertEquals("terror", book.getCategory()); + } + + @Test + public void BookSetterAndGetterQuantityTest() { + book.setQuantity(3); + assertEquals(3, book.getQuantity()); + } + + @Test + void BookDefaultConstructorTest(){ + Book book = new Book(); + assertNotNull(book); + } + + @Test + void shouldBeCorrectInstantiated(){ + assertEquals("novel", dummyBook.getCategory()); + assertEquals("978-84-415-4301-0", dummyBook.getIsbn()); + assertEquals("The unicorn project", dummyBook.getTitle()); + assertEquals(1, dummyBook.getQuantity()); + } + + @Test + void shouldBeTheSameObject(){ + assertEquals(dummyBook, dummyBook2); + } + + @Test + void shouldBeTheSameHashCode(){ + assertEquals(dummyBook.hashCode(), dummyBook2.hashCode()); + } + @Test + void shouldBeUpdateQuantityToTen(){ + dummyBook.setQuantity(10); + assertEquals(10, dummyBook.getQuantity()); + } + @Test + void shouldUpdateCategory(){ + dummyBook.setCategory("comedy"); + assertEquals("comedy", dummyBook.getCategory()); + } + + @Test + void shouldUpdateTitle(){ + dummyBook.setTitle("The fenix project"); + assertEquals("The fenix project", dummyBook.getTitle()); + } + + @Test + void shouldBePassISBNValidator(){ + assertTrue(Validator.checkISBNFormat(dummyBook.getIsbn())); + } + + @Test + void shouldBePassNotNullTitleValidator(){ + assertTrue(Validator.notBlankValidatorBooks(dummyBook.getTitle())); + } + +} diff --git a/src/test/java/com/ironhack/ironLibrary/model/IssueTest.java b/src/test/java/com/ironhack/ironLibrary/model/IssueTest.java new file mode 100644 index 00000000..d378e598 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/model/IssueTest.java @@ -0,0 +1,25 @@ +package com.ironhack.ironLibrary.model; + + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; +public class IssueTest { + + @Test + public void createIssue(){ + Student student = new Student("09003688800", "Carlos"); + Book book = new Book(); + Issue IssueOne = new Issue(); + Issue IssueTwo = new Issue(student, book); + + assertNotNull(IssueOne); + assertNotNull(IssueTwo); + assertNotNull(IssueTwo.getIssueDate()); + assertNotNull(IssueTwo.getReturnDate()); + assertNotNull(IssueTwo); + assertEquals(student, IssueTwo.getIssueStudent()); + assertEquals(book, IssueTwo.getIssueBook()); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/model/StudentTest.java b/src/test/java/com/ironhack/ironLibrary/model/StudentTest.java new file mode 100644 index 00000000..130e06e8 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/model/StudentTest.java @@ -0,0 +1,18 @@ +package com.ironhack.ironLibrary.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StudentTest { + + + @Test + void createStudent(){ + Student studentQA = new Student(); + Student studentQA2 = new Student("09003688800","Test"); + assertNotNull(studentQA); + assertNotNull(studentQA2); + } + +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/repository/AuthorRepositoryTest.java b/src/test/java/com/ironhack/ironLibrary/repository/AuthorRepositoryTest.java new file mode 100644 index 00000000..ced2c2a8 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/repository/AuthorRepositoryTest.java @@ -0,0 +1,99 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +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.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class AuthorRepositoryTest { + + @Autowired + private AuthorRepository authorRepository; + + private List dummyListAuthor; + private List dummyListBook; + + @BeforeEach + void setUp() { + dummyListBook = new ArrayList<>(); + dummyListBook.add(new Book("978-84-415-4301-0", "The unicorn project", "novel", 1)); + dummyListBook.add(new Book("978-84-415-4301-1", "Siddarta", "novel",3)); + dummyListBook.add(new Book("978-84-415-4301-2","La condesa sangrienta", "novel", 10)); + dummyListBook.add(new Book("978-84-415-4301-3","Sherlock Holmes","crime",1 )); + + dummyListAuthor = new ArrayList<>(); + dummyListAuthor.add(new Author("Gene Kim", "g.kim@gmail.com", dummyListBook.get(0))); + dummyListAuthor.add(new Author("Herman Hesse", "h.hesse@gmail.com",dummyListBook.get(1))); + dummyListAuthor.add(new Author("Alejandra Pizarnik", "alejandra.pizarnik@gmail.com",dummyListBook.get(2))); + dummyListAuthor.add(new Author("Arthur Conan Doyle","a.c.doyle@mail.com", dummyListBook.get(3))); + + authorRepository.saveAll(dummyListAuthor); + } + + @AfterEach + void tearDown() { + authorRepository.deleteAll(); + } + + @Test + void shouldReturnACorrectBookIfUseFindBookByAuthor() { + Optional maybeBook = authorRepository.findBookByAuthor("Gene Kim"); + assertTrue(maybeBook.isPresent(), "The book should not be null"); + maybeBook.ifPresent(book -> { + assertEquals("The unicorn project", book.getTitle()); + assertEquals("978-84-415-4301-0", book.getIsbn()); + assertEquals(1, book.getQuantity()); + assertEquals("novel", book.getCategory()); + }); + } + + @Test + void shouldReturnEmptyIfWeWantToFindABookByAuthorThatNotExist(){ + Optional maybeBook = authorRepository.findBookByAuthor("J.K Rowling"); + assertFalse(maybeBook.isPresent()); + } + + @Test + void getAllBooksWithAuthor(){ + List listObject = new ArrayList<>(); + + Optional> getBooks = authorRepository.findAllBooksWithAuthors(); + if(getBooks.isPresent()){ + listObject = getBooks.get(); + } + assertEquals(4, listObject.size()); + } + + @Test + void allBookAuthorsAreCorrect(){ + List listObject = new ArrayList<>(); + List listAuthor = new ArrayList<>(); + + Optional> getBooks = authorRepository.findAllBooksWithAuthors(); + + if(getBooks.isPresent()){ + listObject = getBooks.get(); + } + for( Object[] a : listObject){ + listAuthor.add((Author) a[1]); + } + + assertEquals("Gene Kim", listAuthor.get(0).getName()); + assertEquals("Herman Hesse", listAuthor.get(1).getName()); + assertEquals("Alejandra Pizarnik", listAuthor.get(2).getName()); + assertEquals("Arthur Conan Doyle", listAuthor.get(3).getName()); + + } + + +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/repository/BookRepositoryTest.java b/src/test/java/com/ironhack/ironLibrary/repository/BookRepositoryTest.java new file mode 100644 index 00000000..09b9fdd0 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/repository/BookRepositoryTest.java @@ -0,0 +1,114 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Book; +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 java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class BookRepositoryTest { + int quantityOfNovelBooks = 0; + @Autowired + private BookRepository bookRepository; + + private Book dummyBook; + @BeforeEach + void setUp() { + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + bookRepository.save(dummyBook); + } + + @AfterEach + void tearDown() { + bookRepository.deleteAll(); + } + + @Test + void shouldBeGetTheBook(){ + Optional maybeBook = bookRepository.findById("978-84-415-4301-0"); + assertTrue(maybeBook.isPresent()); + } + + + @Test + void shouldBeOneQuantityBook(){ + Optional maybeBook = bookRepository.findById("978-84-415-4301-0"); + if(maybeBook.isPresent()){ + Book book = maybeBook.get(); + assertEquals(1, book.getQuantity()); + } + } + + @Test + void shouldBeTheCorrectTitle(){ + Optional maybeBook = bookRepository.findById("978-84-415-4301-0"); + if(maybeBook.isPresent()){ + Book book = maybeBook.get(); + assertEquals("The unicorn project", book.getTitle()); + } + } + + @Test + void shouldBeTheCorrectCategory(){ + Optional maybeBook = bookRepository.findById("978-84-415-4301-0"); + if(maybeBook.isPresent()){ + Book book = maybeBook.get(); + assertEquals("novel", book.getCategory()); + } + } + + @Test + void shouldGetAllBooksUsingFindAllByCategory() { + Book newBook = new Book("978-84-415-4302-0", "The fenix project", "novel", 10); + bookRepository.save(newBook); + Optional> maybeListOfBooks = bookRepository.findAllByCategory("novel"); + if(maybeListOfBooks.isPresent()){ + List listOfBooks = maybeListOfBooks.get(); + assertEquals(2, listOfBooks.size()); + } + } + + @Test + void shouldGetTheRightQuantityOfBooksUsingFindAllByCategory(){ + Book newBooks = new Book("978-84-415-4302-0", "The fenix project", "novel", 10); + bookRepository.save(newBooks); + Optional> maybeListOfBooks = bookRepository.findAllByCategory("novel"); + if(maybeListOfBooks.isPresent()){ + maybeListOfBooks.get().forEach(book -> { + quantityOfNovelBooks = quantityOfNovelBooks + book.getQuantity(); + }); + assertEquals(11, quantityOfNovelBooks); + } + } + + @Test + void shouldGetTheRightBookUsingFindOneByTitle() { + Optional maybeBook = bookRepository.findOneByTitle("The unicorn project"); + maybeBook.ifPresent(book -> assertEquals("The unicorn project", book.getTitle())); + } + + @Test + void shouldGetFalseIfWeFindTheWrongTitleUsingFindOneByTitle() { + Optional maybeBook = bookRepository.findOneByTitle("The unicorn project"); + maybeBook.ifPresent(book -> assertNotEquals("The fenix project", book.getTitle())); + } + + @Test + void testFindByIsbn_HappyPath(){ + Optional maybeBook = bookRepository.findByIsbn("978-84-415-4301-0"); + maybeBook.ifPresent(book -> assertEquals("The unicorn project", book.getTitle())); + } + + @Test + void testFindByIsbn_NegativePath_NonISBNRegisteredOnDataBase(){ + Optional optionalBook = bookRepository.findByIsbn("978-84-415-4301-1"); + assertTrue(optionalBook.isEmpty(), "Expected Optional to be empty"); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/repository/IssueRepositoryTest.java b/src/test/java/com/ironhack/ironLibrary/repository/IssueRepositoryTest.java new file mode 100644 index 00000000..2183afe0 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/repository/IssueRepositoryTest.java @@ -0,0 +1,112 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +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 java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class IssueRepositoryTest { + + @Autowired + private IssueRepository issueRepository; + @Autowired + private BookRepository bookRepository; + @Autowired + private StudentRepository studentRepository; + + private Book dummyBook; + private Book dummyBook2; + private Student dummyStudent; + private Student dummyStudent2; + private Issue dummyIssue; + private Issue dummyIssue2; + + @BeforeEach + void setUp() { + Issue issue = new Issue(); + dummyStudent = new Student("09003688800", "Pedro"); + dummyStudent2 = new Student("09003688801", "Maria"); + studentRepository.save(dummyStudent); + + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + dummyBook2 = new Book("978-84-415-4302-0", "The fenix project", "novel", 1); + bookRepository.saveAll(List.of(dummyBook, dummyBook2)); + + dummyIssue = new Issue(dummyStudent, dummyBook); + issueRepository.save(issue); + } + + @AfterEach + void tearDown() { + issueRepository.deleteAll(); + bookRepository.deleteAll(); + studentRepository.deleteAll(); + } + + @Test + void shouldFindOneBookIdWeUseFindAllBooksByUsn() { + issueRepository.save(dummyIssue); + Optional> maybeListOfBooksIssued = issueRepository.findAllBooksByUsn(dummyStudent.getUsn()); + if (maybeListOfBooksIssued.isPresent()) { + List listOfBooksIssued = maybeListOfBooksIssued.get(); + assertEquals(1, listOfBooksIssued.size()); + } + } + + @Test + void shouldNotFindAnyBookIdWeUseFindAllBooksByUsn() { + Optional> maybeListOfBooksIssued = issueRepository.findAllBooksByUsn(dummyStudent2.getUsn()); + if (maybeListOfBooksIssued.isPresent()) { + List listOfBooksIssued = maybeListOfBooksIssued.get(); + assertEquals(0, listOfBooksIssued.size()); + } + } + + @Test + void shouldFindAllBooksAndIssuesByUsn() { + issueRepository.save(dummyIssue); + Optional> optionalListObject = issueRepository.findAllBooksAndIssuesByUsn(dummyStudent.getUsn()); + if (optionalListObject.isPresent()) { + List listObject = optionalListObject.get(); + Object[] firstElement = listObject.get(0); + Book book = (Book) firstElement[0]; + Issue issue = (Issue) firstElement[1]; + assertEquals(1, listObject.size()); + assertEquals("The unicorn project", book.getTitle()); + assertEquals("Pedro", issue.getIssueStudent().getName()); + } + } + + @Test + void shouldNotFindBooksAndIssuesByUsn() { + Optional> optionalListObject = issueRepository.findAllBooksAndIssuesByUsn(dummyStudent.getUsn()); + if (optionalListObject.isPresent()) { + List listObject = optionalListObject.get(); + assertEquals(0, listObject.size()); + } + } + + @Test + void saveItemTest() { + assertEquals(1, issueRepository.count()); + } + + @Test + void deleteItemTest() { + Optional firstIssue = issueRepository.findAll().stream().findFirst(); + assertTrue(firstIssue.isPresent()); + issueRepository.delete(firstIssue.get()); + assertEquals(0, issueRepository.count()); + } +} + diff --git a/src/test/java/com/ironhack/ironLibrary/repository/StudentRepositoryTest.java b/src/test/java/com/ironhack/ironLibrary/repository/StudentRepositoryTest.java new file mode 100644 index 00000000..5a742435 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/repository/StudentRepositoryTest.java @@ -0,0 +1,45 @@ +package com.ironhack.ironLibrary.repository; + +import com.ironhack.ironLibrary.model.Student; +import org.junit.jupiter.api.AfterAll; +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 StudentRepositoryTest { + @Autowired + private StudentRepository studentRepository; + + @BeforeEach + void setUp() { + Student student1 = new Student("09003688800", "Student1"); + Student student2 = new Student("09003688801", "Student2"); + studentRepository.save(student1); + studentRepository.save(student2); + } + + @AfterEach + void tearDown() { + studentRepository.deleteAll(); + } + + @Test + void checkSaveItem() { + assertEquals(2, studentRepository.count()); + } + + @Test + void findByUsnAndNameTest() { + Optional student = studentRepository.findByUsnAndName("09003688801", "Student2"); + assertTrue(student.isPresent()); + assertEquals("Student2", student.get().getName()); + } +} diff --git a/src/test/java/com/ironhack/ironLibrary/service/AuthorServiceImplTest.java b/src/test/java/com/ironhack/ironLibrary/service/AuthorServiceImplTest.java new file mode 100644 index 00000000..7c3a3706 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/service/AuthorServiceImplTest.java @@ -0,0 +1,58 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.repository.AuthorRepository; +import com.ironhack.ironLibrary.repository.BookRepository; +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 AuthorServiceImplTest { + + @Autowired + private AuthorRepository authorRepository; + @Autowired + private BookRepository bookRepository; + + @Autowired + private IAuthorService authorService; + + private Author dummyAuthor, dummyAuthor2; + private Book dummyBook, dummyBook2; + + @BeforeEach + void setUp() { + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + dummyAuthor = new Author("Gene Kim", "g.kim@gmail.com", dummyBook); + dummyBook2 = new Book("978-84-415-4301-1", "The unicorn project II", "novel", 1); + dummyAuthor2 = new Author("Gene Kim2", "g.kim@gmail.com", dummyBook2); + authorRepository.save(dummyAuthor); + authorService.save(dummyAuthor2); + } + + @AfterEach + void tearDown() { + authorRepository.deleteAll(); + } + + @Test + void validateSameBehaviorUsingRepositoryOrServiceClass(){ + List authorList = authorRepository.findAll(); + + Author author1 = authorList.get(0); + Author author2 = authorList.get(1); + + assertNotEquals(author1, author2); + } + + +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/service/BookServiceImplTest.java b/src/test/java/com/ironhack/ironLibrary/service/BookServiceImplTest.java new file mode 100644 index 00000000..dd9d9104 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/service/BookServiceImplTest.java @@ -0,0 +1,57 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.repository.AuthorRepository; +import com.ironhack.ironLibrary.repository.BookRepository; +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 static org.junit.jupiter.api.Assertions.assertNotEquals; + +@SpringBootTest +class BookServiceImplTest { + + @Autowired + private AuthorRepository authorRepository; + @Autowired + private BookRepository bookRepository; + + @Autowired + private IAuthorService authorService; + + @Autowired + private IBookService bookService; + + private Author dummyAuthor, dummyAuthor2; + private Book dummyBook, dummyBook2; + + @BeforeEach + void setUp() { + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + dummyAuthor = new Author("Gene Kim", "g.kim@gmail.com", dummyBook); + dummyBook2 = new Book("978-84-415-4301-1", "The unicorn project II", "novel", 1); + dummyAuthor2 = new Author("Gene Kim2", "g.kim@gmail.com", dummyBook2); + authorRepository.save(dummyAuthor); + authorService.save(dummyAuthor2); + } + + @AfterEach + void tearDown() { + authorRepository.deleteAll(); + } + + @Test + void validateSameBehaviorUsingRepositoryOrServiceClass(){ + + Book book1 = bookService.findByIsbn("978-84-415-4301-0").get(); + Book book2 = bookService.findByIsbn("978-84-415-4301-1").get(); + + assertNotEquals(book1, book2); + } + + +} diff --git a/src/test/java/com/ironhack/ironLibrary/service/IssueServiceImplTest.java b/src/test/java/com/ironhack/ironLibrary/service/IssueServiceImplTest.java new file mode 100644 index 00000000..63eca025 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/service/IssueServiceImplTest.java @@ -0,0 +1,65 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import com.ironhack.ironLibrary.repository.BookRepository; +import com.ironhack.ironLibrary.repository.IssueRepository; +import com.ironhack.ironLibrary.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.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest +public class IssueServiceImplTest { + @Autowired + private IssueRepository issueRepository; + @Autowired + private BookRepository bookRepository; + @Autowired + private StudentRepository studentRepository; + @Autowired + private IIssueService issueService; + + private Book dummyBook; + private Book dummyBook2; + private Student dummyStudent; + private Student dummyStudent2; + private Issue dummyIssue; + private Issue dummyIssue2; + + @BeforeEach + void setUp() { + dummyStudent = new Student("09003688800", "Pedro"); + studentRepository.save(dummyStudent); + dummyBook = new Book("978-84-415-4301-0", "The unicorn project", "novel", 1); + bookRepository.save(dummyBook); + Issue issue = new Issue(dummyStudent, dummyBook); + issueRepository.save(issue); + } + + @AfterEach + void tearDown() { + issueRepository.deleteAll(); + bookRepository.deleteAll(); + studentRepository.deleteAll(); + } + + @Test + void findAllBooksIssuedByUsnPositiveTest(){ + Optional> optionalBookListService = issueService.findAllBooksIssuedByUsn(dummyStudent.getUsn()); + assertTrue(optionalBookListService.isPresent()); + List bookList1 = optionalBookListService.get(); + assertEquals(1, bookList1.size()); + assertEquals("The unicorn project", bookList1.get(0).getTitle()); + + } +} diff --git a/src/test/java/com/ironhack/ironLibrary/service/MenuServiceImplTest.java b/src/test/java/com/ironhack/ironLibrary/service/MenuServiceImplTest.java new file mode 100644 index 00000000..a91bc009 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/service/MenuServiceImplTest.java @@ -0,0 +1,405 @@ +package com.ironhack.ironLibrary.service; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import com.ironhack.ironLibrary.repository.AuthorRepository; +import com.ironhack.ironLibrary.repository.BookRepository; +import com.ironhack.ironLibrary.repository.IssueRepository; +import com.ironhack.ironLibrary.repository.StudentRepository; +import com.ironhack.ironLibrary.utils.InvalidBookInformationException; +import com.ironhack.ironLibrary.utils.NoBookFoundException; +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.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class MenuServiceImplTest { + + @Autowired + private IBookService bookService; + + @Autowired + private IAuthorService authorService; + @Autowired + private IIssueService issueService; + + @Autowired + private IStudentService studentService; + + @Autowired + private IMenuService menuService; + + @Autowired + private AuthorRepository authorRepository; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private IssueRepository issueRepository; + + @Autowired + private StudentRepository studentRepository; + + @Test + public void testAddBookWithValidInformation() { + List validInformation = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + assertDoesNotThrow(() -> menuService.addBook(validInformation)); + } + + @Test + public void testAddBookWithInvalidInformation() { + List invalidInformation = Arrays.asList( + "XXX-YYY-JJJ", + "1 Book", + "Fiction", + "Superm@n", + "my mail", + "hey" + ); + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class, + () -> menuService.addBook(invalidInformation)); + assertEquals("The provided information is invalid. Please check the format", exception.getMessage()); + } + + @Test + public void testAddBookWithIncompleteInformation() { + List incompleteInformation = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com" + ); + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class, + () -> menuService.addBook(incompleteInformation)); + assertEquals("The book and author information must be a six-element string list.", exception.getMessage()); + } + + @Test + public void testAddBookWithExtraInformation() { + List incompleteInformation = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10", + "10" + ); + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class, + () -> menuService.addBook(incompleteInformation)); + assertEquals("The book and author information must be a six-element string list.", exception.getMessage()); + } + + @Test + public void testAddBookSaveAndFindByIsbn() { + List validInformation = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + assertDoesNotThrow(() -> menuService.addBook(validInformation)); + Book savedBook = bookService.findByIsbn("978-84-415-4302-0").orElse(null); + assertNotNull(savedBook); + assertEquals("978-84-415-4302-0", savedBook.getIsbn()); + assertEquals("The fenix project", savedBook.getTitle()); + assertEquals("novel", savedBook.getCategory()); + assertEquals(10, savedBook.getQuantity()); + + Author savedAuthor = authorService.findByAuthorBook(savedBook).get(); + assertNotNull(savedAuthor); + assertEquals("Gene Kim", savedAuthor.getName()); + assertEquals("g.kim@gmail.com", savedAuthor.getEmail()); + } + + @Test + void testSearchBookByAuthor() { + List validInformation = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + assertDoesNotThrow(() -> menuService.addBook(validInformation)); + try{ + Book book = menuService.searchBookByAuthor("Gene Kim"); + assertEquals("The fenix project", book.getTitle()); + assertEquals("978-84-415-4302-0", book.getIsbn()); + }catch (NoBookFoundException e){ + fail("An NoBookFoundException exception was thrown when it was not expected."); + } + } + + @Test + void testGetBookByAuthorGoesWrong(){ + String authorName = "Paco Wall"; + NoBookFoundException exception = assertThrows(NoBookFoundException.class, () -> menuService.searchBookByAuthor(authorName)); + assertEquals("No book found for author: " + authorName, exception.getMessage()); + } + + @Test + void testGetBookByAuthorGoesWrongWhenAuthorNameIsAnEmptyString(){ + String authorName = ""; + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class, () -> menuService.searchBookByAuthor(authorName)); + assertEquals("The provided information is invalid. Please check the format", exception.getMessage()); + } + + private static List> getListOfBooksToSave() { + List book1 = Arrays.asList( + "978-84-415-4302-0", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + List book2 = Arrays.asList( + "978-84-415-4302-1", + "The unicorn project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + List> listOfBooksToSave = new ArrayList<>(); + listOfBooksToSave.add(book1); + listOfBooksToSave.add(book2); + return listOfBooksToSave; + } + + @Test + void testSearchBookByCategory() { + List> listOfBooksToSave = getListOfBooksToSave(); + for(List book: listOfBooksToSave){ + menuService.addBook(book); + } + try{ + List listOfBooks = menuService.searchBookByCategory("novel"); + assertEquals(2, listOfBooks.size()); + assertEquals("The fenix project", listOfBooks.get(0).getTitle()); + }catch(NoBookFoundException e){ + fail("An NoBookFoundException exception was thrown when it was not expected."); + } + } + + @Test + void testSearchBookByCategoryNotFoundAnyBook(){ + String Category = "comedy"; + NoBookFoundException exception = assertThrows(NoBookFoundException.class, () -> menuService.searchBookByCategory(Category)); + assertEquals("No books found for this category: " + Category, exception.getMessage()); + } + + @Test + void testSearchBookByCategoryGoesWrong(){ + String Category = ""; + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class, () -> menuService.searchBookByCategory(Category)); + assertEquals("The provided information is invalid. Please check the format", exception.getMessage()); + } + + @Test + void testIssueBookToStudentGoWrongWithAIsbnWrong(){ + List issueData = Arrays.asList( + "09003688801", + "Pedro", + "978-84-415-5302-1" + ); + studentService.save(issueData.get(0), issueData.get(1)); + NoBookFoundException exception = assertThrows(NoBookFoundException.class,() -> menuService.issueBookToStudent(issueData)); + assertEquals("No books are found with that ISBN", exception.getMessage()); + } + + @Test + void testIssueBookToStudentGoWrongWithAUsnWrong(){ + List issueData = Arrays.asList( + "3", + "Pedro", + "978-84-415-5302-1" + ); + studentService.save(issueData.get(0), issueData.get(1)); + InvalidBookInformationException exception = assertThrows(InvalidBookInformationException.class,() -> menuService.issueBookToStudent(issueData)); + assertEquals("The provided information is invalid. Please check the format", exception.getMessage()); + } + + @Test + void testIssueBookToStudentGoWrongWithUnavailableQuantity(){ + List issueData = Arrays.asList( + "09003688802", + "Pedro", + "978-84-415-4302-1" + ); + List bookData = Arrays.asList( + "978-84-415-4302-1", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "0" + ); + menuService.addBook(bookData); + studentService.save(issueData.get(0), issueData.get(1)); + NoBookFoundException exception = assertThrows(NoBookFoundException.class,() -> menuService.issueBookToStudent(issueData)); + assertEquals("Quantity unavailable", exception.getMessage()); + } + + @Test + void testIssueBookToStudent() throws NoBookFoundException { + List issueData = Arrays.asList( + "09003688800", + "Pedro", + "978-84-415-4302-1" + ); + List bookData = Arrays.asList( + "978-84-415-4302-1", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + menuService.addBook(bookData); + String usnStudent = issueData.get(0); + String name = issueData.get(1); + + studentService.save(usnStudent,name); + assertDoesNotThrow(() -> menuService.issueBookToStudent(issueData)); + Optional> optionalBookList = issueService.findAllBooksIssuedByUsn(usnStudent); + if(optionalBookList.isPresent()){ + List bookList = optionalBookList.get(); + assertEquals(1, bookList.size()); + assertEquals(9, bookList.get(0).getQuantity()); + } + } + + @Test + void searchBooksAlongAuthors() { + List bookData = Arrays.asList( + "978-84-415-4302-1", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + List bookData1 = Arrays.asList( + "978-84-415-4303-1", + "Harry potter y la piedra filosofal", + "comedy", + "JK ROWLING", + "jk.rowling@gmail.com", + "2" + ); + menuService.addBook(bookData); + menuService.addBook(bookData1); + try{ + List listOffBooksAlongWithAuthor = menuService.searchBooksAlongAuthors(); + assertEquals(2, listOffBooksAlongWithAuthor.size()); + Object[] bookAlongWithAuthor = listOffBooksAlongWithAuthor.get(0); + Author author = (Author) bookAlongWithAuthor[1]; + Book book = (Book) bookAlongWithAuthor[0]; + assertEquals("novel", book.getCategory()); + assertEquals("Gene Kim", author.getName()); + Object[] bookAlongWithAuthor2 = listOffBooksAlongWithAuthor.get(1); + Author author1 = (Author) bookAlongWithAuthor2[1]; + Book book1 = (Book) bookAlongWithAuthor2[0]; + assertEquals("comedy", book1.getCategory()); + assertEquals("JK ROWLING", author1.getName()); + + }catch(NoBookFoundException e){ + fail("An NoBookFoundException exception was thrown when it was not expected."); + } + } + + @Test + void testSearchBooksByUsnProperFunction() throws Exception { + List bookData = Arrays.asList( + "978-84-415-4302-1", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + List issueData = Arrays.asList( + "09003688800", + "Pedro", + "978-84-415-4302-1" + ); + menuService.addBook(bookData); + String usnStudent = issueData.get(0); + String name = issueData.get(1); + studentService.save(usnStudent,name); + + try { + menuService.issueBookToStudent(issueData); + List objectList = menuService.searchBooksByUsn(usnStudent); + assertEquals(1, objectList.size()); + + Book book = (Book) objectList.get(0)[0]; + Issue issue = (Issue) objectList.get(0)[1]; + assertEquals("The fenix project", book.getTitle()); + assertEquals("Pedro", issue.getIssueStudent().getName()); + } catch (Exception e){ + fail(); + } + } + + @Test + void testSearchBooksByUsnWrongUsn() throws Exception { + List bookData = Arrays.asList( + "978-84-415-4302-1", + "The fenix project", + "novel", + "Gene Kim", + "g.kim@gmail.com", + "10" + ); + List issueData = Arrays.asList( + "09003688800", + "Pedro", + "978-84-415-4302-1" + ); + menuService.addBook(bookData); + String usnStudent = issueData.get(0); + String name = issueData.get(1); + studentService.save(usnStudent,name); + try { + menuService.issueBookToStudent(issueData); + assertThrows(Exception.class, () -> { + menuService.searchBooksByUsn("00001"); + }); + } catch (Exception e){ + fail(); + } + } + + @AfterEach + void tearDown() { + issueRepository.deleteAll(); + authorRepository.deleteAll(); + bookRepository.deleteAll(); + studentRepository.deleteAll(); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/utils/DataOutputTest.java b/src/test/java/com/ironhack/ironLibrary/utils/DataOutputTest.java new file mode 100644 index 00000000..538c4b8d --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/DataOutputTest.java @@ -0,0 +1,135 @@ +package com.ironhack.ironLibrary.utils; + +import com.ironhack.ironLibrary.model.Author; +import com.ironhack.ironLibrary.model.Book; +import com.ironhack.ironLibrary.model.Issue; +import com.ironhack.ironLibrary.model.Student; +import de.vandermeer.asciitable.AsciiTable; +import de.vandermeer.asciithemes.TA_GridThemes; +import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DataOutputTest { + + private static Book book1; + private static Book book2; + private static List books; + + private static Author author1; + private static Author author2; + + private static Student student1; + private static Student student2; + + private static Issue issue1; + private static Issue issue2; + + + @BeforeAll + static void setUp(){ + book1 = new Book("978-92-95-055-02-1", "First title", "romance", 3); + book2 = new Book("978-92-95-055-02-2", "Second title", "terror", 5); + books = new ArrayList<>(); + books.add(book1); + books.add(book2); + + author1 = new Author("Author first", "author@email.com", book1); + author2 = new Author("Author second", "author2@email.com", book2); + + student1 = new Student("01", "First student"); + student2 = new Student("02", "Second student"); + + issue1 = new Issue(student1, book1); + issue2 = new Issue(student2, book2); + } + + + @Test + @DisplayName("Validate oneBookTable output") + void oneBookTableTest(){ + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books"); + asciiTable.addRow(book1.getIsbn(), book1.getTitle(), book1.getCategory(), book1.getQuantity()); + assertEquals(asciiTable.render(), DataOutput.oneBookTable(book1)); + } + + @Test + @DisplayName("Validate listBookTable output") + void listBookTableTest(){ + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books"); + for (Book book : books){ + asciiTable.addRow(book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity()); + } + assertEquals(asciiTable.render(), DataOutput.listBookTable(books)); + } + + @Test + @DisplayName("Validate listBookTable output with empty list") + void listBookTableEmptyListTest(){ + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + List noneBooks = new ArrayList<>(); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books"); + assertEquals(asciiTable.render(), DataOutput.listBookTable(noneBooks)); + } + + @Test + @DisplayName("Validate listBookTableWithAuthor output") + void listBookTableWithAuthorTest(){ + List lstObjects= new ArrayList<>(); + lstObjects.add(new Object[]{book1, author1}); + lstObjects.add(new Object[]{book2, author2}); + + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + asciiTable.addRow("Book ISBN", "Book Title", "Category", "No of Books", + "Author name", "Author mail"); + for (Object[] obj : lstObjects){ + Book book = (Book) obj[0]; + Author author = (Author) obj[1]; + asciiTable.addRow(book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity(), + author.getName(), author.getEmail()); + } + assertEquals(asciiTable.render(), DataOutput.listBookTableWithAuthor(lstObjects)); + } + + @Test + @DisplayName("Validate bookIssuedDate output") + void bookIssuedDateTest(){ + assertEquals("Book issued. Return date : " + DateFormatter.largeDateFormat(issue1.getReturnDate()), + DataOutput.bookIssuedDate(issue1)); + } + + @Test + @DisplayName("Validate listBookTableByUsn output") + void listBookTableByUsnTest(){ + List lstObjects= new ArrayList<>(); + lstObjects.add(new Object[]{book1, issue1}); + + AsciiTable asciiTable = new AsciiTable(); + asciiTable.getContext().setGridTheme(TA_GridThemes.NONE); + asciiTable.setTextAlignment(TextAlignment.LEFT); + asciiTable.addRow("Book Title", "Student Name", "Return date"); + for (Object[] obj : lstObjects){ + Book book = (Book) obj[0]; + Issue issue = (Issue) obj[1]; + asciiTable.addRow(book.getTitle(), student1.getName(), + DateFormatter.simpleDateFormat(issue.getReturnDate())); + } + assertEquals(asciiTable.render(), DataOutput.listBookTableByUsn(lstObjects, student1)); + } +} diff --git a/src/test/java/com/ironhack/ironLibrary/utils/DateFormatterTest.java b/src/test/java/com/ironhack/ironLibrary/utils/DateFormatterTest.java new file mode 100644 index 00000000..0d8bfad9 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/DateFormatterTest.java @@ -0,0 +1,29 @@ +package com.ironhack.ironLibrary.utils; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DateFormatterTest { + @Test + @DisplayName("Validate proper format date: yyyy-MM-dd HH:mm:ss") + void simpleDateFormatTest() { + LocalDateTime time = LocalDateTime.now(); + assertEquals(time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), + DateFormatter.simpleDateFormat(time)); + } + + @Test + @DisplayName("Validate proper format date: EEE MMM dd HH:mm:ss zzz yyyy") + void largeDateFormatTest() { + LocalDateTime time = LocalDateTime.now(); + DateTimeFormatter formatDate = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", + Locale.ENGLISH); + assertEquals(time.atZone(ZoneId.of("Europe/Helsinki")).format(formatDate), + DateFormatter.largeDateFormat(time)); + } +} diff --git a/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTest.java b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTest.java new file mode 100644 index 00000000..b26a1347 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTest.java @@ -0,0 +1,54 @@ +package com.ironhack.ironLibrary.utils; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + + +class ValidatorTest { + + @ParameterizedTest + @DisplayName("Should validate correct ISBN") + @ValueSource(strings = {"978-92-95-055-02-5", "971-52-15-055-02-5", "971-52-15-755-12-3"} ) + void isCheckISBNFormatValid_when_correct_ISBN(String isbn) { + assertTrue(Validator.checkISBNFormat(isbn)); + } + + @ParameterizedTest + @DisplayName("Should invalidate incorrect ISBN") + @ValueSource(strings = {"a78-92-952-055-02-5", "p71-52-1sd-055-02-5", "xxxs-52-15-755-12-0w"} ) + void isCheckISBNFormatNotValid_when_incorrect_ISBN(String isbn) { + assertFalse(Validator.checkISBNFormat(isbn)); + } + + @ParameterizedTest + @DisplayName("Should validate correct Email") + @ValueSource(strings = {"test@edu.es", "ironhack_private@ironhack.es", "no-reply@ironhack.com"} ) + void isCheckEmailValid_when_correct_Email(String email) { + assertTrue(Validator.checkEmailFormat(email)); + } + + @ParameterizedTest + @DisplayName("Should validate correct Email") + @ValueSource(strings = {"test@edu.e", "ironhack_!private@ironhack.es", "@ironhack.com"} ) + void isCheckEmailInvalid_when_incorrect_Email(String email) { + assertFalse(Validator.checkEmailFormat(email)); + } + + @Test + @DisplayName("Should return True with Correct usn") + void testShouldReturnTrueCheckUsnFormat() { + assertTrue(Validator.checkUsnFormat("09003688800")); + } + + @Test + @DisplayName("Should return False with Incorrect usn") + void testShouldReturnFalseCheckUsnFormatWithWrongUsn(){ + assertFalse(Validator.checkUsnFormat("3")); + } + + +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestInteger.java b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestInteger.java new file mode 100644 index 00000000..7190fa6d --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestInteger.java @@ -0,0 +1,39 @@ +package com.ironhack.ironLibrary.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ValidatorTestInteger { + + + @Test + public void testValidateIntegerWithValidInput() { + Validator validator = new Validator(); + String validInput = "12345"; + assertTrue(validator.validateInteger(validInput)); + } + + @Test + public void testValidateIntegerWithInvalidInput() { + Validator validator = new Validator(); + String invalidInput = "abc"; + String invalidInput2 = "226,98"; + assertFalse(validator.validateInteger(invalidInput)); + assertFalse(validator.validateInteger(invalidInput2)); + } + + @Test + public void testValidateNonEmptyIntegerWithEmptyInput() { + Validator validator = new Validator(); + assertFalse(validator.validateInteger("")); + } + + @Test + public void testValidateNonEmptyIntegerWithNullInput() { + Validator validator = new Validator(); + assertFalse(validator.validateInteger(null)); + } + + +} diff --git a/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestStrings.java b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestStrings.java new file mode 100644 index 00000000..c3dbc736 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorTestStrings.java @@ -0,0 +1,62 @@ +package com.ironhack.ironLibrary.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ValidatorTestStrings { + + @Test + public void testNotBlankValidatorBooksValidInput() { + String input = "The Book Title"; + assertTrue(Validator.notBlankValidatorBooks(input)); + } + + @Test + public void testNotBlankValidatorBooksNullInput() { + String input = null; + assertFalse(Validator.notBlankValidatorBooks(input)); + } + + @Test + public void testNotBlankValidatorBooksEmptyInput() { + String input = ""; + assertFalse(Validator.notBlankValidatorBooks(input)); + } + + @Test + public void testNotBlankValidatorBooksWhitespaceInput() { + String input = " "; + assertFalse(Validator.notBlankValidatorBooks(input)); + } + + @Test + public void testValidateStringGeneralFormatWithValidInput() { + String input = "John Doe"; + assertTrue(Validator.validateStringGeneralFormat(input)); + } + + @Test + public void testValidateStringGeneralFormatWithAccentedCharacters() { + String input = "José García"; + assertTrue(Validator.validateStringGeneralFormat(input)); + } + + @Test + public void testValidateStringGeneralFormatWithInvalidInput() { + String input = "123 Main Street"; + assertFalse(Validator.validateStringGeneralFormat(input)); + } + + @Test + public void testValidateStringGeneralFormatWithEmptyInput() { + String input = ""; + assertFalse(Validator.validateStringGeneralFormat(input)); + } + + @Test + public void testValidateStringGeneralFormatWithNullInput() { + String input = null; + assertFalse(Validator.validateStringGeneralFormat(input)); + } +} \ No newline at end of file diff --git a/src/test/java/com/ironhack/ironLibrary/utils/ValidatorUserInputTest.java b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorUserInputTest.java new file mode 100644 index 00000000..60470625 --- /dev/null +++ b/src/test/java/com/ironhack/ironLibrary/utils/ValidatorUserInputTest.java @@ -0,0 +1,31 @@ +package com.ironhack.ironLibrary.utils; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +@SpringBootTest +public class ValidatorUserInputTest { + + @Test + public void testUserInputWithValidISBN() { + + String expectedInput = "978-84-415-4302-0"; + String printText = "Enter isbn: "; + String methodName = "checkISBNFormat"; + String suggestedInputFormat = "The ISBN must follow the next format: 978-92-95055-02-5"; + + InputStream inputStream = new ByteArrayInputStream(expectedInput.getBytes()); + System.setIn(inputStream); + + String userInput = Validator.userInput(printText, true, methodName, suggestedInputFormat); + + assertEquals(expectedInput, userInput); + } + +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 00000000..98620472 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,12 @@ +spring.application.name=ironLibrary +spring.datasource.url=jdbc:mysql://localhost:3306/library_test?createDatabaseIfNotExist=TRUE +spring.datasource.username=root +spring.datasource.password=root + +spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect + +spring.jpa.show-sql=true +spring.jpa.open-in-view=true +app.menu.enabled=false \ No newline at end of file