1
// Copyright 2007, Google Inc.
3
// Redistribution and use in source and binary forms, with or without
4
// modification, are permitted provided that the following conditions are met:
6
// 1. Redistributions of source code must retain the above copyright notice,
7
// this list of conditions and the following disclaimer.
8
// 2. Redistributions in binary form must reproduce the above copyright notice,
9
// this list of conditions and the following disclaimer in the documentation
10
// and/or other materials provided with the distribution.
11
// 3. Neither the name of Google Inc. nor the names of its contributors may be
12
// used to endorse or promote products derived from this software without
13
// specific prior written permission.
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
// This file defines all the builtins that can be used inside Gears unit tests.
29
* Whether the installed Gears extension is a debug build.
31
var isDebug = google.gears.factory.getBuildInfo().indexOf('dbg') > -1;
34
* Whether the installed Gears extension is an official build.
36
var isOfficial = google.gears.factory.getBuildInfo().indexOf('official') > -1;
39
* Whether the installed Gears extension is for a particular platform.
41
var isWin32 = google.gears.factory.getBuildInfo().indexOf('win32') > -1;
42
var isWince = google.gears.factory.getBuildInfo().indexOf('wince') > -1;
43
var isOsx = google.gears.factory.getBuildInfo().indexOf('osx') > -1;
44
var isAndroid = google.gears.factory.getBuildInfo().indexOf('android') > -1;
47
* Whether the installed Gears extension is for a particular browser.
49
var isIE = google.gears.factory.getBuildInfo().indexOf(';ie') > -1;
50
var isFirefox = google.gears.factory.getBuildInfo().indexOf(';firefox') > -1;
51
var isSafari = google.gears.factory.getBuildInfo().indexOf(';safari') > -1;
52
var isNPAPI = google.gears.factory.getBuildInfo().indexOf(';npapi') > -1;
53
var isOpera = google.gears.factory.getBuildInfo().indexOf(';opera') > -1;
56
* Whether the installed Gears extension has the test scriptable object.
57
* See also the definition of USING_CCTESTS in gears\tools\config.mk.
59
var isUsingCCTests = isDebug || !isOfficial;
62
* A shared timer tests can use.
64
var timer = google.gears.factory.create('beta.timer');
67
* Assert that something is true and throw an error if not.
69
* @param expr The expression to test. This will be coerced to bool if it isn't
71
* @param optMessage The message to display if expr is not true, or a function
72
* which will return the message.
74
function assert(expr, optMessage) {
76
if (isFunction(optMessage)) {
77
throw new Error(optMessage());
78
} else if (isString(optMessage)) {
79
throw new Error(optMessage);
81
throw new Error('Assertion failed');
87
* Format error message with optional error message.
89
* @param message The original error message.
90
* @param optDescription An optional description of what went wrong.
92
function formatErrorMessage(message, optDescription) {
94
return optDescription + ' - ' + message;
101
* Assert that two values are equal, as defined by ===. A strict equality test
102
* is used; 4 and "4" are not equal. Also two different objects with the same
103
* properties compare as false.
105
* @param expected The expected value.
106
* @param actual The actual value.
107
* @param optDescription An optional description of what went wrong.
109
function assertEqual(expected, actual, optDescription) {
110
// === seems to be buggy on Safari:
111
// https://bugs.webkit.org/show_bug.cgi?id=20305 . Work around this by
112
// comparing object addresses. Converting an NPObject to a string returns a
113
// string with the address embedded, so we compare these.
115
// toString() doesn't seem to be defined for Gears objects in Safari.
116
function asString(object) {
117
return '%s'.subs(object);
120
function isNPObject(object) {
122
var string = asString(object);
123
return string && string.indexOf('NPObject') == 0;
127
function generateMessage() {
128
var message = 'Expected: %s (%s), actual: %s (%s)'.subs(
129
expected, typeof expected, actual, typeof actual);
130
return formatErrorMessage(message, optDescription);
133
if (isSafari && isNPObject(expected) && isNPObject(actual)) {
134
assert(asString(expected) == asString(actual), generateMessage);
136
assert(expected === actual, generateMessage);
142
* Assert that two values are equal. This function will inspect object
143
* object properties and array members. Is a function is encountered the only
144
* check that is performed is to assert that they expected and actual are of
145
* type function. Otherwise, a strict equality test is used; 4 and "4" are not
148
* @param expected Any type containing the expected value.
149
* @param actual Any type containing the actual value.
150
* @param optDescription An optional description of what went wrong.
152
function assertEqualAnyType(expected, actual, optDescription) {
153
if (isArray(expected) && isArray(actual)) {
154
assertArrayEqual(expected, actual, optDescription);
155
} else if (isObject(expected) && isObject(actual)) {
156
assertObjectEqual(expected, actual, optDescription);
157
} else if (isFunction(expected) && isFunction(actual)) {
158
// functions are only tested for type
160
assertEqual(expected, actual, optDescription);
165
* Assert that all values in two arrays are equal. A strict equality test is
166
* used; 4 and "4" are not equal.
168
* @param expected The array containing expected values.
169
* @param actual The array containing actual values.
170
* @param optDescription An optional description of what went wrong.
172
function assertArrayEqual(expected, actual, optDescription) {
173
function notArrayErrorMessage(array, optDescription) {
175
var message = 'Expected array, actual: %s (%s)'.subs(array, typeof array);
176
return formatErrorMessage(message, optDescription);
180
assert(isArray(expected), notArrayErrorMessage(expected, optDescription));
181
assert(isArray(actual), notArrayErrorMessage(actual, optDescription));
182
assert(expected.length == actual.length, function() {
183
var message = 'Expected array length: %s actual length: %s'.subs(
184
expected.length, actual.length);
185
return formatErrorMessage(message, optDescription);
188
for (var i = 0; i < expected.length; ++expected) {
189
assertEqualAnyType(expected[i], actual[i], function() {
190
var message = 'Expected element in array at %s: %s (%s) actual: %s (%s)'
191
.subs(i, expected[i], typeof expected[i], actual[i],
193
return formatErrorMessage(message, optDescription);
199
* Assert that all properties in two objects are equal. A strict equality test
200
* is used; 4 and "4" are not equal.
202
* @param expected The object containing expected values.
203
* @param actual The object containing actual values.
204
* @param optDescription An optional description of what went wrong.
206
function assertObjectEqual(expected, actual, optDescription) {
207
function notObjectErrorMessage(array, optDescription) {
209
var message = 'Expected object, actual: %s (%s)'.subs(
210
array, typeof array);
211
return formatErrorMessage(message, optDescription);
215
assert(isObject(expected), notObjectErrorMessage(expected, optDescription));
216
assert(isObject(actual), notObjectErrorMessage(actual, optDescription));
218
for (property in expected) {
219
assertEqualAnyType(expected[property], actual[property], optDescription);
222
for (property in actual) {
223
assertEqualAnyType(expected[property], actual[property], optDescription);
228
* Assert that two blobs probably have the same content. Checks the content of
229
* the blob in debug mode, and the lengths in release mode.
231
* @param expected The expected blob.
232
* @param actual The actual blob.
233
* @param optDescription An optional description of what went wrong.
235
function assertBlobProbablyEqual(expected, actual, optDescription) {
236
if (optDescription) {
237
optDescription += ' ';
241
assert(expected.length == actual.length, optDescription +
242
'Mismatched blob: expected: %s bytes, actual: %s bytes'.
243
subs(expected.length, actual.length));
246
assert(actual.hasSameContentsAs(expected), optDescription +
247
'Mismatched blob: same size, different contents');
252
* Assert that two values are not equal. A strict equality test is used; 4 and
255
* @param unexpected The unexpected value.
256
* @param actual The actual value.
257
* @param optDescription An optional description of what went wrong.
259
function assertNotEqual(unexpected, actual, optDescription) {
260
assert(unexpected !== actual, function() {
261
var message = 'Expected value other than "%s" (%s)'.subs(
262
unexpected, typeof unexpected);
263
return formatErrorMessage(message, optDescription);
268
* Assert a value is null. This tests for strict equality to null, no coercion
271
* @param val The value expected to be null.
272
* @param optDescription An optional description of what went wrong.
274
function assertNull(val, optDescription) {
275
assert(val === null, function() {
276
var message = "Expected null value.";
277
return formatErrorMessage(message, optDescription);
282
* Assert a value is not null. This tests for strict equality to null, no
285
* @param val The value expected to be non-null.
286
* @param optDescription An optional description of what went wrong.
288
function assertNotNull(val, optDescription) {
289
assert(val !== null, function() {
290
var message = "Unexpected null value.";
291
return formatErrorMessage(message, optDescription);
296
* Assert that a function produces an error.
298
* @param fn This function will be run. If it produces an error, the assert
299
* succeeds. Otherwise, it fails.
300
* @param optExpectedError An optional error message that is expected. If the
301
* message that results from running fn contains this substring, the assert
302
* succeeds. Otherwise, it fails.
303
* @param optDescription An optional description of what went wrong.
305
function assertError(fn, optExpectedError, optDescription) {
309
if (!optExpectedError) {
312
var actualError = e.message || e.toString();
313
if (actualError.indexOf(optExpectedError) > -1) {
319
var message = 'Did not receive expected error';
321
if (optExpectedError) {
322
message += ': "' + optExpectedError + '"';
325
throw new Error(formatErrorMessage(message, optDescription));
329
* Starts the current test running asynchronously. The next test will not be
330
* started until completeAsync() is called.
332
function startAsync() {
333
Harness.current_.startAsync();
337
* Marks the currently running asynchronous test as successful and starts the
340
function completeAsync() {
341
Harness.current_.completeAsync();
345
* Wait for one or more global errors to occur before starting the next test. If
346
* the errors do not occur, occur out of order, or if some other error occurs,
347
* the test is marked failed.
349
* @param errorMessages Array of expected error substrings. When an error occurs
350
* the first item in this array is removed and compared to the full error text.
351
* If it occurs as a substring, the expected error is considered found.
352
* Otherwise the test is marked failed.
354
function waitForGlobalErrors(errorMessages) {
355
Harness.current_.waitForGlobalErrors(errorMessages);
359
* Process a resultset and ensure it is closed, even if there is an error.
360
* @param rs The resultset to process.
361
* @param fn A function that will receive the resultset as an argument.
363
function handleResult(rs, fn) {
373
* Utility to send an HTTP request.
374
* @param url The url to fetch
375
* @param method The http method (ie. 'GET' or 'POST')
376
* @param data The data to send, may be null
377
* @param callback The function which will be called upon completion of the
378
* request. If cb_request is true, the callback receives the request object.
379
* Otherwise, the callback receives the contents on a 200 response and null on
380
* any other response.
381
* @param cb_request Controls the argument to callback.
383
function sendHttpRequest(url, method, data, callback, cb_request) {
384
var req = google.gears.factory.create('beta.httprequest');
386
// TODO(aa): We are seeing sporadic failures in these tests. A theory is that
387
// HttpRequest is getting gc'd. Remove this test of that theory when it is
388
// proven or disproven.
389
global.kungFuGrip = req;
391
req.onreadystatechange = function() {
392
if (req.readyState == 4) {
395
} else if (req.status == 200) {
396
callback(req.responseText);
403
req.open(method, url, true); // async
408
* Utility to asynchronously get a URL and return the content.
409
* @param url The url to fetch
410
* @param callback Will be called with contents of URL, or null if the request
413
function httpGet(url, callback) {
414
sendHttpRequest(url, 'GET', null, callback, false);
418
* Utility to asynchronously get a URL and return the request object.
419
* @param url The url to fetch
420
* @param callback Will be called with request object.
422
function httpGetAsRequest(url, callback) {
423
sendHttpRequest(url, 'GET', null, callback, true);
427
* Utility to asynchronously POST to a URL and return the content.
428
* @param url The url to fetch
429
* @param data The data to post
430
* @param callback Will be called with contents of URL, or null if the request
433
function httpPost(url, data, callback) {
434
sendHttpRequest(url, 'POST', data, callback, false);
438
* Utility to asynchronously POST to a URL and return the request object.
439
* @param url The url to fetch
440
* @param data The data to post
441
* @param callback Will be called with request object.
443
function httpPostAsRequest(url, callback) {
444
sendHttpRequest(url, 'POST', data, callback, true);
447
// cookie functions courtesy ppk: http://www.quirksmode.org/js/cookies.html
449
function createTestCookie(name, value, optDays) {
451
var date = new Date();
452
date.setTime(date.getTime()+(optDays*24*60*60*1000));
453
var expires = "; expires="+date.toGMTString();
455
else var expires = "";
456
document.cookie = name+"="+value+expires+"; path=/";
459
function readTestCookie(name) {
460
var nameEQ = name + "=";
461
var ca = document.cookie.split(';');
462
for(var i=0;i < ca.length;i++) {
464
while (c.charAt(0)==' ') c = c.substring(1,c.length);
465
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
470
function eraseTestCookie(name) {
471
createTestCookie(name,"",-1);