/*
 * 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
 */
/* jshint node:true */
'use strict';

var PlaintextProofTestData = require('../data/plaintext-proof-data');
var ProgressMeterTestData = require('../data/progress-meter-data');
var ValidationTestData = require('../data/validation-data');
var zkProof = require('../../lib/index');
var elGamal = require('scytl-elgamal');

describe('The zero-knowledge proof module should be able to ...', function() {
  var proofService_;

  var group_;
  var anotherGroup_;
  var secret_;
  var ciphertext_;
  var secretForCiphertextWithLessElements_;
  var ciphertextWithLessElements_;
  var secretFromAnotherGroup_;
  var ciphertextFromAnotherGroup_;
  var publicKey_;
  var publicKeyWithLessElements_;
  var publicKeyFromAnotherGroup_;
  var plaintext_;
  var plaintextWithLessElements_;
  var plaintextFromAnotherGroup_;
  var callback_;
  var nonObject_;
  var emptyObject_;
  var nonNumber_;
  var nonPositiveNumber_;
  var nonString_;
  var nonArray_;
  var emptyArray_;
  var nonObjectArray_;
  var nonFunction_;
  var nonAuxiliaryData_;
  var nonProofObject_;
  var proofHandler_;
  var proof_;

  beforeAll(function() {
    proofService_ = zkProof.newService();

    var testData = new PlaintextProofTestData();
    var elGamalService = elGamal.newService();
    group_ = testData.getGroup();
    anotherGroup_ = testData.getAnotherGroup();
    var encryptedElements = testData.getEncryptedElements();
    secret_ = encryptedElements.secret;
    ciphertext_ = elGamalService.newEncryptedElements(
        encryptedElements.gamma, encryptedElements.phis);
    var encryptedElementsWithLessElements =
        testData.getEncryptedElementsWithLessElements();
    secretForCiphertextWithLessElements_ =
        encryptedElementsWithLessElements.secret;
    ciphertextWithLessElements_ = elGamalService.newEncryptedElements(
        encryptedElementsWithLessElements.gamma,
        encryptedElementsWithLessElements.phis);
    var encryptedElementsFromAnotherGroup =
        testData.getEncryptedElementsFromAnotherGroup();
    secretFromAnotherGroup_ = encryptedElementsFromAnotherGroup.secret;
    ciphertextFromAnotherGroup_ = elGamalService.newEncryptedElements(
        encryptedElementsFromAnotherGroup.gamma,
        encryptedElementsFromAnotherGroup.phis);
    publicKey_ = testData.getPublicKey();
    publicKeyWithLessElements_ = testData.getPublicKeyWithLessElements();
    publicKeyFromAnotherGroup_ = testData.getPublicKeyFromAnotherGroup();
    plaintext_ = testData.getPlaintext();
    plaintextWithLessElements_ = testData.getPlaintextWithLessElements();
    plaintextFromAnotherGroup_ = testData.getPlaintextFromAnotherGroup();

    var progressMeterTestData = new ProgressMeterTestData();
    callback_ = progressMeterTestData.progressCallback;

    var validationTestData = new ValidationTestData();
    nonObject_ = validationTestData.getNonObject();
    emptyObject_ = validationTestData.getEmptyObject();
    nonNumber_ = validationTestData.getNonNumber();
    nonPositiveNumber_ = validationTestData.getNonPositiveNumber();
    nonString_ = validationTestData.getNonString();
    nonArray_ = validationTestData.getNonArray();
    emptyArray_ = validationTestData.getEmptyArray();
    nonObjectArray_ = validationTestData.getNonObjectArray();
    nonFunction_ = validationTestData.getNonFunction();
    nonAuxiliaryData_ = validationTestData.getNonAuxiliaryData();
    nonProofObject_ = validationTestData.getNonProofObject();

    proofHandler_ =
        proofService_.newPlaintextProofHandler(group_).init(publicKey_);
    proof_ = proofHandler_.generate(secret_, plaintext_, ciphertext_);
  });

  beforeEach(function() {
    proofHandler_ =
        proofService_.newPlaintextProofHandler(group_).init(publicKey_);
  });

  describe('create a zero-knowledge proof service that should be able to ..', function() {
    describe('create a plaintext proof handler that should be able to', function() {
      it('throw an error when being created, using invalid input data',
         function() {
           expect(function() {
             proofService_.newPlaintextProofHandler();
           }).toThrow();

           expect(function() {
             proofService_.newPlaintextProofHandler(undefined);
           }).toThrow();

           expect(function() {
             proofService_.newPlaintextProofHandler(null);
           }).toThrow();

           expect(function() {
             proofService_.newPlaintextProofHandler(nonObject_);
           }).toThrow();

           expect(function() {
             proofService_.newPlaintextProofHandler(emptyObject_);
           }).toThrow();
         });

      it('throw an error when being initialized, using invalid input data',
         function() {
           expect(function() {
             proofHandler_.init(undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.init(null);
           }).toThrow();

           expect(function() {
             proofHandler_.init(nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(publicKeyFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when generating a plaintext proof, using an invalid secret',
         function() {
           expect(function() {
             proofHandler_.generate(undefined, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(null, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(nonObject_, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(emptyObject_, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secretFromAnotherGroup_, plaintext_, ciphertext_);
           }).toThrow();
         });

      it('throw an error when generating a plaintext proof, using an invalid plaintext',
         function() {
           expect(function() {
             proofHandler_.generate(secret_, undefined, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, null, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, nonArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, emptyArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, nonObjectArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintextWithLessElements_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintextFromAnotherGroup_, ciphertext_);
           }).toThrow();
         });

      it('throw an error when generating a plaintext proof, using an invalid ciphertext',
         function() {
           expect(function() {
             proofHandler_.generate(secret_, plaintext_, undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, plaintext_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, plaintext_, nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, plaintext_, emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintext_, ciphertextWithLessElements_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintext_, ciphertextFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when generating a plaintext proof, using invalid optional data',
         function() {
           expect(function() {
             proofHandler_.generate(
                 secret_, plaintext_, ciphertext_, {data: nonAuxiliaryData_});
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintext_, ciphertext_,
                 {preComputation: nonObject_});
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, plaintext_, ciphertext_,
                 {preComputation: nonProofObject_});
           }).toThrow();
         });

      it('throw an error when verifying a plaintext proof, using an invalid proof',
         function() {
           expect(function() {
             proofHandler_.verify(undefined, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(null, plaintext_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(nonProofObject_, plaintext_, ciphertext_);
           }).toThrow();
         });

      it('throw an error when verifying a plaintext proof, using an invalid plaintext',
         function() {
           expect(function() {
             proofHandler_.verify(proof_, undefined, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, null, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, nonArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, emptyArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, nonObjectArray_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, plaintextWithLessElements_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, plaintextFromAnotherGroup_, ciphertext_);
           }).toThrow();
         });

      it('throw an error when verifying a plaintext proof, using an invalid ciphertext',
         function() {
           expect(function() {
             proofHandler_.verify(proof_, plaintext_, undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, plaintext_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, plaintext_, nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, plaintext_, emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, ciphertextWithLessElements_, ciphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, plaintext_, ciphertextFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when verifying a plaintext proof, using invalid optional data',
         function() {
           expect(function() {
             proofHandler_.verify(
                 proof_, plaintext_, ciphertext_, {data: nonAuxiliaryData_});
           }).toThrow();
         });

      it('throw an error when measuring plaintext proof progress, using invalid input data',
         function() {
           expect(function() {
             proofHandler_.measureProgress();
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(null);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(nonFunction_);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, nonNumber_);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, nonPositiveNumber_);
           }).toThrow();
         });
    });
  });
});
