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

import static junitparams.JUnitParamsRunner.$;

import java.security.Security;

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

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.cryptolib.primitives.securerandom.constants.SecureRandomConstants;
import com.scytl.cryptolib.proofs.proof.Proof;
import com.scytl.cryptolib.test.tools.utils.CommonTestDataGenerator;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

/**
 * Tests of Proofs service API input validation.
 */
@RunWith(JUnitParamsRunner.class)
public class ProofsServiceValidationTest {

    private static ProofsService _proofsServiceForDefaultPolicy;

    private static String _whiteSpaceString;

    static {
        try {
            setUp();
        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException("Setup failed for class "
                + ProofsServiceValidationTest.class.getSimpleName());
        }
    }

    public static void setUp() throws GeneralCryptoLibException {

        Security.addProvider(new BouncyCastleProvider());

        _proofsServiceForDefaultPolicy = new ProofsService();

        _whiteSpaceString = CommonTestDataGenerator
            .getWhiteSpaceString(CommonTestDataGenerator.getInt(1,
                SecureRandomConstants.MAXIMUM_GENERATED_STRING_LENGTH));
    }

    @AfterClass
    public static void tearDown() {

        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

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

    @Test
    @Parameters(method = "createProofsService")
    public void testProofsServiceCreationValidation(String path,
            String errorMsg) throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        new ProofsService(path);
    }

    public static Object[] createProofsService()
            throws GeneralCryptoLibException {

        return $($(null, "Properties file path is null."),
            $("", "Properties file path is blank."),
            $(_whiteSpaceString, "Properties file path is blank."));
    }

    @Test
    @Parameters(method = "createProofPreComputer")
    public void testProofPreComputerCreationValidation(ZpSubgroup group,
            String errorMsg) throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        _proofsServiceForDefaultPolicy.createProofPreComputerAPI(group);
    }

    public static Object[] createProofPreComputer() {

        return $($(null, "Zp subgroup is null."));
    }

    @Test
    @Parameters(method = "createProofGenerator")
    public void testProofGeneratorCreationValidation(ZpSubgroup group,
            String errorMsg) throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        _proofsServiceForDefaultPolicy.createProofProverAPI(group);
    }

    public static Object[] createProofGenerator() {

        return $($(null, "Zp subgroup is null."));
    }

    @Test
    @Parameters(method = "createProofVerifier")
    public void testProofVerifierCreationValidation(ZpSubgroup group,
            String errorMsg) throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        _proofsServiceForDefaultPolicy.createProofVerifierAPI(group);
    }

    public static Object[] createProofVerifier() {

        return $($(null, "Zp subgroup is null."));
    }

    @Test
    @Parameters(method = "deserializeProof")
    public void testProofDeserializationValidation(String jsonStr,
            String errorMsg) throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        Proof.fromJson(jsonStr);
    }

    public static Object[] deserializeProof()
            throws GeneralCryptoLibException {

        String proofWithNullHashValue =
            "{\"zkProof\":{\"q\":\"Cw==\",\"hash\":null,\"values\":[\"AQ==\",\"BA==\"]}}";
        String proofWithNullExponentsList =
            "{\"zkProof\":{\"q\":\"Cw==\",\"hash\":\"Cg==\",\"values\":null}}";
        String proofWithEmptyExponentsList =
            "{\"zkProof\":{\"q\":\"Cw==\",\"hash\":\"Cg==\",\"values\":[]}}";
        String proofWithNullInExponentsList =
            "{\"zkProof\":{\"q\":\"Cw==\",\"hash\":\"Cg==\",\"values\":[\"AQ==\",null]}}";
        String proofWithNullQ =
            "{\"zkProof\":{\"q\":null,\"hash\":\"Cg==\",\"values\":[\"AQ==\",\"BA==\"]}}";

        return $($(null, "Proof JSON string is null."),
            $("", "Proof JSON string is blank."),
            $(_whiteSpaceString, "Proof JSON string is blank."),
            $(proofWithNullHashValue, "Exponent value is null."),
            $(proofWithNullExponentsList,
                "List of proof exponents is null."),
            $(proofWithEmptyExponentsList,
                "List of proof exponents is empty."),
            $(proofWithNullInExponentsList, "Exponent value is null."),
            $(proofWithNullQ, "Zp subgroup q parameter is null."));
    }
}
