Bug 1027215 - Generic Python code for parsing reftest manifests; r=roc
authorGregory Szorc <gps@mozilla.com>
Tue, 17 Jun 2014 17:29:57 -0700
changeset 189821 ffaf206fd0189e6c88ec4b773996b4e64448f7f8
parent 189818 776f6d341b3f013672a861a4ee0283c120e3e46f
child 189822 ab997ac497a0bb14d6d91cddce91085a13275431
push id26998
push userttaubert@mozilla.com
push dateMon, 23 Jun 2014 12:37:15 +0000
treeherdermozilla-central@335b6610fe0c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1027215
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1027215 - Generic Python code for parsing reftest manifests; r=roc The immediate goal of this patch is to give the build system and testing tools the knowledge to identify reftest files and directories. Parsing extra metadata out of reftest manifests is currently a non-requirement, but may be supported some day.
build/mach_bootstrap.py
build/virtualenv_packages.txt
layout/tools/reftest/reftest/__init__.py
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -33,16 +33,17 @@ SEARCH_PATHS = [
     'python/configobj',
     'python/jsmin',
     'python/psutil',
     'python/which',
     'build/pymake',
     'config',
     'dom/bindings',
     'dom/bindings/parser',
+    'layout/tools/reftest',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
     'testing/xpcshell',
     'testing/marionette/client',
     'testing/marionette/client/marionette',
     'testing/marionette/transport',
     'testing/mozbase/mozcrash',
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -12,13 +12,14 @@ which.pth:python/which
 ply.pth:other-licenses/ply/
 codegen.pth:python/codegen/
 mock.pth:python/mock-1.0.0
 mozilla.pth:build
 mozilla.pth:config
 mozilla.pth:xpcom/typelib/xpt/tools
 mozilla.pth:dom/bindings
 mozilla.pth:dom/bindings/parser
+mozilla.pth:layout/tools/reftest
 moztreedocs.pth:tools/docs
 copy:build/buildconfig.py
 packages.txt:testing/mozbase/packages.txt
 objdir:build
 gyp.pth:media/webrtc/trunk/tools/gyp/pylib
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/reftest/__init__.py
@@ -0,0 +1,125 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import unicode_literals
+
+import os
+import re
+
+RE_COMMENT = re.compile(r'\s+#')
+RE_HTTP = re.compile(r'HTTP\((\.\.(\/\.\.)*)\)')
+RE_PROTOCOL = re.compile(r'^\w+:')
+FAILURE_TYPES = (
+    'fails',
+    'fails-if',
+    'needs-focus',
+    'random',
+    'random-if',
+    'silentfail',
+    'silentfail-if',
+    'skip',
+    'skip-if',
+    'slow',
+    'slow-if',
+    'fuzzy',
+    'fuzzy-if',
+    'require-or',
+    'asserts',
+    'asserts-if',
+)
+PREF_ITEMS = (
+    'pref',
+    'test-pref',
+    'ref-pref',
+)
+
+class ReftestManifest(object):
+    """Represents a parsed reftest manifest.
+
+    We currently only capture file information because that is the only thing
+    tools require.
+    """
+    def __init__(self):
+        self.path = None
+        self.dirs = set()
+        self.files = set()
+        self.manifests = set()
+
+    def load(self, path):
+        """Parse a reftest manifest file."""
+        normalized = os.path.normpath(os.path.abspath(path))
+        self.manifests.add(normalized)
+        if not self.path:
+            self.path = normalized
+
+        mdir = os.path.dirname(normalized)
+        self.dirs.add(mdir)
+
+        with open(path, 'r') as fh:
+            urlprefix = ''
+            for line in fh:
+                line = line.decode('utf-8')
+
+                # Entire line is a comment.
+                if line.startswith('#'):
+                    continue
+
+                # Comments can begin mid line. Strip them.
+                m = RE_COMMENT.search(line)
+                if m:
+                    line = line[:m.start()]
+
+                line = line.strip()
+                if not line:
+                    continue
+
+                items = line.split()
+                tests = []
+
+                for i in range(len(items)):
+                    item = items[i]
+
+                    if item.startswith(FAILURE_TYPES):
+                        continue
+                    if item.startswith(PREF_ITEMS):
+                        continue
+                    if item == 'HTTP':
+                        continue
+
+                    m = RE_HTTP.match(item)
+                    if m:
+                        # Need to package the referenced directory.
+                        self.dirs.add(os.path.normpath(os.path.join(
+                            mdir, m.group(1))))
+                        continue
+
+                    if item == 'url-prefix':
+                        urlprefix = items[i+1]
+                        break
+
+                    if item == 'default-preferences':
+                        break
+
+                    if item == 'include':
+                        self.load(os.path.join(mdir, items[i+1]))
+                        break
+
+                    if item == 'load' or item == 'script':
+                        tests.append(items[i+1])
+                        break
+
+                    if item == '==' or item == '!=':
+                        tests.extend(items[i+1:i+3])
+                        break
+
+                for f in tests:
+                    # We can't package about: or data: URIs.
+                    # Discarding data isn't correct for a parser. But retaining
+                    # all data isn't currently a requirement.
+                    if RE_PROTOCOL.match(f):
+                        continue
+
+                    test = os.path.normpath(os.path.join(mdir, urlprefix + f))
+                    self.files.add(test)
+                    self.dirs.add(os.path.dirname(test))