test_servicepane.js
Go to the documentation of this file.
1 
31 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
32 
33 function DBG(s) { log('DBG:test_servicepane: '+s); }
34 
35 var testModule = {
36  classId: Components.ID("{0da5eace-1dd2-11b2-a64a-eb82fc5ef0c3}"),
37  classDescription: "Songbird Test Service Pane Module",
38  contractId: "@songbirdnest.com/servicepane/test-module;1",
39 
40  _registered: false,
41  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneModule,
42  Ci.nsIFactory]),
43 
44  _processEvents: function() {
45  let mainThread = Cc["@mozilla.org/thread-manager;1"]
46  .getService(Ci.nsIThreadManager)
47  .mainThread;
48  while (mainThread.hasPendingEvents())
49  mainThread.processNextEvent(true);
50  },
51 
52  addToCategory: function() {
53  if (!this._registered) {
54  // Need to register component first
55  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
56  registrar.registerFactory(this.classId, this.classDescription,
57  this.contractId, this);
58  this._registered = true;
59  }
60 
61  this._servicePaneInitParams = null;
62 
63  let catMgr = Cc["@mozilla.org/categorymanager;1"]
64  .getService(Ci.nsICategoryManager);
65  catMgr.addCategoryEntry("service-pane", "service," + this.contractId,
66  this.contractId, false, true);
67 
68  // Notifications are sent asynchronously, wait for them to be processed
69  this._processEvents();
70 
71  // servicePaneInit should have been called, return the arguments we received
72  return this._servicePaneInitParams;
73  },
74 
75  removeFromCategory: function() {
76  let catMgr = Cc["@mozilla.org/categorymanager;1"]
77  .getService(Ci.nsICategoryManager);
78  catMgr.deleteCategoryEntry("service-pane", "service," + this.contractId,
79  false);
80 
81  if (this._registered) {
82  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
83  registrar.unregisterFactory(this.classId, this);
84  this._registered = false;
85  }
86 
87  // Notifications are sent asynchronously, wait for them
88  this._processEvents();
89  },
90 
91  createInstance: function(outer, iid) {
92  return this.QueryInterface(iid);
93  },
94 
95  _servicePaneInitParams: null,
96  servicePaneInit: function() {
97  DBG("testModule.servicePaneInit() called");
98  this._servicePaneInitParams = arguments;
99  },
100 
101  _fillContextMenuParams: null,
102  fillContextMenu: function() {
103  DBG("testModule.fillContextMenu() called");
104  this._fillContextMenuParams = arguments;
105  },
106 
107  _fillNewItemMenuParams: null,
108  fillNewItemMenu: function() {
109  DBG("testModule.fillNewItemMenu() called");
110  this._fillNewItemMenuParams = arguments;
111  },
112 
113  _onSelectionChangedParams: null,
114  onSelectionChanged: function() {
115  DBG("testModule.onSelectionChanged() called");
116  this._onSelectionChangedParams = arguments;
117  },
118 
119  _canDropParams: null,
120  _canDropResult: false,
121  canDrop: function() {
122  DBG("testModule.canDrop() called");
123  this._canDropParams = arguments;
124  return this._canDropResult;
125  },
126 
127  _onDropParams: null,
128  onDrop: function() {
129  DBG("testModule.onDrop() called");
130  this._onDropParams = arguments;
131  },
132 
133  _onDragGestureParams: null,
134  _onDragGestureResult: false,
135  onDragGesture: function() {
136  DBG("testModule.onDragGesture() called");
137  this._onDragGestureParams = arguments;
138  return this._onDragGestureResult;
139  },
140 
141  _onBeforeRenameParams: null,
142  onBeforeRename: function() {
143  DBG("testModule.onBeforeRename() called");
144  this._onBeforeRenameParams = arguments;
145  },
146 
147  _onRenameParams: null,
148  onRename: function() {
149  DBG("testModule.onRename() called");
150  this._onRenameParams = arguments;
151  },
152 
153  stringbundle: null
154 };
155 
156 function testAttributes(aNode) {
157  // Node shouldn't have any attributes yet
158  assertEqual(serializeTree(aNode), '[node/]');
159  assertEqual(aNode.getAttribute("foo"), null);
160  assertEqual(aNode.getAttributeNS("ns", "foo"), null);
161  assertFalse(aNode.hasAttribute("foo"));
162  assertFalse(aNode.hasAttributeNS("ns", "foo"));
163 
164  // Try changing an attribute then
165  aNode.setAttribute("foo", "bar");
166  assertEqual(aNode.getAttribute("foo"), "bar");
167  assertEqual(aNode.getAttributeNS("ns", "foo"), null);
168  assertTrue(aNode.hasAttribute("foo"));
169  assertFalse(aNode.hasAttributeNS("ns", "foo"));
170  assertEqual(serializeTree(aNode), '[node foo="bar"/]');
171 
172  aNode.setAttribute("foo", "baz");
173  assertEqual(serializeTree(aNode), '[node foo="baz"/]');
174 
175  aNode.removeAttribute("foo");
176  assertEqual(serializeTree(aNode), '[node/]');
177 
178  assertEqual(aNode.getAttribute("foo"), null);
179  assertFalse(aNode.hasAttribute("foo"));
180 
181  // Same thing with namespaces
182  aNode.setAttributeNS("ns", "foo", "bar");
183  assertEqual(aNode.getAttributeNS("ns", "foo"), "bar");
184  assertEqual(aNode.getAttributeNS("wrongns", "foo"), null);
185  assertEqual(aNode.getAttribute("foo"), null);
186  assertTrue(aNode.hasAttributeNS("ns", "foo"));
187  assertFalse(aNode.hasAttributeNS("wrongns", "foo"));
188  assertFalse(aNode.hasAttribute("foo"));
189  assertEqual(serializeTree(aNode), '[node ns:foo="bar"/]');
190 
191  aNode.setAttributeNS("ns", "foo", "baz");
192  assertEqual(serializeTree(aNode), '[node ns:foo="baz"/]');
193 
194  aNode.removeAttribute("foo");
195  aNode.removeAttributeNS("wrongns", "foo");
196  assertEqual(serializeTree(aNode), '[node ns:foo="baz"/]');
197 
198  aNode.removeAttributeNS("ns", "foo");
199  assertEqual(serializeTree(aNode), '[node/]');
200 
201  assertEqual(aNode.getAttributeNS("ns", "foo"), null);
202  assertFalse(aNode.hasAttributeNS("ns", "foo"));
203 
204  // How about multiple attributes?
205  aNode.setAttribute("foo", "bar");
206  aNode.setAttribute("bar", "foo");
207  aNode.setAttributeNS("ns", "foo", "baz");
208  assertEqual(serializeTree(aNode), '[node bar="foo" foo="bar" ns:foo="baz"/]');
209  assertTrue(aNode.hasAttribute("foo"));
210  assertTrue(aNode.hasAttribute("bar"));
211  assertTrue(aNode.hasAttributeNS("ns", "foo"));
212 
213  aNode.removeAttribute("foo");
214  assertEqual(serializeTree(aNode), '[node bar="foo" ns:foo="baz"/]');
215 
216  aNode.removeAttribute("wrongns", "foo");
217  assertEqual(serializeTree(aNode), '[node bar="foo" ns:foo="baz"/]');
218 
219  aNode.removeAttributeNS("ns", "foo");
220  assertEqual(serializeTree(aNode), '[node bar="foo"/]');
221 
222  aNode.removeAttribute("bar");
223  assertEqual(serializeTree(aNode), '[node/]');
224 
225  assertFalse(aNode.hasAttribute("foo"));
226  assertFalse(aNode.hasAttribute("bar"));
227  assertFalse(aNode.hasAttributeNS("ns", "foo"));
228 
229  // Now test the properties defined for some string attributes
230  let stringProps = ["id", "className", "url", "image", "name", "tooltip",
231  "contractid", "stringbundle", "dndDragTypes",
232  "dndAcceptNear", "dndAcceptIn", "contentPrefix"];
233  for each (let prop in stringProps) {
234  DBG("Testing node property " + prop);
235 
236  // Special handling for "className" property - attribute name is "class"
237  let attr = (prop == "className" ? "class" : prop);
238 
239  assertEqual(aNode.getAttribute(attr), null);
240  assertEqual(aNode[prop], null);
241  assertFalse(aNode.hasAttribute(attr));
242 
243  aNode[prop] = "foo"
244  assertEqual(aNode.getAttribute(attr), "foo");
245  assertEqual(aNode[prop], "foo");
246  assertTrue(aNode.hasAttribute(attr));
247 
248  aNode[prop] = null;
249  assertEqual(aNode.getAttribute(attr), null);
250  assertEqual(aNode[prop], null);
251  assertFalse(aNode.hasAttribute(attr));
252 
253  DBG("ok");
254  }
255 
256  // Now test the boolean properties
257  let booleanProps = {hidden: false, editable: false, isOpen: true};
258  for (let prop in booleanProps) {
259  DBG("Testing node property " + prop);
260 
261  let defaultVal = booleanProps[prop];
262 
263  assertEqual(aNode.getAttribute(prop), null);
264  assertEqual(aNode[prop], defaultVal);
265  assertFalse(aNode.hasAttribute(prop));
266 
267  aNode[prop] = !defaultVal;
268  assertEqual(aNode.getAttribute(prop), defaultVal ? "false" : "true");
269  assertEqual(aNode[prop], !defaultVal);
270  assertTrue(aNode.hasAttribute(prop));
271 
272  aNode[prop] = defaultVal;
273  assertEqual(aNode.getAttribute(prop), defaultVal ? "true" : "false");
274  assertEqual(aNode[prop], defaultVal);
275  assertTrue(aNode.hasAttribute(prop));
276 
277  aNode.removeAttribute(prop);
278 
279  DBG("ok");
280  }
281 
282  // "properties" is just a different name for "className"
283  aNode.className = "class1 class2";
284  assertEqual(aNode.properties, "class1 class2");
285  assertEqual(serializeTree(aNode), '[node class="class1 class2"/]');
286 
287  aNode.properties = null;
288  assertEqual(aNode.className, null);
289 
290  // "displayName" should be a translated version of the "name" property
291  aNode.name = "&test_dummy";
292  assertEqual(aNode.displayName, "&test_dummy");
293 
294  aNode.stringbundle = "data:text/plain,test_dummy=foo";
295  assertEqual(aNode.displayName, "foo");
296 
297  aNode.name = "test_dummy";
298  assertEqual(aNode.displayName, "test_dummy");
299 
300  aNode.name = "&test_dummy";
301  assertEqual(aNode.displayName, "foo");
302 
303  aNode.stringbundle = "data:text/plain,test_dummy=bar";
304  assertEqual(aNode.displayName, "bar");
305 
306  aNode.stringbundle = null;
307  assertEqual(aNode.displayName, "&test_dummy");
308 
309  // displayName should be able to use module's string bundle
310  testModule.addToCategory();
311  testModule.stringbundle = "data:text/plain,test_dummy=module-foo";
312  aNode.contractid = testModule.contractId;
313  assertEqual(aNode.displayName, "module-foo");
314 
315  aNode.contractid = null;
316  assertEqual(aNode.displayName, "&test_dummy");
317 
318  // Once the module is removed it should no longer use it
319  testModule.removeFromCategory();
320  aNode.contractid = testModule.contractId;
321  assertEqual(aNode.displayName, "&test_dummy");
322 
323  aNode.contractid = null;
324  aNode.name = null;
325  assertEqual(aNode.displayName, null);
326 
327  // Node still shouldn't have any attributes at the end of the test
328  assertEqual(serializeTree(aNode), '[node/]');
329 }
330 
331 
332 function testTreeManipulation(SPS, aRoot) {
333  let hadException;
334 
335  // Root shouldn't have any children yet
336  assertEqual(serializeTree(aRoot), '[node/]');
337 
338  let node1 = SPS.createNode();
339  assertTrue(node1 instanceof Ci.sbIServicePaneNode);
340  node1.id = "node1";
341 
342  let node2 = SPS.createNode();
343  assertTrue(node2 instanceof Ci.sbIServicePaneNode);
344  node2.id = "node2";
345 
346  let node3 = SPS.createNode();
347  assertTrue(node3 instanceof Ci.sbIServicePaneNode);
348  node3.id = "node3";
349 
350  // Initially all relational properties should be null
351  assertEqual(aRoot.firstChild, null);
352  assertEqual(aRoot.lastChild, null);
353  assertEqual(node1.parentNode, null);
354  assertEqual(node1.nextSibling, null);
355  assertEqual(node1.previousSibling, null);
356 
357  // Appending node as first child
358  aRoot.appendChild(node1);
359  node1.appendChild(node2);
360  assertEqual(serializeTree(aRoot), '[node][node id="node1"][node id="node2"/][/node][/node]');
361 
362  // Appending node as second child
363  aRoot.appendChild(node3);
364  assertEqual(serializeTree(aRoot), '[node][node id="node1"][node id="node2"/][/node][node id="node3"/][/node]');
365 
366  // Relational properties should be a lot more interesting now
367  assertEqual(aRoot.firstChild, node1);
368  assertEqual(aRoot.lastChild, node3);
369  assertEqual(node1.firstChild, node2);
370  assertEqual(node1.lastChild, node2);
371  assertEqual(node3.firstChild, null);
372  assertEqual(node3.lastChild, null);
373  assertEqual(node1.parentNode, aRoot);
374  assertEqual(node2.parentNode, node1);
375  assertEqual(node3.parentNode, aRoot);
376  assertEqual(node1.nextSibling, node3);
377  assertEqual(node1.previousSibling, null);
378  assertEqual(node2.nextSibling, null);
379  assertEqual(node2.previousSibling, null);
380  assertEqual(node3.nextSibling, null);
381  assertEqual(node3.previousSibling, node1);
382 
383  // Appending a node that is already in a different part of the tree
384  aRoot.appendChild(node2);
385  assertEqual(serializeTree(aRoot), '[node][node id="node1"/][node id="node3"/][node id="node2"/][/node]');
386 
387  aRoot.appendChild(node1);
388  assertEqual(serializeTree(aRoot), '[node][node id="node3"/][node id="node2"/][node id="node1"/][/node]');
389 
390  // Removing a node
391  aRoot.removeChild(node3);
392  assertEqual(serializeTree(aRoot), '[node][node id="node2"/][node id="node1"/][/node]');
393 
394  // Removing a node that isn't a child should throw
395  hadException = false;
396  try {
397  node1.removeChild(node2);
398  }
399  catch (e) {
400  hadException = true;
401  }
402  assertTrue(hadException);
403 
404  hadException = false;
405  try {
406  node1.removeChild(node3);
407  }
408  catch (e) {
409  hadException = true;
410  }
411  assertTrue(hadException);
412 
413  // Inserting a node before another
414  aRoot.insertBefore(node3, node1);
415  assertEqual(serializeTree(aRoot), '[node][node id="node2"/][node id="node3"/][node id="node1"/][/node]');
416 
417  // Inserting a node that is already in a different part of the tree
418  aRoot.insertBefore(node3, node2);
419  assertEqual(serializeTree(aRoot), '[node][node id="node3"/][node id="node2"/][node id="node1"/][/node]');
420 
421  // Test relational properties again
422  assertEqual(aRoot.firstChild, node3);
423  assertEqual(aRoot.lastChild, node1);
424  assertEqual(node1.firstChild, null);
425  assertEqual(node1.lastChild, null);
426  assertEqual(node2.firstChild, null);
427  assertEqual(node2.lastChild, null);
428  assertEqual(node3.firstChild, null);
429  assertEqual(node3.lastChild, null);
430  assertEqual(node1.parentNode, aRoot);
431  assertEqual(node2.parentNode, aRoot);
432  assertEqual(node3.parentNode, aRoot);
433  assertEqual(node1.nextSibling, null);
434  assertEqual(node1.previousSibling, node2);
435  assertEqual(node2.nextSibling, node1);
436  assertEqual(node2.previousSibling, node3);
437  assertEqual(node3.nextSibling, node2);
438  assertEqual(node3.previousSibling, null);
439 
440  // Inserting before a node that isn't a child should throw
441  hadException = false;
442  try {
443  node1.insertBefore(node3, node2);
444  }
445  catch (e) {
446  hadException = true;
447  }
448  assertTrue(hadException);
449 
450  aRoot.removeChild(node2);
451  hadException = false;
452  try {
453  node1.insertBefore(node3, node2);
454  }
455  catch (e) {
456  hadException = true;
457  }
458  assertTrue(hadException);
459 
460  // Replacing a node
461  aRoot.replaceChild(node2, node1);
462  assertEqual(serializeTree(aRoot), '[node][node id="node3"/][node id="node2"/][/node]');
463 
464  // Replacing with a node that is already part of the tree
465  aRoot.replaceChild(node3, node2);
466  assertEqual(serializeTree(aRoot), '[node][node id="node3"/][/node]');
467 
468  // Replacing a node that isn't a child should throw
469  hadException = false;
470  try {
471  aRoot.replaceChild(node1, node2);
472  }
473  catch (e) {
474  hadException = true;
475  }
476  assertTrue(hadException);
477 
478  node3.appendChild(node2);
479  hadException = false;
480  try {
481  aRoot.replaceChild(node1, node2);
482  }
483  catch (e) {
484  hadException = true;
485  }
486  assertTrue(hadException);
487 
488  // Inserting a parent node into the child should throw
489  let rootParent = aRoot.parentNode;
490  hadException = false;
491  try {
492  aRoot.appendChild(aRoot)
493  }
494  catch (e) {
495  hadException = true;
496  }
497  assertTrue(hadException);
498 
499  hadException = false;
500  try {
501  node3.appendChild(aRoot)
502  }
503  catch (e) {
504  hadException = true;
505  }
506  assertTrue(hadException);
507 
508  hadException = false;
509  try {
510  node2.appendChild(aRoot)
511  }
512  catch (e) {
513  hadException = true;
514  }
515  assertTrue(hadException);
516 
517  assertEqual(rootParent, aRoot.parentNode);
518 
519  // Clean up
520  aRoot.removeChild(node3);
521  assertEqual(serializeTree(aRoot), '[node/]');
522 }
523 
524 
525 function testNodeByAttribute(SPS, aRoot)
526 {
527  let methods = {id: "getNode", url: "getNodeForURL"};
528  let attributes = ["id", "url"];
529 
530  let node1 = SPS.createNode();
531  assertTrue(node1 instanceof Ci.sbIServicePaneNode);
532  node1.id = "id_node1";
533  node1.url = "url_node1";
534 
535  let node2 = SPS.createNode();
536  assertTrue(node2 instanceof Ci.sbIServicePaneNode);
537  node2.id = "id_node2";
538  node2.url = "url_node2";
539 
540  // We didn't add the nodes yet, they shouldn't be returned
541  for each (let attr in attributes) {
542  let method = methods[attr];
543  assertEqual(SPS[method](attr + "_node1"), null);
544  assertEqual(SPS[method](attr + "_node2"), null);
545  }
546 
547  // Add the nodes - they should be returned now
548  aRoot.appendChild(node2);
549  aRoot.insertBefore(node1, node2);
550  for each (let attr in attributes) {
551  let method = methods[attr];
552  assertEqual(SPS[method](attr + "_node1"), node1);
553  assertEqual(SPS[method](attr + "_node2"), node2);
554  }
555 
556  // Moving nodes in the tree shouldn't change anything
557  node1.appendChild(node2);
558  for each (let attr in attributes) {
559  let method = methods[attr];
560  assertEqual(SPS[method](attr + "_node1"), node1);
561  assertEqual(SPS[method](attr + "_node2"), node2);
562  }
563 
564  // Removing the root node should remove its children as well
565  aRoot.removeChild(node1);
566  for each (let attr in attributes) {
567  let method = methods[attr];
568  assertEqual(SPS[method](attr + "_node1"), null);
569  assertEqual(SPS[method](attr + "_node2"), null);
570  }
571 
572  // Re-adding the root node should re-add its children as well
573  aRoot.appendChild(node1);
574  for each (let attr in attributes) {
575  let method = methods[attr];
576  assertEqual(SPS[method](attr + "_node1"), node1);
577  assertEqual(SPS[method](attr + "_node2"), node2);
578  }
579 
580  // Changing the attribute should make sure the node is returned by its new attribute
581  node1.id = "id_node3";
582  node1.url = "url_node3";
583  for each (let attr in attributes) {
584  let method = methods[attr];
585  assertEqual(SPS[method](attr + "_node1"), null);
586  assertEqual(SPS[method](attr + "_node2"), node2);
587  assertEqual(SPS[method](attr + "_node3"), node1);
588  }
589 
590  // Changing the attribute back should change everything back
591  node1.id = "id_node1";
592  node1.url = "url_node1";
593  for each (let attr in attributes) {
594  let method = methods[attr];
595  assertEqual(SPS[method](attr + "_node1"), node1);
596  assertEqual(SPS[method](attr + "_node2"), node2);
597  assertEqual(SPS[method](attr + "_node3"), null);
598  }
599 
600  // For duplicate IDs/URLs any one of the nodes should be returned
601  node2.id = "id_node1";
602  node2.url = "url_node1";
603  for each (let attr in attributes) {
604  let method = methods[attr];
605  let node = SPS[method](attr + "_node1");
606  assertTrue(node == node1 || node == node2);
607  }
608 
609  // Changing the attribute back should restore consistency
610  node2.id = "id_node2";
611  node2.url = "url_node2";
612  for each (let attr in attributes) {
613  let method = methods[attr];
614  assertEqual(SPS[method](attr + "_node1"), node1);
615  assertEqual(SPS[method](attr + "_node2"), node2);
616  }
617 
618  // Removing the attribute should make sure the node isn't returned
619  node1.id = null;
620  node1.url = null;
621  for each (let attr in attributes) {
622  let method = methods[attr];
623  assertEqual(SPS[method](attr + "_node1"), null);
624  assertEqual(SPS[method](attr + "_node2"), node2);
625  }
626 
627  // Try getting nodes by generic attributes without namespaces
628  let nodes;
629  node1.setAttribute("foo", "bar");
630  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
631  assertEqual(nodes.length, 1);
632  assertEqual(nodes.queryElementAt(0, Ci.sbIServicePaneNode), node1);
633 
634  nodes = SPS.getNodesByAttributeNS(null, "foo", "not bar");
635  assertEqual(nodes.length, 0);
636 
637  nodes = SPS.getNodesByAttributeNS("wrongns", "foo", "bar");
638  assertEqual(nodes.length, 0);
639 
640  node2.setAttribute("foo", "not bar")
641  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
642  assertEqual(nodes.length, 1);
643  assertEqual(nodes.queryElementAt(0, Ci.sbIServicePaneNode), node1);
644 
645  node2.setAttribute("foo", "bar")
646  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
647  assertEqual(nodes.length, 2);
648 
649  node1.removeAttribute("foo");
650  node2.removeAttribute("foo");
651  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
652  assertEqual(nodes.length, 0);
653 
654  // Now the same thing with namespaces
655  node1.setAttributeNS("ns", "foo", "bar");
656  nodes = SPS.getNodesByAttributeNS("ns", "foo", "bar");
657  assertEqual(nodes.length, 1);
658  assertEqual(nodes.queryElementAt(0, Ci.sbIServicePaneNode), node1);
659 
660  nodes = SPS.getNodesByAttributeNS("ns", "foo", "not bar");
661  assertEqual(nodes.length, 0);
662 
663  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
664  assertEqual(nodes.length, 0);
665 
666  node2.setAttributeNS("ns", "foo", "not bar")
667  nodes = SPS.getNodesByAttributeNS("ns", "foo", "bar");
668  assertEqual(nodes.length, 1);
669  assertEqual(nodes.queryElementAt(0, Ci.sbIServicePaneNode), node1);
670 
671  node2.setAttributeNS("ns", "foo", "bar")
672  nodes = SPS.getNodesByAttributeNS("ns", "foo", "bar");
673  assertEqual(nodes.length, 2);
674 
675  node1.removeAttributeNS("ns", "foo");
676  node2.removeAttributeNS("ns", "foo");
677  nodes = SPS.getNodesByAttributeNS("ns", "foo", "bar");
678  assertEqual(nodes.length, 0);
679 
680  // Make sure that nodes aren't found by attribute outside document
681  node1.setAttribute("foo", "bar");
682  aRoot.removeChild(node1);
683  nodes = SPS.getNodesByAttributeNS(null, "foo", "bar");
684  assertEqual(nodes.length, 0);
685 
686  // Root node should still have no children after the test
687  assertEqual(serializeTree(aRoot), '[node/]');
688 }
689 
690 
691 function testAddRemoveNode(SPS, aRoot) {
692  // This should add a node to the root
693  let node1 = SPS.addNode("node1", aRoot, true);
694  assertTrue(node1 instanceof Ci.sbIServicePaneNode);
695  assertEqual(node1.id, "node1");
696  assertTrue(node1.isContainer);
697  assertEqual(node1.parentNode, aRoot);
698  assertEqual(aRoot.lastChild, node1);
699 
700 
701  // Without an ID parameter a random ID should be generated
702  let node2 = SPS.addNode(null, aRoot, true);
703  assertTrue(node2 instanceof Ci.sbIServicePaneNode);
704  assertNotEqual(node2.id, null);
705  assertTrue(node2.isContainer);
706  assertEqual(node2.parentNode, aRoot);
707  assertEqual(node2.previousSibling, node1);
708  assertEqual(node2.nextSibling, null);
709 
710  let node3 = SPS.addNode(null, aRoot, false);
711  assertTrue(node3 instanceof Ci.sbIServicePaneNode);
712  assertNotEqual(node3.id, null);
713  assertNotEqual(node3.id, node2.id);
714  assertFalse(node3.isContainer);
715 
716  // This should remove a node
717  SPS.removeNode(node2);
718  assertEqual(node2.parentNode, null);
719  assertEqual(node1.nextSibling, node3);
720  assertEqual(node3.previousSibling, node1);
721 
722  // Clean up
723  aRoot.removeChild(node1);
724  aRoot.removeChild(node3);
725 }
726 
727 
728 function testModuleInteraction(SPS, aRoot) {
729  aRoot.id = "test-root";
730  aRoot.editable = "true";
731 
732  function FakeElement(aTagName) {
733  this.tagName = aTagName;
734  }
735  FakeElement.prototype = {
736  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMXULElement]),
737  setAttribute: function FakeElement_setAttribute(aAttr, aVal) void(0),
738  appendChild: function FakeElement_appendChild(aChild) void(0),
739  get ownerDocument() ({
740  createElement: function fakeDocument_createElement(aTagName) {
741  return new FakeElement(aTagName);
742  }
743  }),
744  get wrappedJSObject() this
745  };
746  let fakeElement = new FakeElement();
747  let fakeWindow = {
748  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWindow]),
749  get wrappedJSObject() this
750  };
751 
752  // Adding module to category should call servicePaneInit with SPS as parameter
753  let initArgs = testModule.addToCategory();
754  assertArraysEqual(initArgs, [SPS]);
755 
756  // fillContextMenu should get node by ID and pass other parameters to modules
757  // unchanged
758  testModule._fillContextMenuParams = null;
759  SPS.fillContextMenu(aRoot, fakeElement, fakeWindow);
760  assertNotEqual(testModule._fillContextMenuParams, null);
761  assertEqual(testModule._fillContextMenuParams.length, 3);
762  assertEqual(testModule._fillContextMenuParams[0], aRoot);
763  assertEqual(testModule._fillContextMenuParams[1].wrappedJSObject, fakeElement);
764  assertEqual(testModule._fillContextMenuParams[2].wrappedJSObject, fakeWindow);
765  testModule._fillContextMenuParams = null;
766 
767  // fillNewItemMenu should get node by ID and pass other parameters to modules
768  // unchanged
769  testModule._fillNewItemMenuParams = null;
770  SPS.fillNewItemMenu(aRoot, fakeElement, fakeWindow);
771  assertNotEqual(testModule._fillNewItemMenuParams, null);
772  assertEqual(testModule._fillNewItemMenuParams.length, 3);
773  assertEqual(testModule._fillNewItemMenuParams[0], aRoot);
774  assertEqual(testModule._fillNewItemMenuParams[1].wrappedJSObject, fakeElement);
775  assertEqual(testModule._fillNewItemMenuParams[2].wrappedJSObject, fakeWindow);
776  testModule._fillNewItemMenuParams = null;
777 
778  // onSelectionChanged should get node by ID and pass other parameters to modules
779  // unchanged
780  testModule._onSelectionChangedParams = null;
781  SPS.onSelectionChanged(aRoot, fakeElement, fakeWindow);
782  assertNotEqual(testModule._onSelectionChangedParams, null);
783  assertEqual(testModule._onSelectionChangedParams.length, 3);
784  assertEqual(testModule._onSelectionChangedParams[0], aRoot);
785  assertEqual(testModule._onSelectionChangedParams[1].wrappedJSObject, fakeElement);
786  assertEqual(testModule._onSelectionChangedParams[2].wrappedJSObject, fakeWindow);
787  testModule._onSelectionChangedParams = null;
788 
789  // onBeforeRename should trigger node's owner
790  aRoot.contractid = testModule.contractId;
791  testModule._onBeforeRenameParams = null;
792  SPS.onBeforeRename(aRoot);
793  assertNotEqual(testModule._onBeforeRenameParams, null);
794  assertArraysEqual(testModule._onBeforeRenameParams, [aRoot]);
795  testModule._onBeforeRenameParams = null;
796  aRoot.contractid = null;
797 
798  // onRename should trigger node's owner
799  aRoot.contractid = testModule.contractId;
800  testModule._onRenameParams = null;
801  SPS.onRename(aRoot, "Dummy title");
802  assertNotEqual(testModule._onRenameParams, null);
803  assertArraysEqual(testModule._onRenameParams, [aRoot, "Dummy title"]);
804  testModule._onRenameParams = null;
805  aRoot.contractid = null;
806 
807  // After module's removal it should no longer be triggered
808  testModule.removeFromCategory();
809 
810  testModule._fillContextMenuParams = null;
811  SPS.fillContextMenu(aRoot, fakeElement, fakeWindow);
812  assertEqual(testModule._fillContextMenuParams, null);
813  testModule._fillContextMenuParams = null;
814 
815  testModule._fillNewItemMenuParams = null;
816  SPS.fillNewItemMenu(aRoot, fakeElement, fakeWindow);
817  assertEqual(testModule._fillNewItemMenuParams, null);
818  testModule._fillNewItemMenuParams = null;
819 
820  testModule._onSelectionChangedParams = null;
821  SPS.onSelectionChanged(aRoot, fakeElement, fakeWindow);
822  assertEqual(testModule._onSelectionChangedParams, null);
823  testModule._onSelectionChangedParams = null;
824 
825  aRoot.contractid = testModule.contractId;
826  testModule._onRenameParams = null;
827  SPS.onRename(aRoot, "Dummy title");
828  assertEqual(testModule._onRenameParams, null);
829  aRoot.contractid = null;
830  testModule._onRenameParams = null;
831 
832  // Clean up
833  aRoot.id = null;
834  aRoot.removeAttribute("editable");
835 }
836 
837 
838 function testListeners (SPS, aRoot) {
839  let calls = [];
840  let hadException = false;
841 
842  let testListener = {
843  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneMutationListener]),
844 
845  attrModified: function(aNode, aAttrName, aNamespace, aOldValue, aNewValue) {
846  calls.push(["attrModified", aNode, aAttrName, aNamespace, aOldValue, aNewValue]);
847  },
848 
849  nodeInserted: function(aNode, aParent, aBefore) {
850  calls.push(["nodeInserted", aNode, aParent, aBefore]);
851  },
852 
853  nodeRemoved: function(aNode, aParent) {
854  calls.push(["nodeRemoved", aNode, aParent]);
855  }
856  };
857 
858  let node1 = SPS.createNode();
859  assertTrue(node1 instanceof Ci.sbIServicePaneNode);
860 
861  let node2 = SPS.createNode();
862  assertTrue(node2 instanceof Ci.sbIServicePaneNode);
863 
864  // Changes outside the tree shouldn't trigger listeners
865  SPS.root.addMutationListener(testListener);
866  node1.addMutationListener(testListener);
867  node1.setAttribute("foo", "bar");
868  node1.removeAttribute("foo", "bar");
869  node1.appendChild(node2);
870  node1.removeChild(node2);
871  assertEqual(calls.length, 0);
872  SPS.root.removeMutationListener(testListener);
873 
874  // Adding a child to the tree should trigger listeners on it
875  aRoot.appendChild(node1);
876  assertEqual(calls.length, 1);
877  assertArraysEqual(calls[0], ["nodeInserted", node1, aRoot, null]);
878  calls = [];
879 
880  // Adding a child below the node should also trigger listeners
881  node1.appendChild(node2);
882  assertEqual(calls.length, 1);
883  assertArraysEqual(calls[0], ["nodeInserted", node2, node1, null]);
884  calls = [];
885 
886  // Removing a child below the node should trigger listeners
887  node1.removeChild(node2);
888  assertEqual(calls.length, 1);
889  assertArraysEqual(calls[0], ["nodeRemoved", node2, node1]);
890  calls = [];
891 
892  // Removing the node itself from the tree should trigger listeners
893  aRoot.removeChild(node1);
894  assertEqual(calls.length, 1);
895  assertArraysEqual(calls[0], ["nodeRemoved", node1, aRoot]);
896  aRoot.appendChild(node1);
897  calls = [];
898 
899  // Adding a node next to you shouldn't trigger listeners however
900  aRoot.insertBefore(node2, node1);
901  assertEqual(calls.length, 0);
902 
903  // Moving a node already in the tree should trigger both removal and insertion
904  node1.removeMutationListener(testListener);
905  aRoot.addMutationListener(testListener);
906  aRoot.insertBefore(node1, node2);
907  assertEqual(calls.length, 2);
908  assertArraysEqual(calls[0], ["nodeRemoved", node1, aRoot]);
909  assertArraysEqual(calls[1], ["nodeInserted", node1, aRoot, node2]);
910  aRoot.removeChild(node2);
911  calls = [];
912 
913  // Replacing a child should also trigger removal and the insertion
914  aRoot.replaceChild(node2, node1);
915  assertEqual(calls.length, 2);
916  assertArraysEqual(calls[0], ["nodeRemoved", node1, aRoot]);
917  assertArraysEqual(calls[1], ["nodeInserted", node2, aRoot, null]);
918  calls = [];
919 
920  // Test attribute modification in tree
921  node2.setAttribute("foo", "bar");
922  assertEqual(calls.length, 1);
923  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, null, "bar"]);
924  calls = [];
925 
926  node2.setAttribute("foo", "baz");
927  assertEqual(calls.length, 1);
928  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, "bar", "baz"]);
929  calls = [];
930 
931  node2.removeAttribute("foo");
932  assertEqual(calls.length, 1);
933  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, "baz", null]);
934  calls = [];
935 
936  node2.setAttributeNS("ns", "foo", "bar");
937  assertEqual(calls.length, 1);
938  assertArraysEqual(calls[0], ["attrModified", node2, "foo", "ns", null, "bar"]);
939  calls = [];
940 
941  node2.removeAttributeNS("ns", "foo");
942  assertEqual(calls.length, 1);
943  assertArraysEqual(calls[0], ["attrModified", node2, "foo", "ns", "bar", null]);
944  calls = [];
945 
946  // Same tests with the listener on the node itself rather than a parent node
947  aRoot.removeMutationListener(testListener);
948  node2.addMutationListener(testListener);
949 
950  node2.setAttribute("foo", "bar");
951  assertEqual(calls.length, 1);
952  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, null, "bar"]);
953  calls = [];
954 
955  node2.setAttribute("foo", "baz");
956  assertEqual(calls.length, 1);
957  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, "bar", "baz"]);
958  calls = [];
959 
960  node2.removeAttribute("foo");
961  assertEqual(calls.length, 1);
962  assertArraysEqual(calls[0], ["attrModified", node2, "foo", null, "baz", null]);
963  calls = [];
964 
965  node2.setAttributeNS("ns", "foo", "bar");
966  assertEqual(calls.length, 1);
967  assertArraysEqual(calls[0], ["attrModified", node2, "foo", "ns", null, "bar"]);
968  calls = [];
969 
970  node2.removeAttributeNS("ns", "foo");
971  assertEqual(calls.length, 1);
972  assertArraysEqual(calls[0], ["attrModified", node2, "foo", "ns", "bar", null]);
973  calls = [];
974 
975  // Test for consistent call order when listeners modify tree structure themselves
976  node2.removeMutationListener(testListener);
977  let modifyingListener = {
978  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneMutationListener]),
979 
980  attrModified: function(aNode, aAttrName, aNamespace, aOldValue, aNewValue) {},
981 
982  nodeInserted: function(aNode, aParent, aBefore) {
983  if (aNode == node2 && aParent == node1)
984  aRoot.appendChild(node2);
985  },
986 
987  nodeRemoved: function(aNode, aParent) {}
988  };
989  aRoot.appendChild(node1);
990  aRoot.addMutationListener(modifyingListener);
991  aRoot.addMutationListener(testListener);
992  node1.appendChild(node2);
993  assertEqual(calls.length, 4);
994  assertArraysEqual(calls[0], ["nodeRemoved", node2, aRoot]);
995  assertArraysEqual(calls[1], ["nodeInserted", node2, node1, null]);
996  assertArraysEqual(calls[2], ["nodeRemoved", node2, node1]);
997  assertArraysEqual(calls[3], ["nodeInserted", node2, aRoot, null]);
998  aRoot.removeMutationListener(modifyingListener);
999  aRoot.removeMutationListener(testListener);
1000  calls = [];
1001 
1002  modifyingListener = {
1003  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneMutationListener]),
1004 
1005  attrModified: function(aNode, aAttrName, aNamespace, aOldValue, aNewValue) {},
1006 
1007  nodeInserted: function(aNode, aParent, aBefore) {},
1008 
1009  nodeRemoved: function(aNode, aParent) {
1010  if (aNode == node2)
1011  aParent.appendChild(node2);
1012  }
1013  };
1014  aRoot.addMutationListener(modifyingListener);
1015  aRoot.addMutationListener(testListener);
1016  aRoot.removeChild(node2);
1017  assertEqual(calls.length, 2);
1018  assertArraysEqual(calls[0], ["nodeRemoved", node2, aRoot]);
1019  assertArraysEqual(calls[1], ["nodeInserted", node2, aRoot, null]);
1020  aRoot.removeMutationListener(modifyingListener);
1021  aRoot.removeMutationListener(testListener);
1022  calls = [];
1023 
1024  // Test listeners modifying tree in ways that make moving a node impossible
1025  modifyingListener = {
1026  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneMutationListener]),
1027 
1028  attrModified: function(aNode, aAttrName, aNamespace, aOldValue, aNewValue) {},
1029 
1030  nodeInserted: function(aNode, aParent, aBefore) {},
1031 
1032  nodeRemoved: function(aNode, aParent) {
1033  aParent.appendChild(aNode);
1034  }
1035  };
1036  aRoot.addMutationListener(modifyingListener);
1037  hadException = false;
1038  try {
1039  node1.appendChild(node2);
1040  }
1041  catch (e) {
1042  hadException = true;
1043  }
1044  assertTrue(hadException, "mutation listener prevented removing the node - insertBefore should throw");
1045  assertEqual(node2.parentNode, aRoot, "node wasn't moved, mutation listener prevented that");
1046  aRoot.removeMutationListener(modifyingListener);
1047 
1048  modifyingListener = {
1049  QueryInterface: XPCOMUtils.generateQI([Ci.sbIServicePaneMutationListener]),
1050 
1051  attrModified: function(aNode, aAttrName, aNamespace, aOldValue, aNewValue) {},
1052 
1053  nodeInserted: function(aNode, aParent, aBefore) {},
1054 
1055  nodeRemoved: function(aNode, aParent) {
1056  aParent.removeChild(node1);
1057  }
1058  };
1059  aRoot.addMutationListener(modifyingListener);
1060  hadException = false;
1061  try {
1062  aRoot.insertBefore(node2, node1);
1063  }
1064  catch (e) {
1065  hadException = true;
1066  }
1067  assertTrue(hadException, "mutation listener removed our anchor node - insertBefore should throw");
1068  assertEqual(node2.parentNode, null, "node2 was removed but mutation listener prevented inserting");
1069  aRoot.removeMutationListener(modifyingListener);
1070  aRoot.appendChild(node2);
1071 
1072  // Test listeners added via deprecated SPS.addListener() API
1073  node2.id = "node2";
1074  testListener = {
1075  nodePropertyChanged: function(aNodeId, aProperty) {
1076  calls.push([aNodeId, aProperty]);
1077  }
1078  };
1079  SPS.addListener(testListener);
1080 
1081  node2.setAttribute("foo", "bar");
1082  assertEqual(calls.length, 1);
1083  assertArraysEqual(calls[0], ["node2", "foo"]);
1084  calls = [];
1085 
1086  node2.removeAttribute("foo");
1087  assertEqual(calls.length, 1);
1088  assertArraysEqual(calls[0], ["node2", "foo"]);
1089  calls = [];
1090 
1091  node2.setAttributeNS("http://example.com/", "foo", "bar");
1092  assertEqual(calls.length, 1);
1093  assertArraysEqual(calls[0], ["node2", "http://example.com/foo"]);
1094  calls = [];
1095 
1096  node2.removeAttributeNS("http://example.com/", "foo");
1097  assertEqual(calls.length, 1);
1098  assertArraysEqual(calls[0], ["node2", "http://example.com/foo"]);
1099  calls = [];
1100 
1101  let node3 = SPS.addNode("node3", aRoot, true);
1102  assertEqual(calls.length, 1);
1103  assertArraysEqual(calls[0], ["node3", "id"]);
1104  calls = [];
1105 
1106  // Listeners should no longer be triggered after calling removeListener
1107  SPS.removeListener(testListener);
1108 
1109  node2.setAttribute("foo", "bar");
1110  assertEqual(calls.length, 0);
1111 
1112  // Clean up
1113  aRoot.removeChild(node2);
1114  aRoot.removeChild(node3);
1115 }
1116 
1117 function testContentPrefix(SPS, aRoot)
1118 {
1119  var node = SPS.createNode();
1120 
1121  var prefix = "prefix/";
1122  node.url = prefix + "node";
1123  node.contentPrefix = prefix;
1124 
1125  // Nothing has been added, so we shouldn't return nodes yet
1126  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_EXACT),null,
1127  "getNodeForURL should return null when the node has not been added");
1128  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_PREFIX), null,
1129  "getNodeForURL should return null when the node has not been added");
1130  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_EXACT), null,
1131  "getNodeForURL should return null when the node has not been added");
1132  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_PREFIX), null,
1133  "getNodeForURL should return null when the node has not been added");
1134  assertEqual(SPS.getNodeForURL("other/other", SPS.URL_MATCH_PREFIX), null,
1135  "getNodeForURL should return null when the node has not been added");
1136 
1137  // Add the node.
1138  aRoot.appendChild(node);
1139  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_EXACT), node,
1140  "an exact match for a node's url should return the node");
1141  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_PREFIX), node,
1142  "prefix matches for exact urls should return a node");
1143  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_EXACT), null,
1144  "exact matches for the wrong url should return null");
1145  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_PREFIX), node,
1146  "prefix matches for urls with the right prefix should return a node");
1147  assertEqual(SPS.getNodeForURL("other/other", SPS.URL_MATCH_PREFIX), null,
1148  "prefix matches for urls with the wrong prefix should return null");
1149 
1150  // We should still get prefix matches if we remove the url attribute;
1151  node.url = null;
1152  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_EXACT), null,
1153  "exact matches should return null if nodes don't have url attributes");
1154  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_PREFIX), node,
1155  "prefix matches should return a node when the node has the right prefix");
1156  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_EXACT), null,
1157  "exact matches should return null if nodes don't have url attributes");
1158  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_PREFIX), node,
1159  "prefix matches for urls with the right prefix should return a node");
1160  assertEqual(SPS.getNodeForURL("other/other", SPS.URL_MATCH_PREFIX), null,
1161  "prefix matches for urls with the wrong prefix should return null");
1162 
1163  // Add back the url, remove the contentPrefix
1164  node.url = prefix + "node";
1165  node.contentPrefix = null;
1166  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_EXACT), node,
1167  "exact matches for the right url should return a node");
1168  // URL_MATCH_PREFIX should still return exact url matches, even if there
1169  // is no contentPrefix set. The matching is designed this way purposefully
1170  // for backwards compatibility (i.e. an existing getNodeForURL call in the
1171  // codebase can be changed to SPS.URL_MATCH_PREFIX without changing the
1172  // behavior for nodes that don't set a contentPrefix)
1173  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_PREFIX), node,
1174  "prefix matches should succeed if the url match is exact");
1175  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_EXACT), null,
1176  "exact matches should return null when no node has the right url");
1177  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_PREFIX), null,
1178  "prefix matches should return null when no node has the right url or prefix");
1179  assertEqual(SPS.getNodeForURL("other/other", SPS.URL_MATCH_PREFIX), null,
1180  "prefix matches should return null when no node has the right url or prefix");
1181 
1182  // Remove the node
1183  SPS.removeNode(node);
1184  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_EXACT), null,
1185  "exact matches should return null when there are no nodes");
1186  assertEqual(SPS.getNodeForURL("prefix/node", SPS.URL_MATCH_PREFIX), null,
1187  "prefix matches should return null when there are no nodes");
1188  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_EXACT), null,
1189  "exact matches should return null when there are no nodes");
1190  assertEqual(SPS.getNodeForURL("prefix/other", SPS.URL_MATCH_PREFIX), null,
1191  "prefix matches should return null when there are no nodes");
1192  assertEqual(SPS.getNodeForURL("other/other", SPS.URL_MATCH_PREFIX), null,
1193  "prefix matches should return null when there are no nodes");
1194 
1195  // Root node should still have no children after the test
1196  assertEqual(serializeTree(aRoot), '[node/]');
1197 }
1198 
1199 function runTest() {
1200  let SPS = Cc["@songbirdnest.com/servicepane/service;1"]
1201  .getService(Ci.sbIServicePaneService);
1202 
1203  // okay, did we get it?
1204  assertNotEqual(SPS, null, "Failed to get service pane service");
1205 
1206  // Do we have a valid root?
1207  assertTrue(SPS.root instanceof Ci.sbIServicePaneNode,
1208  "Service pane service root is not a service pane node");
1209 
1210  // Can we create new nodes?
1211  let testRoot = SPS.createNode();
1212  assertTrue(testRoot instanceof Ci.sbIServicePaneNode,
1213  "created node is not a service pane node");
1214 
1215  // Test attribute functions while not in tree
1216  assertEqual(testRoot.parentNode,
1217  null,
1218  "service pane node should not have a parent");
1219  testAttributes(testRoot);
1220 
1221  // Now test them while in tree
1222  SPS.root.appendChild(testRoot);
1223  assertEqual(testRoot.parentNode,
1224  SPS.root,
1225  "service pane node's parent should be the service pane service root");
1226  testAttributes(testRoot);
1227 
1228  // Test manipulation of a subtree that isn't part of the tree
1229  SPS.root.removeChild(testRoot);
1230  assertEqual(testRoot.parentNode,
1231  null,
1232  "service pane node should have no parent after being removed");
1233  testTreeManipulation(SPS, testRoot);
1234 
1235  // Now test it while the subtree is attached to the tree
1236  SPS.root.appendChild(testRoot);
1237  assertEqual(testRoot.parentNode,
1238  SPS.root,
1239  "service pane node's parent should be the service pane service root");
1240  testTreeManipulation(SPS, testRoot);
1241 
1242  // Test deprecated SPS.addNode/removeNode methods
1243  testAddRemoveNode(SPS, testRoot);
1244 
1245  // Test whether querying SPS for nodes works correctly
1246  testNodeByAttribute(SPS, testRoot);
1247 
1248  // Test functions that are forwarded to modules
1249  testModuleInteraction(SPS, testRoot);
1250 
1251  // Test listeners
1252  testListeners(SPS, testRoot);
1253 
1254  // Test getting nodes by contentPrefix
1255  testContentPrefix(SPS, testRoot);
1256 
1257  // Clean up
1258  SPS.root.removeChild(testRoot);
1259 }
var testModule
const Cc
var registrar
tabData attributes[name]
function assertNotEqual(aExpected, aActual, aMessage)
imageContainer appendChild(newImage)
function testAttributes(aNode)
function log(s)
function testListeners(SPS, aRoot)
sidebarFactory createInstance
Definition: nsSidebar.js:351
sbOSDControlService prototype QueryInterface
function assertTrue(aTest, aMessage)
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
function assertEqual(aExpected, aActual, aMessage)
function DBG(s)
function testTreeManipulation(SPS, aRoot)
sbDeviceServicePane prototype servicePaneInit
function assertArraysEqual(a1, a2)
function testAddRemoveNode(SPS, aRoot)
function testContentPrefix(SPS, aRoot)
return null
Definition: FeedWriter.js:1143
function testNodeByAttribute(SPS, aRoot)
var testListener
menuItem setAttribute("handlerType","client")
let node
return!aWindow arguments!aWindow arguments[0]
function assertFalse(aTest, aMessage)
function url(spec)
function testModuleInteraction(SPS, aRoot)
const Ci
var hidden
function serializeTree(aNode)
Common service pane helper functions.
function runTest()
Advanced DataRemote unit tests.
sbDeviceServicePane prototype nodeInserted
sbDeviceServicePane prototype nodeRemoved