layout/reftests/w3c-css/import-tests.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/reftests/w3c-css/import-tests.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,317 @@
     1.4 +#!/usr/bin/python
     1.5 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.6 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.8 +import os
     1.9 +from optparse import OptionParser
    1.10 +from subprocess import Popen, PIPE
    1.11 +import xml.dom.minidom
    1.12 +import html5lib
    1.13 +import shutil
    1.14 +import sys
    1.15 +import re
    1.16 +
    1.17 +# FIXME:
    1.18 +#   * Import more tests rather than just the very limited set currently
    1.19 +#     chosen.
    1.20 +#   * Read in a (checked-in) input file with a list of test assertions
    1.21 +#     expected to fail.
    1.22 +#   * Read in a (checked-in) input file with a list of reference choices
    1.23 +#     for tests with multiple rel="match" references.  (But still go
    1.24 +#     though all those references in case they, in turn, have references.)
    1.25 +
    1.26 +# Eventually we should import all the tests that have references.  (At
    1.27 +# least for a subset of secs.  And we probably want to organize the
    1.28 +# directory structure by spec to avoid constant file moves when files
    1.29 +# move in the W3C repository.  And we probably also want to import each
    1.30 +# test only once, even if it covers more than one spec.)
    1.31 +
    1.32 +# But for now, let's just import a few sets of tests.
    1.33 +
    1.34 +gSubtrees = [
    1.35 +    os.path.join("approved", "css3-namespace", "src"),
    1.36 +    #os.path.join("approved", "css3-multicol", "src"),
    1.37 +    os.path.join("contributors", "opera", "submitted", "css3-conditional"),
    1.38 +    #os.path.join("contributors", "opera", "submitted", "multicol")
    1.39 +]
    1.40 +
    1.41 +gPrefixedProperties = [
    1.42 +    "column-count",
    1.43 +    "column-fill",
    1.44 +    "column-gap",
    1.45 +    "column-rule",
    1.46 +    "column-rule-color",
    1.47 +    "column-rule-style",
    1.48 +    "column-rule-width",
    1.49 +    "columns",
    1.50 +    "column-span",
    1.51 +    "column-width"
    1.52 +]
    1.53 +
    1.54 +gDefaultPreferences = {
    1.55 +    "css3-conditional": "pref(layout.css.supports-rule.enabled,true)"
    1.56 +}
    1.57 +
    1.58 +gLog = None
    1.59 +gFailList = {}
    1.60 +gDestPath = None
    1.61 +gSrcPath = None
    1.62 +support_dirs_mapped = set()
    1.63 +filemap = {}
    1.64 +speclinkmap = {}
    1.65 +propsaddedfor = []
    1.66 +tests = []
    1.67 +gOptions = None
    1.68 +gArgs = None
    1.69 +gTestfiles = []
    1.70 +gTestFlags = {}
    1.71 +
    1.72 +def log_output_of(subprocess):
    1.73 +    global gLog
    1.74 +    subprocess.wait()
    1.75 +    if (subprocess.returncode != 0):
    1.76 +        raise StandardError("error while running subprocess")
    1.77 +    gLog.write(subprocess.stdout.readline().rstrip())
    1.78 +
    1.79 +def write_log_header():
    1.80 +    global gLog, gSrcPath
    1.81 +    gLog.write("Importing revision: ")
    1.82 +    log_output_of(Popen(["hg", "parent", "--template={node}"],
    1.83 +                  stdout=PIPE, cwd=gSrcPath))
    1.84 +    gLog.write("\nfrom repository: ")
    1.85 +    log_output_of(Popen(["hg", "paths", "default"],
    1.86 +                  stdout=PIPE, cwd=gSrcPath))
    1.87 +    gLog.write("\n")
    1.88 +
    1.89 +def remove_existing_dirs():
    1.90 +    global gDestPath
    1.91 +    # Remove existing directories that we're going to regenerate.  This
    1.92 +    # is necessary so that we can give errors in cases where our import
    1.93 +    # might copy two files to the same location, which we do by giving
    1.94 +    # errors if a copy would overwrite a file.
    1.95 +    for dirname in os.listdir(gDestPath):
    1.96 +        fulldir = os.path.join(gDestPath, dirname)
    1.97 +        if not os.path.isdir(fulldir):
    1.98 +            continue
    1.99 +        shutil.rmtree(fulldir)
   1.100 +
   1.101 +def populate_test_files():
   1.102 +    global gSubtrees, gTestfiles
   1.103 +    for subtree in gSubtrees:
   1.104 +        for dirpath, dirnames, filenames in os.walk(subtree, topdown=True):
   1.105 +            if "support" in dirnames:
   1.106 +               dirnames.remove("support")
   1.107 +            if "reftest" in dirnames:
   1.108 +               dirnames.remove("reftest")
   1.109 +            for f in filenames:
   1.110 +                if f == "README" or \
   1.111 +                   f.find("-ref.") != -1:
   1.112 +                    continue
   1.113 +                gTestfiles.append(os.path.join(dirpath, f))
   1.114 +
   1.115 +    gTestfiles.sort()
   1.116 +
   1.117 +def copy_file(test, srcfile, destname, isSupportFile=False):
   1.118 +    global gDestPath, gLog, gSrcPath
   1.119 +    if not srcfile.startswith(gSrcPath):
   1.120 +        raise StandardError("Filename " + srcfile + " does not start with " + gSrcPath)
   1.121 +    logname = srcfile[len(gSrcPath):]
   1.122 +    gLog.write("Importing " + logname + " to " + destname + "\n")
   1.123 +    destfile = os.path.join(gDestPath, destname)
   1.124 +    destdir = os.path.dirname(destfile)
   1.125 +    if not os.path.exists(destdir):
   1.126 +        os.makedirs(destdir)
   1.127 +    if os.path.exists(destfile):
   1.128 +        raise StandardError("file " + destfile + " already exists")
   1.129 +    copy_and_prefix(test, srcfile, destfile, gPrefixedProperties, isSupportFile)
   1.130 +
   1.131 +def copy_support_files(test, dirname, spec):
   1.132 +    if dirname in support_dirs_mapped:
   1.133 +        return
   1.134 +    support_dirs_mapped.add(dirname)
   1.135 +    support_dir = os.path.join(dirname, "support")
   1.136 +    if not os.path.exists(support_dir):
   1.137 +        return
   1.138 +    for dirpath, dirnames, filenames in os.walk(support_dir):
   1.139 +        for fn in filenames:
   1.140 +            if fn == "LOCK":
   1.141 +                continue
   1.142 +            full_fn = os.path.join(dirpath, fn)
   1.143 +            copy_file(test, full_fn, os.path.join(spec, "support", full_fn[len(support_dir)+1:]), True)
   1.144 +
   1.145 +def map_file(fn, spec):
   1.146 +    if fn in filemap:
   1.147 +        return filemap[fn]
   1.148 +    destname = os.path.join(spec, os.path.basename(fn))
   1.149 +    filemap[fn] = destname
   1.150 +    load_flags_for(fn, spec)
   1.151 +    copy_file(destname, fn, destname, False)
   1.152 +    copy_support_files(destname, os.path.dirname(fn), spec)
   1.153 +    return destname
   1.154 +
   1.155 +def load_flags_for(fn, spec):
   1.156 +    global gTestFlags
   1.157 +    document = get_document_for(fn, spec)
   1.158 +    destname = os.path.join(spec, os.path.basename(fn))
   1.159 +    gTestFlags[destname] = []
   1.160 +
   1.161 +    for meta in document.getElementsByTagName("meta"):
   1.162 +        name = meta.getAttribute("name")
   1.163 +        if name == "flags":
   1.164 +            gTestFlags[destname] = meta.getAttribute("content").split()
   1.165 +
   1.166 +def get_document_for(fn, spec):
   1.167 +    document = None # an xml.dom.minidom document
   1.168 +    if fn.endswith(".htm") or fn.endswith(".html"):
   1.169 +        # An HTML file
   1.170 +        f = open(fn, "r")
   1.171 +        parser = html5lib.HTMLParser(tree=html5lib.treebuilders.getTreeBuilder("dom"))
   1.172 +        document = parser.parse(f)
   1.173 +        f.close()
   1.174 +    else:
   1.175 +        # An XML file
   1.176 +        document = xml.dom.minidom.parse(fn)
   1.177 +    return document
   1.178 +
   1.179 +def add_test_items(fn, spec):
   1.180 +    document = get_document_for(fn, spec)
   1.181 +    refs = []
   1.182 +    notrefs = []
   1.183 +    for link in document.getElementsByTagName("link"):
   1.184 +        rel = link.getAttribute("rel")
   1.185 +        if rel == "help" and spec == None:
   1.186 +            specurl = link.getAttribute("href")
   1.187 +            startidx = specurl.find("/TR/")
   1.188 +            if startidx != -1:
   1.189 +                startidx = startidx + 4
   1.190 +                endidx = specurl.find("/", startidx)
   1.191 +                if endidx != -1:
   1.192 +                    spec = str(specurl[startidx:endidx])
   1.193 +        if rel == "match":
   1.194 +            arr = refs
   1.195 +        elif rel == "mismatch":
   1.196 +            arr = notrefs
   1.197 +        else:
   1.198 +            continue
   1.199 +        arr.append(os.path.join(os.path.dirname(fn), str(link.getAttribute("href"))))
   1.200 +    if len(refs) > 1:
   1.201 +        raise StandardError("Need to add code to specify which reference we want to match.")
   1.202 +    if spec is None:
   1.203 +        raise StandardError("Could not associate test with specification")
   1.204 +    for ref in refs:
   1.205 +        tests.append(["==", map_file(fn, spec), map_file(ref, spec)])
   1.206 +    for notref in notrefs:
   1.207 +        tests.append(["!=", map_file(fn, spec), map_file(notref, spec)])
   1.208 +    # Add chained references too
   1.209 +    for ref in refs:
   1.210 +        add_test_items(ref, spec=spec)
   1.211 +    for notref in notrefs:
   1.212 +        add_test_items(notref, spec=spec)
   1.213 +
   1.214 +def copy_and_prefix(test, aSourceFileName, aDestFileName, aProps, isSupportFile=False):
   1.215 +    global gTestFlags
   1.216 +    newFile = open(aDestFileName, 'w')
   1.217 +    unPrefixedFile = open(aSourceFileName)
   1.218 +    testName = aDestFileName[len(gDestPath)+1:]
   1.219 +    ahemFontAdded = False
   1.220 +    for line in unPrefixedFile:
   1.221 +        replacementLine = line
   1.222 +        searchRegex = "\s*<style\s*"
   1.223 +
   1.224 +        if not isSupportFile and not ahemFontAdded and 'ahem' in gTestFlags[test] and re.search(searchRegex, line):
   1.225 +            # First put our ahem font declation before the first <style>
   1.226 +            # element
   1.227 +            ahemFontDecl = "<style type=\"text/css\"><![CDATA[\n@font-face "\
   1.228 +                           "{\n  font-family: Ahem;\n  src: url("\
   1.229 +                           "\"../../../fonts/Ahem.ttf\");\n}\n]]></style>\n"
   1.230 +            newFile.write(ahemFontDecl)
   1.231 +            ahemFontAdded = True
   1.232 +
   1.233 +        for rule in aProps:
   1.234 +            replacementLine = replacementLine.replace(rule, "-moz-" + rule)
   1.235 +        newFile.write(replacementLine)
   1.236 +
   1.237 +    newFile.close()
   1.238 +    unPrefixedFile.close()
   1.239 +
   1.240 +def read_options():
   1.241 +    global gArgs, gOptions
   1.242 +    op = OptionParser()
   1.243 +    op.usage = \
   1.244 +    '''%prog <clone of hg repository>
   1.245 +            Import reftests from a W3C hg repository clone. The location of
   1.246 +            the local clone of the hg repository must be given on the command
   1.247 +            line.'''
   1.248 +    (gOptions, gArgs) = op.parse_args()
   1.249 +    if len(gArgs) != 1:
   1.250 +        op.error("Too few arguments specified.")
   1.251 +
   1.252 +def setup_paths():
   1.253 +    global gSubtrees, gDestPath, gSrcPath
   1.254 +    # FIXME: generate gSrcPath with consistent trailing / regardless of input.
   1.255 +    # (We currently expect the argument to have a trailing slash.)
   1.256 +    gSrcPath = gArgs[0]
   1.257 +    if not os.path.isdir(gSrcPath) or \
   1.258 +    not os.path.isdir(os.path.join(gSrcPath, ".hg")):
   1.259 +        raise StandardError("source path does not appear to be a mercurial clone")
   1.260 +
   1.261 +    gDestPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "received")
   1.262 +    newSubtrees = []
   1.263 +    for relPath in gSubtrees:
   1.264 +        newSubtrees[len(gSubtrees):] = [os.path.join(gSrcPath, relPath)]
   1.265 +    gSubtrees = newSubtrees
   1.266 +
   1.267 +def setup_log():
   1.268 +    global gLog
   1.269 +    # Since we're going to commit the tests, we should also commit
   1.270 +    # information about where they came from.
   1.271 +    gLog = open(os.path.join(gDestPath, "import.log"), "w")
   1.272 +
   1.273 +def read_fail_list():
   1.274 +    global gFailList
   1.275 +    dirname = os.path.realpath(__file__).split(os.path.sep)
   1.276 +    dirname = os.path.sep.join(dirname[:len(dirname)-1])
   1.277 +    failListFile = open(os.path.join(dirname, "failures.list"), "r")
   1.278 +    gFailList = [x for x in [x.lstrip().rstrip() for x in failListFile] if bool(x)
   1.279 +                 and not x.startswith("#")]
   1.280 +    failListFile.close()
   1.281 +
   1.282 +def main():
   1.283 +    global gDestPath, gLog, gTestfiles, gTestFlags, gFailList
   1.284 +    read_options()
   1.285 +    setup_paths()
   1.286 +    read_fail_list()
   1.287 +    setup_log()
   1.288 +    write_log_header()
   1.289 +    remove_existing_dirs()
   1.290 +    populate_test_files()
   1.291 +
   1.292 +    for t in gTestfiles:
   1.293 +        add_test_items(t, spec=None)
   1.294 +
   1.295 +    listfile = open(os.path.join(gDestPath, "reftest.list"), "w")
   1.296 +    listfile.write("# THIS FILE IS AUTOGENERATED BY {0}\n# DO NOT EDIT!\n".format(os.path.basename(__file__)))
   1.297 +    lastDefaultPreferences = None
   1.298 +    for test in tests:
   1.299 +        defaultPreferences = gDefaultPreferences.get(test[1].split("/")[0], None)
   1.300 +        if defaultPreferences != lastDefaultPreferences:
   1.301 +            if defaultPreferences is None:
   1.302 +                listfile.write("\ndefault-preferences\n\n")
   1.303 +            else:
   1.304 +                listfile.write("\ndefault-preferences {0}\n\n".format(defaultPreferences))
   1.305 +            lastDefaultPreferences = defaultPreferences
   1.306 +        key = 0
   1.307 +        while not test[key] in gTestFlags.keys() and key < len(test):
   1.308 +            key = key + 1
   1.309 +        testKey = test[key]
   1.310 +        if 'ahem' in gTestFlags[testKey]:
   1.311 +            test = ["HTTP(../../..)"] + test
   1.312 +        if testKey in gFailList:
   1.313 +            test = ["fails"] + test
   1.314 +        listfile.write(" ".join(test) + "\n")
   1.315 +    listfile.close()
   1.316 +
   1.317 +    gLog.close()
   1.318 +
   1.319 +if __name__ == '__main__':
   1.320 +    main()

mercurial