/*
 * 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
 */
describe('Secure Random Generator: ', function() {
  'use strict';

  it('should exist a cryptolib module', function() {
    cryptolib('primitives.securerandom', function(box) {
      expect(box.primitives.securerandom).toBeDefined();
    });

  });

  describe('CryptoScytlRandomBytes: ', function() {
    it('should generate a random array of bytes', function() {
      cryptolib('primitives.securerandom', function(box) {

        var secureRandomFactory =
            new box.primitives.securerandom.factory.SecureRandomFactory();
        var srg = secureRandomFactory.getCryptoRandomBytes();
        expect(srg.nextRandom(10)).toBeDefined();
      });
    });

    it('should throw an exception when a negative length is passed',
       function() {
         cryptolib('primitives.securerandom', function(box) {

           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomBytes();

           var thrownException = false;
           try {
             secureRandom.nextRandom(-1);
           } catch (error) {
             thrownException = true;
           }

           expect(thrownException).toBeTruthy();
         });
       });

    it('should throw an exception when a length that is not a number is passed',
       function() {
         cryptolib('primitives.securerandom', function(box) {
           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomBytes();

           var thrownException = false;
           try {
             secureRandom.nextRandom('AAA');
           } catch (error) {
             thrownException = true;
           }

           expect(thrownException).toBeTruthy();
         });
       });

    it('should throw an exception when a large length is passed', function() {
      cryptolib('primitives.securerandom', function(box) {
        var secureRandomFactory =
            new box.primitives.securerandom.factory.SecureRandomFactory();
        var secureRandom = secureRandomFactory.getCryptoRandomBytes();

        var thrownException = false;
        try {
          secureRandom.nextRandom(4097);
        } catch (error) {
          thrownException = true;
        }

        expect(thrownException).toBeTruthy();
      });
    });

    it('throw an error when the given provider is wrong.', function() {
      var f = function(box) {
        var secureRandomFactory =
            new box.primitives.securerandom.factory.SecureRandomFactory();
        var thrownError = false;
        try {
          secureRandomFactory.getCryptoRandomBytes();
        } catch (error) {
          thrownError = true;
        }
        expect(thrownError).toBeTruthy();
      };
      f.policies = {primitives: {secureRandom: {provider: 'WRONG'}}};
      cryptolib('primitives.securerandom', f);
    });
  });

  describe('CryptoScytlRandomInteger: ', function() {
    it('should generate a random BigInteger specifying the number of bytes this number should have',
       function() {
         cryptolib('primitives.securerandom', function(box) {
           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomInteger();

           var n;

           for (var length = 1; length <= 100; length++) {
             n = ((new box.forge.jsbn.BigInteger('10')).pow(length))
                     .subtract(box.forge.jsbn.BigInteger.ONE);

             var randomBigInteger = secureRandom.nextRandom(length);

             expect(randomBigInteger).toBeDefined();

             var greaterOrEqualThanZero = false;

             if (randomBigInteger.compareTo(forge.jsbn.BigInteger.ZERO) >= 0) {
               greaterOrEqualThanZero = true;
             }

             expect(greaterOrEqualThanZero).toBeTruthy();

             var withinRange = false;

             if (randomBigInteger.compareTo(n) <= 0) {
               withinRange = true;
             }

             expect(withinRange).toBeTruthy();
           }
         });
       });

    it('should generate a random BigInteger according to the specified bit length',
       function() {
         cryptolib('primitives.securerandom', function(box) {
           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomInteger();

           for (var bitLength = 1; bitLength <= 300; bitLength++) {
             var randomBigInteger = secureRandom.nextRandomByBits(bitLength);
             expect(randomBigInteger).toBeDefined();
             expect(randomBigInteger.bitLength() <= bitLength).toBeTruthy();
           }
         });
       });

    it('should throw an exception when a negative length is passed',
       function() {
         cryptolib('primitives.securerandom', function(box) {
           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomInteger();

           var thrownException = false;
           try {
             secureRandom.nextRandom(-1);
           } catch (error) {
             thrownException = true;
           }

           expect(thrownException).toBeTruthy();
         });
       });

    it('should throw an exception when a length that is not a number is passed',
       function() {
         cryptolib('primitives.securerandom', function(box) {
           var secureRandomFactory =
               new box.primitives.securerandom.factory.SecureRandomFactory();
           var secureRandom = secureRandomFactory.getCryptoRandomInteger();

           var thrownException = false;
           try {
             secureRandom.nextRandom('AAA');
           } catch (error) {
             thrownException = true;
           }

           expect(thrownException).toBeTruthy();
         });
       });

    it('should throw an exception when a large length is passed', function() {
      cryptolib('primitives.securerandom', function(box) {
        var secureRandomFactory =
            new box.primitives.securerandom.factory.SecureRandomFactory();
        var secureRandom = secureRandomFactory.getCryptoRandomInteger();

        var thrownException = false;
        try {
          secureRandom.nextRandom(513);
        } catch (error) {
          thrownException = true;
        }

        expect(thrownException).toBeTruthy();
      });
    });

    it('throw an error when the given provider is wrong', function() {
      var f = function(box) {
        var secureRandomFactory =
            new box.primitives.securerandom.factory.SecureRandomFactory();
        var thrownError = false;
        try {
          secureRandomFactory.getCryptoRandomInteger();
        } catch (error) {
          thrownError = true;
        }
        expect(thrownError).toBeTruthy();
      };

      f.policies = {primitives: {secureRandom: {provider: 'WRONG'}}};

      cryptolib('primitives.securerandom', f);
    });
  });
});
