package de.renew.formalism;

import org.junit.jupiter.api.Test;

import de.renew.formalism.java.ChannelCheckNode;
import de.renew.simulatorontology.shadow.SyntaxException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ChannelCheckNodeTest {

    @Test
    public void testChannelCheckNode() {
        //given
        String name = "testName";
        int arity = 5;

        //when
        final ChannelCheckNode testChannelCheck = new ChannelCheckNode(name, arity);

        //then
        assertEquals(name, testChannelCheck._name);
        assertEquals(arity, testChannelCheck._arity);
    }

    @Test
    public void testCheckThrowsSyntaxExceptionWhenResultNotNull() {
        //given
        String name = "testName";
        int arity = 5;
        final ChannelCheckNode testChannelCheck = new ChannelCheckNode(name, arity);

        //when
        final SyntaxException exception =
            assertThrows(SyntaxException.class, testChannelCheck::check);

        //then
        assertEquals("Channel testName(*,*,*,*,*) cannot be satisfied.", exception.getMessage());
    }

    @Test
    public void testCheckRecursivelyThrowsSyntaxException() {
        //given
        String name = "testName";
        int arity = 5;
        final ChannelCheckNode testChannelCheck = new ChannelCheckNode(name, arity);

        //when
        final SyntaxException exception =
            assertThrows(SyntaxException.class, testChannelCheck::check);

        //then
        assertEquals("Channel testName(*,*,*,*,*) cannot be satisfied.", exception.getMessage());
    }

    @Test
    public void testMakeChannelName() {
        //given
        int arity = 3;
        String name = "testName";
        final ChannelCheckNode testChannelCheck = new ChannelCheckNode(name, arity);

        //when
        final String resultChannelName = testChannelCheck.makeChannelName();

        //then
        assertEquals("testName(*,*,*)", resultChannelName);
    }

    @Test
    void testHashCode() {
        //given
        String name = "testName";
        int arity = 5;
        final ChannelCheckNode testChannelCheck = new ChannelCheckNode(name, arity);

        //when
        final int testHash = name.hashCode() + arity * 135;

        //then
        assertEquals(testHash, testChannelCheck.hashCode());
    }

    @Test
    void testEqualsTrue() {
        //given
        final ChannelCheckNode checkNodeA = new ChannelCheckNode("testName", 5);
        final ChannelCheckNode checkNodeB = new ChannelCheckNode("testName", 5);

        //when
        boolean isEqual = checkNodeA.equals(checkNodeB);

        //then
        assertTrue(isEqual);
    }

    @Test
    void testEqualsArityDiffers() {
        //given
        final ChannelCheckNode checkNodeA = new ChannelCheckNode("testName", 5);
        final ChannelCheckNode checkNodeB = new ChannelCheckNode("testName", 4);

        //when
        boolean isEqual = checkNodeA.equals(checkNodeB);

        //then
        assertFalse(isEqual);
    }

    @Test
    void testEqualsNameDiffers() {
        //given
        final ChannelCheckNode checkNodeA = new ChannelCheckNode("testName", 5);
        final ChannelCheckNode checkNodeB = new ChannelCheckNode("otherName", 5);

        //when
        boolean isEqual = checkNodeA.equals(checkNodeB);

        //then
        assertFalse(isEqual);
    }

    @Test
    void testEqualsNameAndArityDiffer() {
        //given
        final ChannelCheckNode checkNodeA = new ChannelCheckNode("testName", 5);
        final ChannelCheckNode checkNodeB = new ChannelCheckNode("otherName", 23);

        //when
        boolean isEqual = checkNodeA.equals(checkNodeB);

        //then
        assertFalse(isEqual);
    }

}
