package dst.ass1.jpa.tests;

import static org.hamcrest.CoreMatchers.isA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import javax.persistence.PersistenceException;

import org.hibernate.PropertyValueException;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.Test;

import dst.ass1.jpa.model.ICourse;
import dst.ass1.jpa.model.IMetadata;

/**
 * Tests if the ICourse and IMetadata relation is implemented correctly.
 */
public class Ass1_1_1_07Test extends Ass1_TestBase {

    @Test
    public void testMetadataAssociation() {
        ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id);
        assertNotNull(course1);
        assertEquals(testData.metadata1Id, course1.getMetadata().getId());

        ICourse course2 = daoFactory.createCourseDAO().findById(testData.course2Id);
        assertNotNull(course2);
        assertEquals(testData.metadata2Id, course2.getMetadata().getId());
    }

    @Test
    public void testMetadataNonOptionalConstraint() {
        expectedException.expect(PersistenceException.class);
        expectedException.expectCause(isA(PropertyValueException.class));
        expectedException.expectMessage("not-null property");

        ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id);
        assertNotNull(course1);
        course1.setMetadata(null);
        em.getTransaction().begin();
        em.persist(course1);
        em.flush();
    }

    @Test
    public void testMetadataUniqueConstraint() throws Exception {
        ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id);
        IMetadata metadata1 = course1.getMetadata();

        ICourse course5 = modelFactory.createCourse();
        course5.setName("course5");
        course5.setMetadata(metadata1);

        em.getTransaction().begin();
        expectedException.expect(PersistenceException.class);
        expectedException.expectCause(isA(ConstraintViolationException.class));
        expectedException.reportMissingExceptionWithMessage(
                "Persisting the same metadata object with a different course should result in a constraint violation"
        );
        em.persist(course5);
        em.flush();
    }

    @Test
    public void testCourseMetadataDeleteCascade() throws Exception {
        ICourse course = daoFactory.createCourseDAO().findById(testData.course4Id);
        Long metadataId = course.getMetadata().getId();

        em.getTransaction().begin();
        try {
            em.remove(course);
            em.flush();
        } catch (PersistenceException e) {
            throw new AssertionError("Removing a course should not result in a PersistenceException", e);
        }
        em.getTransaction().commit();

        em.getTransaction().begin();
        IMetadata metadata = em.find(modelFactory.createMetadata().getClass(), metadataId);
        assertNull("Expected metadata to be null after associated course was deleted", metadata);
    }


}
