282b7007f71e1e25582330be7b5df55f0b479d80
[platform/framework/web/crosswalk.git] / src / chrome / test / data / extensions / api_test / messaging / externally_connectable / sites / assertions.js
1 // Copyright 2013 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
5 (function() {
6
7 // We are going to kill all of the builtins, so hold onto the ones we need.
8 var defineGetter = Object.prototype.__defineGetter__;
9 var defineSetter = Object.prototype.__defineSetter__;
10 var Error = window.Error;
11 var forEach = Array.prototype.forEach;
12 var push = Array.prototype.push;
13 var hasOwnProperty = Object.prototype.hasOwnProperty;
14 var getOwnPropertyNames = Object.getOwnPropertyNames;
15 var stringify = JSON.stringify;
16
17 // Kill all of the builtins functions to give us a fairly high confidence that
18 // the environment our bindings run in can't interfere with our code.
19 // These are taken from the ECMAScript spec.
20 var builtinTypes = [
21   Object, Function, Array, String, Boolean, Number, Math, Date, RegExp, JSON,
22 ];
23
24 function clobber(obj, name, qualifiedName) {
25   // Clobbering constructors would break everything.
26   // Clobbering toString is annoying.
27   // Clobbering __proto__ breaks in ways that grep can't find.
28   // Clobbering Function.call would make it impossible to implement these tests.
29   // Clobbering Object.valueOf breaks v8.
30   if (name == 'constructor' ||
31       name == 'toString' ||
32       name == '__proto__' ||
33       qualifiedName == 'Function.call' ||
34       qualifiedName == 'Object.valueOf') {
35     return;
36   }
37   if (typeof(obj[name]) == 'function') {
38     obj[name] = function() {
39       throw new Error('Clobbered ' + qualifiedName + ' function');
40     };
41   } else {
42     defineGetter.call(obj, name, function() {
43       throw new Error('Clobbered ' + qualifiedName + ' getter');
44     });
45   }
46 }
47
48 forEach.call(builtinTypes, function(builtin) {
49   var prototype = builtin.prototype;
50   var typename = '<unknown>';
51   if (prototype) {
52     typename = prototype.constructor.name;
53     forEach.call(getOwnPropertyNames(prototype), function(name) {
54       clobber(prototype, name, typename + '.' + name);
55     });
56   }
57   forEach.call(getOwnPropertyNames(builtin), function(name) {
58     clobber(builtin, name, typename + '.' + name);
59   });
60   if (builtin.name)
61     clobber(window, builtin.name, 'window.' + builtin.name);
62 });
63
64 // Codes for test results. Must match ExternallyConnectableMessagingTest::Result
65 // in c/b/extensions/extension_messages_apitest.cc.
66 var results = {
67   OK: 0,
68   NAMESPACE_NOT_DEFINED: 1,
69   FUNCTION_NOT_DEFINED: 2,
70   COULD_NOT_ESTABLISH_CONNECTION_ERROR: 3,
71   OTHER_ERROR: 4,
72   INCORRECT_RESPONSE_SENDER: 5,
73   INCORRECT_RESPONSE_MESSAGE: 6,
74 };
75
76 // Make the messages sent vaguely complex, but unambiguously JSON-ifiable.
77 var kMessage = [{'a': {'b': 10}}, 20, 'c\x10\x11'];
78
79 // Our tab's location. Normally this would be our document's location but if
80 // we're an iframe it will be the location of the parent - in which case,
81 // expect to be told.
82 var tabLocationHref = null;
83
84 if (parent == window) {
85   tabLocationHref = document.location.href;
86 } else {
87   window.addEventListener('message', function listener(event) {
88     window.removeEventListener(listener);
89     tabLocationHref = event.data;
90   });
91 }
92
93 function checkLastError(reply) {
94   if (!chrome.runtime.lastError)
95     return true;
96   var kCouldNotEstablishConnection =
97     'Could not establish connection. Receiving end does not exist.';
98   if (chrome.runtime.lastError.message == kCouldNotEstablishConnection)
99     reply(results.COULD_NOT_ESTABLISH_CONNECTION_ERROR);
100   else
101     reply(results.OTHER_ERROR);
102   return false;
103 }
104
105 function checkResponse(response, reply, expectedMessage) {
106   // The response will be an echo of both the original message *and* the
107   // MessageSender (with the tab field stripped down).
108   //
109   // First check the sender was correct.
110   var incorrectSender = false;
111   if (!hasOwnProperty.call(response.sender, 'tab')) {
112     console.warn('Expected a tab, got none');
113     incorrectSender = true;
114   }
115   if (response.sender.tab.url != tabLocationHref) {
116     console.warn('Expected tab url ' + tabLocationHref + ' got ' +
117                  response.sender.tab.url);
118     incorrectSender = true;
119   }
120   if (hasOwnProperty.call(response.sender, 'id')) {
121     console.warn('Expected no id, got "' + response.sender.id + '"');
122     incorrectSender = true;
123   }
124   if (response.sender.url != document.location.href) {
125     console.warn('Expected url ' + document.location.href + ' got ' +
126                  response.sender.url);
127     incorrectSender = true;
128   }
129   if (incorrectSender) {
130     reply(results.INCORRECT_RESPONSE_SENDER);
131     return false;
132   }
133
134   // Check the correct content was echoed.
135   var expectedJson = stringify(expectedMessage);
136   var actualJson = stringify(response.message);
137   if (actualJson == expectedJson)
138     return true;
139   console.warn('Expected message ' + expectedJson + ' got ' + actualJson);
140   reply(results.INCORRECT_RESPONSE_MESSAGE);
141   return false;
142 }
143
144 function sendToBrowser(msg) {
145   domAutomationController.send(msg);
146 }
147
148 function sendToBrowserForTlsChannelId(result) {
149   // Because the TLS channel ID tests read the TLS either an error code or the
150   // TLS channel ID string from the same value, they require the result code
151   // to be sent as a string.
152   // String() is clobbered, so coerce string creation with +.
153   sendToBrowser("" + result);
154 }
155
156 function checkRuntime(reply) {
157   if (!reply)
158     reply = sendToBrowser;
159
160   if (!chrome.runtime) {
161     reply(results.NAMESPACE_NOT_DEFINED);
162     return false;
163   }
164
165   if (!chrome.runtime.connect || !chrome.runtime.sendMessage) {
166     reply(results.FUNCTION_NOT_DEFINED);
167     return false;
168   }
169   return true;
170 }
171
172 function checkRuntimeForTlsChannelId() {
173   return checkRuntime(sendToBrowserForTlsChannelId);
174 }
175
176 function checkTlsChannelIdResponse(response) {
177   if (chrome.runtime.lastError) {
178     if (chrome.runtime.lastError.message == kCouldNotEstablishConnection)
179       sendToBrowserForTlsChannelId(
180           results.COULD_NOT_ESTABLISH_CONNECTION_ERROR);
181     else
182       sendToBrowserForTlsChannelId(results.OTHER_ERROR);
183     return;
184   }
185   if (response.sender.tlsChannelId !== undefined)
186     sendToBrowserForTlsChannelId(response.sender.tlsChannelId);
187   else
188     sendToBrowserForTlsChannelId('');
189 }
190
191 window.actions = {
192   appendIframe: function(src) {
193     var iframe = document.createElement('iframe');
194     // When iframe has loaded, notify it of our tab location (probably
195     // document.location) to use in its assertions, then continue.
196     iframe.addEventListener('load', function listener() {
197       iframe.removeEventListener('load', listener);
198       iframe.contentWindow.postMessage(tabLocationHref, '*');
199       sendToBrowser(true);
200     });
201     iframe.src = src;
202     document.body.appendChild(iframe);
203   }
204 };
205
206 window.assertions = {
207   canConnectAndSendMessages: function(extensionId, message) {
208     if (!checkRuntime())
209       return;
210
211     if (!message)
212       message = kMessage;
213
214     if (!message)
215       message = kMessage;
216
217     function canSendMessage(reply) {
218       chrome.runtime.sendMessage(extensionId, message, function(response) {
219         if (checkLastError(reply) && checkResponse(response, reply, message))
220           reply(results.OK);
221       });
222     }
223
224     function canConnectAndSendMessages(reply) {
225       var port = chrome.runtime.connect(extensionId);
226       port.postMessage(message, function() {
227         checkLastError(reply);
228       });
229       port.postMessage(message, function() {
230         checkLastError(reply);
231       });
232       var pendingResponses = 2;
233       var ok = true;
234       port.onMessage.addListener(function(response) {
235         pendingResponses--;
236         ok = ok && checkLastError(reply) &&
237             checkResponse(response, reply, message);
238         if (pendingResponses == 0 && ok)
239           reply(results.OK);
240       });
241     }
242
243     canSendMessage(function(result) {
244       if (result != results.OK)
245         sendToBrowser(result);
246       else
247         canConnectAndSendMessages(sendToBrowser);
248     });
249   },
250
251   areAnyRuntimePropertiesDefined: function(names) {
252     var result = false;
253     if (chrome.runtime) {
254       forEach.call(names, function(name) {
255         if (chrome.runtime[name]) {
256           console.log('runtime.' + name + ' is defined');
257           result = true;
258         }
259       });
260     }
261     sendToBrowser(result);
262   },
263
264   getTlsChannelIdFromPortConnect: function(extensionId, includeTlsChannelId,
265                                            message) {
266     if (!checkRuntimeForTlsChannelId())
267       return;
268
269     if (!message)
270       message = kMessage;
271
272     var port = chrome.runtime.connect(extensionId,
273         {'includeTlsChannelId': includeTlsChannelId});
274     port.onMessage.addListener(checkTlsChannelIdResponse);
275     port.postMessage(message);
276   },
277
278   getTlsChannelIdFromSendMessage: function(extensionId, includeTlsChannelId,
279                                            message) {
280     if (!checkRuntimeForTlsChannelId())
281       return;
282
283     if (!message)
284       message = kMessage;
285
286     chrome.runtime.sendMessage(extensionId, message,
287         {'includeTlsChannelId': includeTlsChannelId},
288         checkTlsChannelIdResponse);
289   }
290 };
291
292 }());