0% found this document useful (0 votes)
4 views

Unit 6 Assignment Generic Library

The document outlines the development of a generic library catalog system in Java, focusing on managing various library items like books and DVDs using generic programming concepts. It includes the creation of a LibraryItem class and a LibraryCatalog class, along with a command-line interface for user interaction and comprehensive testing for functionality. The structure consists of several Java files, including LibraryItem.java, LibraryCatalog.java, Main.java, and LibraryCatalogTest.java.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Unit 6 Assignment Generic Library

The document outlines the development of a generic library catalog system in Java, focusing on managing various library items like books and DVDs using generic programming concepts. It includes the creation of a LibraryItem class and a LibraryCatalog class, along with a command-line interface for user interaction and comprehensive testing for functionality. The structure consists of several Java files, including LibraryItem.java, LibraryCatalog.java, Main.java, and LibraryCatalogTest.java.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 30

Generic Library Catalog

Introduction

This assignment focuses on developing a generic library catalog system in Java. The
core objective is to leverage generic programming concepts to create a flexible and
reusable application capable of managing various types of library items, such as
books, DVDs, and magazines. The system will feature a generic Catalog class and a
generic LibraryItem class, ensuring seamless compatibility and extensibility. Key
functionalities will include adding, removing, and retrieving library items, coupled with
robust error handling for a smooth user experience. A simple command-line interface
will allow users to interact with the catalog, and comprehensive testing will validate its
functionality across different item types.

As per this assignment, I will provide Java source code for a generic library catalog, a
LibraryItem class, and a command-line interface. I will also include comprehensive
testing and demonstrate error handling.

The solution will be structured into the following files:


1. LibraryItem.java: A generic class representing a library item.
2. LibraryCatalog.java: A generic class for managing the library catalog.
3. Main.java: The main class to run the command-line interface and demonstrate
functionality.
4. LibraryCatalogTest.java: A JUnit test class for comprehensive testing.

1. LibraryItem.java
Java

// LibraryItem.java
package com.michigan.library;

/**
* Represents a generic library item with a title, author, and item ID.
* This class is generic to allow for different types of item IDs (e.g., String, Integer).
*
* @param <ID> The type of the item ID.
*/
public class LibraryItem<ID> {
private String title;
private String author;
private ID itemID;

/**
* Constructs a new LibraryItem.
*
* @param title The title of the item.
* @param author The author of the item.
* @param itemID The unique identifier of the item.
*/
public LibraryItem(String title, String author, ID itemID) {
this.title
= title;
this.author = author;
this.itemID = itemID;
}

/**
* Returns the title of the library item.
* @return The title.
*/
public String getTitle() {
return title;
}

/**
* Sets the title of the library item.
* @param title The new title.
*/
public void setTitle(String title) {
this.title = title;
}

/**
* Returns the author of the library item.
* @return The author.
*/
public String getAuthor() {
return author;
}
/**
* Sets the author of the library item.
* @param author The new author.
*/
public void void setAuthor(String author) {
this.author = author;
}

/**
* Returns the item ID of the library item.
* @return The item ID.
*/
public ID getItemID() {
return itemID;
}

/**
* Sets the item ID of the library item.
* @param itemID The new item ID.
*/
public void setItemID(ID itemID) {
this.itemID = itemID;
}

/**
* Returns a string representation of the LibraryItem.
* @return A formatted string with item details.
*/
@Override
public String toString() {
return "Title: '"+ title + '\'' +
", Author: '" + author + '\'' +
", Item ID: " + itemID;
}

/**
* Overrides the equals method to compare LibraryItem objects based on their itemID.
*
* @param o The object to compare with.
* @return true if the objects are equal, false otherwise.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LibraryItem<?> that = (LibraryItem<?>) o;
return itemID != null ? itemID.equals(that.itemID) : that.itemID == null;
}

/**
* Overrides the hashCode method.
*
* @return The hash code of the itemID.
*/
@Override
public int hashCode() {
return itemID != null ? itemID.hashCode() : 0;
}
}

2. LibraryCatalog.java
Java

