/*
 * 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
 */
beforeEach(function() {
  'use strict';

  cryptoPRNG.startEntropyCollection();

  cryptoPRNG.stopEntropyCollectionAndCreatePRNG();

  cryptolibPolicies = {
    homomorphic: {
      cipher: {
        secureRandom:
            {provider: Config.homomorphic.cipher.secureRandom.provider.SCYTL}
      }
    },
    asymmetric: {
      keypair: {
        encryption: {
          algorithm: Config.asymmetric.keypair.encryption.algorithm.RSA,
          provider: Config.asymmetric.keypair.encryption.provider.FORGE,
          keyLength: Config.asymmetric.keypair.encryption.keyLength.KL_2048,
          publicExponent: Config.asymmetric.keypair.encryption.publicExponent.F4
        },
        secureRandom:
            {provider: Config.asymmetric.keypair.secureRandom.provider.SCYTL}
      },
      signer: {
        algorithm: Config.asymmetric.signer.algorithm.RSA,
        provider: Config.asymmetric.signer.provider.FORGE,
        hash: Config.asymmetric.signer.hash.SHA256,
        padding: {
          PSS: {
            name: Config.asymmetric.signer.padding.PSS.name,
            hash: Config.asymmetric.signer.padding.PSS.hash.SHA256,
            mask: {
              MGF1: {
                name: Config.asymmetric.signer.padding.PSS.mask.MGF1.name,
                hash: Config.asymmetric.signer.padding.PSS.mask.MGF1.hash.SHA256
              }
            },
            saltLengthBytes:
                Config.asymmetric.signer.padding.PSS.saltLengthBytes.SL_32
          }
        },
        publicExponent: Config.asymmetric.signer.publicExponent.F4,
        secureRandom:
            {provider: Config.asymmetric.signer.secureRandom.provider.SCYTL}
      },
      cipher: {
        algorithm: Config.asymmetric.cipher.algorithm.RSA_KEM,
        secretKeyLengthBytes: Config.asymmetric.cipher.algorithm.RSA_KEM
                                  .secretKeyLengthBytes.KL_16,
        ivLengthBytes:
            Config.asymmetric.cipher.algorithm.RSA_KEM.ivLengthBytes.IVL_12,
        tagLengthBytes:
            Config.asymmetric.cipher.algorithm.RSA_KEM.tagLengthBytes.TL_16,
        deriver: Config.asymmetric.cipher.algorithm.RSA_KEM.deriver.name.KDF1,
        hash: Config.asymmetric.cipher.algorithm.RSA_KEM.deriver.messagedigest
                  .algorithm.SHA256,
        symmetricCipher:
            Config.asymmetric.cipher.algorithm.RSA_KEM.cipher.AESGCM,
        provider: Config.asymmetric.cipher.provider.FORGE,
        secureRandom:
            {provider: Config.asymmetric.cipher.secureRandom.provider.SCYTL}
      }
    },
    primitives: {
      secureRandom: {provider: Config.primitives.secureRandom.provider.SCYTL},
      messagedigest: {
        algorithm: Config.primitives.messagedigest.algorithm.SHA256,
        provider: Config.primitives.messagedigest.provider.FORGE
      },
      derivation: {
        pbkdf: {
          provider: Config.primitives.derivation.pbkdf.provider.FORGE,
          hash: Config.primitives.derivation.pbkdf.hash.SHA256,
          saltLengthBytes:
              Config.primitives.derivation.pbkdf.saltLengthBytes.SL_20,
          keyLengthBytes:
              Config.primitives.derivation.pbkdf.keyLengthBytes.KL_32,
          iterations: Config.primitives.derivation.pbkdf.iterations.I_1
        }
      }
    },
    stores: {},
    symmetric: {
      secretkey: {
        encryption: {
          lengthBytes: Config.symmetric.secretkey.encryption.lengthBytes.SK_16
        },
        mac: {lengthBytes: Config.symmetric.secretkey.mac.lengthBytes.SK_32},
        secureRandom:
            {provider: Config.symmetric.secretkey.secureRandom.provider.SCYTL}
      },
      cipher: {
        provider: Config.symmetric.cipher.provider.FORGE,
        algorithm: {
          AES128_GCM: {
            name: Config.symmetric.cipher.algorithm.AES128_GCM.name,
            keyLengthBytes:
                Config.symmetric.cipher.algorithm.AES128_GCM.keyLengthBytes,
            tagLengthBytes:
                Config.symmetric.cipher.algorithm.AES128_GCM.tagLengthBytes
          }
        },
        initializationVectorLengthBytes:
            Config.symmetric.cipher.initializationVectorLengthBytes.IV_12,
        secureRandom:
            {provider: Config.symmetric.cipher.secureRandom.provider.SCYTL}
      },
      mac: {
        hash: Config.symmetric.mac.hash.SHA256,
        provider: Config.symmetric.mac.provider.FORGE
      }
    },
    proofs: {
      secureRandom: {provider: Config.proofs.secureRandom.provider.SCYTL},
      messagedigest: {
        algorithm: Config.proofs.messagedigest.algorithm.SHA256,
        provider: Config.proofs.messagedigest.provider.FORGE
      },
      charset: Config.proofs.charset.UTF8
    },
    digitalenvelope: {
      symmetric: {
        secretkey: {
          encryption: {
            lengthBytes: Config.symmetric.secretkey.encryption.lengthBytes.SK_16
          },
          mac: {lengthBytes: Config.symmetric.secretkey.mac.lengthBytes.SK_32},
          secureRandom: {
            provider: Config.symmetric.secretkey.secureRandom.provider.SCYTL
          }
        },
        cipher: {
          provider: Config.symmetric.cipher.provider.FORGE,
          algorithm: {
            AES128_GCM: {
              name: Config.symmetric.cipher.algorithm.AES128_GCM.name,
              keyLengthBytes:
                  Config.symmetric.cipher.algorithm.AES128_GCM.keyLengthBytes,
              tagLengthBytes:
                  Config.symmetric.cipher.algorithm.AES128_GCM.tagLengthBytes
            }
          },
          initializationVectorLengthBytes:
              Config.symmetric.cipher.initializationVectorLengthBytes.IV_12,
          secureRandom:
              {provider: Config.symmetric.cipher.secureRandom.provider.SCYTL}
        },
        mac: {
          hash: Config.symmetric.mac.hash.SHA256,
          provider: Config.symmetric.mac.provider.FORGE
        }
      },
      asymmetric: {
        cipher: {
          algorithm: Config.asymmetric.cipher.algorithm.RSA_KEM,
          secretKeyLengthBytes: Config.asymmetric.cipher.algorithm.RSA_KEM
                                    .secretKeyLengthBytes.KL_16,
          ivLengthBytes:
              Config.asymmetric.cipher.algorithm.RSA_KEM.ivLengthBytes.IVL_12,
          tagLengthBytes:
              Config.asymmetric.cipher.algorithm.RSA_KEM.tagLengthBytes.TL_16,
          deriver: Config.asymmetric.cipher.algorithm.RSA_KEM.deriver.name.KDF1,
          hash: Config.asymmetric.cipher.algorithm.RSA_KEM.deriver.messagedigest
                    .algorithm.SHA256,
          symmetricCipher:
              Config.asymmetric.cipher.algorithm.RSA_KEM.cipher.AESGCM,
          provider: Config.asymmetric.cipher.provider.FORGE,
          secureRandom: {
            provider: Config.asymmetric.cipher.secureRandom.provider.SCYTL
          }
        }
      }
    }
  };
});

