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

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;

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

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;

/**
 * Tests the PEM utilities.
 */
public class PemUtilsTest {

    private static final String RSA_PRIVATE_KEY_PATH =
        "/pem/rsaPrivateKey.pem";

    private static final String RSA_PUBLIC_KEY_PATH =
        "/pem/rsaPublicKey.pem";

    private static final String X509_CERTIFICATE_PATH =
        "/pem/x509Certificate.pem";

    private static final String RSA_PRIVATE_KEY_WITH_NO_NEWLINES_PATH =
        "/pem/rsaPrivateKeyWithNoNewlines.pem";

    private static final String RSA_PUBLIC_KEY_WITH_NO_NEWLINES_PATH =
        "/pem/rsaPublicKeyWithNoNewlines.pem";

    private static final String X509_CERTIFICATE_WITH_NO_NEWLINES_PATH =
        "/pem/x509CertificateWithNoNewlines.pem";

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {

        Security.addProvider(new BouncyCastleProvider());
    }

    @AfterClass
    public static void cleanUp() {

        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testReadingRsaPublicKeyFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn = removeNewLines(loadPem(RSA_PUBLIC_KEY_PATH));

        PublicKey key = PemUtils.publicKeyFromPem(pemStrIn);
        String pemStrOut = removeNewLines(PemUtils.publicKeyToPem(key));

        assertEquals(pemStrIn, pemStrOut);
    }

    @Test
    public void testReadingRsaPrivateKeyFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn = removeNewLines(loadPem(RSA_PRIVATE_KEY_PATH));

        PrivateKey key = PemUtils.privateKeyFromPem(pemStrIn);
        String pemStrOut = removeNewLines(PemUtils.privateKeyToPem(key));

        assertEquals(pemStrIn, pemStrOut);
    }

    @Test
    public void testReadingX509CertificateFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn = removeNewLines(loadPem(X509_CERTIFICATE_PATH));

        Certificate cert = PemUtils.certificateFromPem(pemStrIn);
        String pemStrOut = removeNewLines(PemUtils.certificateToPem(cert));

        assertEquals(pemStrIn, pemStrOut);
    }

    @Test
    public void testReadingRsaPublicKeyWithNoNewlinesFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn =
            removeNewLines(loadPem(RSA_PUBLIC_KEY_WITH_NO_NEWLINES_PATH));

        PublicKey key = PemUtils.publicKeyFromPem(pemStrIn);
        String pemStrOut = removeNewLines(PemUtils.publicKeyToPem(key));

        assertEquals(pemStrIn, pemStrOut);
    }

    @Test
    public void testReadingRsaPrivateKeyWithNoNewlinesFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn =
            removeNewLines(loadPem(RSA_PRIVATE_KEY_WITH_NO_NEWLINES_PATH));

        PrivateKey key = PemUtils.privateKeyFromPem(pemStrIn);
        String pemStrOut = removeNewLines(PemUtils.privateKeyToPem(key));

        assertEquals(pemStrIn, pemStrOut);
    }

    @Test
    public void testReadingX509CertificateWithNoNewlinesFromAndWritingToPem()
            throws IOException, GeneralCryptoLibException {

        String pemStrIn = removeNewLines(
            loadPem(X509_CERTIFICATE_WITH_NO_NEWLINES_PATH));

        Certificate certificate = PemUtils.certificateFromPem(pemStrIn);
        String pemStrOut =
            removeNewLines(PemUtils.certificateToPem(certificate));

        assertEquals(pemStrIn, pemStrOut);
    }

    private String removeNewLines(final String str) {
        return str.replace("\n", "").replace("\r", "");
    }
    
    private String loadPem(String resource) throws IOException {
        StringBuilder pem = new StringBuilder();
        try (InputStream stream = getClass().getResourceAsStream(resource);
                Reader reader = new InputStreamReader(stream,
                    StandardCharsets.UTF_8);) {
            int c;
            while ((c = reader.read()) != -1) {
                pem.append((char) c);
            }
        }
        return pem.toString();
    }
}
