/*
 * 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.service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.SecureRandom;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.primitives.securerandom.constants.SecureRandomConstants;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomString;

/**
 * Tests of the primitives service API.
 */
public class PrimitivesServiceTest {

    private static PrimitivesService _primitivesServiceForDefaultPolicy;

    private static byte[] _data;

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {
        Security.addProvider(new BouncyCastleProvider());

        _primitivesServiceForDefaultPolicy = new PrimitivesService();

        _data =
            new PrimitivesService()
                .getCryptoRandomBytes()
                .nextRandom(
                    getInt(
                        1,
                        SecureRandomConstants.MAXIMUM_GENERATED_BYTE_ARRAY_LENGTH));
    }

    @AfterClass
    public static void removeBouncyCastleProvider() {

        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public void whenGetByteRandom() throws GeneralCryptoLibException {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getCryptoRandomBytes());
    }

    @Test
    public void whenGetIntegerRandom() {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getCryptoRandomInteger());
    }

    @Test
    public void whenGetStringRandom() {

        CryptoAPIRandomString randomString =
            _primitivesServiceForDefaultPolicy
                .get32CharAlphabetCryptoRandomString();

        Assert.assertNotNull(randomString);
    }

    @Test
    public void whenGetKDFDeriver() {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getKDFDeriver());
    }

    @Test
    public void whenGetPBKDFDeriver() {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getPBKDFDeriver());
    }

    @Test
    public void whenGetDerivedFromPassword() {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getPBKDFDeriver());
    }

    @Test
    public void whenGetHash() throws GeneralCryptoLibException {

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getHash(_data));
    }

    @Test
    public void whenGetHashForDataInputStream()
            throws GeneralCryptoLibException {

        InputStream dataInputStream = new ByteArrayInputStream(_data);

        Assert.assertNotNull(_primitivesServiceForDefaultPolicy
            .getHash(dataInputStream));
    }

    @Test
    public void whenShuffling() throws GeneralCryptoLibException {

        List<String> list = new ArrayList<String>();
        list.add("I");
        list.add("LOVE");
        list.add("WRITING");
        list.add("UNIT");
        list.add("TESTS");
        list.add("FOR");
        list.add("THE");
        list.add("SEC TEAM");
        list.add("FOREVER");
        list.add("AND EVER");

        List<String> previousList = new ArrayList<String>(list);

        _primitivesServiceForDefaultPolicy.shuffle(list);

        Assert.assertFalse(previousList.equals(list));
    }

    private static int getInt(final int min, final int max)
            throws GeneralCryptoLibException {

        SecureRandom secureRandom = new SecureRandom();

        int randomInt = 0;
        do {
            randomInt = secureRandom.nextInt(max + 1);
        } while (randomInt < min);

        return randomInt;
    }
}
