Roll src/third_party/WebKit 9301d6f:4619053 (svn 201058:201059)
[chromium-blink-merge.git] / extensions / renderer / resources / test_custom_bindings.js
blob7310f06144f50a8966996e3b5d6c5c584b1e90b2
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.
5 // test_custom_bindings.js
6 // mini-framework for ExtensionApiTest browser tests
8 var binding = require('binding').Binding.create('test');
10 var environmentSpecificBindings = require('test_environment_specific_bindings');
11 var GetExtensionAPIDefinitionsForTest =
12     requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest;
13 var GetAPIFeatures = requireNative('test_features').GetAPIFeatures;
14 var natives = requireNative('test_native_handler');
15 var uncaughtExceptionHandler = require('uncaught_exception_handler');
16 var userGestures = requireNative('user_gestures');
18 var RunWithNativesEnabled = requireNative('v8_context').RunWithNativesEnabled;
19 var GetModuleSystem = requireNative('v8_context').GetModuleSystem;
21 binding.registerCustomHook(function(api) {
22   var chromeTest = api.compiledApi;
23   var apiFunctions = api.apiFunctions;
25   chromeTest.tests = chromeTest.tests || [];
27   var currentTest = null;
28   var lastTest = null;
29   var testsFailed = 0;
30   var testCount = 1;
31   var failureException = 'chrome.test.failure';
33   // Helper function to get around the fact that function names in javascript
34   // are read-only, and you can't assign one to anonymous functions.
35   function testName(test) {
36     return test ? (test.name || test.generatedName) : "(no test)";
37   }
39   function testDone() {
40     environmentSpecificBindings.testDone(chromeTest.runNextTest);
41   }
43   function allTestsDone() {
44     if (testsFailed == 0) {
45       chromeTest.notifyPass();
46     } else {
47       chromeTest.notifyFail('Failed ' + testsFailed + ' of ' +
48                              testCount + ' tests');
49     }
50   }
52   var pendingCallbacks = 0;
54   apiFunctions.setHandleRequest('callbackAdded', function() {
55     pendingCallbacks++;
57     var called = null;
58     return function() {
59       if (called != null) {
60         var redundantPrefix = 'Error\n';
61         chromeTest.fail(
62           'Callback has already been run. ' +
63           'First call:\n' +
64           $String.slice(called, redundantPrefix.length) + '\n' +
65           'Second call:\n' +
66           $String.slice(new Error().stack, redundantPrefix.length));
67       }
68       called = new Error().stack;
70       pendingCallbacks--;
71       if (pendingCallbacks == 0) {
72         chromeTest.succeed();
73       }
74     };
75   });
77   apiFunctions.setHandleRequest('runNextTest', function() {
78     // There may have been callbacks which were interrupted by failure
79     // exceptions.
80     pendingCallbacks = 0;
82     lastTest = currentTest;
83     currentTest = chromeTest.tests.shift();
85     if (!currentTest) {
86       allTestsDone();
87       return;
88     }
90     try {
91       chromeTest.log("( RUN      ) " + testName(currentTest));
92       uncaughtExceptionHandler.setHandler(function(message, e) {
93         if (e !== failureException)
94           chromeTest.fail('uncaught exception: ' + message);
95       });
96       currentTest.call();
97     } catch (e) {
98       uncaughtExceptionHandler.handle(e.message, e);
99     }
100   });
102   apiFunctions.setHandleRequest('fail', function(message) {
103     chromeTest.log("(  FAILED  ) " + testName(currentTest));
105     var stack = {};
106     Error.captureStackTrace(stack, chromeTest.fail);
108     if (!message)
109       message = "FAIL (no message)";
111     message += "\n" + stack.stack;
112     console.log("[FAIL] " + testName(currentTest) + ": " + message);
113     testsFailed++;
114     testDone();
116     // Interrupt the rest of the test.
117     throw failureException;
118   });
120   apiFunctions.setHandleRequest('succeed', function() {
121     console.log("[SUCCESS] " + testName(currentTest));
122     chromeTest.log("(  SUCCESS )");
123     testDone();
124   });
126   apiFunctions.setHandleRequest('runWithNativesEnabled', function(callback) {
127     RunWithNativesEnabled(callback);
128   });
130   apiFunctions.setHandleRequest('getModuleSystem', function(context) {
131     return GetModuleSystem(context);
132   });
134   apiFunctions.setHandleRequest('assertTrue', function(test, message) {
135     chromeTest.assertBool(test, true, message);
136   });
138   apiFunctions.setHandleRequest('assertFalse', function(test, message) {
139     chromeTest.assertBool(test, false, message);
140   });
142   apiFunctions.setHandleRequest('assertBool',
143                                 function(test, expected, message) {
144     if (test !== expected) {
145       if (typeof(test) == "string") {
146         if (message)
147           message = test + "\n" + message;
148         else
149           message = test;
150       }
151       chromeTest.fail(message);
152     }
153   });
155   apiFunctions.setHandleRequest('checkDeepEq', function(expected, actual) {
156     if ((expected === null) != (actual === null))
157       return false;
159     if (expected === actual)
160       return true;
162     if (typeof(expected) !== typeof(actual))
163       return false;
165     for (var p in actual) {
166       if ($Object.hasOwnProperty(actual, p) &&
167           !$Object.hasOwnProperty(expected, p)) {
168         return false;
169       }
170     }
171     for (var p in expected) {
172       if ($Object.hasOwnProperty(expected, p) &&
173           !$Object.hasOwnProperty(actual, p)) {
174         return false;
175       }
176     }
178     for (var p in expected) {
179       var eq = true;
180       switch (typeof(expected[p])) {
181         case 'object':
182           eq = chromeTest.checkDeepEq(expected[p], actual[p]);
183           break;
184         case 'function':
185           eq = (typeof(actual[p]) != 'undefined' &&
186                 expected[p].toString() == actual[p].toString());
187           break;
188         default:
189           eq = (expected[p] == actual[p] &&
190                 typeof(expected[p]) == typeof(actual[p]));
191           break;
192       }
193       if (!eq)
194         return false;
195     }
196     return true;
197   });
199   apiFunctions.setHandleRequest('assertEq',
200                                 function(expected, actual, message) {
201     var error_msg = "API Test Error in " + testName(currentTest);
202     if (message)
203       error_msg += ": " + message;
204     if (typeof(expected) == 'object') {
205       if (!chromeTest.checkDeepEq(expected, actual)) {
206         error_msg += "\nActual: " + $JSON.stringify(actual) +
207                      "\nExpected: " + $JSON.stringify(expected);
208         chromeTest.fail(error_msg);
209       }
210       return;
211     }
212     if (expected != actual) {
213       chromeTest.fail(error_msg +
214                        "\nActual: " + actual + "\nExpected: " + expected);
215     }
216     if (typeof(expected) != typeof(actual)) {
217       chromeTest.fail(error_msg +
218                        " (type mismatch)\nActual Type: " + typeof(actual) +
219                        "\nExpected Type:" + typeof(expected));
220     }
221   });
223   apiFunctions.setHandleRequest('assertNoLastError', function() {
224     if (chrome.runtime.lastError != undefined) {
225       chromeTest.fail("lastError.message == " +
226                        chrome.runtime.lastError.message);
227     }
228   });
230   apiFunctions.setHandleRequest('assertLastError', function(expectedError) {
231     chromeTest.assertEq(typeof(expectedError), 'string');
232     chromeTest.assertTrue(chrome.runtime.lastError != undefined,
233         "No lastError, but expected " + expectedError);
234     chromeTest.assertEq(expectedError, chrome.runtime.lastError.message);
235   });
237   apiFunctions.setHandleRequest('assertThrows',
238                                 function(fn, self, args, message) {
239     chromeTest.assertTrue(typeof fn == 'function');
240     try {
241       fn.apply(self, args);
242       chromeTest.fail('Did not throw error: ' + fn);
243     } catch (e) {
244       if (e != failureException && message !== undefined) {
245         if (message instanceof RegExp) {
246           chromeTest.assertTrue(message.test(e.message),
247                                 e.message + ' should match ' + message)
248         } else {
249           chromeTest.assertEq(message, e.message);
250         }
251       }
252     }
253   });
255   function safeFunctionApply(func, args) {
256     try {
257       if (func)
258         return $Function.apply(func, undefined, args);
259     } catch (e) {
260       var msg = "uncaught exception " + e;
261       chromeTest.fail(msg);
262     }
263   };
265   // Wrapper for generating test functions, that takes care of calling
266   // assertNoLastError() and (optionally) succeed() for you.
267   apiFunctions.setHandleRequest('callback', function(func, expectedError) {
268     if (func) {
269       chromeTest.assertEq(typeof(func), 'function');
270     }
271     var callbackCompleted = chromeTest.callbackAdded();
273     return function() {
274       if (expectedError == null) {
275         chromeTest.assertNoLastError();
276       } else {
277         chromeTest.assertLastError(expectedError);
278       }
280       var result;
281       if (func) {
282         result = safeFunctionApply(func, arguments);
283       }
285       callbackCompleted();
286       return result;
287     };
288   });
290   apiFunctions.setHandleRequest('listenOnce', function(event, func) {
291     var callbackCompleted = chromeTest.callbackAdded();
292     var listener = function() {
293       event.removeListener(listener);
294       safeFunctionApply(func, arguments);
295       callbackCompleted();
296     };
297     event.addListener(listener);
298   });
300   apiFunctions.setHandleRequest('listenForever', function(event, func) {
301     var callbackCompleted = chromeTest.callbackAdded();
303     var listener = function() {
304       safeFunctionApply(func, arguments);
305     };
307     var done = function() {
308       event.removeListener(listener);
309       callbackCompleted();
310     };
312     event.addListener(listener);
313     return done;
314   });
316   apiFunctions.setHandleRequest('callbackPass', function(func) {
317     return chromeTest.callback(func);
318   });
320   apiFunctions.setHandleRequest('callbackFail', function(expectedError, func) {
321     return chromeTest.callback(func, expectedError);
322   });
324   apiFunctions.setHandleRequest('runTests', function(tests) {
325     chromeTest.tests = tests;
326     testCount = chromeTest.tests.length;
327     chromeTest.runNextTest();
328   });
330   apiFunctions.setHandleRequest('getApiDefinitions', function() {
331     return GetExtensionAPIDefinitionsForTest();
332   });
334   apiFunctions.setHandleRequest('getApiFeatures', function() {
335     return GetAPIFeatures();
336   });
338   apiFunctions.setHandleRequest('isProcessingUserGesture', function() {
339     return userGestures.IsProcessingUserGesture();
340   });
342   apiFunctions.setHandleRequest('runWithUserGesture', function(callback) {
343     chromeTest.assertEq(typeof(callback), 'function');
344     return userGestures.RunWithUserGesture(callback);
345   });
347   apiFunctions.setHandleRequest('runWithoutUserGesture', function(callback) {
348     chromeTest.assertEq(typeof(callback), 'function');
349     return userGestures.RunWithoutUserGesture(callback);
350   });
352   apiFunctions.setHandleRequest('setExceptionHandler', function(callback) {
353     chromeTest.assertEq(typeof(callback), 'function');
354     uncaughtExceptionHandler.setHandler(callback);
355   });
357   apiFunctions.setHandleRequest('getWakeEventPage', function() {
358     return natives.GetWakeEventPage();
359   });
361   environmentSpecificBindings.registerHooks(api);
364 exports.binding = binding.generate();