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}