15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivar sendRequestNatives = requireNative('sendRequest');
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function registerHooks(api) {
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var chromeTest = api.compiledApi;
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var apiFunctions = api.apiFunctions;
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  apiFunctions.setHandleRequest('notifyPass', function() {
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    requireAsync('testNatives').then(function(natives) {
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      natives.NotifyPass();
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    });
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  });
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  apiFunctions.setHandleRequest('notifyFail', function(message) {
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    requireAsync('testNatives').then(function(natives) {
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      natives.NotifyFail(message);
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    });
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  });
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  apiFunctions.setHandleRequest('log', function() {
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    requireAsync('testNatives').then(function(natives) {
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      natives.Log($Array.join(arguments, ' '));
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    });
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  });
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function testDone(runNextTest) {
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Use a promise here to allow previous test contexts to be eligible for
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // garbage collection.
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Promise.resolve().then(function() {
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      runNextTest();
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    });
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function exportTests(tests, runTests, exports) {
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  $Array.forEach(tests, function(test) {
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    exports[test.name] = function() {
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      runTests([test]);
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    };
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  });
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * A fake implementation of setTimeout and clearTimeout.
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @constructor
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction TimeoutManager() {
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.timeouts_ = {};
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.nextTimeoutId_ = 0;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.currentTime = 0;
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.autorunEnabled_ = false;
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Installs setTimeout and clearTimeout into the global object.
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTimeoutManager.prototype.installGlobals = function() {
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var global = sendRequestNatives.GetGlobal({});
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  global.setTimeout = this.setTimeout_.bind(this);
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  global.clearTimeout = this.clearTimeout_.bind(this);
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Starts auto-running of timeout callbacks. Until |numCallbacksToRun| callbacks
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * have run, any timeout callbacks set by calls to setTimeout (including before
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * the call to run) will cause the currentTime to be advanced to the time of
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * the timeout.
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTimeoutManager.prototype.run = function(numCallbacksToRun) {
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.numCallbacksToRun_ = numCallbacksToRun;
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Promise.resolve().then(this.autoRun_.bind(this));
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Runs timeout callbacks with earliest timeout.
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @private
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTimeoutManager.prototype.autoRun_ = function() {
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (this.numCallbacksToRun_ <= 0 || $Object.keys(this.timeouts_).length == 0)
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Bucket the timeouts by their timeout time.
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var timeoutsByTimeout = {};
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var timeoutIds = $Object.keys(this.timeouts_);
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (var i = 0; i < timeoutIds.length; i++) {
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var timeout = this.timeouts_[timeoutIds[i]];
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var timeMs = timeout.timeMs;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!timeoutsByTimeout[timeMs])
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      timeoutsByTimeout[timeMs] = [];
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timeoutsByTimeout[timeMs].push(timeout);
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.currentTime =
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      $Function.apply(Math.min, null, $Object.keys((timeoutsByTimeout)));
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Run all timeouts in the earliest timeout bucket.
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var timeouts = timeoutsByTimeout[this.currentTime];
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (var i = 0; i < timeouts.length; i++) {
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var currentTimeout = timeouts[i];
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!this.timeouts_[currentTimeout.id])
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      continue;
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.numCallbacksToRun_--;
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    delete this.timeouts_[currentTimeout.id];
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    try {
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      currentTimeout.target();
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } catch (e) {
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      console.log('error calling timeout target ' + e.stack);
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Continue running any later callbacks.
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Promise.resolve().then(this.autoRun_.bind(this));
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * A fake implementation of setTimeout. This does not support passing callback
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * arguments.
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @private
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTimeoutManager.prototype.setTimeout_ = function(target, timeoutMs) {
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var timeoutId = this.nextTimeoutId_++;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.timeouts_[timeoutId] = {
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    id: timeoutId,
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    target: target,
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timeMs: timeoutMs + this.currentTime,
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (this.autorunEnabled_)
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Promise.resolve().then(this.autoRun_.bind(this));
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return timeoutId;
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * A fake implementation of clearTimeout.
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @private
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTimeoutManager.prototype.clearTimeout_ = function(timeoutId) {
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (this.timeouts_[timeoutId])
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    delete this.timeouts_[timeoutId];
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)exports.registerHooks = registerHooks;
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)exports.testDone = testDone;
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)exports.exportTests = exportTests;
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciexports.TimeoutManager = TimeoutManager;
147