Add the ability to code generated prepopulated static nested structs
[chromium-blink-merge.git] / extensions / renderer / resources / test_custom_bindings.js
blob5ffbf6cbf9e98f852f4a9ee8457e211cb240e7c7
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 uncaughtExceptionHandler = require('uncaught_exception_handler');
15 var userGestures = requireNative('user_gestures');
17 var RunWithNativesEnabledModuleSystem =
18     requireNative('v8_context').RunWithNativesEnabledModuleSystem;
20 binding.registerCustomHook(function(api) {
21   var chromeTest = api.compiledApi;
22   var apiFunctions = api.apiFunctions;
24   chromeTest.tests = chromeTest.tests || [];
26   var currentTest = null;
27   var lastTest = null;
28   var testsFailed = 0;
29   var testCount = 1;
30   var failureException = 'chrome.test.failure';
32   // Helper function to get around the fact that function names in javascript
33   // are read-only, and you can't assign one to anonymous functions.
34   function testName(test) {
35     return test ? (test.name || test.generatedName) : "(no test)";
36   }
38   function testDone() {
39     environmentSpecificBindings.testDone(chromeTest.runNextTest);
40   }
42   function allTestsDone() {
43     if (testsFailed == 0) {
44       chromeTest.notifyPass();
45     } else {
46       chromeTest.notifyFail('Failed ' + testsFailed + ' of ' +
47                              testCount + ' tests');
48     }
49   }
51   var pendingCallbacks = 0;
53   apiFunctions.setHandleRequest('callbackAdded', function() {
54     pendingCallbacks++;
56     var called = null;
57     return function() {
58       if (called != null) {
59         var redundantPrefix = 'Error\n';
60         chromeTest.fail(
61           'Callback has already been run. ' +
62           'First call:\n' +
63           $String.slice(called, redundantPrefix.length) + '\n' +
64           'Second call:\n' +
65           $String.slice(new Error().stack, redundantPrefix.length));
66       }
67       called = new Error().stack;
69       pendingCallbacks--;
70       if (pendingCallbacks == 0) {
71         chromeTest.succeed();
72       }
73     };
74   });
76   apiFunctions.setHandleRequest('runNextTest', function() {
77     // There may have been callbacks which were interrupted by failure
78     // exceptions.
79     pendingCallbacks = 0;
81     lastTest = currentTest;
82     currentTest = chromeTest.tests.shift();
84     if (!currentTest) {
85       allTestsDone();
86       return;
87     }
89     try {
90       chromeTest.log("( RUN      ) " + testName(currentTest));
91       uncaughtExceptionHandler.setHandler(function(message, e) {
92         if (e !== failureException)
93           chromeTest.fail('uncaught exception: ' + message);
94       });
95       currentTest.call();
96     } catch (e) {
97       uncaughtExceptionHandler.handle(e.message, e);
98     }
99   });
101   apiFunctions.setHandleRequest('fail', function(message) {
102     chromeTest.log("(  FAILED  ) " + testName(currentTest));
104     var stack = {};
105     Error.captureStackTrace(stack, chromeTest.fail);
107     if (!message)
108       message = "FAIL (no message)";
110     message += "\n" + stack.stack;
111     console.log("[FAIL] " + testName(currentTest) + ": " + message);
112     testsFailed++;
113     testDone();
115     // Interrupt the rest of the test.
116     throw failureException;
117   });
119   apiFunctions.setHandleRequest('succeed', function() {
120     console.log("[SUCCESS] " + testName(currentTest));
121     chromeTest.log("(  SUCCESS )");
122     testDone();
123   });
125   apiFunctions.setHandleRequest('runWithModuleSystem', function(callback) {
126     RunWithNativesEnabledModuleSystem(callback);
127   });
129   apiFunctions.setHandleRequest('assertTrue', function(test, message) {
130     chromeTest.assertBool(test, true, message);
131   });
133   apiFunctions.setHandleRequest('assertFalse', function(test, message) {
134     chromeTest.assertBool(test, false, message);
135   });
137   apiFunctions.setHandleRequest('assertBool',
138                                 function(test, expected, message) {
139     if (test !== expected) {
140       if (typeof(test) == "string") {
141         if (message)
142           message = test + "\n" + message;
143         else
144           message = test;
145       }
146       chromeTest.fail(message);
147     }
148   });
150   apiFunctions.setHandleRequest('checkDeepEq', function(expected, actual) {
151     if ((expected === null) != (actual === null))
152       return false;
154     if (expected === actual)
155       return true;
157     if (typeof(expected) !== typeof(actual))
158       return false;
160     for (var p in actual) {
161       if ($Object.hasOwnProperty(actual, p) &&
162           !$Object.hasOwnProperty(expected, p)) {
163         return false;
164       }
165     }
166     for (var p in expected) {
167       if ($Object.hasOwnProperty(expected, p) &&
168           !$Object.hasOwnProperty(actual, p)) {
169         return false;
170       }
171     }
173     for (var p in expected) {
174       var eq = true;
175       switch (typeof(expected[p])) {
176         case 'object':
177           eq = chromeTest.checkDeepEq(expected[p], actual[p]);
178           break;
179         case 'function':
180           eq = (typeof(actual[p]) != 'undefined' &&
181                 expected[p].toString() == actual[p].toString());
182           break;
183         default:
184           eq = (expected[p] == actual[p] &&
185                 typeof(expected[p]) == typeof(actual[p]));
186           break;
187       }
188       if (!eq)
189         return false;
190     }
191     return true;
192   });
194   apiFunctions.setHandleRequest('assertEq',
195                                 function(expected, actual, message) {
196     var error_msg = "API Test Error in " + testName(currentTest);
197     if (message)
198       error_msg += ": " + message;
199     if (typeof(expected) == 'object') {
200       if (!chromeTest.checkDeepEq(expected, actual)) {
201         error_msg += "\nActual: " + $JSON.stringify(actual) +
202                      "\nExpected: " + $JSON.stringify(expected);
203         chromeTest.fail(error_msg);
204       }
205       return;
206     }
207     if (expected != actual) {
208       chromeTest.fail(error_msg +
209                        "\nActual: " + actual + "\nExpected: " + expected);
210     }
211     if (typeof(expected) != typeof(actual)) {
212       chromeTest.fail(error_msg +
213                        " (type mismatch)\nActual Type: " + typeof(actual) +
214                        "\nExpected Type:" + typeof(expected));
215     }
216   });
218   apiFunctions.setHandleRequest('assertNoLastError', function() {
219     if (chrome.runtime.lastError != undefined) {
220       chromeTest.fail("lastError.message == " +
221                        chrome.runtime.lastError.message);
222     }
223   });
225   apiFunctions.setHandleRequest('assertLastError', function(expectedError) {
226     chromeTest.assertEq(typeof(expectedError), 'string');
227     chromeTest.assertTrue(chrome.runtime.lastError != undefined,
228         "No lastError, but expected " + expectedError);
229     chromeTest.assertEq(expectedError, chrome.runtime.lastError.message);
230   });
232   apiFunctions.setHandleRequest('assertThrows',
233                                 function(fn, self, args, message) {
234     chromeTest.assertTrue(typeof fn == 'function');
235     try {
236       fn.apply(self, args);
237       chromeTest.fail('Did not throw error: ' + fn);
238     } catch (e) {
239       if (e != failureException && message !== undefined) {
240         if (message instanceof RegExp) {
241           chromeTest.assertTrue(message.test(e.message),
242                                 e.message + ' should match ' + message)
243         } else {
244           chromeTest.assertEq(message, e.message);
245         }
246       }
247     }
248   });
250   function safeFunctionApply(func, args) {
251     try {
252       if (func)
253         return $Function.apply(func, undefined, args);
254     } catch (e) {
255       var msg = "uncaught exception " + e;
256       chromeTest.fail(msg);
257     }
258   };
260   // Wrapper for generating test functions, that takes care of calling
261   // assertNoLastError() and (optionally) succeed() for you.
262   apiFunctions.setHandleRequest('callback', function(func, expectedError) {
263     if (func) {
264       chromeTest.assertEq(typeof(func), 'function');
265     }
266     var callbackCompleted = chromeTest.callbackAdded();
268     return function() {
269       if (expectedError == null) {
270         chromeTest.assertNoLastError();
271       } else {
272         chromeTest.assertLastError(expectedError);
273       }
275       var result;
276       if (func) {
277         result = safeFunctionApply(func, arguments);
278       }
280       callbackCompleted();
281       return result;
282     };
283   });
285   apiFunctions.setHandleRequest('listenOnce', function(event, func) {
286     var callbackCompleted = chromeTest.callbackAdded();
287     var listener = function() {
288       event.removeListener(listener);
289       safeFunctionApply(func, arguments);
290       callbackCompleted();
291     };
292     event.addListener(listener);
293   });
295   apiFunctions.setHandleRequest('listenForever', function(event, func) {
296     var callbackCompleted = chromeTest.callbackAdded();
298     var listener = function() {
299       safeFunctionApply(func, arguments);
300     };
302     var done = function() {
303       event.removeListener(listener);
304       callbackCompleted();
305     };
307     event.addListener(listener);
308     return done;
309   });
311   apiFunctions.setHandleRequest('callbackPass', function(func) {
312     return chromeTest.callback(func);
313   });
315   apiFunctions.setHandleRequest('callbackFail', function(expectedError, func) {
316     return chromeTest.callback(func, expectedError);
317   });
319   apiFunctions.setHandleRequest('runTests', function(tests) {
320     chromeTest.tests = tests;
321     testCount = chromeTest.tests.length;
322     chromeTest.runNextTest();
323   });
325   apiFunctions.setHandleRequest('getApiDefinitions', function() {
326     return GetExtensionAPIDefinitionsForTest();
327   });
329   apiFunctions.setHandleRequest('getApiFeatures', function() {
330     return GetAPIFeatures();
331   });
333   apiFunctions.setHandleRequest('isProcessingUserGesture', function() {
334     return userGestures.IsProcessingUserGesture();
335   });
337   apiFunctions.setHandleRequest('runWithUserGesture', function(callback) {
338     chromeTest.assertEq(typeof(callback), 'function');
339     return userGestures.RunWithUserGesture(callback);
340   });
342   apiFunctions.setHandleRequest('runWithoutUserGesture', function(callback) {
343     chromeTest.assertEq(typeof(callback), 'function');
344     return userGestures.RunWithoutUserGesture(callback);
345   });
347   apiFunctions.setHandleRequest('setExceptionHandler', function(callback) {
348     chromeTest.assertEq(typeof(callback), 'function');
349     uncaughtExceptionHandler.setHandler(callback);
350   });
352   environmentSpecificBindings.registerHooks(api);
355 exports.binding = binding.generate();