/*
 * 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.cryptolib.primitives.securerandom.factory;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

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

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.commons.constants.Constants;
import com.scytl.cryptolib.primitives.securerandom.configuration.SecureRandomPolicyFromProperties;
import com.scytl.cryptolib.primitives.securerandom.constants.SecureRandomConstants;

public class CryptoByteRandomTest {

    private CryptoRandomBytes _cryptoByteRandom;

    @Before
    public void setUp() throws GeneralCryptoLibException {
        _cryptoByteRandom =
            new SecureRandomFactory(new SecureRandomPolicyFromProperties(
                Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH))
                    .createByteRandom();
    }

    @Test
    public void testThatGeneratesTheGivenNumberOfBytes()
            throws GeneralCryptoLibException {

        byte[] bytes = _cryptoByteRandom.nextRandom(10);

        assertEquals(10, bytes.length);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void whenGiveAnIncorrectLength()
            throws GeneralCryptoLibException {

        _cryptoByteRandom.nextRandom(
            SecureRandomConstants.MAXIMUM_GENERATED_BYTE_ARRAY_LENGTH + 1);
    }

    @Test
    public void testThatGeneratesBytesNotInBlackList()
            throws GeneralCryptoLibException {
        Set<Byte[]> blackList = new HashSet<Byte[]>();

        for (int i = Byte.MIN_VALUE; i < Byte.MAX_VALUE; i++) {
            blackList.add(new Byte[] {(byte) i });
        }

        Byte[] bytes = {_cryptoByteRandom.nextRandom(1, blackList)[0]};

        for (Byte[] blackListed: blackList) {
            if (Arrays.equals(blackListed, bytes)) {
                fail("Returned value must not be black listed.");
            }
        }
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testThatNotGeneratesBytesWhenBlackListIsFull()
            throws GeneralCryptoLibException {
        Set<Byte[]> blackList = new HashSet<Byte[]>();

        for (int i = 0; i < 256; i++) {
            blackList.add(new Byte[] {(byte) i });
        }

        _cryptoByteRandom.nextRandom(1, blackList);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testThatNotGeneratesBytesWhenBlackListHasElementsOfDifferentLength()
            throws GeneralCryptoLibException {
        Set<Byte[]> blackList = new HashSet<Byte[]>();

        blackList.add(new Byte[] {0});
        blackList.add(new Byte[] {1, 2});

        _cryptoByteRandom.nextRandom(1, blackList);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testThatNotGeneratesBytesWhenBlackListIsNull()
            throws GeneralCryptoLibException {

        _cryptoByteRandom.nextRandom(1, null);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testThatNotGeneratesBytesWhenLengthIsNull()
            throws GeneralCryptoLibException {

        _cryptoByteRandom.nextRandom(0);
    }
}
