package de.uni_hamburg.fs;

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

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class JavaConceptTest {

    @BeforeEach
    void setUp() {
        TypeSystem.newInstance();
    }

    @Test
    void testConstructorWithClass() {
        // given
        Class<?> testClass = String.class;

        // when
        JavaConcept javaConcept = new JavaConcept(testClass);

        // then
        assertThat(javaConcept).isNotNull();
        assertThat(javaConcept.getJavaClass()).isEqualTo(testClass);
        assertThat(javaConcept.getName()).isEqualTo("String");
        assertThat(javaConcept.getNamespace()).isEqualTo("java.lang");
        assertThat(javaConcept.getFullName()).isEqualTo("java.lang.String");
    }

    @Test
    void testIsaRelationship() {
        // given
        JavaConcept listConcept = new JavaConcept(List.class);
        JavaConcept arrayListConcept = new JavaConcept(ArrayList.class);

        // when & then
        assertThat(arrayListConcept.isa(listConcept)).isTrue();
        assertThat(listConcept.isa(arrayListConcept)).isFalse();
    }

    @Test
    void testIsNotARelationship() {
        // given
        JavaConcept stringConcept = new JavaConcept(String.class);
        JavaConcept integerConcept = new JavaConcept(Integer.class);

        // when & then
        assertThat(stringConcept.isNotA(integerConcept)).isTrue();
        assertThat(integerConcept.isNotA(stringConcept)).isTrue();
    }

    @Test
    void testIsExtensional() {
        // given
        JavaConcept javaConcept = new JavaConcept(String.class);

        // when
        boolean extensional = javaConcept.isExtensional();

        // then
        assertThat(extensional).isFalse();
    }

    @Test
    void testFeatureIsApprop() {
        // given
        JavaConcept arrayListConcept = new JavaConcept(ArrayList.class);
        Name sizeFeature = new Name("size");

        // when
        boolean isApprop = arrayListConcept.isApprop(sizeFeature);

        // then
        assertThat(isApprop).isTrue();
    }

    @Test
    void testCanInstantiate() {
        // given
        JavaConcept stringConcept = new JavaConcept(String.class);
        JavaConcept listConcept = new JavaConcept(List.class);

        // when & then
        assertThat(stringConcept.canInstantiate()).isTrue();
        assertThat(listConcept.canInstantiate()).isFalse();
        assertThat(new JavaConcept(ArrayList.class).canInstantiate()).isTrue();
    }

    @Test
    void testEquals() {
        // given
        JavaConcept concept1 = new JavaConcept(String.class);
        JavaConcept concept2 = new JavaConcept(String.class);
        JavaConcept concept3 = new JavaConcept(Integer.class);

        // when & then
        assertThat(concept1).isEqualTo(concept2);
        assertThat(concept1).isNotEqualTo(concept3);
        assertThat(concept1).isNotEqualTo(null);
    }

    @Test
    void testToFeatureName() {
        // given
        String getter1 = "getName";
        String getter2 = "isActive";
        String getter3 = "getURL";
        String notGetter = "calculate";

        // when & then
        assertThat(JavaConcept.toFeatureName(getter1)).isEqualTo("name");
        assertThat(JavaConcept.toFeatureName(getter2)).isEqualTo("active");
        assertThat(JavaConcept.toFeatureName(getter3)).isEqualTo("URL");
        assertThat(JavaConcept.toFeatureName(notGetter)).isEqualTo("calculate");
    }

    @Test
    void testGetVisibilityLevel() {
        // when & then
        assertThat(JavaConcept.getVisibilityLevel('-')).isEqualTo(0);
        assertThat(JavaConcept.getVisibilityLevel('#')).isEqualTo(1);
        assertThat(JavaConcept.getVisibilityLevel('+')).isEqualTo(2);
    }
}