/*
 * 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.mathematical.groups.impl;

import static junitparams.JUnitParamsRunner.$;

import java.math.BigInteger;

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.test.tools.configuration.ZpSubgroupLoader;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

/**
 * Tests of the Zp subgroup input validation.
 */
@RunWith(JUnitParamsRunner.class)
public class ZpSubgroupValidationTest {

    private static BigInteger _p;

    private static BigInteger _q;

    private static BigInteger _g;

    private static BigInteger _pMinusOne;

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

    public static void setUp() throws GeneralCryptoLibException {

        ZpSubgroupLoader zpSubgroupLoader = new ZpSubgroupLoader();

        _p = zpSubgroupLoader.getP();
        _q = zpSubgroupLoader.getQ();
        _g = zpSubgroupLoader.getG();

        _pMinusOne = _p.subtract(BigInteger.ONE);
    }

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

    @Test
    @Parameters(method = "createZpSubgroup")
    public void testZpSubgroupCreationValidation(BigInteger g,
            BigInteger p, BigInteger q, String errorMsg)
            throws GeneralCryptoLibException {

        thrown.expect(GeneralCryptoLibException.class);
        thrown.expectMessage(errorMsg);
        new ZpSubgroup(g, p, q);
    }

    public static Object[] createZpSubgroup() {

        return $($(null, _q, _g, "Zp subgroup generator is null."),
            $(_g, null, _q, "Zp subgroup p parameter is null."),
            $(_g, _p, null, "Zp subgroup q parameter is null."),
            $(_g, _p, BigInteger.ZERO,
                "Zp subgroup q parameter must be greater than or equal to : 1; Found 0"),
            $(_g, _p, _p,
                "Zp subgroup q parameter must be less than or equal to Zp subgroup p parameter minus 1: "
                    + _pMinusOne + "; Found " + _p),
            $(BigInteger.ONE, _p, _q,
                "Zp subgroup generator must be greater than or equal to : 2; Found 1"),
            $(_p, _p, _q,
                "Zp subgroup generator must be less than or equal to Zp subgroup p parameter minus 1: "
                    + _pMinusOne + "; Found " + _p));
    }

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

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

    public static Object[] deserializeZpSubgroup() {

        String nullPParamJsonStr =
            "{\"zpSubgroup\":{\"q\":\"Cw==\",\"p\":null,\"g\":\"Ag==\"}}";
        String nullQParamJsonStr =
            "{\"zpSubgroup\":{\"q\":null,\"p\":\"Fw==\",\"g\":\"Ag==\"}}";
        String nullGeneratorJsonStr =
            "{\"zpSubgroup\":{\"q\":\"Cw==\",\"p\":\"Fw==\",\"g\":null}}";
        String zeroQParamJsonStr =
            "{\"zpSubgroup\":{\"q\":\"AA==\",\"p\":\"Fw==\",\"g\":\"Ag==\"}}";
        String tooLargeQParamJsonStr =
            "{\"zpSubgroup\":{\"q\":\"Fw==\",\"p\":\"Fw==\",\"g\":\"Ag==\"}}";
        String oneGeneratorJsonStr =
            "{\"zpSubgroup\":{\"q\":\"Cw==\",\"p\":\"Fw==\",\"g\":\"AQ==\"}}";
        String tooLargeGeneratorJsonStr =
            "{\"zpSubgroup\":{\"q\":\"Cw==\",\"p\":\"Fw==\",\"g\":\"Fw==\"}}";

        return $($(null, "ZpSubgroup JSON string is null."),
            $("", "ZpSubgroup JSON string is blank."),
            $("   ", "ZpSubgroup JSON string is blank."),
            $(nullPParamJsonStr, "Zp subgroup p parameter is null."),
            $(nullQParamJsonStr, "Zp subgroup q parameter is null."),
            $(nullGeneratorJsonStr, "Zp subgroup generator is null."),
            $(zeroQParamJsonStr,
                "Zp subgroup q parameter must be greater than or equal to : 1; Found 0"),
            $(tooLargeQParamJsonStr,
                "Zp subgroup q parameter must be less than or equal to Zp subgroup p parameter minus 1: "),
            $(oneGeneratorJsonStr,
                "Zp subgroup generator must be greater than or equal to : 2; Found 1"),
            $(tooLargeGeneratorJsonStr,
                "Zp subgroup generator must be less than or equal to Zp subgroup p parameter minus 1: "));
    }
}
