1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5var sendRequestNatives = requireNative('sendRequest'); 6 7function registerHooks(api) { 8 var chromeTest = api.compiledApi; 9 var apiFunctions = api.apiFunctions; 10 11 apiFunctions.setHandleRequest('notifyPass', function() { 12 requireAsync('testNatives').then(function(natives) { 13 natives.NotifyPass(); 14 }); 15 }); 16 17 apiFunctions.setHandleRequest('notifyFail', function(message) { 18 requireAsync('testNatives').then(function(natives) { 19 natives.NotifyFail(message); 20 }); 21 }); 22 23 apiFunctions.setHandleRequest('log', function() { 24 requireAsync('testNatives').then(function(natives) { 25 natives.Log($Array.join(arguments, ' ')); 26 }); 27 }); 28 29} 30 31function testDone(runNextTest) { 32 // Use a promise here to allow previous test contexts to be eligible for 33 // garbage collection. 34 Promise.resolve().then(function() { 35 runNextTest(); 36 }); 37} 38 39function exportTests(tests, runTests, exports) { 40 $Array.forEach(tests, function(test) { 41 exports[test.name] = function() { 42 runTests([test]); 43 return true; 44 }; 45 }); 46} 47 48/** 49 * A fake implementation of setTimeout and clearTimeout. 50 * @constructor 51 */ 52function TimeoutManager() { 53 this.timeouts_ = {}; 54 this.nextTimeoutId_ = 0; 55 this.currentTime = 0; 56 this.autorunEnabled_ = false; 57} 58 59/** 60 * Installs setTimeout and clearTimeout into the global object. 61 */ 62TimeoutManager.prototype.installGlobals = function() { 63 var global = sendRequestNatives.GetGlobal({}); 64 global.setTimeout = this.setTimeout_.bind(this); 65 global.clearTimeout = this.clearTimeout_.bind(this); 66}; 67 68/** 69 * Starts auto-running of timeout callbacks. Until |numCallbacksToRun| callbacks 70 * have run, any timeout callbacks set by calls to setTimeout (including before 71 * the call to run) will cause the currentTime to be advanced to the time of 72 * the timeout. 73 */ 74TimeoutManager.prototype.run = function(numCallbacksToRun) { 75 this.numCallbacksToRun_ = numCallbacksToRun; 76 Promise.resolve().then(this.autoRun_.bind(this)); 77}; 78 79/** 80 * Runs timeout callbacks with earliest timeout. 81 * @private 82 */ 83TimeoutManager.prototype.autoRun_ = function() { 84 if (this.numCallbacksToRun_ <= 0 || $Object.keys(this.timeouts_).length == 0) 85 return; 86 87 // Bucket the timeouts by their timeout time. 88 var timeoutsByTimeout = {}; 89 var timeoutIds = $Object.keys(this.timeouts_); 90 for (var i = 0; i < timeoutIds.length; i++) { 91 var timeout = this.timeouts_[timeoutIds[i]]; 92 var timeMs = timeout.timeMs; 93 if (!timeoutsByTimeout[timeMs]) 94 timeoutsByTimeout[timeMs] = []; 95 timeoutsByTimeout[timeMs].push(timeout); 96 } 97 this.currentTime = 98 $Function.apply(Math.min, null, $Object.keys((timeoutsByTimeout))); 99 // Run all timeouts in the earliest timeout bucket. 100 var timeouts = timeoutsByTimeout[this.currentTime]; 101 for (var i = 0; i < timeouts.length; i++) { 102 var currentTimeout = timeouts[i]; 103 if (!this.timeouts_[currentTimeout.id]) 104 continue; 105 this.numCallbacksToRun_--; 106 delete this.timeouts_[currentTimeout.id]; 107 try { 108 currentTimeout.target(); 109 } catch (e) { 110 console.log('error calling timeout target ' + e.stack); 111 } 112 } 113 // Continue running any later callbacks. 114 Promise.resolve().then(this.autoRun_.bind(this)); 115}; 116 117/** 118 * A fake implementation of setTimeout. This does not support passing callback 119 * arguments. 120 * @private 121 */ 122TimeoutManager.prototype.setTimeout_ = function(target, timeoutMs) { 123 var timeoutId = this.nextTimeoutId_++; 124 this.timeouts_[timeoutId] = { 125 id: timeoutId, 126 target: target, 127 timeMs: timeoutMs + this.currentTime, 128 }; 129 if (this.autorunEnabled_) 130 Promise.resolve().then(this.autoRun_.bind(this)); 131 return timeoutId; 132}; 133 134/** 135 * A fake implementation of clearTimeout. 136 * @private 137 */ 138TimeoutManager.prototype.clearTimeout_ = function(timeoutId) { 139 if (this.timeouts_[timeoutId]) 140 delete this.timeouts_[timeoutId]; 141}; 142 143exports.registerHooks = registerHooks; 144exports.testDone = testDone; 145exports.exportTests = exportTests; 146exports.TimeoutManager = TimeoutManager; 147