001package edu.pdx.cs.joy.jdbc; 002 003import org.junit.jupiter.api.AfterEach; 004import org.junit.jupiter.api.BeforeEach; 005import org.junit.jupiter.api.Test; 006 007import java.sql.Connection; 008import java.sql.SQLException; 009import java.util.List; 010 011import static org.hamcrest.MatcherAssert.assertThat; 012import static org.hamcrest.Matchers.*; 013import static org.junit.jupiter.api.Assertions.assertThrows; 014 015public class CourseDAOTest { 016 017 private Connection connection; 018 private CourseDAO courseDAO; 019 private DepartmentDAO departmentDAO; 020 021 @BeforeEach 022 public void setUp() throws SQLException { 023 // Create an in-memory H2 database 024 connection = H2DatabaseHelper.createInMemoryConnection("test"); 025 026 // Drop tables if they exist from a previous test, then create them 027 // Note: Must drop courses first due to foreign key constraint 028 CourseDAOImpl.dropTable(connection); 029 DepartmentDAOImpl.dropTable(connection); 030 031 // Create departments table first, then courses (due to foreign key) 032 DepartmentDAOImpl.createTable(connection); 033 CourseDAOImpl.createTable(connection); 034 035 // Initialize the DAOs with the connection 036 courseDAO = new CourseDAOImpl(connection); 037 departmentDAO = new DepartmentDAOImpl(connection); 038 } 039 040 @AfterEach 041 public void tearDown() throws SQLException { 042 if (connection != null && !connection.isClosed()) { 043 // Drop tables and close the connection 044 // Note: Must drop courses first due to foreign key constraint 045 CourseDAOImpl.dropTable(connection); 046 DepartmentDAOImpl.dropTable(connection); 047 connection.close(); 048 } 049 } 050 051 @Test 052 public void testPersistAndFetchCourse() throws SQLException { 053 // Create and persist a department first (required for foreign key) 054 Department department = new Department("Computer Science"); 055 departmentDAO.save(department); 056 057 // Get the auto-generated department ID 058 int csDepartmentId = department.getId(); 059 060 // Create a course 061 String javaCourseName = "Introduction to Java"; 062 int credits = 4; 063 Course course = new Course(javaCourseName, csDepartmentId, credits); 064 065 // Persist the course 066 courseDAO.save(course); 067 068 // Verify that an ID was auto-generated 069 int generatedId = course.getId(); 070 assertThat(generatedId, is(greaterThan(0))); 071 072 // Fetch the course by title 073 Course fetchedCourse = courseDAO.findByTitle(javaCourseName); 074 075 // Validate the fetched course using Hamcrest assertions 076 assertThat(fetchedCourse, is(notNullValue())); 077 assertThat(fetchedCourse.getId(), is(equalTo(generatedId))); 078 assertThat(fetchedCourse.getTitle(), is(equalTo(javaCourseName))); 079 assertThat(fetchedCourse.getDepartmentId(), is(equalTo(csDepartmentId))); 080 assertThat(fetchedCourse.getCredits(), is(equalTo(credits))); 081 } 082 083 @Test 084 public void testFetchNonExistentCourse() throws SQLException { 085 // Try to fetch a course that doesn't exist 086 Course fetchedCourse = courseDAO.findByTitle("Nonexistent Course"); 087 088 // Validate that null is returned 089 assertThat(fetchedCourse, is(nullValue())); 090 } 091 092 @Test 093 public void testPersistMultipleCourses() throws SQLException { 094 // Create and persist departments first (required for foreign key) 095 Department csDepartment = new Department("Computer Science"); 096 Department mathDepartment = new Department("Mathematics"); 097 098 departmentDAO.save(csDepartment); 099 departmentDAO.save(mathDepartment); 100 101 // Get the auto-generated department IDs 102 int csDepartmentId = csDepartment.getId(); 103 int mathDepartmentId = mathDepartment.getId(); 104 105 // Create multiple courses 106 String dataStructuresName = "Data Structures"; 107 String algorithmsName = "Algorithms"; 108 String calculusName = "Calculus"; 109 110 Course course1 = new Course(dataStructuresName, csDepartmentId, 4); 111 Course course2 = new Course(algorithmsName, csDepartmentId, 3); 112 Course course3 = new Course(calculusName, mathDepartmentId, 4); 113 114 // Persist all courses 115 courseDAO.save(course1); 116 courseDAO.save(course2); 117 courseDAO.save(course3); 118 119 // Fetch courses by department 120 List<Course> coursesByDept102 = courseDAO.findByDepartmentId(csDepartmentId); 121 List<Course> coursesByDept103 = courseDAO.findByDepartmentId(mathDepartmentId); 122 123 // Validate using Hamcrest matchers 124 assertThat(coursesByDept102, hasSize(2)); 125 assertThat(coursesByDept102, hasItem(hasProperty("title", is(dataStructuresName)))); 126 assertThat(coursesByDept102, hasItem(hasProperty("title", is(algorithmsName)))); 127 128 assertThat(coursesByDept103, hasSize(1)); 129 assertThat(coursesByDept103, hasItem(hasProperty("title", is(calculusName)))); 130 } 131 132 @Test 133 public void testForeignKeyConstraintPreventsInvalidDepartmentId() { 134 // Try to create a course with a non-existent department ID 135 Course course = new Course("Database Systems", 999, 3); 136 137 // Attempting to save should throw an SQLException due to foreign key constraint 138 SQLException exception = assertThrows(SQLException.class, () -> { 139 courseDAO.save(course); 140 }); 141 assertThat(exception.getMessage(), containsString("Referential integrity")); 142 } 143 144 @Test 145 public void testCreditsArePersisted() throws SQLException { 146 // Create and persist a department first (required for foreign key) 147 Department department = new Department("Mathematics"); 148 departmentDAO.save(department); 149 int deptId = department.getId(); 150 151 // Create courses with different credit values 152 Course threeCredits = new Course("Statistics", deptId, 3); 153 Course fourCredits = new Course("Linear Algebra", deptId, 4); 154 Course fiveCredits = new Course("Abstract Algebra", deptId, 5); 155 156 // Persist all courses 157 courseDAO.save(threeCredits); 158 courseDAO.save(fourCredits); 159 courseDAO.save(fiveCredits); 160 161 // Fetch the courses and verify credits 162 Course fetchedThree = courseDAO.findByTitle("Statistics"); 163 Course fetchedFour = courseDAO.findByTitle("Linear Algebra"); 164 Course fetchedFive = courseDAO.findByTitle("Abstract Algebra"); 165 166 assertThat(fetchedThree.getCredits(), is(equalTo(3))); 167 assertThat(fetchedFour.getCredits(), is(equalTo(4))); 168 assertThat(fetchedFive.getCredits(), is(equalTo(5))); 169 } 170 171 @Test 172 public void testUpdateCourse() throws SQLException { 173 // Create and persist a department first (required for foreign key) 174 Department department = new Department("Computer Science"); 175 departmentDAO.save(department); 176 int deptId = department.getId(); 177 178 // Create and persist a course 179 Course course = new Course("Database Systems", deptId, 3); 180 courseDAO.save(course); 181 182 int courseId = course.getId(); 183 assertThat(courseId, is(greaterThan(0))); 184 185 // Update the course 186 course.setTitle("Advanced Database Systems"); 187 course.setCredits(4); 188 courseDAO.update(course); 189 190 // Fetch the course and verify it was updated 191 Course updatedCourse = courseDAO.findByTitle("Advanced Database Systems"); 192 assertThat(updatedCourse, is(notNullValue())); 193 assertThat(updatedCourse.getId(), is(equalTo(courseId))); 194 assertThat(updatedCourse.getTitle(), is(equalTo("Advanced Database Systems"))); 195 assertThat(updatedCourse.getCredits(), is(equalTo(4))); 196 197 // Verify the old title doesn't exist anymore 198 Course oldCourse = courseDAO.findByTitle("Database Systems"); 199 assertThat(oldCourse, is(nullValue())); 200 } 201 202}