/*
 * 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.certificates.bean.extensions;

import java.util.EnumSet;

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

import com.scytl.cryptolib.certificates.constants.X509CertificateConstants;

/**
 * Test of the class KeyUsageExtension.
 */
public class KeyUsageExtensionTest {

    private static final int NUM_KEY_USAGES_IN_CA_CERT_EXTENSION = 2;

    private static final int NUM_KEY_USAGES_IN_SIGN_CERT_EXTENSION = 2;

    private static final int NUM_KEY_USAGES_IN_ENCRYPT_CERT_EXTENSION = 2;

    private static final boolean CA_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL =
        true;

    private static final boolean SIGN_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL =
        false;

    private static final boolean ENCRYPT_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL =
        false;

    private static EnumSet<CertificateKeyUsage> _caCertKeyUsages;

    private static EnumSet<CertificateKeyUsage> _signCertKeyUsages;

    private static EnumSet<CertificateKeyUsage> _encryptCertKeyUsages;

    private static CertificateKeyUsageExtension _caCertKeyUsageExtension;

    private static CertificateKeyUsageExtension _signCertKeyUsageExtension;

    private static CertificateKeyUsageExtension _encryptCertKeyUsageExtension;

    @BeforeClass
    public static void setUp() {

        _caCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.KEY_CERT_SIGN,
                CertificateKeyUsage.CRL_SIGN);
        _signCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.DIGITAL_SIGNATURE,
                CertificateKeyUsage.NON_REPUDIATION);
        _encryptCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.KEY_ENCIPHERMENT,
                CertificateKeyUsage.DATA_ENCIPHERMENT);

        _caCertKeyUsageExtension =
            new CertificateKeyUsageExtension(
                CA_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL, _caCertKeyUsages);
        _signCertKeyUsageExtension =
            new CertificateKeyUsageExtension(
                SIGN_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL,
                _signCertKeyUsages);
        _encryptCertKeyUsageExtension =
            new CertificateKeyUsageExtension(
                ENCRYPT_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL,
                _encryptCertKeyUsages);
    }

    @Test
    public void retrieveExtensionType() {

        boolean caCertExtensionTypeRetrieved =
            _caCertKeyUsageExtension.getExtensionType() == ExtensionType.KEY_USAGE;

        boolean signCertExtensionTypeRetrieved =
            _signCertKeyUsageExtension.getExtensionType() == ExtensionType.KEY_USAGE;

        boolean encryptCertExtensionTypeRetrieved =
            _encryptCertKeyUsageExtension.getExtensionType() == ExtensionType.KEY_USAGE;

        assert (caCertExtensionTypeRetrieved
            && signCertExtensionTypeRetrieved && encryptCertExtensionTypeRetrieved);
    }

    @Test
    public void retrieveIsCriticalFlag() {

        boolean caCertIsCriticalFlagRetrieved =
            _caCertKeyUsageExtension.isCritical() == CA_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL;

        boolean signCertIsCriticalFlagRetrieved =
            _signCertKeyUsageExtension.isCritical() == SIGN_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL;

        boolean encryptCertIsCriticalFlagRetrieved =
            _encryptCertKeyUsageExtension.isCritical() == ENCRYPT_CERT_KEY_USAGE_EXTENSION_IS_CRITICAL;

        assert (caCertIsCriticalFlagRetrieved
            && signCertIsCriticalFlagRetrieved && encryptCertIsCriticalFlagRetrieved);
    }

    @Test
    public void retrieveInternallySetIsCriticalFlag() {

        CertificateKeyUsageExtension caCertKeyUsageExtension =
            new CertificateKeyUsageExtension(_caCertKeyUsages);
        boolean caCertIsCriticalFlagRetrieved =
            caCertKeyUsageExtension.isCritical() == X509CertificateConstants.CERTIFICATE_EXTENSION_IS_CRITICAL_FLAG_DEFAULT;

        CertificateKeyUsageExtension signCertKeyUsageExtension =
            new CertificateKeyUsageExtension(_signCertKeyUsages);
        boolean signCertIsCriticalFlagRetrieved =
            signCertKeyUsageExtension.isCritical() == X509CertificateConstants.CERTIFICATE_EXTENSION_IS_CRITICAL_FLAG_DEFAULT;

        CertificateKeyUsageExtension encryptCertKeyUsageExtension =
            new CertificateKeyUsageExtension(_encryptCertKeyUsages);
        boolean encryptCertIsCriticalFlagRetrieved =
            encryptCertKeyUsageExtension.isCritical() == X509CertificateConstants.CERTIFICATE_EXTENSION_IS_CRITICAL_FLAG_DEFAULT;

        assert (caCertIsCriticalFlagRetrieved
            && signCertIsCriticalFlagRetrieved && encryptCertIsCriticalFlagRetrieved);
    }

    @Test
    public void retrieveKeyUsages() {

        EnumSet<CertificateKeyUsage> caCertKeyUsages =
            _caCertKeyUsageExtension.getKeyUsages();
        boolean caCertKeyUsagesRetrieved =
            (caCertKeyUsages.size() == NUM_KEY_USAGES_IN_CA_CERT_EXTENSION)
                && (caCertKeyUsages.containsAll(_caCertKeyUsages));

        EnumSet<CertificateKeyUsage> signCertKeyUsages =
            _signCertKeyUsageExtension.getKeyUsages();
        boolean signCertKeyUsagesRetrieved =
            (signCertKeyUsages.size() == NUM_KEY_USAGES_IN_SIGN_CERT_EXTENSION)
                && (signCertKeyUsages.containsAll(_signCertKeyUsages));

        EnumSet<CertificateKeyUsage> encryptCertKeyUsages =
            _encryptCertKeyUsageExtension.getKeyUsages();
        boolean encryptCertKeyUsagesRetrieved =
            (encryptCertKeyUsages.size() == NUM_KEY_USAGES_IN_ENCRYPT_CERT_EXTENSION)
                && (encryptCertKeyUsages
                    .containsAll(_encryptCertKeyUsages));

        assert (caCertKeyUsagesRetrieved && signCertKeyUsagesRetrieved && encryptCertKeyUsagesRetrieved);
    }

    @Test
    public void addExcessKeyUsages() {

        EnumSet<CertificateKeyUsage> caCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.KEY_CERT_SIGN,
                CertificateKeyUsage.CRL_SIGN,
                CertificateKeyUsage.KEY_CERT_SIGN,
                CertificateKeyUsage.CRL_SIGN);
        boolean caCertKeyUsagesNotDuplicated =
            (caCertKeyUsages.size() == NUM_KEY_USAGES_IN_CA_CERT_EXTENSION)
                && (caCertKeyUsages.containsAll(_caCertKeyUsages));

        EnumSet<CertificateKeyUsage> signCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.DIGITAL_SIGNATURE,
                CertificateKeyUsage.NON_REPUDIATION,
                CertificateKeyUsage.DIGITAL_SIGNATURE,
                CertificateKeyUsage.NON_REPUDIATION,
                CertificateKeyUsage.NON_REPUDIATION);
        boolean signCertKeyUsagesNotDuplicated =
            (signCertKeyUsages.size() == NUM_KEY_USAGES_IN_SIGN_CERT_EXTENSION)
                && (signCertKeyUsages.containsAll(_signCertKeyUsages));

        EnumSet<CertificateKeyUsage> encryptCertKeyUsages =
            EnumSet.of(CertificateKeyUsage.KEY_ENCIPHERMENT,
                CertificateKeyUsage.DATA_ENCIPHERMENT,
                CertificateKeyUsage.DATA_ENCIPHERMENT,
                CertificateKeyUsage.KEY_ENCIPHERMENT,
                CertificateKeyUsage.KEY_ENCIPHERMENT);
        boolean encryptCertKeyUsagesNotDuplicated =
            (encryptCertKeyUsages.size() == NUM_KEY_USAGES_IN_ENCRYPT_CERT_EXTENSION)
                && (encryptCertKeyUsages
                    .containsAll(_encryptCertKeyUsages));

        assert (caCertKeyUsagesNotDuplicated
            && signCertKeyUsagesNotDuplicated && encryptCertKeyUsagesNotDuplicated);
    }

}
