/*
 * 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
 */
/**
 * Created by riglesias on 17/03/15.
 */
package com.scytl.products.ov.ei.services.domain.service;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt;
import com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.crypto.InputDataFormatterService;
import com.scytl.products.ov.ei.services.domain.model.vote.ReceiptFactoryImpl;

/**
 * Test class for the ReceiptGenerator
 */
@RunWith(MockitoJUnitRunner.class)
public class ReceiptFactoryTest {

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

    @Mock
    InputDataFormatterService inputDataFormatterServiceMock;

    @Mock
    PrimitivesServiceAPI primitivesServiceMock;

    @Mock
    private Logger logger;

    private static final String authToken = "{\"signature\":\"signature\"}";

    private static final String encryptedOptions =
        "132412342134;asdfasdfasdf.AVeryLongStringWithTheEncryptedOptionsafasdf12312423asdfnmlourjvlmaldjfoqwer14ad34fas1avjsjjj;.";

    private static Vote vote;

    @Spy
    @InjectMocks
    ReceiptFactoryImpl receiptFactory;

    @Before
    public void setup() {
        vote = new Vote();
        vote.setAuthenticationToken("authenticationToken");
        vote.setAuthenticationTokenSignature("authenticationTokenSignature");
        vote.setBallotBoxId("ballotBoxId");
        vote.setBallotId("ballotId");
        vote.setCertificate("certificate");
        vote.setCipherTextExponentiations("cipherTextExponentiations");
        vote.setCorrectnessIds("correctnessIds");
        vote.setCredentialId("credentialId");
        vote.setElectionEventId("electionEventId");
        vote.setEncryptedOptions("encryptedOptions");
        vote.setEncryptedPartialChoiceCodes("encryptedPartialChoiceCodes");
        vote.setEncryptedWriteIns("encryptedWriteIns");
        vote.setExponentiationProof("exponentiationProof");
        vote.setPlaintextEqualityProof("plaintextEqualityProof");
        vote.setSchnorrProof("schnorrProof");
        vote.setSignature("signature");
        vote.setTenantId("tenantId");
        vote.setVerificationCardId("verificationCardId");
        vote.setVerificationCardPKSignature("verificationCardPKSignature");
        vote.setVerificationCardPublicKey("verificationCardPublicKey");
        vote.setVerificationCardSetId("verificationCardSetId");
        vote.setVotingCardId("votingCardId");
    }

    @Test
    public void generatesReceiptCorrectlyWithoutConfirmation()
            throws ApplicationException, CryptographicOperationException, GeneralCryptoLibException {
        vote.setEncryptedOptions(encryptedOptions);
        vote.setElectionEventId("1");
        vote.setVotingCardId("1");
        vote.setVerificationCardPublicKey("PK");

        vote.setCipherTextExponentiations(null);
        vote.setPlaintextEqualityProof(null);
        vote.setEncryptedPartialChoiceCodes(null);
        vote.setExponentiationProof(null);

        when(inputDataFormatterServiceMock.concatenate(vote.getEncryptedOptions(), authToken, vote.getElectionEventId(),
            vote.getVotingCardId(), vote.getVerificationCardPublicKey())).thenReturn("concatenation".getBytes());

        when(primitivesServiceMock.getHash(Mockito.any(byte[].class))).thenReturn("hash".getBytes());

        Receipt result = receiptFactory.generate(vote, authToken);

        assertNotNull(result);
    }

    @Test
    public void generatesReceiptCorrectlyWithConfirmation()
            throws ApplicationException, CryptographicOperationException, GeneralCryptoLibException {
        vote.setEncryptedOptions(encryptedOptions);
        vote.setElectionEventId("1");
        vote.setVotingCardId("1");
        vote.setVerificationCardPublicKey("PK");

        when(inputDataFormatterServiceMock.concatenate(vote.getEncryptedOptions(), authToken, vote.getElectionEventId(),
            vote.getVotingCardId(), vote.getVerificationCardPublicKey())).thenReturn("concatenation".getBytes());

        when(primitivesServiceMock.getHash(Mockito.any(byte[].class))).thenReturn("hash".getBytes());

        Receipt result = receiptFactory.generate(vote, authToken);

        assertNotNull(result);
    }

