blob: c090c9545bb0e6fdf4c1ee68e712ca7faf98745f [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Common test utilities.
/**
* Allows console.log output.
*/
var showConsoleLogOutput = false;
/**
* Conditionally allow console.log output based off of showConsoleLogOutput.
*/
console.log = function() {
var originalConsoleLog = console.log;
return function() {
if (showConsoleLogOutput) {
originalConsoleLog.apply(console, arguments);
}
};
}();
function emptyMock() {}
// Container for event handlers added by mocked 'addListener' functions.
var mockEventHandlers = {};
/**
* Mocks 'addListener' function of an API event. The mocked function will keep
* track of handlers.
* @param {Object} topLevelContainer Top-level container of the original
* function. Can be either 'chrome' or 'instrumented'.
* @param {string} eventIdentifier Event identifier, such as
* 'runtime.onSuspend'.
*/
function mockChromeEvent(topLevelContainer, eventIdentifier) {
var eventIdentifierParts = eventIdentifier.split('.');
var eventName = eventIdentifierParts.pop();
var originalMethodContainer = topLevelContainer;
var mockEventContainer = mockEventHandlers;
eventIdentifierParts.forEach(function(fragment) {
originalMethodContainer =
originalMethodContainer[fragment] =
originalMethodContainer[fragment] || {};
mockEventContainer =
mockEventContainer[fragment] =
mockEventContainer[fragment] || {};
});
mockEventContainer[eventName] = [];
originalMethodContainer[eventName] = {
addListener: function(callback) {
mockEventContainer[eventName].push(callback);
}
};
}
/**
* Gets the array of event handlers added by a mocked 'addListener' function.
* @param {string} eventIdentifier Event identifier, such as
* 'runtime.onSuspend'.
* @return {Array.<Function>} Array of handlers.
*/
function getMockHandlerContainer(eventIdentifier) {
var eventIdentifierParts = eventIdentifier.split('.');
var mockEventContainer = mockEventHandlers;
eventIdentifierParts.forEach(function(fragment) {
mockEventContainer = mockEventContainer[fragment];
});
return mockEventContainer;
}
/**
* MockPromise
* The JS test harness expects all calls to complete synchronously.
* As a result, we can't use built-in JS promises since they run asynchronously.
* Instead of mocking all possible calls to promises, a skeleton
* implementation is provided to get the tests to pass.
*
* This functionality and logic originates from ECMAScript 6's spec of promises.
*/
var Promise = function() {
function PromisePrototypeObject(asyncTask) {
function isThenable(value) {
return (typeof value === 'object') && isCallable(value.then);
}
function isCallable(value) {
return typeof value === 'function';
}
function callResolveRejectFunc(func) {
var funcResult;
var funcResolved = false;
func(
function(resolveResult) {
funcResult = resolveResult;
funcResolved = true;
},
function(rejectResult) {
funcResult = rejectResult;
funcResolved = false;
});
return { result: funcResult, resolved: funcResolved };
}
function then(onResolve, onReject) {
var resolutionHandler =
isCallable(onResolve) ? onResolve : function() { return result; };
var rejectionHandler =
isCallable(onReject) ? onReject : function() { return result; };
var handlerResult =
resolved ? resolutionHandler(result) : rejectionHandler(result);
var promiseResolved = resolved;
if (isThenable(handlerResult)) {
var resolveReject = callResolveRejectFunc(handlerResult.then);
handlerResult = resolveReject.result;
promiseResolved = resolveReject.resolved;
}
if (promiseResolved) {
return Promise.resolve(handlerResult);
} else {
return Promise.reject(handlerResult);
}
}
// Promises use the function name "catch" to call back error handlers.
// We can't use "catch" since function or variable names cannot use the word
// "catch".
function catchFunc(onRejected) {
return this.then(undefined, onRejected);
}
var resolveReject = callResolveRejectFunc(asyncTask);
var result = resolveReject.result;
var resolved = resolveReject.resolved;
if (isThenable(result)) {
var thenResolveReject = callResolveRejectFunc(result.then);
result = thenResolveReject.result;
resolved = thenResolveReject.resolved;
}
return {then: then, catch: catchFunc, isPromise: true};
}
function all(arrayOfPromises) {
var results = [];
for (i = 0; i < arrayOfPromises.length; i++) {
if (arrayOfPromises[i].isPromise) {
arrayOfPromises[i].then(function(result) {
results[i] = result;
});
} else {
results[i] = arrayOfPromises[i];
}
}
var promise = new PromisePrototypeObject(function(resolve) {
resolve(results);
});
return promise;
}
function resolve(value) {
var promise = new PromisePrototypeObject(function(resolve) {
resolve(value);
});
return promise;
}
function reject(value) {
var promise = new PromisePrototypeObject(function(resolve, reject) {
reject(value);
});
return promise;
}
PromisePrototypeObject.all = all;
PromisePrototypeObject.resolve = resolve;
PromisePrototypeObject.reject = reject;
return PromisePrototypeObject;
}();
/**
* Sets up the test to expect a Chrome Local Storage call.
* @param {Object} fixture Mock JS Test Object.
* @param {Object} defaultObject Storage request default object.
* @param {Object} result Storage result.
* @param {boolean=} opt_AllowRejection Allow Promise Rejection
*/
function expectChromeLocalStorageGet(
fixture, defaultObject, result, opt_AllowRejection) {
if (opt_AllowRejection === undefined) {
fixture.mockApis.expects(once()).
fillFromChromeLocalStorage(eqJSON(defaultObject)).
will(returnValue(Promise.resolve(result)));
} else {
fixture.mockApis.expects(once()).
fillFromChromeLocalStorage(eqJSON(defaultObject), opt_AllowRejection).
will(returnValue(Promise.resolve(result)));
}
}