/*
 * 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.symmetric.key.configuration;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.commons.constants.Constants;
import com.scytl.cryptolib.commons.utils.system.OperatingSystem;
import com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider;

import mockit.Deencapsulation;

public class SymmetricKeyPolicyFromPropertiesTest {

    private static SymmetricKeyPolicyFromProperties _symmetricKeyPolicyFromProperties;

    private static OperatingSystem _os;

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {

        _symmetricKeyPolicyFromProperties =
            new SymmetricKeyPolicyFromProperties(
                Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH);
        _os = OperatingSystem.current();
    }

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

        new SymmetricKeyPolicyFromProperties("somePath");
    }

    @Test(expected = CryptoLibException.class)
    public void whenCreatePolicyInvalidLabels()
            throws GeneralCryptoLibException {
        new SymmetricKeyPolicyFromProperties(
            "properties/cryptolibPolicy_invalidLabels.properties");
    }

    @Test(expected = CryptoLibException.class)
    public void whenCreatePolicyBlankLabels()
            throws GeneralCryptoLibException {
        new SymmetricKeyPolicyFromProperties(
            "properties/cryptolibPolicy_blankLabels.properties");
    }

    @Test
    public void givenPolicyWhenGetHmacConfigThenExpectedValues() {

        ConfigHmacSecretKeyAlgorithmAndSpec hmacSecretKeyConfig =
            _symmetricKeyPolicyFromProperties
                .getHmacSecretKeyAlgorithmAndSpec();

        assertEquals("HmacSHA256", hmacSecretKeyConfig.getAlgorithm());
        assertEquals(256, hmacSecretKeyConfig.getKeyLengthInBits());
    }

    @Test
    public void givenPolicyWhenGetSecretKeyConfigThenExpectedValues() {

        ConfigSecretKeyAlgorithmAndSpec secretKeyConfig =
            _symmetricKeyPolicyFromProperties
                .getSecretKeyAlgorithmAndSpec();

        assertEquals("AES", secretKeyConfig.getAlgorithm());
        assertEquals(128, secretKeyConfig.getKeyLength());
    }

    @Test
    public void givenPolicyWhenGetSecureRandomConfigThenExpectedValues() {

        ConfigSecureRandomAlgorithmAndProvider expectedSecureRandomConfig =
            getOSDependentSecureRandomConfig();

        ConfigSecureRandomAlgorithmAndProvider secureRandomConfig =
            _symmetricKeyPolicyFromProperties
                .getSecureRandomAlgorithmAndProvider();

        assertEquals(expectedSecureRandomConfig, secureRandomConfig);
    }

    @Test
    public void givenMockedLinuxWhenGetSecureRandomConfigThenExpectedValue()
            throws GeneralCryptoLibException {
        Deencapsulation.setField(OperatingSystem.class, "current",
            OperatingSystem.LINUX);

        SymmetricKeyPolicyFromProperties symmetricKeyPolicyFromProperties =
            new SymmetricKeyPolicyFromProperties(
                Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH);

        ConfigSecureRandomAlgorithmAndProvider secureRandomConfig =
            symmetricKeyPolicyFromProperties
                .getSecureRandomAlgorithmAndProvider();

        assertEquals(
            ConfigSecureRandomAlgorithmAndProvider.NATIVE_PRNG_SUN,
            secureRandomConfig);
    }

    @Test
    public void givenMockedWindowsWhenGetSecureRandomConfigThenExpectedValue()
            throws GeneralCryptoLibException {

        Deencapsulation.setField(OperatingSystem.class, "current",
            OperatingSystem.WINDOWS);

        SymmetricKeyPolicyFromProperties symmetricKeyPolicyFromProperties =
            new SymmetricKeyPolicyFromProperties(
                Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH);

        ConfigSecureRandomAlgorithmAndProvider secureRandomConfig =
            symmetricKeyPolicyFromProperties
                .getSecureRandomAlgorithmAndProvider();

        assertEquals(
            ConfigSecureRandomAlgorithmAndProvider.PRNG_SUN_MSCAPI,
            secureRandomConfig);
    }

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

        Deencapsulation.setField(OperatingSystem.class, "current",
            OperatingSystem.OTHER);

        new SymmetricKeyPolicyFromProperties(
            Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH);
    }

    @After
    public void revertSystemHelper() {
        Deencapsulation.setField(OperatingSystem.class, "current", _os);
    }

    private static ConfigSecureRandomAlgorithmAndProvider getOSDependentSecureRandomConfig() {

        switch (OperatingSystem.current()) {

        case WINDOWS:
            return ConfigSecureRandomAlgorithmAndProvider.PRNG_SUN_MSCAPI;
        case LINUX:
            return ConfigSecureRandomAlgorithmAndProvider.NATIVE_PRNG_SUN;
        default:
            throw new CryptoLibException("OS not supported");
        }
    }
}
