package function.builtin.math;

import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;

import org.junit.Test;

import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.math.DIVIDE.DivideByZeroException;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;

public class REMAINDERTest extends SymbolAndFunctionCleaner {

    @Test
    public void rem() {
        String input = "(rem 5 3)";

        assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
    }

    @Test
    public void remainder() {
        String input = "(remainder 11 7)";

        assertSExpressionsMatch(new LispNumber("4"), evaluateString(input));
    }

    @Test
    public void dividendGreaterThanDivisor() {
        String input = "(rem 21 19)";

        assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
    }

    @Test
    public void dividendLessThanDivisor() {
        String input = "(rem 5 239)";

        assertSExpressionsMatch(new LispNumber("5"), evaluateString(input));
    }

    @Test
    public void dividendEqualToDivisor() {
        String input = "(rem 5 5)";

        assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
    }

    @Test
    public void dividendMultipleOfDivisor() {
        String input = "(rem 20 5)";

        assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
    }

    @Test
    public void divisorOfOne() {
        String input = "(rem 5 1)";

        assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
    }

    @Test
    public void dividendOfZero() {
        String input = "(rem 0 2309)";

        assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
    }

    @Test
    public void negativeDividend() {
        String input = "(rem -23 25)";

        assertSExpressionsMatch(new LispNumber("-23"), evaluateString(input));
    }

    public void negativeDivisor() {
        String input = "(rem 5 -11)";

        assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
    }

    @Test(expected = DivideByZeroException.class)
    public void divisorOfZero() {
        evaluateString("(rem 5 0)");
    }

    @Test(expected = BadArgumentTypeException.class)
    public void remWithNonNumber() {
        evaluateString("(rem 'a 'b)");
    }

    @Test(expected = TooFewArgumentsException.class)
    public void remWithTooFewArguments() {
        evaluateString("(rem 1)");
    }

    @Test(expected = TooManyArgumentsException.class)
    public void remWithTooManyArguments() {
        evaluateString("(rem 1 2 3)");
    }
}
