/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.ov.mixing.commons.preprocess;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

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

import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.ExpectedException;

import com.scytl.ov.mixing.commons.tests.categories.UltraSlowTest;

@Category(UltraSlowTest.class)
public class PartitionerTest {

    private static List<Integer> minimumBatchSizeList;

    @Rule
    public ExpectedException exception = ExpectedException.none();

    private Partitioner _sut;

    @BeforeClass
    public static void setUp() {

        minimumBatchSizeList = new ArrayList<>();
        minimumBatchSizeList.add(512);
        minimumBatchSizeList.add(1024);
        minimumBatchSizeList.add(2048);
        minimumBatchSizeList.add(4096);
        minimumBatchSizeList.add(8192);

    }

    @Test
    public void provide_partitions_when_the_input_is_lower_than_the_double_of_the_given_minimum_size() {

        for (final Integer minimumSize : minimumBatchSizeList) {

            _sut = new Partitioner(minimumSize);

            for (int i = 1; i < (2 * minimumSize); i++) {

                final List<Integer> generatedPartitionsOfMinimumSize = _sut.generatePartitionsOfMinimumSize(i);

                assertEquals(generatedPartitionsOfMinimumSize.size(), 1);
                assertEquals(generatedPartitionsOfMinimumSize.get(0).intValue(), i);

            }
        }
    }

    @Test
    public void provide_partitions_when_the_input_is_higher_or_equal_than_the_double_of_the_given_minimum_size() {

        for (final Integer minimumSize : minimumBatchSizeList) {

            _sut = new Partitioner(minimumSize);

            for (int i = 2 * minimumSize; i < (3 * minimumSize); i++) {

                final List<Integer> generatedPartitionsOfMinimumSize = _sut.generatePartitionsOfMinimumSize(i);

                int counter = 0;

                for (final Integer integer : generatedPartitionsOfMinimumSize) {

                    counter += integer;

                    assertTrue(integer >= minimumSize);
                    assertFalse(BigInteger.valueOf(integer).isProbablePrime(100));
                }

                assertEquals(counter, i);
            }
        }
    }

    @Test
    public void not_allow_negative_minimum_size() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage(
            "The given minimum size must be higher or equal than one and lower than the maximum value of an integer (int).");

        _sut = new Partitioner(-1);

        exception = ExpectedException.none();

    }

    @Test
    public void not_allow_zero_minimum_size() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage(
            "The given minimum size must be higher or equal than one and lower than the maximum value of an integer (int).");

        _sut = new Partitioner(0);

    }

    @Test
    public void not_allow_too_big_size() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage(
            "The given minimum size must be higher or equal than one and lower than the maximum value of an integer (int).");

        _sut = new Partitioner(Integer.MAX_VALUE);

    }
}