cryptolib.modules.test = cryptolib.modules.test || {};
cryptolib.modules.test.test2 = cryptolib.modules.test.test2 || {};

cryptolib.modules.test.test1 = function(box) {
  'use strict';

  box.test = box.test || {};
  box.test.test1 = {};
};

cryptolib.modules.test.test2 = function(box) {
  'use strict';

  box.test = box.test || {};
  box.test.test2 = {};
};

cryptolib.modules.test.test2.test3 = function(box) {
  'use strict';

  box.test = box.test || {};
  box.test.test2 = box.test.test2 || {};
  box.test.test2.test3 = {};
};

describe('Cryptolib: ', function() {
  'use strict';

  it('Should exist a Cryptolib sandbox', function() {

    cryptolib('*', function(box) {
      expect(box).toBeDefined();
    });
  });

  it('Should have a method that returns the modules names', function() {
    cryptolib('*', function(box) {
      expect(box.getModuleNames).toBeDefined();
    });
  });

  it('Should redefine forge global variable', function() {
    cryptolib('*', function(box) {
      expect(box.forge).toBeDefined();
    });
  });

  it('Should contain a utils modules', function() {
    cryptolib('*', function(box) {
      expect(box.getModuleNames()).toContain('commons');
    });
  });

  it('Should contain all modules', function() {
    cryptolib('*', function(box) {
      expect(box.getModuleNames()).toContain('certificates');
      expect(box.getModuleNames()).toContain('symmetric');
      expect(box.getModuleNames()).toContain('primitives');
      expect(box.getModuleNames()).toContain('asymmetric');
      expect(box.getModuleNames()).toContain('stores');
      expect(box.getModuleNames()).toContain('commons');
    });
  });

  it('should contain a test.test1 module', function() {
    cryptolib('test.test1', function(box) {
      expect(box.getModuleNames()).toContain('test');
    });
  });

  it('should contain a test.test2.test3 module', function() {
    cryptolib('test.test2.test3', function(box) {
      expect(box.getModuleNames()).toContain('test');
    });
  });

  it('should contain a test module', function() {
    cryptolib('test', function(box) {
      expect(box.getModuleNames()).toContain('test');
    });
  });

  it('should contain all test submodules', function() {
    cryptolib('test.*', function(box) {
      expect(box.getModuleNames()).toContain('test');
    });
  });

  describe('policies', function() {
    it('should be defined a policies objects', function() {
      cryptolib('test.*', function(box) {
        expect(box.policies).toBeDefined();
      });
    });

    it('should be defined a policies objects', function() {
      cryptolib('test.*', function(box) {
        expect(box.policies.asymmetric.keypair.encryption.algorithm)
            .toEqual(Config.asymmetric.keypair.encryption.algorithm.RSA);
      });
    });
  });

  describe('Config', function() {
    it('should be an immutable object. i.e. we cannot change any property',
       function() {
         cryptolib('*', function() {
           expect(function() {
             Config.asymmetric.keypair.encryption.algorithm.RSA = 'SCYTL';
           }).toThrow();
           expect(Config.asymmetric.keypair.encryption.algorithm.RSA)
               .toEqual('RSA');
         });
       });
  });

  describe('Cryptolib: ', function() {
    it('should be defined a policies objects', function() {
      cryptolib('test.*', function(box) {
        expect(box.policies.asymmetric.keypair.encryption.algorithm)
            .toEqual(Config.asymmetric.keypair.encryption.algorithm.RSA);
      });
    });
  });
});