// LibraryCatalog.java
package com.michigan.library;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
* A generic library catalog that can store and manage different types of library items.
*
* @param <T> The type of LibraryItem to be stored in the catalog. T must extend LibraryItem.
* @param <ID> The type of the item ID.
*/
public class LibraryCatalog<T extends LibraryItem<ID>, ID> {
private List<T> items;
/**
* Constructs a new, empty LibraryCatalog.
*/
public LibraryCatalog(){
this.items = new ArrayList<>();
}

/**
* Adds a new library item to the catalog.
* If an item with the same ID already exists, it prints a message and does not add it.
*
* @param item The library item to add.
*/
public void addItem(T item) {
if (item == null) {
System.err.println("Error: Cannot add a null item to the catalog.");
return;
}
// Check if an item with the same ID already exists
boolean itemExists = items.stream()
.anyMatch(existingItem ->
existingItem.getItemID().equals(item.getItemID()));
if (itemExists) {
System.out.println("Error: An item with ID '" + item.getItemID() + "' already exists in the
catalog.");
} else {
items.add(item);
System.out.println("Item '" + item.getTitle() + "' (ID: " + item.getItemID() + ") added
to the catalog.");
}
}

/**
* Removes an item from the catalog based on its item ID.
*
* @param itemID The ID of the item to remove.
* @throws IllegalArgumentException if the item with the given ID does not exist.
*/
public void removeItem(ID itemID) throws IllegalArgumentException {
if (itemID == null) {
throw new IllegalArgumentException("Error: Item ID cannot be null for removal.");
}
boolean removed = items.removeIf(item -> item.getItemID().equals(itemID));
if (!removed) {
throw new IllegalArgumentException("Error: Item with ID '" + itemID + "' not found in
the catalog.");
}
System.out.println("Item with ID '" + itemID + "' removed from the catalog.");
}

/**
* Retrieves an item from the catalog based on its item ID.
*
* @param itemID The ID of the item to retrieve.
* @return An Optional containing the LibraryItem if found, or an empty Optional if not found.
*/
public Optional<T> getItemDetails(ID itemID) {
if (itemID == null) {
System.err.println("Error: Item ID cannot be null for retrieval.");
return Optional.empty();
}
return items.stream()
.filter(item -> item.getItemID().equals(itemID))
.findFirst();
}

/**
* Returns an unmodifiable list of all items in the catalog.
*
* @return A list of LibraryItem objects.
*/
public List<T> getAllItems() {
return new ArrayList<>(items); // Return a copy to prevent external modification
}

/**
* Displays all items currently in the catalog.
*/
public void viewCatalog(){
if (items.isEmpty()) {
System.out.println("The catalog is currently empty.");
} else {
System.out.println("\n--- Current Library Catalog ---");
items.forEach(System.out::println);
System.out.println("-----------------------------");
}
}

/**
* Clears all items from the catalog.
* This method is primarily for testing purposes.
*/
public void clearCatalog() {
items.clear();
}

/**
* Returns the number of items in the catalog.
* @return The size of the catalog.
*/
public int getSize(){
return items.size();
}
}

3. Main.java
Java

// Main.java
package com.michigan.library;

import java.util.InputMismatchException;
import java.util.Optional;
import java.util.Scanner;

/**
* Main class to run the command-line interface for the Generic Library Catalog.
*/
public class Main {
public static void main(String[] args) {
// Create a catalog for LibraryItems with String IDs
LibraryCatalog<LibraryItem<String>, String> stringCatalog = new
LibraryCatalog<>();
// Create a catalog for LibraryItems with Integer IDs
LibraryCatalog<LibraryItem<Integer>, Integer> integerCatalog = new
LibraryCatalog<>();

Scanner scanner = new Scanner(System.in);


int choice;

do {
System.out.println("\n--- Library Catalog Menu ---");
System.out.println("1. Use String ID Catalog");
System.out.println("2. Use Integer ID Catalog");
System.out.println("0. Exit");
System.out.print("Enter your choice: ");

try {
choice = scanner.nextInt();
scanner.nextLine(); // Consume newline

switch (choice) {
case 1:
runStringCatalogMenu(scanner, stringCatalog);
break;
case 2:
runIntegerCatalogMenu(scanner, integerCatalog);
break;
case 0:
System.out.println("Exiting Library Catalog. Goodbye!");
break;
default:
System.out.println("Invalid choice. Please try again.");
}
} catch (InputMismatchException e) {
System.out.println("Invalid input. Please enter a number.");
scanner.nextLine(); // Consume the invalid input
choice = -1; // Set an invalid choice to continue loop
}
} while (choice != 0);

scanner.close();
}

/**
* Runs the menu for the String ID Library Catalog.
* @param scanner The Scanner object for user input.
* @param catalog The LibraryCatalog with String IDs.
*/
private static void runStringCatalogMenu(Scanner scanner, LibraryCatalog<LibraryItem<String>,
String> catalog){
int choice;
do {
System.out.println("\n--- String ID Catalog Menu ---");
System.out.println("1. Add Library Item (String ID)");
System.out.println("2. Remove Library Item (String ID)");
System.out.println("3. View Current Catalog (String ID)");
System.out.println("4. Get Item Details (String ID)");
System.out.println("0. Back to Main Menu");
System.out.print("Enter your choice: ");

try {
choice = scanner.nextInt();
scanner.nextLine(); // Consume newline

switch(choice) {
case 1:
addStringItem(scanner, catalog);
break;
case 2:
removeStringItem(scanner, catalog);
break;
case 3:
catalog.viewCatalog();
break;
case 4:
getStringItemDetails(scanner, catalog);
break;
case 0:
System.out.println("Returning to Main Menu.");
break;
default:
System.out.println("Invalid choice. Please try again.");
}
} catch (InputMismatchException e) {
System.out.println("Invalid input. Please enter a number.");
scanner.nextLine(); // Consume the invalid input
choice = -1;
}
} while (choice != 0);
}

/**
* Adds a LibraryItem with a String ID to the catalog.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void addStringItem(Scanner scanner, LibraryCatalog<LibraryItem<String>, String>
catalog) {
System.out.print("Enter Title: ");
String title = scanner.nextLine();
System.out.print("Enter Author: ");
String author = scanner.nextLine();
System.out.print("Enter Item ID (String): ");
String itemID = scanner.nextLine();

LibraryItem<String> newItem = new LibraryItem<>(title, author, itemID);


catalog.addItem(newItem);
}

/**
* Removes a LibraryItem with a String ID from the catalog.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void removeStringItem(Scanner scanner, LibraryCatalog<LibraryItem<String>, String>
catalog) {
System.out.print("Enter Item ID to remove (String): ");
String itemID = scanner.nextLine();
try {
catalog.removeItem(itemID);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
}
}

/**
* Retrieves and displays details of a LibraryItem with a String ID.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void getStringItemDetails(Scanner scanner, LibraryCatalog<LibraryItem<String>,
String> catalog) {
System.out.print("Enter Item ID to retrieve details (String): ");
String itemID = scanner.nextLine();
Optional<LibraryItem<String>> item = catalog.getItemDetails(itemID);
if (item.isPresent()) {
System.out.println("Item Found: " + item.get());
} else {
System.out.println("Item with ID '" + itemID + "' not found.");
}
}

/**
* Runs the menu for the Integer ID Library Catalog.
* @param scanner The Scanner object for user input.
* @param catalog The LibraryCatalog with Integer IDs.
*/
private static void runIntegerCatalogMenu(Scanner scanner, LibraryCatalog<LibraryItem<Integer>,
Integer> catalog) {
intchoice;
do {
System.out.println("\n--- Integer ID Catalog Menu ---");
System.out.println("1. Add Library Item (Integer ID)");
System.out.println("2. Remove Library Item (Integer ID)");
System.out.println("3. View Current Catalog (Integer ID)");
System.out.println("4. Get Item Details (Integer ID)");
System.out.println("0. Back to Main Menu");
System.out.print("Enter your choice: ");

try {
choice = scanner.nextInt();
scanner.nextLine(); // Consume newline

switch (choice) {
case 1:
addIntegerItem(scanner, catalog);
break;
case 2:
removeIntegerItem(scanner, catalog);
break;
case 3:
catalog.viewCatalog();
break;
case 4:
getIntegerItemDetails(scanner, catalog);
break;
case 0:
System.out.println("Returning to Main Menu.");
break;
default:
System.out.println("Invalid choice. Please try again.");
}
} catch (InputMismatchException e) {
System.out.println("Invalid input. Please enter a number.");
scanner.nextLine(); // Consume the invalid input
choice = -1;
}
} while (choice != 0);
}

/**
* Adds a LibraryItem with an Integer ID to the catalog.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void addIntegerItem(Scanner scanner, LibraryCatalog<LibraryItem<Integer>, Integer>
catalog) {
System.out.print("Enter Title: ");
String title = scanner.nextLine();
System.out.print("Enter Author: ");
String author = scanner.nextLine();
System.out.print("Enter Item ID (Integer): ");
try {
Integer itemID = scanner.nextInt();
scanner.nextLine(); // Consume newline
LibraryItem<Integer> newItem = new LibraryItem<>(title, author, itemID);
catalog.addItem(newItem);
} catch (InputMismatchException e) {
System.out.println("Invalid input for Item ID. Please enter an integer.");
scanner.nextLine(); // Consume invalid input
}
}

/**
* Removes a LibraryItem with an Integer ID from the catalog.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void removeIntegerItem(Scanner scanner, LibraryCatalog<LibraryItem<Integer>,
Integer> catalog) {
System.out.print("Enter Item ID to remove (Integer): ");
try {
Integer itemID = scanner.nextInt();
scanner.nextLine(); // Consume newline
try {
catalog.removeItem(itemID);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
}
} catch (InputMismatchException e) {
System.out.println("Invalid input for Item ID. Please enter an integer.");
scanner.nextLine(); // Consume invalid input
}
}

/**
* Retrieves and displays details of a LibraryItem with an Integer ID.
* @param scanner The Scanner object.
* @param catalog The LibraryCatalog.
*/
private static void getIntegerItemDetails(Scanner scanner, LibraryCatalog<LibraryItem<Integer>,
Integer> catalog) {
System.out.print("Enter Item ID to retrieve details (Integer): ");
try {
Integer itemID = scanner.nextInt();
scanner.nextLine(); // Consume newline
Optional<LibraryItem<Integer>> item = catalog.getItemDetails(itemID);
if (item.isPresent()) {
System.out.println("Item Found: " + item.get());
} else {
System.out.println("Item with ID '" + itemID + "' not found.");
}
} catch (InputMismatchException e) {
System.out.println("Invalid input for Item ID. Please enter an integer.");
scanner.nextLine(); // Consume invalid input
}
}
}

4. LibraryCatalogTest.java (JUnit 5)
To run these tests, you'll need to have JUnit 5 set up in your project. If you're using
Maven, add the following to your pom.xml:

XML

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>

Java

// LibraryCatalogTest.java
package com.michigan.library;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Optional;

/**
* Comprehensive test class for the LibraryCatalog and LibraryItem.
*/
public class LibraryCatalogTest {

private LibraryCatalog<LibraryItem<String>, String> stringCatalog;


private LibraryCatalog<LibraryItem<Integer>, Integer> integerCatalog;

private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();


private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;
@BeforeEach
void setUp(){
stringCatalog = new LibraryCatalog<>();
integerCatalog = new LibraryCatalog<>();
System.setOut(new PrintStream(outContent)); // Redirect System.out
System.setErr(new PrintStream(outContent)); // Redirect System.err for error messages
}

// Restore original System.out and System.err after each test


@org.junit.jupiter.api.AfterEach
public void restoreStreams() {
System.setOut(originalOut);
System.setErr(originalErr);
}

@Test
@DisplayName("Test adding a single item with String ID")
void testAddOneStringItem(){
LibraryItem<String> book = new LibraryItem<>("The Great Gatsby", "F. Scott Fitzgerald",
"ISBN001");
stringCatalog.addItem(book);
assertEquals(1, stringCatalog.getSize());
assertTrue(stringCatalog.getItemDetails("ISBN001").isPresent());
assertEquals(book, stringCatalog.getItemDetails("ISBN001").get());
assertTrue(outContent.toString().contains("Item 'The Great Gatsby' (ID: ISBN001) added
to the catalog."));
}

@Test
@DisplayName("Test adding multiple items with String IDs")
{
void testAddMultipleStringItems()
stringCatalog.addItem(new LibraryItem<>("1984", "George Orwell", "ISBN002"));
stringCatalog.addItem(new LibraryItem<>("To Kill a Mockingbird", "Harper Lee",
"ISBN003"));
assertEquals(2, stringCatalog.getSize());
assertTrue(stringCatalog.getItemDetails("ISBN002").isPresent());
assertTrue(stringCatalog.getItemDetails("ISBN003").isPresent());
}

@Test
@DisplayName("Test adding a duplicate item with String ID - error handling")
void testAddDuplicateStringItem(){
LibraryItem<String> item1 = new LibraryItem<>("Duplicate Book", "Author A", "DUP001");
stringCatalog.addItem(item1);
outContent.reset(); // Clear output for next check
stringCatalog.addItem(item1); // Try to add again
assertEquals(1, stringCatalog.getSize()); // Should still be 1 item
assertTrue(outContent.toString().contains("Error: An item with ID 'DUP001' already
exists in the catalog."));
}

@Test
@DisplayName("Test removing an existing item with String ID")
void testRemoveExistingStringItem(){
stringCatalog.addItem(new LibraryItem<>("Item to Remove", "Author R", "REM001"));
assertEquals(1, stringCatalog.getSize());
outContent.reset(); // Clear output for next check

stringCatalog.removeItem("REM001");
assertEquals(0, stringCatalog.getSize());
assertFalse(stringCatalog.getItemDetails("REM001").isPresent());
assertTrue(outContent.toString().contains("Item with ID 'REM001' removed from the
catalog."));
}

@Test
@DisplayName("Test removing a non-existent item with String ID - error handling")
{
void testRemoveNonExistentStringItem()
assertThrows(IllegalArgumentException.class, () ->
stringCatalog.removeItem("NONEXISTENT"));
assertEquals(0, stringCatalog.getSize());
assertTrue(outContent.toString().contains("Error: Item with ID 'NONEXISTENT' not found
in the catalog."));
}
@Test
@DisplayName("Test retrieving details of an existing item with String ID")
{
void testGetExistingStringItemDetails()
LibraryItem<String> item = new LibraryItem<>("Details Book", "Author D", "DET001");
stringCatalog.addItem(item);
Optional<LibraryItem<String>> retrievedItem =
stringCatalog.getItemDetails("DET001");
assertTrue(retrievedItem.isPresent());
assertEquals(item, retrievedItem.get());
}

@Test
@DisplayName("Test retrieving details of a non-existent item with String ID")
{
void testGetNonExistentStringItemDetails()
Optional<LibraryItem<String>> retrievedItem =
stringCatalog.getItemDetails("NOID");
assertFalse(retrievedItem.isPresent());
}

@Test
@DisplayName("Test view catalog when empty")
{
void testViewEmptyStringCatalog()
stringCatalog.viewCatalog();
assertTrue(outContent.toString().contains("The catalog is currently empty."));
}

@Test
@DisplayName("Test view catalog with items")
void testViewStringCatalogWithItems(){
stringCatalog.addItem(new LibraryItem<>("Book A", "Author X", "ID1"));
stringCatalog.addItem(new LibraryItem<>("Book B", "Author Y", "ID2"));
outContent.reset(); // Clear output after add messages

stringCatalog.viewCatalog();
String output = outContent.toString();
assertTrue(output.contains("--- Current Library Catalog ---"));
assertTrue(output.contains("Title: 'Book A', Author: 'Author X', Item ID: ID1"));
assertTrue(output.contains("Title: 'Book B', Author: 'Author Y', Item ID: ID2"));
assertTrue(output.contains("-----------------------------"));
}

@Test
@DisplayName("Test adding a single item with Integer ID")
{
void testAddOneIntegerItem()
LibraryItem<Integer> dvd = new LibraryItem<>("Inception", "Christopher Nolan", 101);
integerCatalog.addItem(dvd);
assertEquals(1, integerCatalog.getSize());
assertTrue(integerCatalog.getItemDetails(101).isPresent());
assertEquals(dvd, integerCatalog.getItemDetails(101).get());
assertTrue(outContent.toString().contains("Item 'Inception' (ID: 101) added to the
catalog."));
}

@Test
@DisplayName("Test adding multiple items with Integer IDs")
void testAddMultipleIntegerItems() {
integerCatalog.addItem(new LibraryItem<>("The Matrix", "Wachowskis", 201));
integerCatalog.addItem(new LibraryItem<>("Pulp Fiction", "Quentin Tarantino", 202));
assertEquals(2, integerCatalog.getSize());
assertTrue(integerCatalog.getItemDetails(201).isPresent());
assertTrue(integerCatalog.getItemDetails(202).isPresent());
}

@Test
@DisplayName("Test adding a duplicate item with Integer ID - error handling")
{
void testAddDuplicateIntegerItem()
LibraryItem<Integer> item1 = new LibraryItem<>("Duplicate Movie", "Director B", 301);
integerCatalog.addItem(item1);
outContent.reset();
integerCatalog.addItem(item1);
assertEquals(1, integerCatalog.getSize());
assertTrue(outContent.toString().contains("Error: An item with ID '301' already exists in
the catalog."));
}

@Test
@DisplayName("Test removing an existing item with Integer ID")
{
void testRemoveExistingIntegerItem()
integerCatalog.addItem(new LibraryItem<>("Movie to Remove", "Director R", 401));
assertEquals(1, integerCatalog.getSize());
outContent.reset();

integerCatalog.removeItem(401);
assertEquals(0, integerCatalog.getSize());
assertFalse(integerCatalog.getItemDetails(401).isPresent());
assertTrue(outContent.toString().contains("Item with ID '401' removed from the
catalog."));
}

@Test
@DisplayName("Test removing a non-existent item with Integer ID - error handling")
{
void testRemoveNonExistentIntegerItem()
assertThrows(IllegalArgumentException.class, () ->
integerCatalog.removeItem(999));
assertEquals(0, integerCatalog.getSize());
assertTrue(outContent.toString().contains("Error: Item with ID '999' not found in the
catalog."));
}

@Test
@DisplayName("Test retrieving details of an existing item with Integer ID")
{
void testGetExistingIntegerItemDetails()
LibraryItem<Integer> item = new LibraryItem<>("Details Movie", "Director D", 501);
integerCatalog.addItem(item);
Optional<LibraryItem<Integer>> retrievedItem =
integerCatalog.getItemDetails(501);
assertTrue(retrievedItem.isPresent());
assertEquals(item, retrievedItem.get());
}
@Test
@DisplayName("Test retrieving details of a non-existent item with Integer ID")
{
void testGetNonExistentIntegerItemDetails()
Optional<LibraryItem<Integer>> retrievedItem =
integerCatalog.getItemDetails(9999);
assertFalse(retrievedItem.isPresent());
}

@Test
@DisplayName("Test LibraryItem equals and hashCode with same ID")
void testLibraryItemEqualitySameID() {
LibraryItem<String> book1 = new LibraryItem<>("Title1", "Author1", "ID1");
LibraryItem<String> book2 = new LibraryItem<>("Title2", "Author2", "ID1"); // Same ID,
different title/author

assertEquals(book1, book2);
assertEquals(book1.hashCode(), book2.hashCode());
}

@Test
@DisplayName("Test LibraryItem equals and hashCode with different ID")
{
void testLibraryItemEqualityDifferentID()
LibraryItem<String> book1 = new LibraryItem<>("Title1", "Author1", "ID1");
LibraryItem<String> book2 = new LibraryItem<>("Title1", "Author1", "ID2"); // Same
title/author, different ID

assertNotEquals(book1, book2);
assertNotEquals(book1.hashCode(), book2.hashCode());
}

@Test
@DisplayName("Test adding null item - error handling")
{
void testAddNullItem()
stringCatalog.addItem(null);
assertEquals(0, stringCatalog.getSize());
assertTrue(outContent.toString().contains("Error: Cannot add a null item to the
catalog."));
}
@Test
@DisplayName("Test removing item with null ID - error handling")
{
void testRemoveItemWithNullID()
assertThrows(IllegalArgumentException.class, () ->
stringCatalog.removeItem(null));
assertTrue(outContent.toString().contains("Error: Item ID cannot be null for removal."));
}

@Test
@DisplayName("Test getting item details with null ID - error handling")
{
void testGetItemDetailsWithNullID()
Optional<LibraryItem<String>> item = stringCatalog.getItemDetails(null);
assertFalse(item.isPresent());
assertTrue(outContent.toString().contains("Error: Item ID cannot be null for retrieval."));
}
}

Project Structure
D:\Unit 6\
├── src\
│ └── com\
│ └── michigan\
│ └── library\
│ ├── LibraryItem.java
│ ├── LibraryCatalog.java
│ └── Main.java
└── src\
└── test\
└── java\
└── com\
└── michigan\
└── library\
└── LibraryCatalogTest.java

How to Compile and Run Your Code


1. Open Command Prompt
Navigate to project root directory (D:\Unit 6) in Command Prompt:

Bash

cd D:\Unit 6

2. Compile the Main Application


Compile core Java files (LibraryItem.java, LibraryCatalog.java, Main.java) into a bin
directory:

Bash

javac -d bin src\com\michigan\library\*.java

● -d bin: This tells the Java compiler to put all the compiled .class files into a new
folder named bin (or create it if it doesn't exist).

3. Run the Main Application


Now that the files are compiled, run the Main class:

Bash

java -cp bin com.michigan.library.Main

● -cp bin: This adds bin directory to the classpath, so the Java Virtual Machine
(JVM) knows where to find your compiled classes (.class files).
● com.michigan.library.Main: This is the fully qualified name of my main class
(including its package).

4. Run JUnit Tests (Requires JUnit 5 Setup)


Running JUnit tests from the command line is a bit more involved as it requires the
JUnit 5 libraries.

A. Download JUnit 5 Console Standalone JAR


Download the junit-platform-console-standalone.jar. The easiest way to get it is from
the Maven Central Repository. Search for "junit-platform-console-standalone" and
download the latest version (e.g., junit-platform-console-standalone-5.10.0.jar).

Create a lib folder inside D:\Unit 6 and place this JAR file there:

D:\Unit 6\
├── src\
│ └── ...
├── lib\
│ └── junit-platform-console-standalone-5.10.0.jar <-- Put it here
└── bin\
└── ...

B. Compile the Test Files


Now compile the test file (LibraryCatalogTest.java), making sure to include your
compiled application code (bin) and the JUnit JAR in the classpath:

Bash

javac -d bin -cp "bin;lib\junit-platform-console-standalone-5.10.0.jar" src\test\java\com\


michigan\library\*.java

● Important for Windows: Notice the use of a semicolon ; to separate paths in the
classpath on Windows. If you were on macOS/Linux, it would be a colon :.
● junit-platform-console-standalone-5.10.0.jar: Make sure this matches the
exact filename of the JAR you downloaded.

C. Run the Tests


Finally, use the JUnit Platform Console Launcher JAR to discover and run tests:

Bash

java -jar lib\junit-platform-console-standalone-5.10.0.jar -cp bin --scan-classpath --


include-classname 'com.michigan.library.LibraryCatalogTest'

● -jar lib\junit-platform-console-standalone-5.10.0.jar: This tells Java to


execute the specified JAR file.
● -cp bin: This adds my compiled classes (both application and test classes, since
we compiled tests into bin) to JUnit's classpath.
● --scan-classpath: This tells JUnit to scan the classpath for test classes.
● --include-classname 'com.michigan.library.LibraryCatalogTest': This
specifically targets your test class.
1.

Output Screenshot (Example Interaction from Main.java):


Conclusion

This assignment successfully demonstrates the application of generic classes and methods in
Java to build a versatile library catalog system. The LibraryItem class, parameterized by the
type of its itemID, and the Catalog class, parameterized by the type of LibraryItem it holds,
showcase the power of generics in achieving code reusability and type safety. The implemented
library operations (add, remove, and retrieve) are robust, with comprehensive error handling for
scenarios like attempting to remove non-existent items. The command-line interface provides a
user-friendly way to interact with the system, and the demonstrated test cases confirm the
catalog's ability to seamlessly manage different types of library items. This generic approach
ensures that the library catalog is flexible and easily extensible to accommodate new item types
in the future without significant code modifications.

References

● Oracle. (n.d.). The Java™ Tutorials: Generics. Retrieved from


https://docs.oracle.com/javase/tutorial/java/generics/index.html
● Bloch, J. (2018). Effective Java. Addison-Wesley Professional.

You might also like