--- a/services/.eslintrc.js
+++ b/services/.eslintrc.js
@@ -1,7 +1,10 @@
"use strict";
module.exports = {
plugins: [
"mozilla"
- ]
+ ],
+ "rules": {
+ "no-throw-literal": 2,
+ },
}
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -276,33 +276,33 @@ RESTRequest.prototype = {
return this.dispatch("DELETE", null, onComplete, onProgress);
},
/**
* Abort an active request.
*/
abort: function abort() {
if (this.status != this.SENT && this.status != this.IN_PROGRESS) {
- throw "Can only abort a request that has been sent.";
+ throw new Error("Can only abort a request that has been sent.");
}
this.status = this.ABORTED;
this.channel.cancel(Cr.NS_BINDING_ABORTED);
if (this.timeoutTimer) {
// Clear the abort timer now that the channel is done.
this.timeoutTimer.clear();
}
},
/** Implementation stuff **/
dispatch: function dispatch(method, data, onComplete, onProgress) {
if (this.status != this.NOT_SENT) {
- throw "Request has already been sent!";
+ throw new Error("Request has already been sent!");
}
this.method = method;
if (onComplete) {
this.onComplete = onComplete;
}
if (onProgress) {
this.onProgress = onProgress;
--- a/services/common/tests/unit/test_load_modules.js
+++ b/services/common/tests/unit/test_load_modules.js
@@ -29,32 +29,32 @@ function expectImportsToSucceed(mm, base
let resource = base + m;
let succeeded = false;
try {
Components.utils.import(resource, {});
succeeded = true;
} catch (e) {}
if (!succeeded) {
- throw "Importing " + resource + " should have succeeded!";
+ throw new Error(`Importing ${resource} should have succeeded!`);
}
}
}
function expectImportsToFail(mm, base = MODULE_BASE) {
for (let m of mm) {
let resource = base + m;
let succeeded = false;
try {
Components.utils.import(resource, {});
succeeded = true;
} catch (e) {}
if (succeeded) {
- throw "Importing " + resource + " should have failed!";
+ throw new Error(`Importing ${resource} should have failed!`);
}
}
}
function run_test() {
expectImportsToSucceed(shared_modules);
expectImportsToSucceed(shared_test_modules, TEST_BASE);
--- a/services/common/tests/unit/test_utils_encodeBase32.js
+++ b/services/common/tests/unit/test_utils_encodeBase32.js
@@ -42,10 +42,10 @@ function run_test() {
// Test failure.
let err;
try {
CommonUtils.decodeBase32("000");
} catch (ex) {
err = ex;
}
- do_check_eq(err, "Unknown character in base32: 0");
+ do_check_eq(err.message, "Unknown character in base32: 0");
}
--- a/services/common/utils.js
+++ b/services/common/utils.js
@@ -150,17 +150,18 @@ this.CommonUtils = {
/**
* Return a timer that is scheduled to call the callback after waiting the
* provided time or as soon as possible. The timer will be set as a property
* of the provided object with the given timer name.
*/
namedTimer: function namedTimer(callback, wait, thisObj, name) {
if (!thisObj || !name) {
- throw "You must provide both an object and a property name for the timer!";
+ throw new Error(
+ "You must provide both an object and a property name for the timer!");
}
// Delay an existing timer if it exists
if (name in thisObj && thisObj[name] instanceof Ci.nsITimer) {
thisObj[name].delay = wait;
return thisObj[name];
}
@@ -298,20 +299,20 @@ this.CommonUtils = {
// undefined | foo == foo.
function accumulate(val) {
ret[rOffset] |= val;
}
function advance() {
c = str[cOffset++];
if (!c || c == "" || c == "=") // Easier than range checking.
- throw "Done"; // Will be caught far away.
+ throw new Error("Done"); // Will be caught far away.
val = key.indexOf(c);
if (val == -1)
- throw "Unknown character in base32: " + c;
+ throw new Error(`Unknown character in base32: ${c}`);
}
// Handle a left shift, restricted to bytes.
function left(octet, shift) {
return (octet << shift) & 0xff;
}
advance();
@@ -347,17 +348,17 @@ this.CommonUtils = {
let cOff = 0;
let rOff = 0;
for (; i < blocks; ++i) {
try {
processBlock(ret, cOff, rOff);
} catch (ex) {
// Handle the detection of padding.
- if (ex == "Done")
+ if (ex.message == "Done")
break;
throw ex;
}
cOff += 8;
rOff += 5;
}
// Slice in case our shift overflowed to the right.
--- a/services/crypto/modules/WeaveCrypto.js
+++ b/services/crypto/modules/WeaveCrypto.js
@@ -102,17 +102,18 @@ WeaveCrypto.prototype = {
ivStr = atob(ivStr);
if (operation !== OPERATIONS.ENCRYPT && operation !== OPERATIONS.DECRYPT) {
throw new Error("Unsupported operation in _commonCrypt.");
}
// We never want an IV longer than the block size, which is 16 bytes
// for AES, neither do we want one smaller; throw in both cases.
if (ivStr.length !== AES_CBC_IV_SIZE) {
- throw "Invalid IV size; must be " + AES_CBC_IV_SIZE + " bytes.";
+ throw new Error(
+ `Invalid IV size; must be ${AES_CBC_IV_SIZE} bytes.`);
}
let iv = this.byteCompressInts(ivStr);
let symKey = this.importSymKey(symKeyStr, operation);
let cryptMethod = (operation === OPERATIONS.ENCRYPT
? crypto.subtle.encrypt
: crypto.subtle.decrypt)
.bind(crypto.subtle);
@@ -171,17 +172,17 @@ WeaveCrypto.prototype = {
switch (operation) {
case OPERATIONS.ENCRYPT:
memo = this._encryptionSymKeyMemo;
break;
case OPERATIONS.DECRYPT:
memo = this._decryptionSymKeyMemo;
break;
default:
- throw "Unsupported operation in importSymKey.";
+ throw new Error("Unsupported operation in importSymKey.");
}
if (encodedKeyString in memo)
return memo[encodedKeyString];
let symmetricKeyBuffer = this.makeUint8Array(encodedKeyString, true);
let algo = { name: CRYPT_ALGO };
let usages = [operation === OPERATIONS.ENCRYPT ? "encrypt" : "decrypt"];
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -594,16 +594,17 @@ this.FxAccountsClient.prototype = {
);
}
throw error;
}
try {
return JSON.parse(response.body);
} catch (error) {
log.error("json parse error on response: " + response.body);
+ // eslint-disable-next-line no-throw-literal
throw {error};
}
},
};
function isInvalidTokenError(error) {
if (error.code != 401) {
return false;
--- a/services/fxaccounts/tests/xpcshell/test_accounts.js
+++ b/services/fxaccounts/tests/xpcshell/test_accounts.js
@@ -116,17 +116,17 @@ function MockFxAccountsClient() {
});
};
this.resendVerificationEmail = function(sessionToken) {
// Return the session token to show that we received it in the first place
return Promise.resolve(sessionToken);
};
- this.signCertificate = function() { throw "no" };
+ this.signCertificate = function() { throw new Error("no"); };
this.signOut = () => Promise.resolve();
this.signOutAndDestroyDevice = () => Promise.resolve({});
FxAccountsClient.apply(this);
}
MockFxAccountsClient.prototype = {
__proto__: FxAccountsClient.prototype
@@ -1163,17 +1163,20 @@ add_task(async function test_sign_out_wi
await promise;
});
add_task(async function test_sign_out_with_remote_error() {
let fxa = new MockFxAccounts();
let remoteSignOutCalled = false;
// Force remote sign out to trigger an error
- fxa.internal.deleteDeviceRegistration = function() { remoteSignOutCalled = true; throw "Remote sign out error"; };
+ fxa.internal.deleteDeviceRegistration = function() {
+ remoteSignOutCalled = true;
+ throw new Error("Remote sign out error");
+ };
let promiseLogout = new Promise(resolve => {
makeObserver(ONLOGOUT_NOTIFICATION, function() {
log.debug("test_sign_out_with_remote_error observed onlogout");
resolve();
});
});
let jane = getTestUser("jane");
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -377,57 +377,57 @@ Store.prototype = {
*
* This is called by the default implementation of applyIncoming(). If using
* applyIncomingBatch(), this won't be called unless your store calls it.
*
* @param record
* The store record to create an item from
*/
async create(record) {
- throw "override create in a subclass";
+ throw new Error("override create in a subclass");
},
/**
* Remove an item in the store from a record.
*
* This is called by the default implementation of applyIncoming(). If using
* applyIncomingBatch(), this won't be called unless your store calls it.
*
* @param record
* The store record to delete an item from
*/
async remove(record) {
- throw "override remove in a subclass";
+ throw new Error("override remove in a subclass");
},
/**
* Update an item from a record.
*
* This is called by the default implementation of applyIncoming(). If using
* applyIncomingBatch(), this won't be called unless your store calls it.
*
* @param record
* The record to use to update an item from
*/
async update(record) {
- throw "override update in a subclass";
+ throw new Error("override update in a subclass");
},
/**
* Determine whether a record with the specified ID exists.
*
* Takes a string record ID and returns a booleans saying whether the record
* exists.
*
* @param id
* string record ID
* @return boolean indicating whether record exists locally
*/
async itemExists(id) {
- throw "override itemExists in a subclass";
+ throw new Error("override itemExists in a subclass");
},
/**
* Create a record from the specified ID.
*
* If the ID is known, the record should be populated with metadata from
* the store. If the ID is not known, the record should be created with the
* delete field set to true.
@@ -435,53 +435,53 @@ Store.prototype = {
* @param id
* string record ID
* @param collection
* Collection to add record to. This is typically passed into the
* constructor for the newly-created record.
* @return record type for this engine
*/
async createRecord(id, collection) {
- throw "override createRecord in a subclass";
+ throw new Error("override createRecord in a subclass");
},
/**
* Change the ID of a record.
*
* @param oldID
* string old/current record ID
* @param newID
* string new record ID
*/
async changeItemID(oldID, newID) {
- throw "override changeItemID in a subclass";
+ throw new Error("override changeItemID in a subclass");
},
/**
* Obtain the set of all known record IDs.
*
* @return Object with ID strings as keys and values of true. The values
* are ignored.
*/
async getAllIDs() {
- throw "override getAllIDs in a subclass";
+ throw new Error("override getAllIDs in a subclass");
},
/**
* Wipe all data in the store.
*
* This function is called during remote wipes or when replacing local data
* with remote data.
*
* This function should delete all local data that the store is managing. It
* can be thought of as clearing out all state and restoring the "new
* browser" state.
*/
async wipe() {
- throw "override wipe in a subclass";
+ throw new Error("override wipe in a subclass");
}
};
this.EngineManager = function EngineManager(service) {
this.service = service;
this._engines = {};
@@ -711,28 +711,28 @@ Engine.prototype = {
},
async sync() {
if (!this.enabled) {
return false;
}
if (!this._sync) {
- throw "engine does not implement _sync method";
+ throw new Error("engine does not implement _sync method");
}
return this._notify("sync", this.name, this._sync)();
},
/**
* Get rid of any local meta-data.
*/
async resetClient() {
if (!this._resetClient) {
- throw "engine does not implement _resetClient method";
+ throw new Error("engine does not implement _resetClient method");
}
return this._notify("reset-client", this.name, this._resetClient)();
},
async _wipeClient() {
await this.resetClient();
this._log.debug("Deleting all local data");
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -458,16 +458,17 @@ BookmarksEngine.prototype = {
}
try {
return this._guidMap = await this._buildGUIDMap();
} catch (ex) {
if (Async.isShutdownException(ex)) {
throw ex;
}
this._log.warn("Error while building GUID map, skipping all other incoming items", ex);
+ // eslint-disable-next-line no-throw-literal
throw {code: Engine.prototype.eEngineAbortApplyIncoming,
cause: ex};
}
},
async _deletePending() {
// Delete pending items -- See the comment above BookmarkStore's deletePending
let newlyModified = await this._store.deletePending();
@@ -672,17 +673,18 @@ BookmarksStore.prototype = {
!record.bmkUri) {
this._log.warn("Skipping malformed query bookmark: " + record.id);
return;
}
// Figure out the local id of the parent GUID if available
let parentGUID = record.parentid;
if (!parentGUID) {
- throw "Record " + record.id + " has invalid parentid: " + parentGUID;
+ throw new Error(
+ `Record ${record.id} has invalid parentid: ${parentGUID}`);
}
this._log.debug("Remote parent is " + parentGUID);
// Do the normal processing of incoming records
await Store.prototype.applyIncoming.call(this, record);
if (record.type == "folder" && record.children) {
this._childrenToOrder[record.id] = record.children;
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -315,17 +315,17 @@ HistoryStore.prototype = {
* returns true if the record is to be applied, false otherwise
* (no visits to add, etc.),
*/
_recordToPlaceInfo: function _recordToPlaceInfo(record) {
// Sort out invalid URIs and ones Places just simply doesn't want.
record.uri = Utils.makeURI(record.histUri);
if (!record.uri) {
this._log.warn("Attempted to process invalid URI, skipping.");
- throw "Invalid URI in record";
+ throw new Error("Invalid URI in record");
}
if (!Utils.checkGUID(record.id)) {
this._log.warn("Encountered record with invalid GUID: " + record.id);
return false;
}
record.guid = record.id;
--- a/services/sync/modules/engines/prefs.js
+++ b/services/sync/modules/engines/prefs.js
@@ -148,17 +148,17 @@ PrefStore.prototype = {
default:
if (value == null) {
// Pref has gone missing. The best we can do is reset it.
this._prefs.reset(pref);
} else {
try {
this._prefs.set(pref, value);
} catch (ex) {
- this._log.trace("Failed to set pref: " + pref + ": " + ex);
+ this._log.trace(`Failed to set pref: ${pref}`, ex);
}
}
}
}
// Notify the lightweight theme manager if the selected theme has changed.
if (selectedThemeIDBefore != selectedThemeIDAfter) {
this._updateLightWeightTheme(selectedThemeIDAfter);
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -115,17 +115,17 @@ this.CryptoWrapper = function CryptoWrap
}
CryptoWrapper.prototype = {
__proto__: WBORecord.prototype,
_logName: "Sync.Record.CryptoWrapper",
ciphertextHMAC: function ciphertextHMAC(keyBundle) {
let hasher = keyBundle.sha256HMACHasher;
if (!hasher) {
- throw "Cannot compute HMAC without an HMAC key.";
+ throw new Error("Cannot compute HMAC without an HMAC key.");
}
return Utils.bytesAsHex(Utils.digestUTF8(this.ciphertext, hasher));
},
/*
* Don't directly use the sync key. Instead, grab a key for this
* collection, which is decrypted with the sync key.
@@ -145,17 +145,17 @@ CryptoWrapper.prototype = {
keyBundle.encryptionKeyB64, this.IV);
this.hmac = this.ciphertextHMAC(keyBundle);
this.cleartext = null;
},
// Optional key bundle.
decrypt: function decrypt(keyBundle) {
if (!this.ciphertext) {
- throw "No ciphertext: nothing to decrypt?";
+ throw new Error("No ciphertext: nothing to decrypt?");
}
if (!keyBundle) {
throw new Error("A key bundle must be supplied to decrypt.");
}
// Authenticate the encrypted blob with the expected HMAC
let computedHMAC = this.ciphertextHMAC(keyBundle);
@@ -168,22 +168,24 @@ CryptoWrapper.prototype = {
let cleartext = Weave.Crypto.decrypt(this.ciphertext,
keyBundle.encryptionKeyB64, this.IV);
let json_result = JSON.parse(cleartext);
if (json_result && (json_result instanceof Object)) {
this.cleartext = json_result;
this.ciphertext = null;
} else {
- throw "Decryption failed: result is <" + json_result + ">, not an object.";
+ throw new Error(
+ `Decryption failed: result is <${json_result}>, not an object.`);
}
// Verify that the encrypted id matches the requested record's id.
if (this.cleartext.id != this.id)
- throw "Record id mismatch: " + this.cleartext.id + " != " + this.id;
+ throw new Error(
+ `Record id mismatch: ${this.cleartext.id} != ${this.id}`);
return this.cleartext;
},
cleartextToString() {
return JSON.stringify(this.cleartext);
},
@@ -493,22 +495,22 @@ CollectionKeyManager.prototype = {
setContents: function setContents(payload, modified) {
let self = this;
this._log.info("Setting collection keys contents. Our last modified: " +
this.lastModified + ", input modified: " + modified + ".");
if (!payload)
- throw "No payload in CollectionKeyManager.setContents().";
+ throw new Error("No payload in CollectionKeyManager.setContents().");
if (!payload.default) {
this._log.warn("No downloaded default key: this should not occur.");
this._log.warn("Not clearing local keys.");
- throw "No default key in CollectionKeyManager.setContents(). Cannot proceed.";
+ throw new Error("No default key in CollectionKeyManager.setContents(). Cannot proceed.");
}
// Process the incoming default key.
let b = new BulkKeyBundle(DEFAULT_KEYBUNDLE_NAME);
b.keyPairB64 = payload.default;
let newDefault = b;
// Process the incoming collections.
@@ -563,17 +565,17 @@ CollectionKeyManager.prototype = {
// storage_keys is a WBO, fetched from storage/crypto/keys.
// Its payload is the default key, and a map of collections to keys.
// We lazily compute the key objects from the strings we're given.
let payload;
try {
payload = storage_keys.decrypt(syncKeyBundle);
} catch (ex) {
- log.warn("Got exception \"" + ex + "\" decrypting storage keys with sync key.");
+ log.warn("Got exception decrypting storage keys with sync key.", ex);
log.info("Aborting updateContents. Rethrowing.");
throw ex;
}
let r = this.setContents(payload, storage_keys.modified);
log.info("Collection keys updated.");
return r;
}
--- a/services/sync/modules/resource.js
+++ b/services/sync/modules/resource.js
@@ -210,17 +210,17 @@ AsyncResource.prototype = {
let listener = new ChannelListener(this._onComplete, this._onProgress,
this._log, this.ABORT_TIMEOUT);
channel.requestMethod = action;
channel.asyncOpen2(listener);
});
},
_onComplete(ex, data, channel) {
- this._log.trace("In _onComplete. Error is " + ex + ".");
+ this._log.trace("In _onComplete. An error occurred.", ex);
if (ex) {
if (!Async.isShutdownException(ex)) {
this._log.warn("${action} request to ${url} failed: ${ex}",
{ action: this.method, url: this.uri.spec, ex});
}
this._deferred.reject(ex);
return;
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -252,18 +252,18 @@ Sync11Service.prototype = {
} else {
this._log.warn("Got error response re-uploading keys. " +
"Continuing sync; let's try again later.");
}
return false; // Don't try again: same keys.
} catch (ex) {
- this._log.warn("Got exception \"" + ex + "\" fetching and handling " +
- "crypto keys. Will try again later.");
+ this._log.warn("Got exception fetching and handling crypto keys. " +
+ "Will try again later.", ex);
return false;
}
},
async handleFetchedKeys(syncKey, cryptoKeys, skipReset) {
// Don't want to wipe if we're just starting up!
let wasBlank = this.collectionKeys.isClear;
let keysChanged = this.collectionKeys.updateContents(syncKey, cryptoKeys);
@@ -570,17 +570,17 @@ Sync11Service.prototype = {
} else {
// Some other problem.
this.status.login = LOGIN_FAILED_SERVER_ERROR;
this.errorHandler.checkServerError(cryptoResp);
this._log.warn("Got status " + cryptoResp.status + " fetching crypto keys.");
return false;
}
} catch (ex) {
- this._log.warn("Got exception \"" + ex + "\" fetching cryptoKeys.");
+ this._log.warn("Got exception fetching cryptoKeys.", ex);
// TODO: Um, what exceptions might we get here? Should we re-throw any?
// One kind of exception: HMAC failure.
if (Utils.isHMACMismatch(ex)) {
this.status.login = LOGIN_FAILED_INVALID_PASSPHRASE;
this.status.sync = CREDENTIALS_CHANGED;
} else {
// In the absence of further disambiguation or more precise
@@ -821,33 +821,33 @@ Sync11Service.prototype = {
}
},
async login() {
async function onNotify() {
this._loggedIn = false;
if (Services.io.offline) {
this.status.login = LOGIN_FAILED_NETWORK_ERROR;
- throw "Application is offline, login should not be called";
+ throw new Error("Application is offline, login should not be called");
}
this._log.info("Logging in the user.");
// Just let any errors bubble up - they've more context than we do!
try {
await this.identity.ensureLoggedIn();
} finally {
this._checkSetup(); // _checkSetup has a side effect of setting the right state.
}
this._updateCachedURLs();
this._log.info("User logged in successfully - verifying login.");
if (!(await this.verifyLogin())) {
// verifyLogin sets the failure states here.
- throw "Login failed: " + this.status.login;
+ throw new Error(`Login failed: ${this.status.login}`);
}
this._loggedIn = true;
return true;
}
let notifier = this._notify("login", "", onNotify.bind(this));
@@ -1369,17 +1369,17 @@ Sync11Service.prototype = {
* Callback function with signature (error, data) where `data' is
* the return value from the server already parsed as JSON.
*
* @return RESTRequest instance representing the request, allowing callers
* to cancel the request.
*/
getStorageInfo: function getStorageInfo(type, callback) {
if (STORAGE_INFO_TYPES.indexOf(type) == -1) {
- throw "Invalid value for 'type': " + type;
+ throw new Error(`Invalid value for 'type': ${type}`);
}
let info_type = "info/" + type;
this._log.trace("Retrieving '" + info_type + "'...");
let url = this.userBaseURL + info_type;
return this.getStorageRequest(url).get(function onComplete(error) {
// Note: 'this' is the request.
if (error) {
--- a/services/sync/modules/util.js
+++ b/services/sync/modules/util.js
@@ -19,19 +19,35 @@ XPCOMUtils.defineLazyModuleGetter(this,
// FxAccountsCommon.js doesn't use a "namespace", so create one here.
XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function() {
let FxAccountsCommon = {};
Cu.import("resource://gre/modules/FxAccountsCommon.js", FxAccountsCommon);
return FxAccountsCommon;
});
/*
+ * Custom exception types.
+ */
+class LockException extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "LockException";
+ }
+}
+
+class HMACMismatch extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "HMACMismatch";
+ }
+}
+
+/*
* Utility functions
*/
-
this.Utils = {
// Alias in functions from CommonUtils. These previously were defined here.
// In the ideal world, references to these would be removed.
nextTick: CommonUtils.nextTick,
namedTimer: CommonUtils.namedTimer,
makeURI: CommonUtils.makeURI,
encodeUTF8: CommonUtils.encodeUTF8,
decodeUTF8: CommonUtils.decodeUTF8,
@@ -94,40 +110,44 @@ this.Utils = {
if (exceptionCallback) {
return exceptionCallback.call(thisArg, ex);
}
return null;
}
};
},
+ throwLockException(label) {
+ throw new LockException(`Could not acquire lock. Label: "${label}".`);
+ },
+
/**
* Wrap a [promise-returning] function to call lock before calling the function
* then unlock when it finishes executing or if it threw an error.
*
* @usage MyObj._lock = Utils.lock;
* MyObj.foo = async function() { await this._lock(func)(); }
*/
lock(label, func) {
let thisArg = this;
return async function WrappedLock() {
if (!thisArg.lock()) {
- throw "Could not acquire lock. Label: \"" + label + "\".";
+ Utils.throwLockException(label);
}
try {
return await func.call(thisArg);
} finally {
thisArg.unlock();
}
};
},
isLockException: function isLockException(ex) {
- return ex && ex.indexOf && ex.indexOf("Could not acquire lock.") == 0;
+ return ex instanceof LockException;
},
/**
* Wrap [promise-returning] functions to notify when it starts and
* finishes executing or if it threw an error.
*
* The message is a combination of a provided prefix, the local name, and
* the event. Possible events are: "start", "finish", "error". The subject
@@ -239,22 +259,22 @@ this.Utils = {
return true;
},
// Generator and discriminator for HMAC exceptions.
// Split these out in case we want to make them richer in future, and to
// avoid inevitable confusion if the message changes.
throwHMACMismatch: function throwHMACMismatch(shouldBe, is) {
- throw "Record SHA256 HMAC mismatch: should be " + shouldBe + ", is " + is;
+ throw new HMACMismatch(
+ `Record SHA256 HMAC mismatch: should be ${shouldBe}, is ${is}`);
},
isHMACMismatch: function isHMACMismatch(ex) {
- const hmacFail = "Record SHA256 HMAC mismatch: ";
- return ex && ex.indexOf && (ex.indexOf(hmacFail) == 0);
+ return ex instanceof HMACMismatch;
},
/**
* Turn RFC 4648 base32 into our own user-friendly version.
* ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
* becomes
* abcdefghijk8mn9pqrstuvwxyz234567
*/
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -60,17 +60,17 @@ function httpd_basic_auth_handler(body,
response.bodyOutputStream.write(body, body.length);
}
/*
* Represent a WBO on the server
*/
function ServerWBO(id, initialPayload, modified) {
if (!id) {
- throw "No ID for ServerWBO!";
+ throw new Error("No ID for ServerWBO!");
}
this.id = id;
if (!initialPayload) {
return;
}
if (typeof initialPayload == "object") {
initialPayload = JSON.stringify(initialPayload);
@@ -530,17 +530,17 @@ function track_collections_helper() {
*/
function info_collections(request, response) {
let body = "Error.";
switch (request.method) {
case "GET":
body = JSON.stringify(collections);
break;
default:
- throw "Non-GET on info_collections.";
+ throw new Error("Non-GET on info_collections.");
}
response.setHeader("Content-Type", "application/json");
response.setHeader("X-Weave-Timestamp",
"" + new_timestamp(),
false);
response.setStatusLine(request.httpVersion, 200, "OK");
response.bodyOutputStream.write(body, body.length);
@@ -1025,17 +1025,17 @@ SyncServer.prototype = {
// Rather than instantiate each WBO's handler function, do it once
// per request. They get hit far less often than do collections.
wbo.handler()(req, resp);
coll.timestamp = resp.newModified;
return resp;
}
return coll.collectionHandler(req, resp);
default:
- throw "Request method " + req.method + " not implemented.";
+ throw new Error("Request method " + req.method + " not implemented.");
}
},
"info": function handleInfo(handler, req, resp, version, username, rest) {
switch (rest) {
case "collections":
let body = JSON.stringify(this.infoCollections(username));
this.respond(req, resp, 200, "OK", body, {
--- a/services/sync/tests/unit/test_bookmark_batch_fail.js
+++ b/services/sync/tests/unit/test_bookmark_batch_fail.js
@@ -4,20 +4,20 @@
_("Making sure a failing sync reports a useful error");
Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/service.js");
add_task(async function run_test() {
let engine = new BookmarksEngine(Service);
await engine.initialize();
engine._syncStartup = async function() {
- throw "FAIL!";
+ throw new Error("FAIL!");
};
try {
_("Try calling the sync that should throw right away");
await engine._sync();
do_throw("Should have failed sync!");
} catch (ex) {
_("Making sure what we threw ended up as the exception:", ex);
- do_check_eq(ex, "FAIL!");
+ do_check_eq(ex.message, "FAIL!");
}
});
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -154,17 +154,17 @@ add_task(async function test_processInco
folder1_payload.children.reverse();
collection.insert(folder1_guid, encryptPayload(folder1_payload));
// Create a bogus record that when synced down will provoke a
// network error which in turn provokes an exception in _processIncoming.
const BOGUS_GUID = "zzzzzzzzzzzz";
let bogus_record = collection.insert(BOGUS_GUID, "I'm a bogus record!");
bogus_record.get = function get() {
- throw "Sync this!";
+ throw new Error("Sync this!");
};
// Make the 10 minutes old so it will only be synced in the toFetch phase.
bogus_record.modified = Date.now() / 1000 - 60 * 10;
engine.lastSync = Date.now() / 1000 - 60;
engine.toFetch = [BOGUS_GUID];
let error;
--- a/services/sync/tests/unit/test_collection_getBatched.js
+++ b/services/sync/tests/unit/test_collection_getBatched.js
@@ -34,17 +34,17 @@ function get_test_collection_info({ tota
}
requests.push({
limit,
offset,
spec: this.spec,
headers: Object.assign({}, this.headers)
});
if (--throwAfter === 0) {
- throw "Some Network Error";
+ throw new Error("Some Network Error");
}
let body = recordRange(limit, offset, totalRecords);
let response = {
obj: body,
success: true,
status: 200,
headers: {}
};
--- a/services/sync/tests/unit/test_errorhandler_filelog.js
+++ b/services/sync/tests/unit/test_errorhandler_filelog.js
@@ -117,17 +117,17 @@ add_test(function test_logOnSuccess_true
readFile(logfile, function(error, data) {
do_check_true(Components.isSuccessCode(error));
do_check_neq(data.indexOf(MESSAGE), -1);
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
run_next_test();
});
});
@@ -184,17 +184,17 @@ add_test(function test_sync_error_logOnE
readFile(logfile, function(error, data) {
do_check_true(Components.isSuccessCode(error));
do_check_neq(data.indexOf(MESSAGE), -1);
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
});
});
// Fake an unsuccessful sync due to prolonged failure.
@@ -251,17 +251,17 @@ add_test(function test_login_error_logOn
readFile(logfile, function(error, data) {
do_check_true(Components.isSuccessCode(error));
do_check_neq(data.indexOf(MESSAGE), -1);
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
});
});
// Fake an unsuccessful login due to prolonged failure.
@@ -323,17 +323,17 @@ add_test(function test_newFailed_errorLo
readFile(logfile, function(error, data) {
do_check_true(Components.isSuccessCode(error));
do_check_neq(data.indexOf(MESSAGE), -1);
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
});
});
// newFailed is nonzero -- should write a log.
@@ -373,17 +373,17 @@ add_test(function test_errorLog_dumpAddo
readFile(logfile, function(error, data) {
do_check_true(Components.isSuccessCode(error));
do_check_neq(data.indexOf("Addons installed"), -1);
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
});
});
// Fake an unsuccessful sync due to prolonged failure.
@@ -425,17 +425,17 @@ add_test(function test_logErrorCleanup_a
return e != logfile.leafName;
}));
do_check_false(entries.hasMoreElements());
// Clean up.
try {
logfile.remove(false);
} catch (ex) {
- dump("Couldn't delete file: " + ex + "\n");
+ dump("Couldn't delete file: " + ex.message + "\n");
// Stupid Windows box.
}
Svc.Prefs.resetBranch("");
run_next_test();
});
let delay = CLEANUP_DELAY + DELAY_BUFFER;
--- a/services/sync/tests/unit/test_records_crypto.js
+++ b/services/sync/tests/unit/test_records_crypto.js
@@ -63,17 +63,17 @@ add_task(async function test_records_cry
log.info("Make sure multiple decrypts cause failures");
let error = "";
try {
payload = cryptoWrap.decrypt(keyBundle);
} catch (ex) {
error = ex;
}
- do_check_eq(error, "No ciphertext: nothing to decrypt?");
+ do_check_eq(error.message, "No ciphertext: nothing to decrypt?");
log.info("Re-encrypting the record with alternate payload");
cryptoWrap.cleartext.stuff = "another payload";
cryptoWrap.encrypt(keyBundle);
let secondIV = cryptoWrap.IV;
payload = cryptoWrap.decrypt(keyBundle);
do_check_eq(payload.stuff, "another payload");
@@ -85,28 +85,28 @@ add_task(async function test_records_cry
cryptoWrap.encrypt(keyBundle);
cryptoWrap.data.id = "other";
error = "";
try {
cryptoWrap.decrypt(keyBundle);
} catch (ex) {
error = ex;
}
- do_check_eq(error, "Record id mismatch: resource != other");
+ do_check_eq(error.message, "Record id mismatch: resource != other");
log.info("Make sure wrong hmacs cause failures");
cryptoWrap.encrypt(keyBundle);
cryptoWrap.hmac = "foo";
error = "";
try {
cryptoWrap.decrypt(keyBundle);
} catch (ex) {
error = ex;
}
- do_check_eq(error.substr(0, 42), "Record SHA256 HMAC mismatch: should be foo");
+ do_check_eq(error.message.substr(0, 42), "Record SHA256 HMAC mismatch: should be foo");
// Checking per-collection keys and default key handling.
generateNewKeys(Service.collectionKeys);
let bookmarkItem = prepareCryptoWrap("bookmarks", "foo");
bookmarkItem.encrypt(Service.collectionKeys.keyForCollection("bookmarks"));
log.info("Ciphertext is " + bookmarkItem.ciphertext);
do_check_true(bookmarkItem.ciphertext != null);
@@ -128,17 +128,17 @@ add_task(async function test_records_cry
// conceivably occur in the real world. Decryption will error, because
// it's not the bookmarks key.
let err;
try {
bookmarkItem.decrypt(Service.collectionKeys._default);
} catch (ex) {
err = ex;
}
- do_check_eq("Record SHA256 HMAC mismatch", err.substr(0, 27));
+ do_check_eq("Record SHA256 HMAC mismatch", err.message.substr(0, 27));
// Explicitly check that it's using the bookmarks key.
// This should succeed.
do_check_eq(bookmarkItem.decrypt(Service.collectionKeys.keyForCollection("bookmarks")).stuff,
"my payload here");
do_check_true(Service.collectionKeys.hasKeysFor(["bookmarks"]));
--- a/services/sync/tests/unit/test_resource.js
+++ b/services/sync/tests/unit/test_resource.js
@@ -440,32 +440,32 @@ add_task(async function test() {
do_check_eq(warnings.pop(), "${action} request to ${url} failed: ${ex}");
do_check_eq(warnings.pop(),
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
// And this is what happens if JS throws an exception.
res18 = new Resource(server.baseURI + "/json");
onProgress = function(rec) {
- throw "BOO!";
+ throw new Error("BOO!");
};
res18._onProgress = onProgress;
let oldWarn = res18._log.warn;
warnings = [];
res18._log.warn = function(msg) { warnings.push(msg) };
error = undefined;
try {
content = await res18.get();
} catch (ex) {
error = ex;
}
// It throws and logs.
- do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
- do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING");
+ do_check_eq(error.result, Cr.NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS);
+ do_check_eq(error.message, "NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS");
do_check_eq(warnings.pop(), "${action} request to ${url} failed: ${ex}");
do_check_eq(warnings.pop(),
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
res18._log.warn = oldWarn;
_("Ensure channel timeouts are thrown appropriately.");
--- a/services/sync/tests/unit/test_resource_async.js
+++ b/services/sync/tests/unit/test_resource_async.js
@@ -567,24 +567,24 @@ add_task(async function test_xpc_excepti
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
});
add_task(async function test_js_exception_handling() {
_("JS exception handling inside fetches.");
let res15 = new AsyncResource(server.baseURI + "/json");
res15._onProgress = function(rec) {
- throw "BOO!";
+ throw new Error("BOO!");
};
let warnings = [];
res15._log.warn = function(msg) { warnings.push(msg); };
await Assert.rejects(res15.get(), error => {
- do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
- do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING");
+ do_check_eq(error.result, Cr.NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS);
+ do_check_eq(error.message, "NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS");
return true;
});
do_check_eq(warnings.pop(),
"${action} request to ${url} failed: ${ex}");
do_check_eq(warnings.pop(),
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
});
--- a/services/sync/tests/unit/test_service_sync_locked.js
+++ b/services/sync/tests/unit/test_service_sync_locked.js
@@ -9,18 +9,24 @@ add_task(async function run_test() {
let debug = [];
let info = [];
function augmentLogger(old) {
let d = old.debug;
let i = old.info;
// For the purposes of this test we don't need to do full formatting
// of the 2nd param, as the ones we care about are always strings.
- old.debug = function(m, p) { debug.push(p ? m + ": " + p : m); d.call(old, m, p); }
- old.info = function(m, p) { info.push(p ? m + ": " + p : m); i.call(old, m, p); }
+ old.debug = function(m, p) {
+ debug.push(p ? m + ": " + (p.message || p) : m);
+ d.call(old, m, p);
+ };
+ old.info = function(m, p) {
+ info.push(p ? m + ": " + (p.message || p) : m);
+ i.call(old, m, p);
+ };
return old;
}
Log.repository.rootLogger.addAppender(new Log.DumpAppender());
augmentLogger(Service._log);
// Avoid daily ping
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -968,24 +968,24 @@ add_task(async function test_processInco
"record-no-" + (2 + APPLY_BATCH_SIZE * 3),
"record-no-" + (1 + APPLY_BATCH_SIZE * 3)];
let engine = makeRotaryEngine();
engine.applyIncomingBatchSize = APPLY_BATCH_SIZE;
engine.__reconcile = engine._reconcile;
engine._reconcile = async function _reconcile(record) {
if (BOGUS_RECORDS.indexOf(record.id) % 2 == 0) {
- throw "I don't like this record! Baaaaaah!";
+ throw new Error("I don't like this record! Baaaaaah!");
}
return this.__reconcile.apply(this, arguments);
};
engine._store._applyIncoming = engine._store.applyIncoming;
engine._store.applyIncoming = async function(record) {
if (BOGUS_RECORDS.indexOf(record.id) % 2 == 1) {
- throw "I don't like this record! Baaaaaah!";
+ throw new Error("I don't like this record! Baaaaaah!");
}
return this._applyIncoming.apply(this, arguments);
};
// Keep track of requests made of a collection.
let count = 0;
let uris = [];
function recording_handler(recordedCollection) {
@@ -1084,17 +1084,18 @@ add_task(async function test_processInco
denomination: "Flying Scotsman"}));
collection._wbos.nodecrypt = new ServerWBO("nodecrypt", "Decrypt this!");
collection._wbos.nodecrypt2 = new ServerWBO("nodecrypt2", "Decrypt this!");
// Patch the fake crypto service to throw on the record above.
Weave.Crypto._decrypt = Weave.Crypto.decrypt;
Weave.Crypto.decrypt = function(ciphertext) {
if (ciphertext == "Decrypt this!") {
- throw "Derp! Cipher finalized failed. Im ur crypto destroyin ur recordz.";
+ throw new Error(
+ "Derp! Cipher finalized failed. Im ur crypto destroyin ur recordz.");
}
return this._decrypt.apply(this, arguments);
};
// Some broken records also exist locally.
let engine = makeRotaryEngine();
engine.enabled = true;
engine._store.items = {nojson: "Valid JSON",
@@ -1675,17 +1676,17 @@ add_task(async function test_sync_partia
engine.lastSync = 123; // needs to be non-zero so that tracker is queried
engine.lastSyncLocal = 456;
// Let the third upload fail completely
var noOfUploads = 0;
collection.post = (function(orig) {
return function() {
if (noOfUploads == 2)
- throw "FAIL!";
+ throw new Error("FAIL!");
noOfUploads++;
return orig.apply(this, arguments);
};
}(collection.post));
// Create a bunch of records (and server side handlers)
for (let i = 0; i < 234; i++) {
let id = "record-no-" + i;
--- a/services/sync/tests/unit/test_telemetry.js
+++ b/services/sync/tests/unit/test_telemetry.js
@@ -113,17 +113,17 @@ add_task(async function test_processInco
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
try {
// Create a bogus record that when synced down will provoke a
// network error which in turn provokes an exception in _processIncoming.
const BOGUS_GUID = "zzzzzzzzzzzz";
let bogus_record = collection.insert(BOGUS_GUID, "I'm a bogus record!");
bogus_record.get = function get() {
- throw "Sync this!";
+ throw new Error("Sync this!");
};
// Make the 10 minutes old so it will only be synced in the toFetch phase.
bogus_record.modified = Date.now() / 1000 - 60 * 10;
engine.lastSync = Date.now() / 1000 - 60;
engine.toFetch = [BOGUS_GUID];
let error, pingPayload, fullPing;
try {
@@ -289,17 +289,17 @@ add_task(async function test_sync_partia
ok(!!ping);
ok(!ping.failureReason);
equal(ping.engines.length, 1);
equal(ping.engines[0].name, "rotary");
ok(!ping.engines[0].incoming);
ok(!ping.engines[0].failureReason);
deepEqual(ping.engines[0].outgoing, [{ sent: 234, failed: 2 }]);
- collection.post = function() { throw "Failure"; }
+ collection.post = function() { throw new Error("Failure"); }
engine._store.items["record-no-1000"] = "Record No. 1000";
engine._tracker.addChangedID("record-no-1000", 1000);
collection.insert("record-no-1000", 1000);
engine.lastSync = 123;
engine.lastSyncLocal = 456;
ping = null;
--- a/services/sync/tests/unit/test_utils_catch.js
+++ b/services/sync/tests/unit/test_utils_catch.js
@@ -1,14 +1,14 @@
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/service.js");
add_task(async function run_test() {
_("Make sure catch when copied to an object will correctly catch stuff");
- let ret, rightThis, didCall, didThrow, wasTen, wasLocked;
+ let ret, rightThis, didCall, didThrow, wasCovfefe, wasLocked;
let obj = {
_catch: Utils.catch,
_log: {
debug(str) {
didThrow = str.search(/^Exception/) == 0;
},
info(str) {
wasLocked = str.indexOf("Cannot start sync: already syncing?") == 0;
@@ -22,92 +22,92 @@ add_task(async function run_test() {
return 5;
})();
},
throwy() {
return this._catch(async function() {
rightThis = this == obj;
didCall = true;
- throw 10;
+ throw new Error("covfefe");
})();
},
callbacky() {
return this._catch(async function() {
rightThis = this == obj;
didCall = true;
- throw 10;
+ throw new Error("covfefe");
}, async function(ex) {
- wasTen = (ex == 10)
+ wasCovfefe = ex && ex.message == "covfefe";
})();
},
lockedy() {
return this._catch(async function() {
rightThis = this == obj;
didCall = true;
- throw ("Could not acquire lock.");
+ Utils.throwLockException(null);
})();
},
lockedy_chained() {
- return this._catch(function() {
+ return this._catch(async function() {
rightThis = this == obj;
didCall = true;
- return Promise.resolve().then( () => { throw ("Could not acquire lock.") });
+ Utils.throwLockException(null);
})();
},
};
_("Make sure a normal call will call and return");
rightThis = didCall = didThrow = wasLocked = false;
ret = await obj.func();
do_check_eq(ret, 5);
do_check_true(rightThis);
do_check_true(didCall);
do_check_false(didThrow);
- do_check_eq(wasTen, undefined);
+ do_check_eq(wasCovfefe, undefined);
do_check_false(wasLocked);
_("Make sure catch/throw results in debug call and caller doesn't need to handle exception");
rightThis = didCall = didThrow = wasLocked = false;
ret = await obj.throwy();
do_check_eq(ret, undefined);
do_check_true(rightThis);
do_check_true(didCall);
do_check_true(didThrow);
- do_check_eq(wasTen, undefined);
+ do_check_eq(wasCovfefe, undefined);
do_check_false(wasLocked);
_("Test callback for exception testing.");
rightThis = didCall = didThrow = wasLocked = false;
ret = await obj.callbacky();
do_check_eq(ret, undefined);
do_check_true(rightThis);
do_check_true(didCall);
do_check_true(didThrow);
- do_check_true(wasTen);
+ do_check_true(wasCovfefe);
do_check_false(wasLocked);
_("Test the lock-aware catch that Service uses.");
obj._catch = Service._catch;
rightThis = didCall = didThrow = wasLocked = false;
- wasTen = undefined;
+ wasCovfefe = undefined;
ret = await obj.lockedy();
do_check_eq(ret, undefined);
do_check_true(rightThis);
do_check_true(didCall);
do_check_true(didThrow);
- do_check_eq(wasTen, undefined);
+ do_check_eq(wasCovfefe, undefined);
do_check_true(wasLocked);
_("Test the lock-aware catch that Service uses with a chained promise.");
rightThis = didCall = didThrow = wasLocked = false;
- wasTen = undefined;
+ wasCovfefe = undefined;
ret = await obj.lockedy_chained();
do_check_eq(ret, undefined);
do_check_true(rightThis);
do_check_true(didCall);
do_check_true(didThrow);
- do_check_eq(wasTen, undefined);
+ do_check_eq(wasCovfefe, undefined);
do_check_true(wasLocked);
});
--- a/services/sync/tests/unit/test_utils_lock.js
+++ b/services/sync/tests/unit/test_utils_lock.js
@@ -60,17 +60,17 @@ add_task(async function run_test() {
_("Make sure code that calls locked code throws");
ret = null;
rightThis = didCall = false;
try {
ret = await obj.throwy();
do_throw("throwy internal call should have thrown!");
} catch (ex) {
// Should throw an Error, not a string.
- do_check_begins(ex, "Could not acquire lock");
+ do_check_begins(ex.message, "Could not acquire lock");
}
do_check_eq(ret, null);
do_check_true(rightThis);
do_check_true(didCall);
_("Lock should be called twice so state 3 is skipped");
do_check_eq(lockState, 4);
do_check_eq(lockedState, 5);
do_check_eq(unlockState, 6);
--- a/services/sync/tests/unit/test_utils_notify.js
+++ b/services/sync/tests/unit/test_utils_notify.js
@@ -16,17 +16,17 @@ add_task(async function run_test() {
return 5;
})();
},
throwy() {
return this.notify("bad", "one", async function() {
rightThis = this == obj;
didCall = true;
- throw 10;
+ throw new Error("covfefe");
})();
}
};
let state = 0;
let makeObs = function(topic) {
let obj2 = {
observe(subject, obsTopic, data) {
@@ -71,29 +71,29 @@ add_task(async function run_test() {
rightThis = didCall = false;
let ts = makeObs("foo:bad:start");
let tf = makeObs("foo:bad:finish");
let te = makeObs("foo:bad:error");
try {
ret = await obj.throwy();
do_throw("throwy should have thrown!");
} catch (ex) {
- do_check_eq(ex, 10);
+ do_check_eq(ex.message, "covfefe");
}
do_check_eq(ret, null);
do_check_true(rightThis);
do_check_true(didCall);
do_check_eq(ts.state, 3);
do_check_eq(ts.subject, undefined);
do_check_eq(ts.topic, "foo:bad:start");
do_check_eq(ts.data, "one");
do_check_eq(tf.state, undefined);
do_check_eq(tf.subject, undefined);
do_check_eq(tf.topic, undefined);
do_check_eq(tf.data, undefined);
do_check_eq(te.state, 4);
- do_check_eq(te.subject, 10);
+ do_check_eq(te.subject.message, "covfefe");
do_check_eq(te.topic, "foo:bad:error");
do_check_eq(te.data, "one");
});
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js
@@ -477,17 +477,17 @@ function _computeKeyCodeFromChar(aChar)
* name begins with "VK_", or a character.
*/
function isKeypressFiredKey(aDOMKeyCode)
{
if (typeof(aDOMKeyCode) == "string") {
if (aDOMKeyCode.indexOf("VK_") == 0) {
aDOMKeyCode = KeyEvent["DOM_" + aDOMKeyCode];
if (!aDOMKeyCode) {
- throw "Unknown key: " + aDOMKeyCode;
+ throw new Error(`Unknown key: ${aDOMKeyCode}`);
}
} else {
// If the key generates a character, it must cause a keypress event.
return true;
}
}
switch (aDOMKeyCode) {
case KeyEvent.DOM_VK_SHIFT:
@@ -524,17 +524,17 @@ function isKeypressFiredKey(aDOMKeyCode)
function synthesizeKey(aKey, aEvent, aWindow)
{
var utils = _getDOMWindowUtils(aWindow);
if (utils) {
var keyCode = 0, charCode = 0;
if (aKey.indexOf("VK_") == 0) {
keyCode = KeyEvent["DOM_" + aKey];
if (!keyCode) {
- throw "Unknown key: " + aKey;
+ throw new Error(`Unknown key: ${aKey}`);
}
} else {
charCode = aKey.charCodeAt(0);
keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
}
var modifiers = _parseModifiers(aEvent);
var flags = 0;
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/httpd.js
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/httpd.js
@@ -1715,17 +1715,17 @@ RequestReader.prototype =
throw HTTP_400;
}
// determine HTTP version
try
{
metadata._httpVersion = new nsHttpVersion(match[1]);
if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_0))
- throw "unsupported HTTP version";
+ throw new Error("unsupported HTTP version");
}
catch (e)
{
// we support HTTP/1.0 and HTTP/1.1 only
throw HTTP_501;
}
@@ -4866,27 +4866,27 @@ function htmlEscape(str)
* or without leading zeros
* @throws
* if versionString does not specify a valid HTTP version number
*/
function nsHttpVersion(versionString)
{
var matches = /^(\d+)\.(\d+)$/.exec(versionString);
if (!matches)
- throw "Not a valid HTTP version!";
+ throw new Error("Not a valid HTTP version!");
/** The major version number of this, as a number. */
this.major = parseInt(matches[1], 10);
/** The minor version number of this, as a number. */
this.minor = parseInt(matches[2], 10);
if (isNaN(this.major) || isNaN(this.minor) ||
this.major < 0 || this.minor < 0)
- throw "Not a valid HTTP version!";
+ throw new Error("Not a valid HTTP version!");
}
nsHttpVersion.prototype =
{
/**
* Returns the standard string representation of the HTTP version represented
* by this (e.g., "1.1").
*/
toString: function ()
--- a/services/sync/tps/extensions/tps/resource/modules/history.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/history.jsm
@@ -181,16 +181,16 @@ var HistoryEntry = {
} else if ("begin" in item && "end" in item) {
let cb = Async.makeSpinningCallback();
let msSinceEpoch = parseInt(usSinceEpoch / 1000);
let filter = {
beginDate: new Date(msSinceEpoch + (item.begin * 60 * 60 * 1000)),
endDate: new Date(msSinceEpoch + (item.end * 60 * 60 * 1000))
};
PlacesUtils.history.removeVisitsByFilter(filter)
- .catch(ex => Logger.AssertTrue(false, "An error occurred while deleting history: " + ex))
+ .catch(ex => Logger.AssertTrue(false, "An error occurred while deleting history: " + ex.message))
.then(result => { cb(null, result) }, err => { cb(err) });
Async.waitForSyncCallback(cb);
} else {
Logger.AssertTrue(false, "invalid entry in delete history");
}
},
};
--- a/services/sync/tps/extensions/tps/resource/quit.js
+++ b/services/sync/tps/extensions/tps/resource/quit.js
@@ -46,14 +46,14 @@ function goQuitApplication() {
forceQuit = Components.interfaces.nsIAppShellService.eForceQuit;
} else {
throw new Error("goQuitApplication: no AppStartup/appShell");
}
try {
appService.quit(forceQuit);
} catch (ex) {
- throw new Error("goQuitApplication: " + ex);
+ throw new Error(`goQuitApplication: ${ex.message}`);
}
return true;
}
--- a/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync_crypto.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync_crypto.js
@@ -25,24 +25,24 @@ async function throwsGen(constraint, f)
} catch (e) {
threw = true;
exception = e;
}
ok(threw, "did not throw an exception");
const debuggingMessage = `got ${exception}, expected ${constraint}`;
- let message = exception;
- if (typeof exception === "object") {
- message = exception.message;
- }
if (typeof constraint === "function") {
- ok(constraint(message), debuggingMessage);
+ ok(constraint(exception), debuggingMessage);
} else {
+ let message = exception;
+ if (typeof exception === "object") {
+ message = exception.message;
+ }
ok(constraint === message, debuggingMessage);
}
}
/**
* An EncryptionRemoteTransformer that uses a fixed key bundle,
* suitable for testing.
*/