blob: 2fbcc3e09be09f5543e126ded5d20781491f7010 [file] [log] [blame]
// Copyright 2014 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.
var sendRequestNatives = requireNative('sendRequest');
function registerHooks(api) {
var chromeTest = api.compiledApi;
var apiFunctions = api.apiFunctions;
apiFunctions.setHandleRequest('notifyPass', function() {
requireAsync('testNatives').then(function(natives) {
natives.NotifyPass();
});
});
apiFunctions.setHandleRequest('notifyFail', function(message) {
requireAsync('testNatives').then(function(natives) {
natives.NotifyFail(message);
});
});
apiFunctions.setHandleRequest('log', function() {
requireAsync('testNatives').then(function(natives) {
natives.Log($Array.join(arguments, ' '));
});
});
}
function testDone(runNextTest) {
// Use a promise here to allow previous test contexts to be eligible for
// garbage collection.
Promise.resolve().then(function() {
runNextTest();
});
}
function exportTests(tests, runTests, exports) {
$Array.forEach(tests, function(test) {
exports[test.name] = function() {
runTests([test]);
return true;
};
});
}
/**
* A fake implementation of setTimeout and clearTimeout.
* @constructor
*/
function TimeoutManager() {
this.timeouts_ = {};
this.nextTimeoutId_ = 0;
this.currentTime = 0;
this.autorunEnabled_ = false;
}
/**
* Installs setTimeout and clearTimeout into the global object.
*/
TimeoutManager.prototype.installGlobals = function() {
var global = sendRequestNatives.GetGlobal({});
global.setTimeout = this.setTimeout_.bind(this);
global.clearTimeout = this.clearTimeout_.bind(this);
};
/**
* Starts auto-running of timeout callbacks. Until |numCallbacksToRun| callbacks
* have run, any timeout callbacks set by calls to setTimeout (including before
* the call to run) will cause the currentTime to be advanced to the time of
* the timeout.
*/
TimeoutManager.prototype.run = function(numCallbacksToRun) {
this.numCallbacksToRun_ = numCallbacksToRun;
Promise.resolve().then(this.autoRun_.bind(this));
};
/**
* Runs timeout callbacks with earliest timeout.
* @private
*/
TimeoutManager.prototype.autoRun_ = function() {
if (this.numCallbacksToRun_ <= 0 || $Object.keys(this.timeouts_).length == 0)
return;
// Bucket the timeouts by their timeout time.
var timeoutsByTimeout = {};
var timeoutIds = $Object.keys(this.timeouts_);
for (var i = 0; i < timeoutIds.length; i++) {
var timeout = this.timeouts_[timeoutIds[i]];
var timeMs = timeout.timeMs;
if (!timeoutsByTimeout[timeMs])
timeoutsByTimeout[timeMs] = [];
timeoutsByTimeout[timeMs].push(timeout);
}
this.currentTime =
$Function.apply(Math.min, null, $Object.keys((timeoutsByTimeout)));
// Run all timeouts in the earliest timeout bucket.
var timeouts = timeoutsByTimeout[this.currentTime];
for (var i = 0; i < timeouts.length; i++) {
var currentTimeout = timeouts[i];
if (!this.timeouts_[currentTimeout.id])
continue;
this.numCallbacksToRun_--;
delete this.timeouts_[currentTimeout.id];
try {
currentTimeout.target();
} catch (e) {
console.log('error calling timeout target ' + e.stack);
}
}
// Continue running any later callbacks.
Promise.resolve().then(this.autoRun_.bind(this));
};
/**
* A fake implementation of setTimeout. This does not support passing callback
* arguments.
* @private
*/
TimeoutManager.prototype.setTimeout_ = function(target, timeoutMs) {
var timeoutId = this.nextTimeoutId_++;
this.timeouts_[timeoutId] = {
id: timeoutId,
target: target,
timeMs: timeoutMs + this.currentTime,
};
if (this.autorunEnabled_)
Promise.resolve().then(this.autoRun_.bind(this));
return timeoutId;
};
/**
* A fake implementation of clearTimeout.
* @private
*/
TimeoutManager.prototype.clearTimeout_ = function(timeoutId) {
if (this.timeouts_[timeoutId])
delete this.timeouts_[timeoutId];
};
exports.registerHooks = registerHooks;
exports.testDone = testDone;
exports.exportTests = exportTests;
exports.TimeoutManager = TimeoutManager;