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

import static mockit.Deencapsulation.getField;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.security.Security;

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

import com.scytl.cryptolib.commons.utils.system.OperatingSystem;
import com.scytl.cryptolib.primitives.derivation.configuration.ConfigKDFDerivationParameters;
import com.scytl.cryptolib.primitives.derivation.configuration.ConfigPBKDFDerivationParameters;
import com.scytl.cryptolib.primitives.derivation.configuration.DerivationPolicy;
import com.scytl.cryptolib.primitives.derivation.configuration.KDFDerivationPolicy;
import com.scytl.cryptolib.primitives.derivation.configuration.PBKDFDerivationPolicy;
import com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider;

public class CryptoKeyDeriverFactoryTest {

    private final DerivationPolicy _derivationPolicy =
        getKeyDerivationPolicy();

    private final CryptoKeyDeriverFactory _cryptoKeyDeriverFactory =
        new CryptoKeyDeriverFactory(_derivationPolicy);

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

    @AfterClass
    public static void removeBouncyCastleProvider() {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public void whenCreateKDFDerivationFactoryUsingAGivenPolicy() {

        KDFDerivationPolicy expectedKDFDerivationPolicy =
            getField(_cryptoKeyDeriverFactory, "_derivationPolicy");

        assertEquals(expectedKDFDerivationPolicy, _derivationPolicy);
    }

    @Test
    public void whenCreatePBKDFDerivationFactoryUsingAGivenPolicy() {

        PBKDFDerivationPolicy expectedDerivedFromPasswordPolicy =
            getField(_cryptoKeyDeriverFactory, "_derivationPolicy");

        assertEquals(expectedDerivedFromPasswordPolicy, _derivationPolicy);
    }

    @Test
    public void whenCreateCryptoKDFDeriver() {

        CryptoKDFDeriver cryptoKDFDeriver =
            _cryptoKeyDeriverFactory.createKDFDeriver();

        assertNotNull(cryptoKDFDeriver);
        assertTrue(cryptoKDFDeriver instanceof CryptoKDFDeriver);
    }

    @Test
    public void whenCreateCryptoPBKDFDeriver() {

        CryptoPBKDFDeriver cryptoPBKDFDeriver =
            _cryptoKeyDeriverFactory.createPBKDFDeriver();

        assertNotNull(cryptoPBKDFDeriver);
        assertTrue(cryptoPBKDFDeriver instanceof CryptoPBKDFDeriver);
    }

    private DerivationPolicy getKeyDerivationPolicyForLinux() {
        return new DerivationPolicy() {

            @Override
            public ConfigKDFDerivationParameters getKDFDerivationParameters() {
                return ConfigKDFDerivationParameters.MGF1_SHA256_BC;
            }

            @Override
            public ConfigPBKDFDerivationParameters getPBKDFDerivationParameters() {
                return ConfigPBKDFDerivationParameters.PBKDF2_1_SHA256_256_BC_KL128;
            }

            @Override
            public ConfigSecureRandomAlgorithmAndProvider getSecureRandomAlgorithmAndProvider() {
                return ConfigSecureRandomAlgorithmAndProvider.NATIVE_PRNG_SUN;
            }
        };
    }

    private DerivationPolicy getKeyDerivationPolicyForWindows() {
        return new DerivationPolicy() {

            @Override
            public ConfigKDFDerivationParameters getKDFDerivationParameters() {
                return ConfigKDFDerivationParameters.MGF1_SHA256_BC;
            }

            @Override
            public ConfigPBKDFDerivationParameters getPBKDFDerivationParameters() {
                return ConfigPBKDFDerivationParameters.PBKDF2_1_SHA256_256_BC_KL128;
            }

            @Override
            public ConfigSecureRandomAlgorithmAndProvider getSecureRandomAlgorithmAndProvider() {
                return ConfigSecureRandomAlgorithmAndProvider.PRNG_SUN_MSCAPI;
            }
        };
    }

    private DerivationPolicy getKeyDerivationPolicy() {
        if (OperatingSystem.WINDOWS.isCurrent()) {
            return getKeyDerivationPolicyForWindows();
        }
        return getKeyDerivationPolicyForLinux();
    }
}