    @Test
    public void generatesReceiptVoteNull() throws ApplicationException, CryptographicOperationException {
        vote.setEncryptedOptions(encryptedOptions);
        vote.setElectionEventId("1");
        vote.setVotingCardId("1");
        vote.setVerificationCardPublicKey("PK");

        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(null, authToken);
    }

    @Test
    public void generatesReceiptAuthTokenNull() throws ApplicationException, CryptographicOperationException {
        vote.setEncryptedOptions(encryptedOptions);
        vote.setElectionEventId("1");
        vote.setVotingCardId("1");
        vote.setVerificationCardPublicKey("PK");

        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, null);
    }

    @Test
    public void generatesReceiptAuhtTokenEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setEncryptedOptions(encryptedOptions);
        vote.setElectionEventId("1");
        vote.setVotingCardId("1");
        vote.setVerificationCardPublicKey("PK");

        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, "");
    }

    @Test
    public void generatesReceiptFailsAndException() throws ApplicationException, CryptographicOperationException {
        String error = "error";
        expectedException.expect(ApplicationException.class);
        expectedException.expectMessage(error);
        doThrow(new ApplicationException(error)).when(receiptFactory).generate(vote, error);
        receiptFactory.generate(vote, error);
    }

    @Test
    public void generatesReceiptAuthenticationTokenNull() throws ApplicationException, CryptographicOperationException {
        vote.setAuthenticationToken(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptAuthenticationTokenSignatureNull()
            throws ApplicationException, CryptographicOperationException {
        vote.setAuthenticationTokenSignature(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptBallotBoxIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setBallotBoxId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptBallotIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setBallotId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesCertificateNull() throws ApplicationException, CryptographicOperationException {
        vote.setCertificate(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptCorrectnessIdsNull() throws ApplicationException, CryptographicOperationException {
        vote.setCorrectnessIds(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptCredentialIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setCredentialId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptElectionEventIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setElectionEventId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptEncryptedOptionsNull() throws ApplicationException, CryptographicOperationException {
        vote.setEncryptedOptions(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptSchnorrProofNull() throws ApplicationException, CryptographicOperationException {
        vote.setSchnorrProof(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptSignatureNull() throws ApplicationException, CryptographicOperationException {
        vote.setSignature(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptTenantIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setTenantId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardPKSignatureNull()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardPKSignature(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardPublicKeyNull()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardPublicKey(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardSetIdNull()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardSetId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVotingCardIdNull() throws ApplicationException, CryptographicOperationException {
        vote.setVotingCardId(null);
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptAuthenticationTokenEmpty()
            throws ApplicationException, CryptographicOperationException {
        vote.setAuthenticationToken("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptAuthenticationTokenSignatureEmpty()
            throws ApplicationException, CryptographicOperationException {
        vote.setAuthenticationTokenSignature("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptBallotBoxIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setBallotBoxId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptBallotIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setBallotId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesCertificateEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setCertificate("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptCorrectnessIdsEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setCorrectnessIds("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptCredentialIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setCredentialId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptElectionEventIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setElectionEventId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptEncryptedOptionsEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setEncryptedOptions("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptSchnorrProofEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setSchnorrProof("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptSignatureEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setSignature("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptTenantIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setTenantId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardPKSignatureEmpty()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardPKSignature("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardPublicKeyEmpty()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardPublicKey("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVerificationCardSetIdEmpty()
            throws ApplicationException, CryptographicOperationException {
        vote.setVerificationCardSetId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }

    @Test
    public void generatesReceiptVotingCardIdEmpty() throws ApplicationException, CryptographicOperationException {
        vote.setVotingCardId("");
        expectedException.expect(ApplicationException.class);
        receiptFactory.generate(vote, authToken);
    }
}
