diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 2cb4e58b..1114125e 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -1,155 +1,156 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * * Author(s): * Maximilian Krambach */ /* global describe, it, expect, Gpgmejs */ /* global inputvalues, fixedLengthString */ describe('Encryption', function () { it('Successful encrypt', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); done(); }); }); }); it('Successful encrypt 5 MB', function (done) { let prm = Gpgmejs.init(); let data = fixedLengthString(5); prm.then(function (context) { context.encrypt( data, inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); done(); }); }); }).timeout(10000); it('Successful encrypt 20 MB', function (done) { let prm = Gpgmejs.init(); let data = fixedLengthString(20); prm.then(function (context) { context.encrypt( data, inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); done(); }); }); }).timeout(20000); it('Successful encrypt 50 MB', function (done) { let prm = Gpgmejs.init(); let data = fixedLengthString(50); prm.then(function (context) { context.encrypt( data, inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); done(); }); }); }).timeout(20000); it('Sending encryption without keys fails', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, null).then(function (answer) { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an('Error'); expect(error.code).to.equal('MSG_INCOMPLETE'); done(); }); }); }); it('Sending encryption without data fails', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( null, inputvalues.encrypt.good.keyid).then(function (answer) { expect(answer).to.be.undefined; }, function (error) { expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('MSG_INCOMPLETE'); done(); }); }); }); it('Sending encryption with non existing keys fails', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, inputvalues.encrypt.bad.fingerprint).then(function (answer) { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an('Error'); expect(error.code).to.not.be.undefined; expect(error.code).to.equal('GNUPG_ERROR'); done(); }); }); }).timeout(5000); - it('Overly large message ( > 65MB) is rejected', function (done) { + it('Overly large message ( > 64MB) is rejected', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( fixedLengthString(65), inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an.instanceof(Error); - // expect(error.code).to.equal('GNUPG_ERROR'); // TODO: there is a 64 MB hard limit at least in chrome at: // chromium//extensions/renderer/messaging_util.cc: // kMaxMessageLength + // The error will be a browser error, not from gnupg or from + // this library done(); }); }); }).timeout(8000); // TODO check different valid parameter }); diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 358757b0..09c43f73 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -1,332 +1,350 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * * Author(s): * Maximilian Krambach */ import {createMessage} from './Message'; import {createKey} from './Key'; import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; export class GPGME_Keyring { constructor(){ } /** * @param {String} pattern (optional) pattern A pattern to search for, * in userIds or KeyIds * @param {Boolean} prepare_sync (optional, default true) if set to true, * Key.armor and Key.hasSecret will be called, so they can be used * inmediately. This allows for full synchronous use. If set to false, * these will initially only be available as Promises in getArmor() and * getHasSecret() * @param {Boolean} search (optional) retrieve the Keys from servers with * the method(s) defined in gnupg (e.g. WKD/HKP lookup) * @returns {Promise.>} * */ getKeys(pattern, prepare_sync, search){ return new Promise(function(resolve, reject) { let msg = createMessage('keylist'); if (pattern !== undefined){ msg.setParameter('keys', pattern); } msg.setParameter('sigs', true); if (search === true){ msg.setParameter('locate', true); } msg.post().then(function(result){ let resultset = []; - let promises = []; if (result.keys.length === 0){ resolve([]); } else { - for (let i=0; i< result.keys.length; i++){ - let k = createKey(result.keys[i].fingerprint); - k.setKeyData(result.keys[i]); - if (prepare_sync === true){ - promises.push(k.getArmor()); - promises.push(k.getHasSecret()); - } - resultset.push(k); - } - if (promises.length > 0) { - Promise.all(promises).then(function() { - resolve(resultset); - }, function(error){ - reject(error); - }); + let secondrequest; + if (prepare_sync === true) { + secondrequest = function() { + msg.setParameter('secret', true); + return msg.post(); + }; } else { - resolve(resultset); + secondrequest = function() { + return Promise.resolve(true); + }; } + secondrequest().then(function(answer) { + for (let i=0; i < result.keys.length; i++){ + if (prepare_sync === true){ + result.keys[i].hasSecret = false; + if (answer && answer.keys) { + for (let j=0; j < answer.keys.length; j++ ){ + if (result.keys[i].fingerprint === + answer.keys[j].fingerprint + ) { + if (answer.keys[j].secret === true){ + result.keys[i].hasSecret = true; + } + break; + } + } + // TODO getArmor() to be used in sync + } + } + let k = createKey(result.keys[i].fingerprint); + k.setKeyData(result.keys[i]); + resultset.push(k); + } + resolve(resultset); + }, function(error){ + reject(error); + }); } }); }); } /** * Fetches the armored public Key blocks for all Keys matchin the pattern * (if no pattern is given, fetches all known to gnupg) * @param {String|Array} pattern (optional) * @returns {Promise} Armored Key blocks */ getKeysArmored(pattern) { return new Promise(function(resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); if (pattern !== undefined){ msg.setParameter('keys', pattern); } msg.post().then(function(result){ resolve(result.data); }, function(error){ reject(error); }); }); } /** * Returns the Key to be used by default for signing operations, * looking up the gpg configuration, or returning the first key that * contains a secret key. * @returns {Promise} * * * TODO: getHasSecret always returns false at this moment, so this fucntion * still does not fully work as intended. * * @async */ getDefaultKey() { let me = this; return new Promise(function(resolve, reject){ let msg = createMessage('config_opt'); msg.setParameter('component', 'gpg'); msg.setParameter('option', 'default-key'); msg.post().then(function(response){ if (response.value !== undefined && response.value.hasOwnProperty('string') && typeof(response.value.string) === 'string' ){ me.getKeys(response.value.string,true).then(function(keys){ if(keys.length === 1){ resolve(keys[0]); } else { reject(gpgme_error('KEY_NO_DEFAULT')); } }, function(error){ reject(error); }); } else { // TODO: this is overly 'expensive' in communication // and probably performance, too me.getKeys(null,true).then(function(keys){ for (let i=0; i < keys.length; i++){ if (keys[i].get('hasSecret') === true){ resolve(keys[i]); break; } if (i === keys.length -1){ reject(gpgme_error('KEY_NO_DEFAULT')); } } }, function(error){ reject(error); }); } }, function(error){ reject(error); }); }); } /** * * @param {String} armored Armored Key block of the Key(s) to be imported * into gnupg * @param {Boolean} prepare_sync prepare the keys for synched use * (see getKeys()). * * @returns {Promise} result: A summary and an array of Keys * considered * * @returns result.summary: Numerical summary of the result. See the * feedbackValues variable for available values and the gnupg documentation * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html * for details on their meaning. * @returns {Array} result.Keys: Array of objects containing: * @returns {GPGME_Key} Key.key The resulting key * @returns {String} Key.status: * 'nochange' if the Key was not changed, * 'newkey' if the Key was imported in gpg, and did not exist * previously, * 'change' if the key existed, but details were updated. For * details, Key.changes is available. * @returns {Boolean} Key.changes.userId: userIds changed * @returns {Boolean} Key.changes.signature: signatures changed * @returns {Boolean} Key.changes.subkey: subkeys changed */ importKey(armored, prepare_sync) { let feedbackValues = ['considered', 'no_user_id', 'imported', 'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys', 'new_signatures', 'new_revocations', 'secret_read', 'secret_imported', 'secret_unchanged', 'skipped_new_keys', 'not_imported', 'skipped_v3_keys']; if (!armored || typeof(armored) !== 'string'){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let me = this; return new Promise(function(resolve, reject){ let msg = createMessage('import'); msg.setParameter('data', armored); msg.post().then(function(response){ let infos = {}; let fprs = []; for (let res=0; res" * @param {*} algo (optional) algorithm (and optionally key size to be * used. See {@link supportedKeyAlgos } below for supported values. * @param {Date} expires (optional) Expiration date. If not set, expiration * will be set to 'never' * * @return {Promise} */ generateKey(userId, algo = 'default', expires){ if ( typeof(userId) !== 'string' || supportedKeyAlgos.indexOf(algo) < 0 || (expires && !(expires instanceof Date)) ){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let me = this; return new Promise(function(resolve, reject){ let msg = createMessage('createkey'); msg.setParameter('userid', userId); msg.setParameter('algo', algo ); if (expires){ msg.setParameter('expires', Math.floor(expires.valueOf()/1000)); } msg.post().then(function(response){ me.getKeys(response.fingerprint, true).then( // TODO make prepare_sync (second parameter) optional here. function(result){ resolve(result); }, function(error){ reject(error); }); }, function(error) { reject(error); }); }); } } /** * A list of algorithms supported for key generation. */ const supportedKeyAlgos = [ 'default', 'rsa', 'rsa2048', 'rsa3072', 'rsa4096', 'dsa', 'dsa2048', 'dsa3072', 'dsa4096', 'elg', 'elg2048', 'elg3072', 'elg4096', 'ed25519', 'cv25519', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'NIST P-256', 'NIST P-384', 'NIST P-521' ]; \ No newline at end of file diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 169e8ebc..04e15ef3 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -1,391 +1,393 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import './node_modules/mocha/mocha'; /*global mocha, it, describe*/ import './node_modules/chai/chai';/*global chai*/ import { helper_params as hp } from './unittest_inputvalues'; import { message_params as mp } from './unittest_inputvalues'; import { whatever_params as wp } from './unittest_inputvalues'; import { key_params as kp } from './unittest_inputvalues'; import { Connection } from './src/Connection'; import { gpgme_error } from './src/Errors'; import { toKeyIdArray , isFingerprint } from './src/Helpers'; import { GPGME_Key , createKey } from './src/Key'; import { GPGME_Keyring } from './src/Keyring'; import {GPGME_Message, createMessage} from './src/Message'; mocha.setup('bdd'); const expect = chai.expect; chai.config.includeStack = true; function unittests (){ describe('Connection testing', function(){ it('Connecting', function(done) { let conn0 = new Connection; conn0.checkConnection().then(function(answer) { expect(answer).to.not.be.empty; expect(answer.gpgme).to.not.be.undefined; expect(answer.gpgme).to.be.a('string'); expect(answer.info).to.be.an('Array'); expect(conn0.disconnect).to.be.a('function'); expect(conn0.post).to.be.a('function'); done(); }); }); it('Disconnecting', function(done) { let conn0 = new Connection; conn0.checkConnection(false).then(function(answer) { expect(answer).to.be.true; conn0.disconnect(); conn0.checkConnection(false).then(function(result) { expect(result).to.be.false; done(); }); }); }); }); describe('Error Object handling', function(){ // TODO: new GPGME_Error codes it('check the Timeout error', function(){ let test0 = gpgme_error('CONN_TIMEOUT'); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('CONN_TIMEOUT'); }); it('Error Object returns generic code if code is not listed', function(){ let test0 = gpgme_error(hp.invalidErrorCode); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('GENERIC_ERROR'); } ); it('Warnings like PARAM_IGNORED should not return errors', function(){ let test0 = gpgme_error('PARAM_IGNORED'); expect(test0).to.be.null; }); }); describe('Fingerprint checking', function(){ it('isFingerprint(): valid Fingerprint', function(){ let test0 = isFingerprint(hp.validFingerprint); expect(test0).to.be.true; }); it('isFingerprint(): invalid Fingerprints', function(){ for (let i=0; i < hp.invalidFingerprints.length; i++){ let test0 = isFingerprint(hp.invalidFingerprints[i]); expect(test0).to.be.false; } }); }); describe('toKeyIdArray() (converting input to fingerprint)', function(){ it('Correct fingerprint string', function(){ let test0 = toKeyIdArray(hp.validFingerprint); expect(test0).to.be.an('array'); expect(test0).to.include(hp.validFingerprint); }); it('correct GPGME_Key', function(){ expect(hp.validGPGME_Key).to.be.an.instanceof(GPGME_Key); let test0 = toKeyIdArray(hp.validGPGME_Key); expect(test0).to.be.an('array'); expect(test0).to.include(hp.validGPGME_Key.fingerprint); }); it('openpgpjs-like object', function(){ let test0 = toKeyIdArray(hp.valid_openpgplike); expect(test0).to.be.an('array').with.lengthOf(1); expect(test0).to.include( hp.valid_openpgplike.primaryKey.getFingerprint()); }); it('Array of valid inputs', function(){ let test0 = toKeyIdArray(hp.validKeys); expect(test0).to.be.an('array'); expect(test0).to.have.lengthOf(hp.validKeys.length); }); it('Incorrect inputs', function(){ it('valid Long ID', function(){ let test0 = toKeyIdArray(hp.validLongId); expect(test0).to.be.empty; }); it('invalidFingerprint', function(){ let test0 = toKeyIdArray(hp.invalidFingerprint); expect(test0).to.be.empty; }); it('invalidKeyArray', function(){ let test0 = toKeyIdArray(hp.invalidKeyArray); expect(test0).to.be.empty; }); it('Partially invalid array', function(){ let test0 = toKeyIdArray(hp.invalidKeyArray_OneBad); expect(test0).to.be.an('array'); expect(test0).to.have.lengthOf( hp.invalidKeyArray_OneBad.length - 1); }); }); }); describe('GPGME_Key', function(){ it('correct Key initialization', function(){ let key = createKey(kp.validKeyFingerprint); expect(key).to.be.an.instanceof(GPGME_Key); }); it('Key has data after a first refresh', function(done) { let key = createKey(kp.validKeyFingerprint); key.refreshKey().then(function(key2){ expect(key2).to.be.an.instanceof(GPGME_Key); expect(key2.get).to.be.a('function'); for (let i=0; i < kp.validKeyProperties.length; i++) { let prop = key2.get(kp.validKeyProperties[i]); expect(prop).to.not.be.undefined; expect(prop).to.be.a('boolean'); } expect(isFingerprint(key2.get('fingerprint'))).to.be.true; expect( key2.get('fingerprint')).to.equal(kp.validKeyFingerprint); expect( key2.get('fingerprint')).to.equal(key.fingerprint); done(); }); }); it('Non-cached key async data retrieval', function (done){ let key = createKey(kp.validKeyFingerprint); key.get('can_authenticate',false).then(function(result){ expect(result).to.be.a('boolean'); done(); }); }); it('Non-cached key async armored Key', function (done){ let key = createKey(kp.validKeyFingerprint); key.get('armored', false).then(function(result){ expect(result).to.be.a('string'); expect(result).to.include('KEY BLOCK-----'); done(); }); }); it('Non-cached key async hasSecret', function (done){ let key = createKey(kp.validKeyFingerprint); key.get('hasSecret', false).then(function(result){ expect(result).to.be.a('boolean'); done(); }); }); it('Non-cached key async hasSecret (no secret in Key)', function (done){ let key = createKey(kp.validFingerprintNoSecret); expect(key).to.be.an.instanceof(GPGME_Key); key.get('hasSecret', false).then(function(result){ expect(result).to.be.a('boolean'); expect(result).to.equal(false); done(); }); }); it('Querying non-existing Key returns an error', function(done) { let key = createKey(kp.invalidKeyFingerprint); key.refreshKey().then(function(){}, function(error){ expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('KEY_NOKEY'); done(); }); }); it('createKey returns error if parameters are wrong', function(){ for (let i=0; i< 4; i++){ let key0 = createKey(wp.four_invalid_params[i]); expect(key0).to.be.an.instanceof(Error); expect(key0.code).to.equal('PARAM_WRONG'); } }); it('malformed GPGME_Key cannot be used', function(){ for (let i=0; i < 4; i++){ let key = new GPGME_Key(wp.four_invalid_params[i]); expect(key.fingerprint).to.be.an.instanceof(Error); expect(key.fingerprint.code).to.equal('KEY_INVALID'); } }); // TODO: tests for subkeys // TODO: tests for userids // TODO: some invalid tests for key/keyring }); describe('GPGME_Keyring', function(){ it('correct Keyring initialization', function(){ let keyring = new GPGME_Keyring; expect(keyring).to.be.an.instanceof(GPGME_Keyring); expect(keyring.getKeys).to.be.a('function'); }); it('Loading Keys from Keyring, to be used synchronously', function(done){ let keyring = new GPGME_Keyring; keyring.getKeys(null, true).then(function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); }); } ); it('Loading specific Key from Keyring, to be used synchronously', function(done){ let keyring = new GPGME_Keyring; keyring.getKeys(kp.validKeyFingerprint, true).then( function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // TODO: preparing sync for armored is still in discussion + // expect(result[0].get('armored')).to.be.a('string'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); } ); } ); it('Querying non-existing Key from Keyring', function(done){ let keyring = new GPGME_Keyring; keyring.getKeys(kp.invalidKeyFingerprint, true).then( function(result){ expect(result).to.be.an('array'); expect(result.length).to.equal(0); done(); } ); }); }); describe('GPGME_Message', function(){ it('creating encrypt Message', function(){ let test0 = createMessage('encrypt'); expect(test0).to.be.an.instanceof(GPGME_Message); expect(test0.isComplete).to.be.false; }); it('Message is complete after setting mandatory data', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); expect(test0.isComplete).to.be.true; }); it('Message is not complete after mandatory data is empty', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', ''); test0.setParameter('keys', hp.validFingerprints); expect(test0.isComplete).to.be.false; }); it('Complete Message contains the data that was set', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); expect(test0.message).to.not.be.null; expect(test0.message).to.have.keys('op', 'data', 'keys', 'chunksize'); expect(test0.message.op).to.equal('encrypt'); expect(test0.message.data).to.equal( mp.valid_encrypt_data); }); it ('Not accepting non-allowed operation', function(){ let test0 = createMessage(mp.invalid_op_action); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('MSG_WRONG_OP'); }); it('Not accepting wrong parameter type', function(){ let test0 = createMessage(mp.invalid_op_type); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('PARAM_WRONG'); }); it('Not accepting wrong parameter name', function(){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let i=0; i < mp.invalid_param_test.invalid_param_names.length; i++){ let ret = test0.setParameter( mp.invalid_param_test.invalid_param_names[i], 'Somevalue'); expect(ret).to.be.an.instanceof(Error); expect(ret.code).to.equal('PARAM_WRONG'); } }); it('Not accepting wrong parameter value', function(){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let j=0; j < mp.invalid_param_test.invalid_values_0.length; j++){ let ret = test0.setParameter( mp.invalid_param_test.validparam_name_0, mp.invalid_param_test.invalid_values_0[j]); expect(ret).to.be.an.instanceof(Error); expect(ret.code).to.equal('PARAM_WRONG'); } }); }); } export default {unittests}; \ No newline at end of file