package sterling.lang.expression;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static sterling.lang.expression.ExpressionFactory.declaration;
import static sterling.lang.expression.ExpressionFactory.object;
import static sterling.lang.expression.ExpressionTestFactory.expression;

import org.junit.Before;
import org.junit.Test;

public class ObjectExpressionTest {

    private ObjectExpression object;
    private ObjectExpression similarObject;
    private ObjectExpression objectWithDifferentMembers;

    @Before
    public void setUp() {
        DeclaredExpression toString = declaration("toString", expression("EXPRESSION_1"));
        DeclaredExpression isNothing = declaration("isNothing", expression("EXPRESSION_2"));
        object = object(toString, isNothing);
        similarObject = object(toString, isNothing);
        objectWithDifferentMembers = object(toString, isNothing, declaration("isDifferent", expression()));
    }

    @Test
    public void shouldShowMembers_whenToString() {
        assertThat(object.toString(), equalTo("(ObjectExpression [isNothing=EXPRESSION_2, toString=EXPRESSION_1])"));
    }

    @Test
    public void shouldBeEqual_whenOtherObjectIsItself() {
        assertThat(object.equals(object), is(true));
        assertThat(object.hashCode(), equalTo(object.hashCode()));
    }

    @Test
    public void shouldBeEqual_whenOtherObjectIsSimilar() {
        assertThat(object.equals(similarObject), is(true));
        assertThat(object.hashCode(), equalTo(similarObject.hashCode()));
    }

    @Test
    @SuppressWarnings({ "PMD.PositionLiteralsFirstInComparisons", "ObjectEqualsNull" })
    public void shouldNotBeEqual_whenOtherObjectIsNull() {
        assertThat(object.equals(null), is(false));
    }

    @Test
    public void shouldNotBeEqual_whenOtherObjectIsUnrelatedType() {
        Object other = new Object();
        assertThat(object.equals(other), is(false));
        assertThat(object.hashCode(), not(equalTo(other.hashCode())));
    }

    @Test
    public void shouldNotBeEqual_whenOtherObjectHasDifferentMembers() {
        assertThat(object.equals(objectWithDifferentMembers), is(false));
        assertThat(object.hashCode(), not(equalTo(objectWithDifferentMembers.hashCode())));
    }
}
