Bug 446281: automated tests for duplicate ids; r=Standard8
authorKarsten Düsterloh <mnyromyr@tprac.de>
Sun, 24 Aug 2008 13:56:08 +0200
changeset 177 c136db2028c9c125306d69e01155bf4d812d30d1
parent 176 b9818424c55b853c5c78aeee6b061e66db0d432b
child 178 0ab76ee87645097134ee5da08e2288e0e9b1832a
push idunknown
push userunknown
push dateunknown
reviewersStandard8
bugs446281
Bug 446281: automated tests for duplicate ids; r=Standard8
suite/common/tests/Makefile.in
suite/common/tests/chrome/Makefile.in
suite/common/tests/chrome/test_idcheck.xul
--- a/suite/common/tests/Makefile.in
+++ b/suite/common/tests/Makefile.in
@@ -16,16 +16,17 @@
 #
 # The Initial Developer of the Original Code is
 # Mozilla.org.
 # Portions created by the Initial Developer are Copyright (C) 2005
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #     Boris Zbarsky <bzbarsky@mit.edu>  (Original author)
+#     Karsten Düsterloh <mnyromyr@tprac.de>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either of the GNU General Public License Version 2 or later (the "GPL"),
 # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -42,9 +43,13 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= test_suite_common
 
 XPCSHELL_TESTS = unit
 
