accessible/tests/mochitest/common.js

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 ////////////////////////////////////////////////////////////////////////////////
     2 // Interfaces
     4 const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
     6 const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
     7 const nsIAccessibleStateChangeEvent =
     8   Components.interfaces.nsIAccessibleStateChangeEvent;
     9 const nsIAccessibleCaretMoveEvent =
    10   Components.interfaces.nsIAccessibleCaretMoveEvent;
    11 const nsIAccessibleTextChangeEvent =
    12   Components.interfaces.nsIAccessibleTextChangeEvent;
    13 const nsIAccessibleVirtualCursorChangeEvent =
    14   Components.interfaces.nsIAccessibleVirtualCursorChangeEvent;
    16 const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
    17 const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
    18 const nsIAccessibleScrollType = Components.interfaces.nsIAccessibleScrollType;
    19 const nsIAccessibleCoordinateType = Components.interfaces.nsIAccessibleCoordinateType;
    21 const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation;
    23 const nsIAccessible = Components.interfaces.nsIAccessible;
    25 const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument;
    26 const nsIAccessibleApplication = Components.interfaces.nsIAccessibleApplication;
    28 const nsIAccessibleText = Components.interfaces.nsIAccessibleText;
    29 const nsIAccessibleEditableText = Components.interfaces.nsIAccessibleEditableText;
    31 const nsIAccessibleHyperLink = Components.interfaces.nsIAccessibleHyperLink;
    32 const nsIAccessibleHyperText = Components.interfaces.nsIAccessibleHyperText;
    34 const nsIAccessibleCursorable = Components.interfaces.nsIAccessibleCursorable;
    35 const nsIAccessibleImage = Components.interfaces.nsIAccessibleImage;
    36 const nsIAccessiblePivot = Components.interfaces.nsIAccessiblePivot;
    37 const nsIAccessibleSelectable = Components.interfaces.nsIAccessibleSelectable;
    38 const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
    39 const nsIAccessibleTableCell = Components.interfaces.nsIAccessibleTableCell;
    40 const nsIAccessibleTraversalRule = Components.interfaces.nsIAccessibleTraversalRule;
    41 const nsIAccessibleValue = Components.interfaces.nsIAccessibleValue;
    43 const nsIObserverService = Components.interfaces.nsIObserverService;
    45 const nsIDOMDocument = Components.interfaces.nsIDOMDocument;
    46 const nsIDOMEvent = Components.interfaces.nsIDOMEvent;
    47 const nsIDOMHTMLDocument = Components.interfaces.nsIDOMHTMLDocument;
    48 const nsIDOMNode = Components.interfaces.nsIDOMNode;
    49 const nsIDOMHTMLElement = Components.interfaces.nsIDOMHTMLElement;
    50 const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
    51 const nsIDOMXULElement = Components.interfaces.nsIDOMXULElement;
    53 const nsIPropertyElement = Components.interfaces.nsIPropertyElement;
    55 ////////////////////////////////////////////////////////////////////////////////
    56 // OS detect
    58 const MAC = (navigator.platform.indexOf("Mac") != -1);
    59 const LINUX = (navigator.platform.indexOf("Linux") != -1);
    60 const SOLARIS = (navigator.platform.indexOf("SunOS") != -1);
    61 const WIN = (navigator.platform.indexOf("Win") != -1);
    63 ////////////////////////////////////////////////////////////////////////////////
    64 // Application detect
    65 // Firefox is assumed by default.
    67 const SEAMONKEY = navigator.userAgent.match(/ SeaMonkey\//);
    69 ////////////////////////////////////////////////////////////////////////////////
    70 // Accessible general
    72 const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
    74 const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE;
    76 const COORDTYPE_SCREEN_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
    77 const COORDTYPE_WINDOW_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
    78 const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
    80 const kEmbedChar = String.fromCharCode(0xfffc);
    82 const kDiscBulletChar = String.fromCharCode(0x2022);
    83 const kDiscBulletText = kDiscBulletChar + " ";
    84 const kCircleBulletText = String.fromCharCode(0x25e6) + " ";
    85 const kSquareBulletText = String.fromCharCode(0x25aa) + " ";
    87 const MAX_TRIM_LENGTH = 100;
    89 /**
    90  * nsIAccessibleRetrieval service.
    91  */
    92 var gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
    93   getService(nsIAccessibleRetrieval);
    95 /**
    96  * Enable/disable logging.
    97  */
    98 function enableLogging(aModules)
    99 {
   100   gAccRetrieval.setLogging(aModules);
   101 }
   102 function disableLogging()
   103 {
   104   gAccRetrieval.setLogging("");
   105 }
   106 function isLogged(aModule)
   107 {
   108   return gAccRetrieval.isLogged(aModule);
   109 }
   111 /**
   112  * Invokes the given function when document is loaded and focused. Preferable
   113  * to mochitests 'addLoadEvent' function -- additionally ensures state of the
   114  * document accessible is not busy.
   115  *
   116  * @param aFunc  the function to invoke
   117  */
   118 function addA11yLoadEvent(aFunc, aWindow)
   119 {
   120   function waitForDocLoad()
   121   {
   122     window.setTimeout(
   123       function()
   124       {
   125         var targetDocument = aWindow ? aWindow.document : document;
   126         var accDoc = getAccessible(targetDocument);
   127         var state = {};
   128         accDoc.getState(state, {});
   129         if (state.value & STATE_BUSY)
   130           return waitForDocLoad();
   132         window.setTimeout(aFunc, 0);
   133       },
   134       0
   135     );
   136   }
   138   SimpleTest.waitForFocus(waitForDocLoad, aWindow);
   139 }
   141 /**
   142  * Analogy of SimpleTest.is function used to compare objects.
   143  */
   144 function isObject(aObj, aExpectedObj, aMsg)
   145 {
   146   if (aObj == aExpectedObj) {
   147     ok(true, aMsg);
   148     return;
   149   }
   151   ok(false,
   152      aMsg + " - got '" + prettyName(aObj) +
   153             "', expected '" + prettyName(aExpectedObj) + "'");
   154 }
   156 ////////////////////////////////////////////////////////////////////////////////
   157 // Helpers for getting DOM node/accessible
   159 /**
   160  * Return the DOM node by identifier (may be accessible, DOM node or ID).
   161  */
   162 function getNode(aAccOrNodeOrID, aDocument)
   163 {
   164   if (!aAccOrNodeOrID)
   165     return null;
   167   if (aAccOrNodeOrID instanceof nsIDOMNode)
   168     return aAccOrNodeOrID;
   170   if (aAccOrNodeOrID instanceof nsIAccessible)
   171     return aAccOrNodeOrID.DOMNode;
   173   node = (aDocument || document).getElementById(aAccOrNodeOrID);
   174   if (!node) {
   175     ok(false, "Can't get DOM element for " + aAccOrNodeOrID);
   176     return null;
   177   }
   179   return node;
   180 }
   182 /**
   183  * Constants indicates getAccessible doesn't fail if there is no accessible.
   184  */
   185 const DONOTFAIL_IF_NO_ACC = 1;
   187 /**
   188  * Constants indicates getAccessible won't fail if accessible doesn't implement
   189  * the requested interfaces.
   190  */
   191 const DONOTFAIL_IF_NO_INTERFACE = 2;
   193 /**
   194  * Return accessible for the given identifier (may be ID attribute or DOM
   195  * element or accessible object) or null.
   196  *
   197  * @param aAccOrElmOrID      [in] identifier to get an accessible implementing
   198  *                           the given interfaces
   199  * @param aInterfaces        [in, optional] the interface or an array interfaces
   200  *                           to query it/them from obtained accessible
   201  * @param aElmObj            [out, optional] object to store DOM element which
   202  *                           accessible is obtained for
   203  * @param aDoNotFailIf       [in, optional] no error for special cases (see
   204  *                            constants above)
   205  */
   206 function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf)
   207 {
   208   if (!aAccOrElmOrID)
   209     return null;
   211   var elm = null;
   213   if (aAccOrElmOrID instanceof nsIAccessible) {
   214     elm = aAccOrElmOrID.DOMNode;
   216   } else if (aAccOrElmOrID instanceof nsIDOMNode) {
   217     elm = aAccOrElmOrID;
   219   } else {
   220     elm = document.getElementById(aAccOrElmOrID);
   221     if (!elm) {
   222       ok(false, "Can't get DOM element for " + aAccOrElmOrID);
   223       return null;
   224     }
   225   }
   227   if (aElmObj && (typeof aElmObj == "object"))
   228     aElmObj.value = elm;
   230   var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null;
   231   if (!acc) {
   232     try {
   233       acc = gAccRetrieval.getAccessibleFor(elm);
   234     } catch (e) {
   235     }
   237     if (!acc) {
   238       if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC))
   239         ok(false, "Can't get accessible for " + aAccOrElmOrID);
   241       return null;
   242     }
   243   }
   245   if (!aInterfaces)
   246     return acc;
   248   if (!(aInterfaces instanceof Array))
   249     aInterfaces = [ aInterfaces ];
   251   for (var index = 0; index < aInterfaces.length; index++) {
   252     try {
   253       acc.QueryInterface(aInterfaces[index]);
   254     } catch (e) {
   255       if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
   256         ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID);
   258       return null;
   259     }
   260   }
   262   return acc;
   263 }
   265 /**
   266  * Return true if the given identifier has an accessible, or exposes the wanted
   267  * interfaces.
   268  */
   269 function isAccessible(aAccOrElmOrID, aInterfaces)
   270 {
   271   return getAccessible(aAccOrElmOrID, aInterfaces, null,
   272                        DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE) ?
   273     true : false;
   274 }
   276 /**
   277  * Return an accessible that contains the DOM node for the given identifier.
   278  */
   279 function getContainerAccessible(aAccOrElmOrID)
   280 {
   281   var node = getNode(aAccOrElmOrID);
   282   if (!node)
   283     return null;
   285   while ((node = node.parentNode) && !isAccessible(node));
   286   return node ? getAccessible(node) : null;
   287 }
   289 /**
   290  * Return root accessible for the given identifier.
   291  */
   292 function getRootAccessible(aAccOrElmOrID)
   293 {
   294   var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document);
   295   return acc ? acc.rootDocument.QueryInterface(nsIAccessible) : null;
   296 }
   298 /**
   299  * Return tab document accessible the given accessible is contained by.
   300  */
   301 function getTabDocAccessible(aAccOrElmOrID)
   302 {
   303   var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document);
   305   var docAcc = acc.document.QueryInterface(nsIAccessible);
   306   var containerDocAcc = docAcc.parent.document;
   308   // Test is running is stand-alone mode.
   309   if (acc.rootDocument == containerDocAcc)
   310     return docAcc;
   312   // In the case of running all tests together.
   313   return containerDocAcc.QueryInterface(nsIAccessible);
   314 }
   316 /**
   317  * Return application accessible.
   318  */
   319 function getApplicationAccessible()
   320 {
   321   return gAccRetrieval.getApplicationAccessible().
   322     QueryInterface(nsIAccessibleApplication);
   323 }
   325 /**
   326  * A version of accessible tree testing, doesn't fail if tree is not complete.
   327  */
   328 function testElm(aID, aTreeObj)
   329 {
   330   testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
   331 }
   333 /**
   334  * Flags used for testAccessibleTree
   335  */
   336 const kSkipTreeFullCheck = 1;
   338 /**
   339  * Compare expected and actual accessibles trees.
   340  *
   341  * @param  aAccOrElmOrID  [in] accessible identifier
   342  * @param  aAccTree       [in] JS object, each field corresponds to property of
   343  *                         accessible object. Additionally special properties
   344  *                         are presented:
   345  *                          children - an array of JS objects representing
   346  *                                      children of accessible
   347  *                          states   - an object having states and extraStates
   348  *                                      fields
   349  * @param aFlags          [in, optional] flags, see constants above
   350  */
   351 function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
   352 {
   353   var acc = getAccessible(aAccOrElmOrID);
   354   if (!acc)
   355     return;
   357   var accTree = aAccTree;
   359   // Support of simplified accessible tree object.
   360   var key = Object.keys(accTree)[0];
   361   var roleName = "ROLE_" + key;
   362   if (roleName in nsIAccessibleRole) {
   363     accTree = {
   364       role: nsIAccessibleRole[roleName],
   365       children: accTree[key]
   366     };
   367   }
   369   // Test accessible properties.
   370   for (var prop in accTree) {
   371     var msg = "Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
   373     switch (prop) {
   374     case "actions": {
   375       testActionNames(acc, accTree.actions);
   376       break;
   377     }
   379     case "attributes":
   380       testAttrs(acc, accTree[prop], true);
   381       break;
   383     case "absentAttributes":
   384       testAbsentAttrs(acc, accTree[prop]);
   385       break;
   387     case "interfaces": {
   388       var ifaces = (accTree[prop] instanceof Array) ?
   389         accTree[prop] : [ accTree[prop] ];
   390       for (var i = 0; i < ifaces.length; i++) {
   391         ok((acc instanceof ifaces[i]),
   392            "No " + ifaces[i] + " interface on " + prettyName(acc));
   393       }
   394       break;
   395     }
   397     case "relations": {
   398       for (var rel in accTree[prop])
   399         testRelation(acc, window[rel], accTree[prop][rel]);
   400       break;
   401     }
   403     case "role":
   404       isRole(acc, accTree[prop], msg);
   405       break;
   407     case "states":
   408     case "extraStates":
   409     case "absentStates":
   410     case "absentExtraStates": {
   411       testStates(acc, accTree["states"], accTree["extraStates"],
   412                  accTree["absentStates"], accTree["absentExtraStates"]);
   413       break;
   414     }
   416     case "tagName":
   417       is(accTree[prop], acc.DOMNode.tagName, msg);
   418       break;
   420     case "textAttrs": {
   421       var prevOffset = -1;
   422       for (var offset in accTree[prop]) {
   423         if (prevOffset !=- 1) {
   424           var attrs = accTree[prop][prevOffset];
   425           testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, offset, true);
   426         }
   427         prevOffset = offset;
   428       }
   430       if (prevOffset != -1) {
   431         var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount;
   432         var attrs = accTree[prop][prevOffset];
   433         testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true);
   434       }
   436       break;
   437     } 
   439     default:
   440       if (prop.indexOf("todo_") == 0)
   441         todo(false, msg);
   442       else if (prop != "children")
   443         is(acc[prop], accTree[prop], msg);
   444     }
   445   }
   447   // Test children.
   448   if ("children" in accTree && accTree["children"] instanceof Array) {
   449     var children = acc.children;
   450     var childCount = children.length;
   452     is(childCount, accTree.children.length,
   453        "Different amount of expected children of " + prettyName(acc) + ".");
   455     if (accTree.children.length == childCount) {
   456       if (aFlags & kSkipTreeFullCheck) {
   457         for (var i = 0; i < childCount; i++) {
   458           var child = children.queryElementAt(i, nsIAccessible);
   459           testAccessibleTree(child, accTree.children[i], aFlags);
   460         }
   461         return;
   462       }
   464       // nsIAccessible::firstChild
   465       var expectedFirstChild = childCount > 0 ?
   466         children.queryElementAt(0, nsIAccessible) : null;
   467       var firstChild = null;
   468       try { firstChild = acc.firstChild; } catch (e) {}
   469       is(firstChild, expectedFirstChild,
   470          "Wrong first child of " + prettyName(acc));
   472       // nsIAccessible::lastChild
   473       var expectedLastChild = childCount > 0 ?
   474         children.queryElementAt(childCount - 1, nsIAccessible) : null;
   475       var lastChild = null;
   476       try { lastChild = acc.lastChild; } catch (e) {}
   477       is(lastChild, expectedLastChild,
   478          "Wrong last child of " + prettyName(acc));
   480       for (var i = 0; i < childCount; i++) {
   481         var child = children.queryElementAt(i, nsIAccessible);
   483         // nsIAccessible::parent
   484         var parent = null;
   485         try { parent = child.parent; } catch (e) {}
   486         is(parent, acc, "Wrong parent of " + prettyName(child));
   488         // nsIAccessible::indexInParent
   489         var indexInParent = -1;
   490         try { indexInParent = child.indexInParent; } catch(e) {}
   491         is(indexInParent, i,
   492            "Wrong index in parent of " + prettyName(child));
   494         // nsIAccessible::nextSibling
   495         var expectedNextSibling = (i < childCount - 1) ?
   496           children.queryElementAt(i + 1, nsIAccessible) : null;
   497         var nextSibling = null;
   498         try { nextSibling = child.nextSibling; } catch (e) {}
   499         is(nextSibling, expectedNextSibling,
   500            "Wrong next sibling of " + prettyName(child));
   502         // nsIAccessible::previousSibling
   503         var expectedPrevSibling = (i > 0) ?
   504           children.queryElementAt(i - 1, nsIAccessible) : null;
   505         var prevSibling = null;
   506         try { prevSibling = child.previousSibling; } catch (e) {}
   507         is(prevSibling, expectedPrevSibling,
   508            "Wrong previous sibling of " + prettyName(child));
   510         // Go down through subtree
   511         testAccessibleTree(child, accTree.children[i], aFlags);
   512       }
   513     }
   514   }
   515 }
   517 /**
   518  * Return true if accessible for the given node is in cache.
   519  */
   520 function isAccessibleInCache(aNodeOrId)
   521 {
   522   var node = getNode(aNodeOrId);
   523   return gAccRetrieval.getAccessibleFromCache(node) ? true : false;
   524 }
   526 /**
   527  * Test accessible tree for defunct accessible.
   528  *
   529  * @param  aAcc       [in] the defunct accessible
   530  * @param  aNodeOrId  [in] the DOM node identifier for the defunct accessible
   531  */
   532 function testDefunctAccessible(aAcc, aNodeOrId)
   533 {
   534   if (aNodeOrId)
   535     ok(!isAccessible(aNodeOrId),
   536        "Accessible for " + aNodeOrId + " wasn't properly shut down!");
   538   var msg = " doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
   540   // firstChild
   541   var success = false;
   542   try {
   543     aAcc.firstChild;
   544   } catch (e) {
   545     success = (e.result == Components.results.NS_ERROR_FAILURE)
   546   }
   547   ok(success, "firstChild" + msg);
   549   // lastChild
   550   success = false;
   551   try {
   552     aAcc.lastChild;
   553   } catch (e) {
   554     success = (e.result == Components.results.NS_ERROR_FAILURE)
   555   }
   556   ok(success, "lastChild" + msg);
   558   // childCount
   559   success = false;
   560   try {
   561     aAcc.childCount;
   562   } catch (e) {
   563     success = (e.result == Components.results.NS_ERROR_FAILURE)
   564   }
   565   ok(success, "childCount" + msg);
   567   // children
   568   success = false;
   569   try {
   570     aAcc.children;
   571   } catch (e) {
   572     success = (e.result == Components.results.NS_ERROR_FAILURE)
   573   }
   574   ok(success, "children" + msg);
   576   // nextSibling
   577   success = false;
   578   try {
   579     aAcc.nextSibling;
   580   } catch (e) {
   581     success = (e.result == Components.results.NS_ERROR_FAILURE);
   582   }
   583   ok(success, "nextSibling" + msg);
   585   // previousSibling
   586   success = false;
   587   try {
   588     aAcc.previousSibling;
   589   } catch (e) {
   590     success = (e.result == Components.results.NS_ERROR_FAILURE);
   591   }
   592   ok(success, "previousSibling" + msg);
   594   // parent
   595   success = false;
   596   try {
   597     aAcc.parent;
   598   } catch (e) {
   599     success = (e.result == Components.results.NS_ERROR_FAILURE);
   600   }
   601   ok(success, "parent" + msg);
   602 }
   604 /**
   605  * Convert role to human readable string.
   606  */
   607 function roleToString(aRole)
   608 {
   609   return gAccRetrieval.getStringRole(aRole);
   610 }
   612 /**
   613  * Convert states to human readable string.
   614  */
   615 function statesToString(aStates, aExtraStates)
   616 {
   617   var list = gAccRetrieval.getStringStates(aStates, aExtraStates);
   619   var str = "";
   620   for (var index = 0; index < list.length - 1; index++)
   621     str += list.item(index) + ", ";
   623   if (list.length != 0)
   624     str += list.item(index)
   626   return str;
   627 }
   629 /**
   630  * Convert event type to human readable string.
   631  */
   632 function eventTypeToString(aEventType)
   633 {
   634   return gAccRetrieval.getStringEventType(aEventType);
   635 }
   637 /**
   638  * Convert relation type to human readable string.
   639  */
   640 function relationTypeToString(aRelationType)
   641 {
   642   return gAccRetrieval.getStringRelationType(aRelationType);
   643 }
   645 function getLoadContext() {
   646   const Ci = Components.interfaces;
   647   return window.QueryInterface(Ci.nsIInterfaceRequestor)
   648                .getInterface(Ci.nsIWebNavigation)
   649                .QueryInterface(Ci.nsILoadContext);
   650 }
   652 /**
   653  * Return text from clipboard.
   654  */
   655 function getTextFromClipboard()
   656 {
   657   var clip = Components.classes["@mozilla.org/widget/clipboard;1"].
   658     getService(Components.interfaces.nsIClipboard);
   659   if (!clip)
   660     return "";
   662   var trans = Components.classes["@mozilla.org/widget/transferable;1"].
   663     createInstance(Components.interfaces.nsITransferable);
   664   trans.init(getLoadContext());
   665   if (!trans)
   666     return "";
   668   trans.addDataFlavor("text/unicode");
   669   clip.getData(trans, clip.kGlobalClipboard);
   671   var str = new Object();
   672   var strLength = new Object();
   673   trans.getTransferData("text/unicode", str, strLength);
   675   if (str)
   676     str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
   677   if (str)
   678     return str.data.substring(0, strLength.value / 2);
   680   return "";
   681 }
   683 /**
   684  * Return pretty name for identifier, it may be ID, DOM node or accessible.
   685  */
   686 function prettyName(aIdentifier)
   687 {
   688   if (aIdentifier instanceof Array) {
   689     var msg = "";
   690     for (var idx = 0; idx < aIdentifier.length; idx++) {
   691       if (msg != "")
   692         msg += ", ";
   694       msg += prettyName(aIdentifier[idx]);
   695     }
   696     return msg;
   697   }
   699   if (aIdentifier instanceof nsIAccessible) {
   700     var acc = getAccessible(aIdentifier);
   701     var msg = "[" + getNodePrettyName(acc.DOMNode);
   702     try {
   703       msg += ", role: " + roleToString(acc.role);
   704       if (acc.name)
   705         msg += ", name: '" + shortenString(acc.name) + "'";
   706     } catch (e) {
   707       msg += "defunct";
   708     }
   710     if (acc)
   711       msg += ", address: " + getObjAddress(acc);
   712     msg += "]";
   714     return msg;
   715   }
   717   if (aIdentifier instanceof nsIDOMNode)
   718     return "[ " + getNodePrettyName(aIdentifier) + " ]";
   720   return " '" + aIdentifier + "' ";
   721 }
   723 /**
   724  * Shorten a long string if it exceeds MAX_TRIM_LENGTH.
   725  * @param aString the string to shorten.
   726  * @returns the shortened string.
   727  */
   728 function shortenString(aString, aMaxLength)
   729 {
   730   if (aString.length <= MAX_TRIM_LENGTH)
   731     return aString;
   733   // Trim the string if its length is > MAX_TRIM_LENGTH characters.
   734   var trimOffset = MAX_TRIM_LENGTH / 2;
   735   return aString.substring(0, trimOffset - 1) + "..." +
   736     aString.substring(aString.length - trimOffset, aString.length);
   737 }
   739 ////////////////////////////////////////////////////////////////////////////////
   740 // General Utils
   741 ////////////////////////////////////////////////////////////////////////////////
   742 /**
   743  * Return main chrome window (crosses chrome boundary)
   744  */
   745 function getMainChromeWindow(aWindow)
   746 {
   747   return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   748                 .getInterface(Components.interfaces.nsIWebNavigation)
   749                 .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
   750                 .rootTreeItem
   751                 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   752                 .getInterface(Components.interfaces.nsIDOMWindow);
   753 }
   755 /** Sets the test plugin(s) initially expected enabled state.
   756  * It will automatically be reset to it's previous value after the test
   757  * ends.
   758  * @param aNewEnabledState [in] the enabled state, e.g. SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED
   759  * @param aPluginName [in, optional] The name of the plugin, defaults to "Test Plug-in"
   760  */
   761 function setTestPluginEnabledState(aNewEnabledState, aPluginName)
   762 {
   763   var plugin = getTestPluginTag(aPluginName);
   764   var oldEnabledState = plugin.enabledState;
   765   plugin.enabledState = aNewEnabledState;
   766   SimpleTest.registerCleanupFunction(function() {
   767     getTestPluginTag(aPluginName).enabledState = oldEnabledState;
   768   });
   769 }
   771 ////////////////////////////////////////////////////////////////////////////////
   772 // Private
   773 ////////////////////////////////////////////////////////////////////////////////
   775 ////////////////////////////////////////////////////////////////////////////////
   776 // Accessible general
   778 function getNodePrettyName(aNode)
   779 {
   780   try {
   781     var tag = "";
   782     if (aNode.nodeType == nsIDOMNode.DOCUMENT_NODE) {
   783       tag = "document";
   784     } else {
   785       tag = aNode.localName;
   786       if (aNode.nodeType == nsIDOMNode.ELEMENT_NODE && aNode.hasAttribute("id"))
   787         tag += "@id=\"" + aNode.getAttribute("id") + "\"";
   788     }
   790     return "'" + tag + " node', address: " + getObjAddress(aNode);
   791   } catch (e) {
   792     return "' no node info '";
   793   }
   794 }
   796 function getObjAddress(aObj)
   797 {
   798   var exp = /native\s*@\s*(0x[a-f0-9]+)/g;
   799   var match = exp.exec(aObj.toString());
   800   if (match)
   801     return match[1];
   803   return aObj.toString();
   804 }
   806 function getTestPluginTag(aPluginName)
   807 {
   808   var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
   809                         .getService(SpecialPowers.Ci.nsIPluginHost);
   810   var tags = ph.getPluginTags();
   811   var name = aPluginName || "Test Plug-in";
   812   for (var tag of tags) {
   813     if (tag.name == name) {
   814       return tag;
   815     }
   816   }
   818   ok(false, "Could not find plugin tag with plugin name '" + name + "'");
   819   return null;
   820 }

mercurial