head_songbird.js
Go to the documentation of this file.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et: */
3 /* ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is mozilla.org code.
17  *
18  * The Initial Developer of the Original Code is Google Inc.
19  * Portions created by the Initial Developer are Copyright (C) 2005
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  * Darin Fisher <darin@meer.net>
24  * Boris Zbarsky <bzbarsky@mit.edu>
25  * John Gaunt <redfive@songbirdnest.com>
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either the GNU General Public License Version 2 or later (the "GPL"), or
29  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40 
41 /*
42  * Original file is mozilla code, pulled into the songbird tree with some slight
43  * modification since it is being used in a different system (XULRunner) than the
44  * original (xpcshell).
45  */
46 
47 // This file contains common code that is loaded with each test file.
48 
49 /*
50  * These get defined in sbTestHarness.js so we don't need to do it here.
51  * const Ci = Components.interfaces;
52  * const Cc = Components.classes;
53  * const Cr = Components.results;
54 */
55 
56 // setup the main thread event queue
57 var _quit = false;
58 var _fail = false;
59 var _skip = false;
60 var _running_event_loop = false;
62 var _test_name = "sbTestHarness";
63 var _test_comp = "testharness";
65 
66 // _extensionStates, when initialized, gives the status of each extension.
67 // The property names are extension IDs (like "mashTape@songbirdnest.com").
68 // Each value is the extension version, if the extension is active, or one
69 // of the _TH_EXTENSION_* contants defined below
71 
72 // Used in _extensionStates when an extension is disabled
73 const _TH_EXTENSION_DISABLED = "disabled";
74 
75 // Used in _extensionStates when an extension is newly installed and won't
76 // be available until the app is relaunched
77 const _TH_EXTENSION_NEEDS_RESTART = "needs-restart";
78 
79 // Used in _extensionStates when the extension RDF data was malformed
80 const _TH_EXTENSION_BAD = "bad";
81 
82 // Thrown to signal a skip, meaning the current test should abort without
83 // registering a failure
84 const _TH_SKIP = {};
85 
86 function doTimeout(delay, func) {
87  var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
88  timer.initWithCallback(func, delay, timer.TYPE_ONE_SHOT);
89 }
90 
91 function doMain() {
92  if (_quit)
93  return;
94 
95  _consoleService.logStringMessage("*** [" + _test_name + "] - running event loop");
96 
97  var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
98  var mainThread = tm.mainThread;
99 
100  while(!_quit) {
101  mainThread.processNextEvent(true);
102  }
103 
104 }
105 
106 function doQuit() {
107  _quit = true;
108 }
109 
110 function dumpStack() {
111  var frame = Components.stack;
112  while (frame != null) {
113  log(frame);
114  frame = frame.caller;
115  }
116 }
117 
118 function doFail(text) {
119  _fail = true;
120  _tests_pending = 0;
121  doQuit();
122  log("*** [" + _test_name + "] - CHECK FAILED: " + text);
123  dumpStack();
124 }
125 
126 function doThrow(text) {
127  doFail(text);
128  throw Cr.NS_ERROR_ABORT;
129 }
130 
131 function assertFalse(aTest, aMessage) {
132  if (aTest) {
133  var msg = (aMessage != null) ? ( " : " + aMessage ) : "";
134  doThrow(aTest + msg);
135  }
136 }
137 
138 function assertTrue(aTest, aMessage) {
139  assertFalse(!aTest, aMessage);
140 }
141 
142 function assertEqual( aExpected, aActual, aMessage) {
143  if (aExpected != aActual) {
144  var msg = (aMessage != null) ? ( " : " + aMessage ) : "";
145  doThrow(aExpected + " != " + aActual + msg);
146  }
147 }
148 
149 function assertNotEqual( aExpected, aActual, aMessage) {
150  if (aExpected == aActual) {
151  var msg = (aMessage != null) ? ( " : " + aMessage ) : "";
152  doThrow(aExpected + " != " + aActual + msg);
153  }
154 }
155 
156 // Assert that the extension with the given ID is active. This function
157 // throws if the extension is disabled or in a bad state or is not present.
158 // It skips (i.e., throws without registering a failure) if the extension
159 // is newly installed and not available until the app relaunches. This
160 // happens whenever a buildbot runs unit tests for the first time after
161 // building.
162 function assertExtension(aExtensionID) {
163  // Initialize the extensions roster the first time through:
164  if (!_extensionStates) {
165  function verbose (aMessage) {
166  // log(">>> " + aMessage);
167  }
168  log("[Test Harness] Scanning extensions...");
169 
170  // Use the rdf:extensions datasource to enumerate extensions and get the
171  // following extension properties:
172  //
173  // addonID - the key to use in _extensionStates
174  // isDisabled - to identify disabled extensions
175  // state - to identify extensions that are newly installed
176  // version - the status string used for extensions that are operational
177  //
178  // Note that the "state" (if present) is not the general state of the
179  // extension, but strictly the outcome of an install operation that
180  // has just completed. If not present, then the extension was installed
181  // during an earlier run of the app. Thus, it can be used to detect
182  // newly installed exensions that won't be ready until the next launch
183  // of the app. This does not appear to be documented, but there's a
184  // slim chance one might discern it from the logic and comments in
185  // extensions.js and nsExtensionManager:
186  //
187  // http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/mozapps/extensions/content/extensions.js#438
188  // * which reveals that when showing the "installs" view, the types variable
189  // is set to build a list of extensions whose "state" is not empty.
190  //
191  // http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/mozapps/extensions/src/nsExtensionManager.js.in#7953
192  // * which states that the state property represents the current phase of
193  // an install
194  //
195  // http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/mozapps/extensions/src/nsExtensionManager.js.in#7617
196  // * which shows that ExtensionsDataSource.updateDownloadState() sets the
197  // state property
198  //
199  // http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/mozapps/extensions/src/nsExtensionManager.js.in#4697
200  // * which shows that EM__setOp() sets the state to "success" (using
201  // updateDownloadState()) if the extension reaches the OP_NEEDS_INSTALL
202  // stage.
203  //
204  // Note that the opType property is cleared before control passes to
205  // Songbird, so the "needs-install" value of this property, which has
206  // a distintly useful sound to it, is gone at this point.
207  //
208  // The following logic is adapted from
209  // http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/mozapps/extensions/content/extensions.js#2311
210 
211 
212  // Set up an enumerator of all extensions:
213 
214  let rdfService = Cc["@mozilla.org/rdf/rdf-service;1"]
215  .getService(Ci.nsIRDFService);
216  let extensionsDS = rdfService.GetDataSource("rdf:extensions");
217  verbose("extensions datasource [" + extensionsDS.URI + "]");
218 
219  let container = Cc["@mozilla.org/rdf/container;1"]
220  .createInstance(Ci.nsIRDFContainer);
221  container.Init(extensionsDS,
222  rdfService.GetResource("urn:mozilla:item:root"));
223  let each = container.GetElements();
224 
225  // Define the properties to look up:
226  const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
227  const ADDONID_ARC = rdfService.GetResource(PREFIX_NS_EM + "addonID");
228  const STATE_ARC = rdfService.GetResource(PREFIX_NS_EM + "state");
229  const DISABLED_ARC = rdfService.GetResource(PREFIX_NS_EM + "isDisabled");
230  const VERSION_ARC = rdfService.GetResource(PREFIX_NS_EM + "version");
231 
232  // Default to a blank set:
233  _extensionStates = {};
234 
235  // Enumerate the extensions:
236  while (each.hasMoreElements()) {
237  let extensionRdf = each.getNext().QueryInterface(Ci.nsIRDFResource);
238  verbose("extension [" + extensionRdf.ValueUTF8 + "]");
239 
240  // Get its add-on ID:
241  let addonID = extensionsDS.GetTarget(extensionRdf, ADDONID_ARC, true);
242  if (!(addonID instanceof Ci.nsIRDFLiteral)) {
243  verbose("INVALID " + ADDONID_ARC.ValueUTF8);
244  continue;
245  }
246 
247  // Get the other properties of interest:
248  let installState = extensionsDS.GetTarget(extensionRdf, STATE_ARC, true);
249  let disabled = extensionsDS.GetTarget(extensionRdf, DISABLED_ARC, true);
250  let version = extensionsDS.GetTarget(extensionRdf, VERSION_ARC, true);
251 
252  // Check for successful install, then disabled status, then record its
253  // version as its status, and finally, mark it as bad if its properties
254  // weren't the expected type:
255  if (installState instanceof Ci.nsIRDFLiteral) {
256  verbose("install state [" + installState.Value + "]");
257  _extensionStates[addonID.Value] =
258  (installState.Value == "success") ? _TH_EXTENSION_NEEDS_RESTART :
260  }
261  else if (disabled instanceof Ci.nsIRDFLiteral &&
262  disabled.Value == "true")
263  {
264  verbose("disabled [" + disabled.Value + "]");
265  _extensionStates[addonID.Value] = _TH_EXTENSION_DISABLED;
266  }
267  else if (version instanceof Ci.nsIRDFLiteral) {
268  verbose("version [" + version.Value + "]");
269  _extensionStates[addonID.Value] = version.Value;
270  }
271  else {
272  verbose("RDF PROPERTIES INFO NOT FOUND <<<\n");
273  _extensionStates[addonID.Value] = _TH_EXTENSION_BAD;
274  }
275 
276  log(" " + addonID.Value + ": " + _extensionStates[addonID.Value]);
277  }
278  }
279 
280  // The list of extensions is initialized. Now check for the one
281  // specified.
282 
283  // Is it listed?
284  assertTrue((aExtensionID in _extensionStates),
285  "No such extension: " + aExtensionID);
286 
287  let status = _extensionStates[aExtensionID];
288 
289  // Is it inoperable?
290  switch (status) {
291  case _TH_EXTENSION_BAD:
292  fail("Required extension failed to install: " + aExtensionID);
293  break;
294 
296  fail("Required extension is disabled: " + aExtensionID);
297  break;
298 
300  skip("Required extension " + aExtensionID +
301  " is newly installed. You must relaunch to run this test.");
302  break;
303  }
304 
305  // The extension is ready. Its status will be its version. Maybe
306  // the caller would like to know this tidbit:
307  return status;
308 }
309 
310 function fail(aMessage) {
311  var msg = (aMessage != null) ? ( "FAIL : " + aMessage ) : "FAIL";
312  doThrow(msg);
313 }
314 
315 function failNoThrow(aMessage) {
316  var msg = (aMessage != null) ? ( "FAIL : " + aMessage ) : "FAIL";
317  doFail(msg);
318 }
319 
320 // Skip the current test without registering a failure
321 function skip(aMessage) {
322  if (!aMessage) {
323  aMessage = "SKIPPING TEST";
324  }
325  log("*** [" + _test_name + "] - WARNING: " + aMessage);
326  throw _TH_SKIP;
327 }
328 
329 function testPending() {
330  log("*** [" + _test_name + "] - test pending");
331  if ( _tests_pending == 0 ) {
332  // start of tests, don't spin wait
333  _tests_pending++;
334  return;
335  }
336 
337  let count = _tests_pending++;
338  while ( count < _tests_pending ) {
339  // sleep for awhile. testFinished will decrement the _tests_pending
340  sleep(100, true);
341  }
342 }
343 
344 function testFinished() {
345  log("*** [" + _test_name + "] - test finished");
346  if (--_tests_pending == 0)
347  doQuit();
348 }
349 
350 function log(s) {
351  _consoleService.logStringMessage(s);
352 }
353 
354 function getPlatform() {
355  var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
356  return sysInfo.getProperty("name");
357 }
358 
359 function sleep(ms, suppressOutput) {
360  var threadManager = Cc["@mozilla.org/thread-manager;1"].
361  getService(Ci.nsIThreadManager);
362  var mainThread = threadManager.mainThread;
363 
364  if (!suppressOutput) {
365  log("*** [" + _test_name + "] - waiting for " + ms + " milliseconds...");
366  }
367  var then = new Date().getTime(), now = then;
368  for (; now - then < ms; now = new Date().getTime()) {
369  mainThread.processNextEvent(true);
370  }
371  if (!suppressOutput) {
372  log("*** [" + _test_name + "] - done waiting.");
373  }
374 }
375 
377  var DEFAULT_PORT = 8180;
378  const ENV_VAR_PORT = "SONGBIRD_TEST_SERVER_PORT";
379 
380  var environment =
381  Components.classes["@mozilla.org/process/environment;1"]
382  .getService(Components.interfaces.nsIEnvironment);
383 
384  var port = DEFAULT_PORT;
385  if (environment.exists(ENV_VAR_PORT)) {
386  var envPort = parseInt(environment.get(ENV_VAR_PORT));
387  if (envPort) {
388  port = envPort;
389  }
390  }
391 
392  log("*** [" + _test_name + "] - using test server port " + port);
393 
394  return port;
395 }
396 
397 function StringArrayEnumerator(aArray) {
398  this._array = aArray;
399  this._current = 0;
400 }
401 
402 StringArrayEnumerator.prototype.hasMore = function() {
403  return this._current < this._array.length;
404 }
405 
406 StringArrayEnumerator.prototype.getNext = function() {
407  return this._array[this._current++];
408 }
409 
410 StringArrayEnumerator.prototype.QueryInterface = function(iid) {
411  if (!iid.equals(Components.interfaces.nsIStringEnumerator) &&
412  !iid.equals(Components.interfaces.nsISupports))
413  throw Components.results.NS_ERROR_NO_INTERFACE;
414  return this;
415 };
416 
417 function ExtensionSchemeMatcher(aExtensions, aSchemes) {
418  this._extensions = aExtensions;
419  this._schemes = aSchemes;
420 }
421 
422 ExtensionSchemeMatcher.prototype.match = function(aStr) {
423 
424  // Short circuit for the most common case
425  if(aStr.lastIndexOf("." + this._extensions[0]) ==
426  aStr.length - this._extensions[0].length + 1) {
427  return true;
428  }
429 
430  var extensionSep = aStr.lastIndexOf(".");
431  if(extensionSep >= 0) {
432  var extension = aStr.substring(extensionSep + 1);
433  var rv = this._extensions.some(function(ext) {
434  return extension == ext;
435  });
436  if(rv) {
437  return true;
438  }
439  }
440 
441  var schemeSep = aStr.indexOf("://");
442  if(schemeSep >= 0) {
443  var scheme = aStr.substring(0, schemeSep);
444  var rv = this._schemes.some(function(sch) {
445  return scheme == sch;
446  });
447  if(rv) {
448  return true;
449  }
450  }
451 
452  return false;
453 }
454 
455 _consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
456 
457 function loadData(databaseGuid, databaseLocation) {
458 
459  var dbq = Cc["@songbirdnest.com/Songbird/DatabaseQuery;1"]
460  .createInstance(Ci.sbIDatabaseQuery);
461 
462  dbq.setDatabaseGUID(databaseGuid);
463  if (databaseLocation) {
464  dbq.databaseLocation = databaseLocation;
465  }
466  dbq.setAsyncQuery(false);
467  dbq.addQuery("create temporary table tmp_rowids (id integer);");
468  dbq.addQuery("begin");
469 
470  var data = readFile("media_items.txt");
471  var a = data.split("\n");
472  for(var i = 0; i < a.length - 1; i++) {
473  var b = a[i].split("\t");
474  dbq.addQuery("insert into media_items (guid, created, updated, content_url, content_mime_type, content_length, hidden, media_list_type_id, is_list) values (?, ?, ?, ?, ?, ?, ?, ?, ?)");
475  dbq.bindStringParameter(0, b[1]);
476  dbq.bindInt64Parameter(1, b[2]);
477  dbq.bindInt64Parameter(2, b[3]);
478  dbq.bindStringParameter(3, b[4]);
479  dbq.bindStringParameter(4, b[5]);
480  if(b[5] == "") {
481  dbq.bindNullParameter(5);
482  }
483  else {
484  dbq.bindInt32Parameter(5, b[6]);
485  }
486  dbq.bindInt32Parameter(6, b[7]);
487  if(b[8] == "" || b[8] == "0") {
488  dbq.bindNullParameter(7);
489  dbq.bindInt32Parameter(8, 0);
490  }
491  else {
492  dbq.bindInt32Parameter(7, b[8]);
493  dbq.bindInt32Parameter(8, 1);
494  }
495  }
496 
497  data = readFile("resource_properties.txt");
498  a = data.split("\n");
499  for(var i = 0; i < a.length - 1; i++) {
500  var b = a[i].split("\t");
501  dbq.addQuery("insert into resource_properties (media_item_id, property_id, obj, obj_searchable, obj_sortable) values ((select media_item_id from media_items where guid = ?), ?, ?, ?, ?)");
502  dbq.bindStringParameter(0, b[0]);
503  dbq.bindInt32Parameter(1, b[1]);
504  dbq.bindStringParameter(2, b[2]);
505  dbq.bindStringParameter(3, b[3]);
506  dbq.bindStringParameter(4, b[4]);
507  }
508 
509  data = readFile("simple_media_lists.txt");
510  a = data.split("\n");
511  for(var i = 0; i < a.length - 1; i++) {
512  var b = a[i].split("\t");
513  dbq.addQuery("insert into simple_media_lists (media_item_id, member_media_item_id, ordinal) values ((select media_item_id from media_items where guid = ?), (select media_item_id from media_items where guid = ?), ?)");
514  dbq.bindStringParameter(0, b[0]);
515  dbq.bindStringParameter(1, b[1]);
516  dbq.bindInt32Parameter(2, b[2]);
517  }
518 
519  // XXXsteve I need to use a temp table here to avoid this bug:
520  // http://www.sqlite.org/cvstrac/tktview?tn=3082
521  /* XXXAus: resource_properties_fts is disabled. See bug 9488 and bug 9617.
522  dbq.addQuery("insert into tmp_rowids select rowid from resource_properties_fts;");
523  dbq.addQuery("insert into resource_properties_fts (rowid, propertyid, obj) " +
524  " select rowid, property_id, obj from resource_properties where rowid not in (" +
525  "select id from tmp_rowids)");
526  */
527  dbq.addQuery("delete from tmp_rowids");
528  dbq.addQuery("insert into tmp_rowids select rowid from resource_properties_fts_all;");
529  dbq.addQuery("insert into resource_properties_fts_all (rowid, alldata) " +
530  " select media_item_id, group_concat(obj, ' ') from resource_properties where media_item_id not in (" +
531  "select id from tmp_rowids) group by media_item_id");
532 
533  dbq.addQuery("insert into resource_properties_fts_all (alldata) values ('foo');");
534 
535  dbq.addQuery("commit");
536  dbq.addQuery("drop table tmp_rowids");
537  dbq.execute();
538  dbq.resetQuery();
539 
540 }
541 
542 function readFile(fileName) {
543 
544  var file = Cc["@mozilla.org/file/directory_service;1"]
545  .getService(Ci.nsIProperties)
546  .get("resource:app", Ci.nsIFile);
547  file.append("testharness");
548  file.append("localdatabaselibrary");
549  file.append(fileName);
550 
551  var data = "";
552  var fstream = Cc["@mozilla.org/network/file-input-stream;1"]
553  .createInstance(Ci.nsIFileInputStream);
554  var sstream = Cc["@mozilla.org/scriptableinputstream;1"]
555  .createInstance(Ci.nsIScriptableInputStream);
556  fstream.init(file, -1, 0, 0);
557  sstream.init(fstream);
558 
559  var str = sstream.read(4096);
560  while (str.length > 0) {
561  data += str;
562  str = sstream.read(4096);
563  }
564 
565  sstream.close();
566  fstream.close();
567  return data;
568 }
569 
570 function createLibrary(databaseGuid, databaseLocation, init) {
571 
572  if (typeof(init) == "undefined") {
573  init = true;
574  }
575 
576  var directory;
577  if (databaseLocation) {
578  directory = databaseLocation.QueryInterface(Ci.nsIFileURL).file;
579  }
580  else {
581  directory = Cc["@mozilla.org/file/directory_service;1"].
582  getService(Ci.nsIProperties).
583  get("ProfD", Ci.nsIFile);
584  directory.append("db");
585  }
586 
587  var file = directory.clone();
588  file.append(databaseGuid + ".db");
589 
590  var libraryFactory =
591  Cc["@songbirdnest.com/Songbird/Library/LocalDatabase/LibraryFactory;1"]
592  .getService(Ci.sbILibraryFactory);
593  var hashBag = Cc["@mozilla.org/hash-property-bag;1"].
594  createInstance(Ci.nsIWritablePropertyBag2);
595  hashBag.setPropertyAsInterface("databaseFile", file);
596  var library = libraryFactory.createLibrary(hashBag);
597  try {
598  if (init) {
599  library.clear();
600  }
601  }
602  catch(e) {
603  }
604 
605  if (init) {
606  loadData(databaseGuid, databaseLocation);
607  }
608  return library;
609 }
610 
611 // assert the equality of two JS arrays
612 // assertEqual is used for each of the items
613 function assertArraysEqual(a1, a2) {
614  assertEqual(a1.length, a2.length, "arrays are different lengths");
615  for (var i=0; i<a1.length; i++) {
616  assertEqual(a1[i], a2[i], "data mismatch at index " + i);
617  }
618 }
619 
620 // assert the equality of two unordered sets, represnted as JS arrays
621 function assertSetsEqual(s1, s2) {
622  for (var i = 0; i < s1.length; i++) {
623  assertTrue(s2.indexOf(s1[i]) >= 0,
624  "set 1 member " + s1[i] + " not in set 2");
625  }
626  for (var i = 0; i < s2.length; i++) {
627  assertTrue(s1.indexOf(s2[i]) >= 0,
628  "set 2 member " + s2[i] + " not in set 1");
629  }
630  assertEqual(s1.length, s2.length, "sets are different lengths");
631 }
632 
633 // assert the equality of the contents of two files
634 function assertFilesEqual(aFile1, aFile2, aMessage) {
635  if (!testFilesEqual(aFile1, aFile2)) {
636  var msg = (aMessage != null) ? ( " : " + aMessage ) : "";
637  doThrow(aFile1.path + " != " + aFile2.path + " " + msg);
638  }
639 }
640 
641 function testFilesEqual(aFile1, aFile2) {
642  if (!aFile1.exists() || !aFile2.exists())
643  return false;
644 
645  var fileStream1 = Cc["@mozilla.org/network/file-input-stream;1"]
646  .createInstance(Ci.nsIFileInputStream);
647  var scriptableFileStream1 = Cc["@mozilla.org/scriptableinputstream;1"]
648  .createInstance(Ci.nsIScriptableInputStream);
649  fileStream1.init(aFile1, -1, 0, 0);
650  scriptableFileStream1.init(fileStream1);
651 
652  var fileStream2 = Cc["@mozilla.org/network/file-input-stream;1"]
653  .createInstance(Ci.nsIFileInputStream);
654  var scriptableFileStream2 = Cc["@mozilla.org/scriptableinputstream;1"]
655  .createInstance(Ci.nsIScriptableInputStream);
656  fileStream2.init(aFile2, -1, 0, 0);
657  scriptableFileStream2.init(fileStream2);
658 
659  var filesEqual = true;
660  do {
661  var data1 = scriptableFileStream1.read(4096);
662  var data2 = scriptableFileStream2.read(4096);
663 
664  if (data1 != data2) {
665  filesEqual = false;
666  break;
667  }
668  } while(data1.length > 0);
669 
670  fileStream1.close();
671  scriptableFileStream1.close();
672  fileStream2.close();
673  scriptableFileStream2.close();
674 
675  return filesEqual;
676 }
677 
679 
680  var file = Cc["@mozilla.org/file/directory_service;1"]
681  .getService(Ci.nsIProperties)
682  .get("resource:app", Ci.nsIFile);
683  file = file.clone();
684 
685  var nodes = path.split("/");
686  for ( var i = 0, end = nodes.length; i < end; i++ )
687  {
688  file.append( nodes[ i ] );
689  }
690 
691  return file;
692 }
693 
700 function getTestFile(aFileName) {
701  return newAppRelativeFile("testharness/" + _test_comp + "/" + aFileName);
702 }
703 
707 function newURI(aURLString)
708 {
709  // Must be a string here
710  if (!(aURLString &&
711  (aURLString instanceof String) || typeof(aURLString) == "string"))
712  throw Components.results.NS_ERROR_INVALID_ARG;
713 
714  var ioService =
715  Components.classes["@mozilla.org/network/io-service;1"]
716  .getService(Components.interfaces.nsIIOService);
717 
718  try {
719  return ioService.newURI(aURLString, null, null);
720  }
721  catch (e) { }
722 
723  return null;
724 }
725 
726 function newFileURI(file)
727 {
728  var ioService =
729  Components.classes["@mozilla.org/network/io-service;1"]
730  .getService(Components.interfaces.nsIIOService);
731  try {
732  return ioService.newFileURI(file);
733  }
734  catch (e) { }
735 
736  return null;
737 }
738 
769 function TestCase(config) {
770 
771  for (var option in config) {
772  this[option] = config[option];
773  }
774 
775  this._stubs = [];
776 }
777 
778 TestCase.prototype = {
779 
780  run: function TestCase_run(args) {
781 
782  if (this.pre && typeof this.pre === 'function')
783  this.pre.apply(this, args);
784 
785  this.exec.apply(this, args);
786 
787  if (this.post && typeof this.post === 'function')
788  this.post.apply(this, args);
789 
790  // Always call unstub so test case instances don't have to worry about it
791  // in their post functions. This is a no-op if there are no stubs.
792  this.unstub();
793 
794  },
795 
796  stub: function TestCase_stub(receiver, property, stub) {
797 
798  this._stubs.push({
799  receiver: receiver,
800  property: property,
801  stash: receiver[property]
802  });
803 
804  if (!(property in receiver)) {
805  // The test should fail if the caller tries to stub a property that
806  // doesn't exist on the receiver object. A stub indicates that the caller
807  // expects that property to exist, so failing here alerts us that
808  // something we expect to be there is no longer there.
809  throw new Error("Attempted to stub property: " + property +
810  "on an object that doesn't contain that property from " +
811  " test case: " + this.desc);
812  }
813 
814  receiver[property] = stub;
815  },
816 
817  unstub: function TestCase_unstub() {
818  var stubs = this._stubs,
819  len = stubs.length;
820 
821  if (len > 0) {
822  for (let i = 0; i < len; i++) {
823  let stub = stubs[i];
824  stub.receiver[stub.property] = stub.stash;
825  }
826  this._stubs = [];
827  }
828  }
829 
830 }
function loadData(databaseGuid, databaseLocation)
function sleep(ms, suppressOutput)
const Cc
var args
Definition: alert.js:8
function TestCase(config)
function fail(aMessage)
function doMain()
function for each(var file in gFilesToClose)
function newAppRelativeFile(path)
function assertNotEqual(aExpected, aActual, aMessage)
var _test_comp
var _consoleService
function log(s)
function testFinished()
var _test_name
var _tests_pending
sidebarFactory createInstance
Definition: nsSidebar.js:351
function assertTrue(aTest, aMessage)
const PREFIX_NS_EM
function assertSetsEqual(s1, s2)
var ioService
version(170)
function assertEqual(aExpected, aActual, aMessage)
function skip(aMessage)
var _quit
function getTestFile(aFileName)
getService(Ci.sbIFaceplateManager)
var _skip
_window init
Definition: FeedWriter.js:1144
function assertArraysEqual(a1, a2)
var count
Definition: test_bug7406.js:32
var _running_event_loop
const _TH_EXTENSION_BAD
function getPlatform()
function doThrow(text)
function assertFilesEqual(aFile1, aFile2, aMessage)
function newFileURI(file)
function testFilesEqual(aFile1, aFile2)
function dumpStack()
return null
Definition: FeedWriter.js:1143
function newURI(aURLString)
function StringArrayEnumerator(aArray)
function assertFalse(aTest, aMessage)
function ExtensionSchemeMatcher(aExtensions, aSchemes)
const _TH_EXTENSION_DISABLED
const _TH_SKIP
const Cr
function failNoThrow(aMessage)
const Ci
function assertExtension(aExtensionID)
function readFile(fileName)
function doFail(text)
function now()
var _extensionStates
function msg
function createLibrary(databaseGuid, databaseLocation, init)
function doTimeout(delay, func)
function getTestServerPortNumber()
observe data
Definition: FeedWriter.js:1329
var _fail
_getSelectedPageStyle s i
const _TH_EXTENSION_NEEDS_RESTART
function doQuit()
var file
function testPending()