+ifdef MOZ_MOCHITEST
+DIRS = chrome
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/suite/common/tests/chrome/Makefile.in
@@ -0,0 +1,51 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is SeaMonkey project code.
+#
+# The Initial Developer of the Original Code is
+# Karsten Düsterloh <mnyromyr@tprac.de>.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = suite/common/tests/chrome
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = 	test_idcheck.xul \
+		$(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(MOZDEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/suite/common/tests/chrome/test_idcheck.xul
@@ -0,0 +1,309 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is SeaMonkey project code.
+   -
+   - The Initial Developer of the Original Code is
+   - Karsten Düsterloh <mnyromyr@tprac.de>
+   - Portions created by the Initial Developer are Copyright (C) 2008
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Chrome Window ID Checking Tests"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="RunTest();">
+  <description>Chrome Window ID Checking Tests</description>
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+    var gLoadedWindows = {};
+
+    // Have all loaded windows been closed again?
+    function AllWindowsClosed()
+    {
+      for each (var e in window.gLoadedWindows)
+        return false;
+      return true;
+    }
+
+    function DumpElementTree(aElement)
+    {
+      // walk upwards from element to DOM root
+      while (aElement)
+      {
+        // print nodeName, id and index in parent
+        let s = "    " + aElement.nodeName + " " + aElement.id + " ";
+        let ix = 0;
+        while (aElement.previousSibling)
+        {
+          aElement = aElement.previousSibling;
+          ++ix;
+        }
+        dump(s + "[" + ix + "]\n");
+        aElement = aElement.parentNode;
+      }
+    }
+
+    function CheckIDs(aDocument, aIgnorableIDs)
+    {
+      var filename = aDocument.location.href.match(/[^/]+$/);
+      // all panes are loaded, now check the ids
+      // first, get the list of all used ids
+      var idList = aDocument.getElementsByAttribute("id", "*");
+      // then store them in another object, checking if it's already there
+      var checkedList = {};
+      var ignoredList = {};
+      for (let i = 0; i < idList.length; ++i)
+      {
+        let id = idList[i].id;
+        let duplicate = (id in checkedList);
+        if (!duplicate)
+        {
+          checkedList[id] = idList[i];
+        }
+        else
+        {
+          // always dump DOM trees of the conflicting elements
+          dump("Double id='" + id + "' detected in " + aDocument.location.href + ":\n");
+          dump("  Tree 0:\n");
+          DumpElementTree(checkedList[id]);
+          dump("  Tree 1:\n");
+          DumpElementTree(idList[i]);
+        }
+        if (aIgnorableIDs.indexOf(id) < 0)
+        {
+          // if the id is not in our ignore list, show its status
+          ok(!duplicate, "check id: " + filename + "#" + id);
+        }
+        else if (!(id in ignoredList))
+        {
+          // mark ignored id tests as todo,
+          // even though we may never (be able to) fix them
+          ignoredList[id] = idList[i];
+          todo(false, "disabled id checks: " + filename + "#" + id);
+        }
+      }
+      
+      // finally, close the loaded window
+      aDocument.defaultView.close();
+    }
+
+    function LoadPaneLoop(aDocument, aPanes, aPaneIndex, aForceLoad)
+    {
+      if (aPaneIndex < aPanes.length)
+      {
+        const WAIT_CYCLE = 10;
+        // may need to load this pane
+        let pane = aPanes[aPaneIndex];
+        if (pane.loaded)
+        {
+          // okay, check/load next one
+          setTimeout(LoadPaneLoop, WAIT_CYCLE, aDocument, aPanes, aPaneIndex + 1, true);
+        }
+        else
+        {
+          // force load once and wait until done
+          if (aForceLoad)
+          {
+            try
+            {
+              aDocument.documentElement.showPane.call(aDocument.documentElement, pane);
+            }
+            catch (ignored) {}
+          }
+          setTimeout(LoadPaneLoop, WAIT_CYCLE, aDocument, aPanes, aPaneIndex, false);
+        }
+      }
+      else
+      {
+        // All preference panes are loaded now!
+
+        // The character_encoding_pane contains two template driven menulists
+        // (viewDefaultCharsetList and sendDefaultCharsetList),
+        // both of which autogenerate the *same* ids for their menuitems.
+        // We alter one set here to avoid unnecessary test failure.
+        // (We probably should remove those RDF templates?)
+        let menulist = aDocument.getElementById("viewDefaultCharsetList")
+                                .getElementsByTagName("menuitem");
+        for each (let menuitem in menulist)
+        {
+          menuitem.id = 'test_idcheck.1.' + menuitem.id;
+          menuitem = menuitem.nextSibling;
+        }
+
+        // now check the ids
+        CheckIDs(aDocument, window.gLoadedWindows[aDocument.location.href]);
+      }
+    }
+
+    function CheckPreferences()
+    {
+      this.removeEventListener("load", window.CheckPreferences, false);
+
+      // Prefpanes are loaded lazily, thus we need to trigger each panel manually
+      // before we can check for doubled ids...
+      var panes = this.document.getElementsByTagName("prefpane");
+      setTimeout(LoadPaneLoop, 0, this.document, panes, 0, true);
+    }
+
+    function CheckGenerics()
+    {
+      this.removeEventListener("load", window.CheckGenerics, false);
+      CheckIDs(this.document, window.gLoadedWindows[this.location.href]);
+    }
+
+    function UncountWindow()
+    {
+      if (this.location.href in window.gLoadedWindows)
+      {
+        this.removeEventListener("unload", window.UncountWindow, false);
+        delete window.gLoadedWindows[this.location.href];
+      }
+    }
+
+    function FinishTest()
+    {
+      if (AllWindowsClosed())
+        SimpleTest.finish();
+      else
+        setTimeout(FinishTest, 1000);
+    }
+
+    function RunTest()
+    {
+      SimpleTest.waitForExplicitFinish();
+      // Basically, this test framework is generic enough to check arbitrary
+      // chrome windows for doubled ids. But certain stuff like preferences
+      // needs some extra processing.
+      // The uriList members have the following format:
+      //    "chrome://uri/of/xul.window":
+      //    [
+      //      check function,
+      //      array of IDs to be ignored during in the test
+      //    ],
+      var uriList =
+      {
+        // Preferences
+        "chrome://communicator/content/pref/preferences.xul":
+          [
+            window.CheckPreferences,
+            []
+          ],
+
+        // Browser
+        "chrome://navigator/content/navigator.xul":
+          [
+            window.CheckGenerics,
+            ["contentAreaContextSet"]
+          ],
+/* need mail account
+        // MailNews
+        "chrome://messenger/content/messenger.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+        "chrome://messenger/content/messengercompose/messengercompose.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+        // Addressbook
+        "chrome://messenger/content/addressbook/addressbook.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+*/
+        // Composer
+        "chrome://editor/content/editor.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+        // Error Console
+        "chrome://global/content/console.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+/* not available yet in chrome tests
+        // Chatzilla
+        "chrome://chatzilla/content/chatzilla.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+        // DOM Inspector
+        "chrome://inspector/content/inspector.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+        // Venkman
+        "chrome://venkman/content/venkman.xul":
+          [
+            window.CheckGenerics,
+            []
+          ],
+*/
+      };
+
+      // run test
+      for (var uri in uriList)
+      {
+        // load the window, but postpone the id check until it's fully loaded
+        window.gLoadedWindows[uri] = uriList[uri][1]; // ignore these ids
+        var win = openDialog(uri, "", "chrome,titlebar,dialog=no,resizable");
+        win.addEventListener("load", uriList[uri][0], false);
+        win.addEventListener("unload", window.UncountWindow, false);
+      }
+
+      // wait for all tests to finish
+      setTimeout(FinishTest, 0);
+    }
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display: none"></div>
+    <pre id="test"></pre>
+  </body>
+
+</window>