package de.uni_hamburg.fs;

import org.junit.jupiter.api.Test;

import collections.CollectionEnumeration;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class EquivRelationTest {

    @Test
    void testUnifyWithIdenticalStructures() throws UnificationFailure {
        // given
        FeatureStructure fs1 = new FeatureStructure(new BasicType("test").newNode());
        FeatureStructure fs2 = new FeatureStructure(new BasicType("test").newNode());

        // when
        Node result = EquivRelation.unify(fs1, fs2);

        // then
        assertThat(result).isNotNull();
    }

    @Test
    void testCanUnifyWithIdenticalStructures() {
        // given
        FeatureStructure fs1 = new FeatureStructure(new BasicType("test").newNode());
        FeatureStructure fs2 = new FeatureStructure(new BasicType("test").newNode());

        // when
        boolean result = EquivRelation.canUnify(fs1, fs2);

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

    @Test
    void testCanUnifyWithIncompatibleStructures() throws UnificationFailure {
        // given
        FeatureStructure fs1 = mock(FeatureStructure.class);
        FeatureStructure fs2 = mock(FeatureStructure.class);
        Node root1 = mock(Node.class);
        Node root2 = mock(Node.class);
        Type type1 = mock(Type.class);
        Type type2 = mock(Type.class);

        when(fs1.getRoot()).thenReturn(root1);
        when(fs2.getRoot()).thenReturn(root2);
        when(root1.getType()).thenReturn(type1);
        when(root2.getType()).thenReturn(type2);
        when(type1.unify(type2)).thenThrow(new UnificationFailure());

        // when
        boolean result = EquivRelation.canUnify(fs1, fs2);

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

    @Test
    void testDeepCopy() {
        // given
        Node mockNode = mock(Node.class);
        Node mockDuplicatedNode = mock(Node.class);
        CollectionEnumeration mockEnumeration = mock(CollectionEnumeration.class);

        when(mockNode.duplicate()).thenReturn(mockDuplicatedNode);
        when(mockDuplicatedNode.featureNames()).thenReturn(mockEnumeration);
        when(mockEnumeration.hasMoreElements()).thenReturn(false);

        // when
        Node result = EquivRelation.deepCopy(mockNode);

        // then
        assertThat(result).isNotNull();
        assertThat(result).isEqualTo(mockDuplicatedNode);

        verify(mockNode).duplicate();
        verify(mockDuplicatedNode).featureNames();
        verify(mockEnumeration).hasMoreElements();
    }

    @Test
    void testGetUnificator() {
        // given
        EquivRelation relation = new EquivRelation();
        Node node = mock(Node.class);

        // when
        Node result = relation.getUnificator(node);

        // then
        assertThat(result).isSameAs(node);
    }

}