test_playlistcommandshelper.js
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2011 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
29 // ============================================================================
30 // GLOBALS & CONSTS
31 // ============================================================================
32 
33 // enable or disable debug output
34 const DEBUG = false;
35 
36 // determines the depth of submenus created within a helper-constructed command
37 const NUMRECURSE = 2;
38 
39 /* determines the number of command subobjects that will be added to and removed
40  * from a helper-constructed commands */
41 const TESTLENGTH = 500;
42 
43 Components.utils.import("resource://app/jsmodules/sbLibraryUtils.jsm");
44 
45 var cmdHelper = Cc["@songbirdnest.com/Songbird/PlaylistCommandsHelper;1"]
46  .getService(Ci.sbIPlaylistCommandsHelper);
47 
48 var cmdMgr = Cc["@songbirdnest.com/Songbird/PlaylistCommandsManager;1"]
49  .createInstance(Ci.sbIPlaylistCommandsManager);
50 
51 const PlaylistCommandsBuilder = new Components.
52  Constructor("@songbirdnest.com/Songbird/PlaylistCommandsBuilder;1",
53  "sbIPlaylistCommandsBuilder");
54 
55 /* If a playlist command is registered with RegisterPlaylistCommandsMediaItem
56  * and does not have a targetFlags (i.e. it doesn't know where it is) we
57  * use this flag to indicate that in the log.
58  * This relies on TARGET_TOOLBAR being the last of the targetFlags. */
59 const INCOMPLETE_TARGET_FLAGS = cmdHelper.TARGET_TOOLBAR << 1;
60 
61 /* Maps of playlist command id -> location flags indicating where that playlist
62  * should be present. Serves as a log to verify that all playlist command
63  * additions and removals are performed correctly. */
64 var typeLocMap = new Object();
65 var guidLocMap = new Object();
66 
67 // a medialist that we'll create for the test
69 // ============================================================================
70 // ENTRY POINT
71 // ============================================================================
72 
73 function runTest () {
74  log("Testing Playlist Commands Helper:");
75  gTestPrefix = "PlaylistCommandsHelper";
76 
77  /* first test that a command created with the playlistCommandsHelper is fully
78  * functional */
80 
81  /* next test all of the other playlistCommandsHelper functions that can
82  * add, remove, or get existing playlist commands */
84  log("OK");
85 }
86 
87 // ============================================================================
88 // TESTS
89 // ============================================================================
90 
91 /* This runs a series of tests that verify the sanity of helper-constructed
92  * sbIPlaylistCommands objects. In particular, verifying that subcommands can
93  * be added to and removed from helper-constructed playlist commands, checking
94  * that all callbacks and shortcuts work properly, and that submenus can be
95  * used within helper-constructed commands.
96  *
97  * The three tests; testAppendInsertRemove, testCommandCallbacksAndShortcuts,
98  * and testSubmenus; can be found in head_playlistcommands.js
99  */
101 
102  _log("- Testing createCommandObject with appending, inserting, " +
103  "and removing subobjects");
104  var newCommandID = "test-id-1";
105  var actionFn = makeTriggerCallback(newCommandID);
106  var newCommand = cmdHelper.createCommandObjectForAction
107  (newCommandID, // an id for the command and action
108  "test-label-1", // the user-facing label
109  "test-tooltip-1", // a tooltip
110  actionFn /* the fn to call on click */);
111  testAppendInsertRemove(newCommand, null, TESTLENGTH, 1);
112  newCommand.shutdown();
113 
114  _log("- Testing createCommandObject with command callbacks and keyboard " +
115  "shortcuts");
116  newCommandID = "test-id-2";
117  actionFn = makeTriggerCallback(newCommandID);
118  newCommand = cmdHelper.createCommandObjectForAction
119  (newCommandID,
120  "test-label-2",
121  "test-tooltip-2",
122  actionFn);
124  newCommand.shutdown();
125 
126  _log("- Testing createCommandObject with submenus");
127  newCommandID = "test-id-3";
128  actionFn = makeTriggerCallback(newCommandID);
129  newCommand = cmdHelper.createCommandObjectForAction
130  (newCommandID,
131  "test-label-3",
132  "test-tooltip-3",
133  actionFn);
134  testSubmenus(newCommand, null, NUMRECURSE, 1);
135  newCommand.shutdown();
136 }
137 
138 /* This is an exhaustive test of playlistCommandsHelper.addCommandObject
139  * and removeCommandObject (and less directly getCommandObject) for all
140  * combinations of added and removed locations, with all combinations of
141  * registering by guid and/or type.
142  *
143  * This test proceeds by establishing some necessary elements, recording
144  * all existing playlist commands in the maps that we'll use for later
145  * verification that our operations were successful (guidLocMap and typeLocMap),
146  * and then testing.
147  *
148  * Testing proceeds by selecting one of the combinations of added locations
149  * and, for each combination of registering for type and/or guid, adding
150  * a command object to those locations. Next, we select a combination of
151  * locations to remove that command object from and attempt to remove the
152  * added command from those locations for both type and guid. We do not check
153  * that the command was actually added for that type, guid, or locations
154  * as removal should fail gracefully and we will verify there were no strange
155  * side effects using the maps.
156  *
157  * Once we verify that those adds and removals occurred properly, we remove the
158  * command object from every place that it was added to cause it to unregister
159  * completely so we can add it again on the next pass.
160  *
161  * The same operations performed for type and guid are interleaved to ensure
162  * there is no breakdown in the strict separation of actions performed on
163  * type and guid.
164  */
166  _log("- Testing addCommandObject and removeCommandObject");
167 
168  // this is all combinations of locations for a command object
169  var locationsArray = [(cmdHelper.TARGET_SERVICEPANE_MENU |
170  cmdHelper.TARGET_TOOLBAR |
171  cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU),
172  (cmdHelper.TARGET_SERVICEPANE_MENU |
173  cmdHelper.TARGET_TOOLBAR),
174  (cmdHelper.TARGET_SERVICEPANE_MENU |
175  cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU),
176  (cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU |
177  cmdHelper.TARGET_TOOLBAR),
178  (cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU),
179  (cmdHelper.TARGET_TOOLBAR),
180  (cmdHelper.TARGET_SERVICEPANE_MENU)];
181 
182  // create a medialist to perform our test with
183  var databaseGUID = "test_playlistcommandshelper";
184  var testLibrary = createLibrary(databaseGUID, false);
185  testMediaList = testLibrary.createMediaList("simple");
186 
187  /* before we start, we should make sure we have a log entry for all playlist
188  * commands that are already registered */
189  logExistingCommands(testMediaList);
190 
191  // for every combination of locations we can add to
192  for (var cmdIndex = 0; cmdIndex < locationsArray.length; cmdIndex++)
193  {
194  // make a new command to test
195  var newCommandID = "test-command-" + cmdIndex;
196  var actionFn = makeTriggerCallback(newCommandID); // from head_playlistcommands
197  var newCommandGUID = cmdHelper.createCommandObjectForAction
198  (newCommandID,
199  "test-label-" + cmdIndex,
200  "test-tooltip-" + cmdIndex,
201  actionFn);
202 
203  /* we need a duplicate so we have one to register to medialist guid and
204  * another to register to medialist type */
205  var newCommandType = newCommandGUID.duplicate();
206 
207  var addLocs = locationsArray[cmdIndex];
208 
209  // for each combination of operations on type and/or guid
210  for (var p = 0; p < 3; p ++)
211  {
212  var addByType = false;
213  var addByGUID = false;
214  switch (p)
215  {
216  case 0:
217  addByType = true;
218  addByGUID = true;
219  break;
220  case 1:
221  addByType = true;
222  break;
223  case 2:
224  addByGUID = true;
225  break;
226  default:
227  continue;
228  }
229 
230  // for each combination of locations that we can remove from
231  for (var j = 0; j < locationsArray.length; j++)
232  {
233  if (DEBUG)
234  {
235  log("\nperforming " + ((addByGUID) ? "addByGUID " : "") +
236  ((addByType) ? "addByType " : "") + "with '" + newCommandID +
237  "'\n" +"Adding to - " + flagsToString(addLocs) + "\n" +
238  "Removing from - " + flagsToString(locationsArray[j]) + "");
239  }
240 
241  // add our command to the chosen locations
242  if (addByGUID)
243  addCommandToLocations(newCommandGUID, testMediaList, addLocs, "guid");
244 
245  if (addByType)
246  addCommandToLocations(newCommandType, testMediaList, addLocs, "type");
247 
248  // select which locations we'll remove that command from, and remove it
249  var removeLocs = locationsArray[j];
250 
251  /* Attempt to remove the commmand from the selected remove locations
252  * irregardless of whether the command was actually added to those
253  * locations or was registered to type or guid.
254  * These calls will fail in those situations, but they should fail
255  * gracefully and we'll check that is the case using our log maps */
256  removeCommandFromLocations(newCommandGUID,
257  testMediaList,
258  removeLocs,
259  "guid");
260  removeCommandFromLocations(newCommandType,
261  testMediaList,
262  removeLocs,
263  "type");
264 
265  /* Remove the command from everywhere that we added it so that it
266  * unregisters and we can use it again. If something goes wrong and
267  * the command is not unregistered correctly, we'll get a
268  * 'Duplicate Command in menu' error on the next pass. */
269  if (addByGUID && guidLocMap[newCommandID] > 0)
270  {
271  if (DEBUG) _log(" complete removing " + newCommandID +
272  " from guid");
273  cmdHelper.removeCommandObjectForGUID(addLocs,
274  testMediaList.guid,
275  newCommandGUID);
276 
277  // and blank the mapping to reflect that this command is now nowhere
278  guidLocMap[newCommandID] = 0;
279  assertCommandLocations(testMediaList);
280  }
281  if (addByType && typeLocMap[newCommandID] > 0)
282  {
283  if (DEBUG) _log(" complete removing " + newCommandID +
284  " from type");
285  cmdHelper.removeCommandObjectForType(addLocs,
286  testMediaList.type,
287  newCommandType);
288 
289  // and blank the mapping to reflect that this command is now nowhere
290  typeLocMap[newCommandID] = 0;
291  assertCommandLocations(testMediaList);
292  }
293  }
294 
295  // our commands should have been removed, now we can shut them down
296  if (DEBUG) _log(" shutting down " + newCommandID + " for guid");
297  newCommandGUID.shutdownCommands();
298  if (DEBUG) _log(" shutting down " + newCommandID + " for type");
299  newCommandType.shutdownCommands();
300  }
301  }
302 
303  // we're done, cleanup our medialist
304  testLibrary.remove(testMediaList);
305 }
306 
307 function addCommandToLocations(newCommand, testMediaList, locations, guidOrType)
308 {
309  if (guidOrType == "type")
310  {
311  if (DEBUG)
312  {
313  _log(" adding " + newCommand.id + " for type: " +
314  flagsToString(addLocs));
315  }
316 
317  cmdHelper.addCommandObjectForType(locations,
318  testMediaList.type,
319  newCommand);
320 
321  // log in our map where the command should be now
322  typeLocMap[newCommand.id] = locations;
323 
324  // check to make sure our added command is where we expect it to be
325  assertCommandLocations(testMediaList);
326  }
327  else {
328  if (DEBUG)
329  {
330  _log(" adding " + newCommand.id + " for guid: " +
331  flagsToString(addLocs));
332  }
333 
334  cmdHelper.addCommandObjectForGUID(locations,
335  testMediaList.guid,
336  newCommand);
337 
338  // log in our map where the command should be now
339  guidLocMap[newCommand.id] = locations;
340 
341  // check to make sure our added command is where we expect it to be
342  assertCommandLocations(testMediaList);
343  }
344 }
345 
346 function removeCommandFromLocations(newCommand,
347  testMediaList,
348  locations,
349  guidOrType)
350 {
351  if (guidOrType == "type")
352  {
353  if (DEBUG)
354  {
355  _log(" removing " + newCommand.id + " from type: " +
356  flagsToString(locations));
357  }
358  cmdHelper.removeCommandObjectForType(locations,
359  testMediaList.type,
360  newCommand);
361 
362  // update our map to track what the command's location should be
363  if (typeLocMap[newCommand.id] > 0)
364  typeLocMap[newCommand.id] = (typeLocMap[newCommand.id] & ~locations);
365  assertCommandLocations(testMediaList);
366  }
367  else {
368  if (DEBUG)
369  {
370  _log(" removing " + newCommand.id + " from guid: " +
371  flagsToString(locations));
372  }
373  cmdHelper.removeCommandObjectForGUID(locations,
374  testMediaList.guid,
375  newCommand);
376  // update our map to track what the command's location should be
377  if (guidLocMap[newCommand.id] > 0)
378  guidLocMap[newCommand.id] = (guidLocMap[newCommand.id] & ~locations);
379  assertCommandLocations(testMediaList);
380  }
381 }
382 
383 
384 /* this function confirms that all playlistcommands are in the locations
385  * logged by guidLocMap and typeLocMap */
386 function assertCommandLocations(testMediaList)
387 {
388  for (var id in guidLocMap)
389  {
390  let foundLocs = findCommandLocations(id, "guid", testMediaList);
391  let checkLocs = guidLocMap[id];
392  assertTrue(checkLocationFlags(foundLocs, checkLocs),
393  "Command with id '" + id + "' is not where it was expected " +
394  "when registered to medialist guid '" + testMediaList.guid +
395  "'.\n" + "Expected at - " + flagsToString(checkLocs) + "\n" +
396  "Found at - " + flagsToString(foundLocs) + "\n");
397  }
398 
399  for (var id in typeLocMap)
400  {
401  let foundLocs = findCommandLocations(id, "type", testMediaList);
402  let checkLocs = typeLocMap[id];
403  assertTrue(checkLocationFlags(foundLocs, checkLocs),
404  "Command with id '" + id + "' is not where it was expected " +
405  "when registered to medialist type '" + testMediaList.type +
406  "'.\n" + "Expected at -" + flagsToString(checkLocs) + "\n" +
407  "Found at -" + flagsToString(foundLocs) + "\n")
408  }
409 }
410 
411 /* This function does the actual check to ensure the locations we found a
412  * command in match those we expect to find it in.
413  *
414  * We cannot just check their equality because commands that are registered
415  * not using the playlistCommandsHelper API do not have targetFlags, so we
416  * can't distinguish if those commands are in the mediaitem context menu,
417  * the toolbar, or both. If we are handling such a command we check what we
418  * can.
419  */
420 function checkLocationFlags(foundLocs, checkLocs)
421 {
422  if (foundLocs != checkLocs)
423  {
424  /* Things don't match up right, but that could be because we don't have
425  * enough information in our checkLocs because the playlist command in
426  * question didn't have targetFlags.
427  * If the command didn't have target flags, we would have set the
428  * INCOMPLETE_TARGET_FLAGS flag. */
429  if (checkLocs & INCOMPLETE_TARGET_FLAGS)
430  {
431  /* This is a playlist command that didn't have target flags.
432  * Our information about the servicepane menu, however, is complete,
433  * so make sure those flags match.
434  * Also, we know that it must be in at least one of the toolbar or
435  * mediaitem context menu, so check for either of those flags. */
436  if ((foundLocs & cmdHelper.TARGET_SERVICEPANE_MENU ==
437  checkLocs & cmdHelper.TARGET_SERVICEPANE_MENU) &&
438  ((foundLocs & cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU) ||
439  (foundLocs & cmdHelper.TARGET_TOOLBAR)))
440  {
441  /* If the servicepane flags match and we know the command is in either
442  * of the mediaitem context menu or toolbar, then that's the best
443  * checking we can do with incomplete target flags. */
444  return true;
445  }
446  }
447 
448  /* The found flags and the check flags don't match, and we didn't get
449  * a pass because of incomplete target flags, so something must be wrong */
450  return false;
451  }
452  else {
453  // the flags match so we pass this check
454  return true;
455  }
456 }
457 
458 /* A utility function to return location flags for those places where the
459  * command whose id is cmdID is registered.
460  *
461  * param cmdID: the id of the command object we want to find the locations of
462  * param guidOrType: either "type" or "guid" indicating to search in the
463  * commands registered to type or guid
464  * param testMediaList: the medialist this test is being performed within.
465  */
466 function findCommandLocations(cmdID, guidOrType, testMediaList)
467 {
468  var foundLocs = 0;
469  if (guidOrType == "type")
470  {
471  // first check the service pane for the command object
472  var spFound = cmdHelper.getCommandObjectForType
473  (cmdHelper.TARGET_SERVICEPANE_MENU,
474  testMediaList.type,
475  cmdID);
476 
477  if (spFound)
478  foundLocs = foundLocs | cmdHelper.TARGET_SERVICEPANE_MENU;
479 
480  // next check the mediaitem context menu
481  var cmFound = cmdHelper.getCommandObjectForType
482  (cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU,
483  testMediaList.type,
484  cmdID);
485  if (cmFound)
486  foundLocs = foundLocs | cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU;
487 
488  // last, check the toolbar
489  var tbFound = cmdHelper.getCommandObjectForType
490  (cmdHelper.TARGET_TOOLBAR,
491  testMediaList.type,
492  cmdID);
493  if (tbFound)
494  foundLocs = foundLocs | cmdHelper.TARGET_TOOLBAR;
495  }
496  else {
497  // first check the service pane for the command object
498  var spFound = cmdHelper.getCommandObjectForGUID
499  (cmdHelper.TARGET_SERVICEPANE_MENU,
500  testMediaList.guid,
501  cmdID);
502  if (spFound)
503  foundLocs = foundLocs | cmdHelper.TARGET_SERVICEPANE_MENU;
504 
505  // next check the mediaitem context menu
506  var cmFound = cmdHelper.getCommandObjectForGUID
507  (cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU,
508  testMediaList.guid,
509  cmdID);
510  if (cmFound)
511  foundLocs = foundLocs | cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU;
512 
513  // last, check the toolbar
514  var tbFound = cmdHelper.getCommandObjectForGUID
515  (cmdHelper.TARGET_TOOLBAR,
516  testMediaList.guid,
517  cmdID);
518  if (tbFound)
519  foundLocs = foundLocs | cmdHelper.TARGET_TOOLBAR;
520  }
521 
522  return foundLocs;
523 }
524 
525 /* A function to add records for those command objects already registered to
526  * testMediaList's type or guid to typeLocMap and guidLocMap so that they can be
527  * accounted for in the test checks
528  */
529 function logExistingCommands(testMediaList)
530 {
531  /* We need to handle things registered with RegisterPlaylistCommandsMediaList
532  * and RegisterPlaylistCommandsMediaItem.
533  * Here we get the root item for each, then get there children, and add
534  * each to the appropriate log */
535  var testGUID = testMediaList.guid;
536 
537  // those registered with RegisterPlaylistCommandsMediaItem
538  var rootGUIDItem = cmdMgr.getPlaylistCommandsMediaItem(testGUID, "");
539  if (rootGUIDItem)
540  {
541  var guidItemChildrenEnum = rootGUIDItem.getChildrenCommandObjects();
542  while(guidItemChildrenEnum.hasMoreElements())
543  {
544  addExistingToLocMap(guidItemChildrenEnum.getNext(),
545  guidLocMap,
546  "mediaitem");
547  }
548  }
549 
550  // those registered with RegisterPlaylistCommandsMediaList
551  var rootGUIDList = cmdMgr.getPlaylistCommandsMediaList(testGUID, "");
552  if (rootGUIDList)
553  {
554  var guidListChildrenEnum = rootGUIDList.getChildrenCommandObjects();
555  while(guidListChildrenEnum.hasMoreElements())
556  {
557  addExistingToLocMap(guidListChildrenEnum.getNext(),
558  guidLocMap,
559  "medialist");
560  }
561  }
562 
563  // do the same but for the type
564  var testType = testMediaList.type;
565 
566  // those registered with RegisterPlaylistCommandsMediaItem
567  var rootTypeItem = cmdMgr.getPlaylistCommandsMediaItem("", testType);
568  if (rootTypeItem)
569  {
570  var typeItemChildrenEnum = rootTypeItem.getChildrenCommandObjects();
571  while(typeItemChildrenEnum.hasMoreElements())
572  {
573  addExistingToLocMap(typeItemChildrenEnum.getNext(),
574  typeLocMap,
575  "mediaitem");
576  }
577  }
578 
579  // those registered with RegisterPlaylistCommandsMediaList
580  var rootTypeList = cmdMgr.getPlaylistCommandsMediaList("", testType);
581  if (rootTypeList)
582  {
583  var typeListChildrenEnum = rootTypeList.getChildrenCommandObjects();
584  while(typeListChildrenEnum.hasMoreElements())
585  {
586  addExistingToLocMap(typeListChildrenEnum.getNext(),
587  typeLocMap,
588  "medialist");
589  }
590  }
591 }
592 
593 function addExistingToLocMap(playlistCommand, locMap, registrationLoc)
594 {
595  playlistCommand = playlistCommand.QueryInterface(Ci.sbIPlaylistCommands);
596  var id = playlistCommand.id;
597 
598  var knownLoc;
599  if (registrationLoc == "medialist")
600  {
601  /* if this playlistcommand was registered with
602  * RegisterPlaylistCommandsMediaList then it must be in the servicepane menu
603  * so we can just set that as our known location */
604  knownLoc = cmdHelper.TARGET_SERVICEPANE_MENU;
605  }
606  else {
607  /* if this playlistcommands was registered with
608  * RegisterPlaylistCommandsMediaItem then we know it is in both or either of
609  * the toolbar and/or the mediaitem context menu. We need targetFlags
610  * to know for more specifically.
611  */
612  knownLoc = playlistCommand.targetFlags
613  }
614 
615  if (!knownLoc || knownLoc == 0)
616  {
617  /* This playlist command does not know where it is. In this situation
618  * we use INCOMPLETE_TARGET_FLAGS to indicate to the function that checks
619  * the map that this playlistCommand could be in both or either of the
620  * toolbar and mediaitem context menu */
621  locMap[id] = (locMap[id] ?
622  (locMap[id] | INCOMPLETE_TARGET_FLAGS) :
624  }
625  else {
626  // this playlist command does know where it is so record that
627  locMap[id] = (locMap[id] ? (locMap[id] | knownLoc) : knownLoc);
628  }
629 }
630 
631 // utility function to print the flags in human-readable form
633 {
634  var str = "";
635  str += "ServicePane:" +
636  ((flags & cmdHelper.TARGET_SERVICEPANE_MENU) > 0) + ", ";
638  {
639  str += "Present in Toolbar and/or Context Menu, but incomplete info";
640  }
641  else {
642  str += "Toolbar:" + ((flags & cmdHelper.TARGET_TOOLBAR) > 0) + ", ";
643  str += "Context Menu:" +
644  ((flags & cmdHelper.TARGET_MEDIAITEM_CONTEXT_MENU) > 0);
645  }
646  return str;
647 }
function addExistingToLocMap(playlistCommand, locMap, registrationLoc)
const PlaylistCommandsBuilder
const Cc
menuItem id
Definition: FeedWriter.js:971
function addCommandToLocations(newCommand, testMediaList, locations, guidOrType)
function runTest()
Advanced DataRemote unit tests.
function log(s)
sbDeviceFirmwareAutoCheckForUpdate prototype flags
function testCreateCommandObjectForAction()
function assertTrue(aTest, aMessage)
function makeTriggerCallback(aActionID)
function removeCommandFromLocations(newCommand, testMediaList, locations, guidOrType)
function checkLocationFlags(foundLocs, checkLocs)
function flagsToString(flags)
function testAddAndRemoveCommandObject()
function testSubmenus(aCommand, aMenuID, aTestLength, aNumSubCommands)
function testAppendInsertRemove(aCommand, aMenuID, aTestLength, aNumSubCommands)
return null
Definition: FeedWriter.js:1143
function createLibrary(databaseGuid, databaseLocation)
Definition: test_load.js:151
var gTestPrefix
function findCommandLocations(cmdID, guidOrType, testMediaList)
function _log(aMsg, aMenuID)
function assertCommandLocations(testMediaList)
function testCommandCallbacksAndShortcuts(aCommand, aMenuID, aTestLength, aNumSubCommands)
const Ci
function logExistingCommands(testMediaList)
const DEBUG
Playlist Commands Helper Unit Test File.
const INCOMPLETE_TARGET_FLAGS