/*
 * $Id$
 * @author aakimov
 * @date   Jul 1, 2016 11:54:52 AM
 *
 * Copyright (C) 2016 Scytl Secure Electronic Voting SA
 *
 * All rights reserved.
 */
package com.scytl.math;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;

import java.math.BigInteger;
import java.util.List;

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

/**
 * Tests of {@link AbstractMultiExponentiator}.
 * 
 * @author aakimov
 */
public class AbstractMultiExponentiatorTest {
    private static List<BigInteger> BASES = asList(BigInteger.valueOf(2),
            BigInteger.valueOf(3));
    private static List<BigInteger> EXPONENTS = asList(BigInteger.valueOf(5),
            BigInteger.valueOf(7));
    private static BigInteger MODULUS = BigInteger.valueOf(11);
    private static final BigInteger RESULT = BigInteger.valueOf(2);
    private TestableMultiExponentiator exponentiator;

    @Before
    public void setUp() {
        exponentiator = new TestableMultiExponentiator(BASES, MODULUS, 3,
                RESULT);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testAbstractMultiExponentiatorNegativeBase() {
        new TestableMultiExponentiator(singletonList(BigInteger.valueOf(-1)),
                MODULUS, 3, RESULT);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testAbstractMultiExponentiatorNegativeModulus() {
        new TestableMultiExponentiator(BASES, MODULUS.negate(), 3, RESULT);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testAbstractMultiExponentiatorNonPositiveExponentLength() {
        new TestableMultiExponentiator(BASES, MODULUS, 0, RESULT);
    }

    @Test
    public void testBases() {
        assertEquals(2, exponentiator.bases().size());
        for (int i = 0; i < BASES.size(); i++) {
            assertEquals(BASES.get(i), exponentiator.bases().get(i));
        }
    }

    @Test
    public void testExponentiate() {
        assertEquals(RESULT, exponentiator.exponentiate(EXPONENTS));
    }

    @Test(expected = IllegalArgumentException.class)
    public void testExponentiateExponentIsTooBig() {
        int length = 1 << exponentiator.maximumBitLengthOfExponent();
        exponentiator.exponentiate(
                asList(BigInteger.ONE, BigInteger.valueOf(length)));
    }

    @Test(expected = IllegalArgumentException.class)
    public void testExponentiateNegativeExponent() {
        List<BigInteger> exponents = asList(BigInteger.ONE,
                BigInteger.valueOf(-1));
        exponentiator.exponentiate(exponents);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testExponentiateWrongNumberOfExponents() {
        exponentiator.exponentiate(singletonList(BigInteger.ONE));
    }

    @Test
    public void testMaximumBitLengthOfExponent() {
        assertEquals(3, exponentiator.maximumBitLengthOfExponent());
    }

    @Test
    public void testModulus() {
        assertEquals(MODULUS, exponentiator.modulus());
    }

    private static class TestableMultiExponentiator
            extends AbstractMultiExponentiator {
        private final BigInteger result;

        public TestableMultiExponentiator(List<BigInteger> bases,
                BigInteger modulus, int maximumBitLengthOfExponent,
                BigInteger result) {
            super(bases, modulus, maximumBitLengthOfExponent);
            this.result = result;
        }

        @Override
        protected BigInteger doExponentiate(BigInteger[] exponents) {
            return result;
        }
    }
}
