Example #1
0
def check_css_globally_unique(repo_root, paths):
    """
    Checks that CSS filenames are sufficiently unique

    This groups files by path classifying them as "test", "reference", or
    "support".

    "test" files must have a unique name across files that share links to the
    same spec.

    "reference" and "support" files, on the other hand, must have globally
    unique names.

    :param repo_root: the repository root
    :param paths: list of all paths
    :returns: a list of errors found in ``paths``

    """
    test_files = defaultdict(set)
    ref_files = defaultdict(set)
    support_files = defaultdict(set)

    for path in paths:
        if os.name == "nt":
            path = path.replace("\\", "/")

        if not path.startswith("css/"):
            continue

        source_file = SourceFile(repo_root, path, "/")
        if source_file.name_is_non_test:
            # If we're name_is_non_test for a reason apart from support, ignore it.
            # We care about support because of the requirement all support files in css/ to be in
            # a support directory; see the start of check_parsed.
            offset = path.find("/support/")
            if offset == -1:
                continue

            parts = source_file.dir_path.split(os.path.sep)
            if (parts[0] in source_file.root_dir_non_test
                    or any(item in source_file.dir_non_test - {"support"}
                           for item in parts) or
                    any(parts[:len(non_test_path)] == list(non_test_path)
                        for non_test_path in source_file.dir_path_non_test)):
                continue

            name = path[offset + 1:]
            support_files[name].add(path)
        elif source_file.name_is_reference:
            ref_files[source_file.name].add(path)
        else:
            name = source_file.name.replace('-manual', '')
            test_files[name].add(path)

    errors = []

    for name, colliding in iteritems(test_files):
        if len(colliding) > 1:
            if not _all_files_equal(
                [os.path.join(repo_root, x) for x in colliding]):
                # Only compute by_spec if there are prima-facie collisions because of cost
                by_spec = defaultdict(set)
                for path in colliding:
                    source_file = SourceFile(repo_root, path, "/")
                    for link in source_file.spec_links:
                        for r in (drafts_csswg_re, w3c_tr_re, w3c_dev_re):
                            m = r.match(link)
                            if m:
                                spec = m.group(1)
                                break
                        else:
                            continue
                        by_spec[spec].add(path)

                for spec, paths in iteritems(by_spec):
                    if not _all_files_equal(
                        [os.path.join(repo_root, x) for x in paths]):
                        for x in paths:
                            context = (name, spec, ", ".join(sorted(paths)))
                            errors.append(
                                rules.CSSCollidingTestName.error(x, context))

    for rule_class, d in [(rules.CSSCollidingRefName, ref_files),
                          (rules.CSSCollidingSupportName, support_files)]:
        for name, colliding in iteritems(d):
            if len(colliding) > 1:
                if not _all_files_equal(
                    [os.path.join(repo_root, x) for x in colliding]):
                    context = (name, ", ".join(sorted(colliding)))

                    for x in colliding:
                        errors.append(rule_class.error(x, context))

    return errors
Example #2
0
def check_parsed(repo_root, path, f):
    source_file = SourceFile(repo_root, path, "/", contents=f.read())

    errors = []

    if path.startswith("css/"):
        if (source_file.type == "support" and
            not source_file.name_is_non_test and
            not source_file.name_is_reference):
            return [("SUPPORT-WRONG-DIR", "Support file not in support directory", path, None)]

        if (source_file.type != "support" and
            not source_file.name_is_reference and
            not source_file.spec_links):
            return [("MISSING-LINK", "Testcase file must have a link to a spec", path, None)]

    if source_file.name_is_non_test or source_file.name_is_manual:
        return []

    if source_file.markup_type is None:
        return []

    if source_file.root is None:
        return [("PARSE-FAILED", "Unable to parse file", path, None)]

    if source_file.type == "manual" and not source_file.name_is_manual:
        return [("CONTENT-MANUAL", "Manual test whose filename doesn't end in '-manual'", path, None)]

    if source_file.type == "visual" and not source_file.name_is_visual:
        return [("CONTENT-VISUAL", "Visual test whose filename doesn't end in '-visual'", path, None)]

    for reftest_node in source_file.reftest_nodes:
        href = reftest_node.attrib.get("href", "").strip(space_chars)
        parts = urlsplit(href)
        if (parts.scheme or parts.netloc) and parts != urlsplit("about:blank"):
            errors.append(("ABSOLUTE-URL-REF",
                     "Reference test with a reference file specified via an absolute URL: '%s'" % href, path, None))
            continue

        ref_url = urljoin(source_file.url, href)
        ref_parts = urlsplit(ref_url)

        if source_file.url == ref_url:
            errors.append(("SAME-FILE-REF",
                           "Reference test which points at itself as a reference",
                           path,
                           None))
            continue

        assert ref_parts.path != ""

        reference_file = os.path.join(repo_root, ref_parts.path[1:])
        reference_rel = reftest_node.attrib.get("rel", "")

        if not os.path.isfile(reference_file):
            errors.append(("NON-EXISTENT-REF",
                     "Reference test with a non-existent '%s' relationship reference: '%s'" % (reference_rel, href), path, None))

    if len(source_file.timeout_nodes) > 1:
        errors.append(("MULTIPLE-TIMEOUT", "More than one meta name='timeout'", path, None))

    for timeout_node in source_file.timeout_nodes:
        timeout_value = timeout_node.attrib.get("content", "").lower()
        if timeout_value != "long":
            errors.append(("INVALID-TIMEOUT", "Invalid timeout value %s" % timeout_value, path, None))

    if source_file.testharness_nodes:
        if len(source_file.testharness_nodes) > 1:
            errors.append(("MULTIPLE-TESTHARNESS",
                           "More than one <script src='/resources/testharness.js'>", path, None))

        testharnessreport_nodes = source_file.root.findall(".//{http://www.w3.org/1999/xhtml}script[@src='/resources/testharnessreport.js']")
        if not testharnessreport_nodes:
            errors.append(("MISSING-TESTHARNESSREPORT",
                           "Missing <script src='/resources/testharnessreport.js'>", path, None))
        else:
            if len(testharnessreport_nodes) > 1:
                errors.append(("MULTIPLE-TESTHARNESSREPORT",
                               "More than one <script src='/resources/testharnessreport.js'>", path, None))

        testharnesscss_nodes = source_file.root.findall(".//{http://www.w3.org/1999/xhtml}link[@href='/resources/testharness.css']")
        if testharnesscss_nodes:
            errors.append(("PRESENT-TESTHARNESSCSS",
                           "Explicit link to testharness.css present", path, None))

        for element in source_file.variant_nodes:
            if "content" not in element.attrib:
                errors.append(("VARIANT-MISSING",
                               "<meta name=variant> missing 'content' attribute", path, None))
            else:
                variant = element.attrib["content"]
                if variant != "" and variant[0] not in ("?", "#"):
                    errors.append(("MALFORMED-VARIANT",
                               "%s <meta name=variant> 'content' attribute must be the empty string or start with '?' or '#'" % path, None))

        seen_elements = {"timeout": False,
                         "testharness": False,
                         "testharnessreport": False}
        required_elements = [key for key, value in {"testharness": True,
                                                    "testharnessreport": len(testharnessreport_nodes) > 0,
                                                    "timeout": len(source_file.timeout_nodes) > 0}.items()
                             if value]

        for elem in source_file.root.iter():
            if source_file.timeout_nodes and elem == source_file.timeout_nodes[0]:
                seen_elements["timeout"] = True
                if seen_elements["testharness"]:
                    errors.append(("LATE-TIMEOUT",
                                   "<meta name=timeout> seen after testharness.js script", path, None))

            elif elem == source_file.testharness_nodes[0]:
                seen_elements["testharness"] = True

            elif testharnessreport_nodes and elem == testharnessreport_nodes[0]:
                seen_elements["testharnessreport"] = True
                if not seen_elements["testharness"]:
                    errors.append(("EARLY-TESTHARNESSREPORT",
                                   "testharnessreport.js script seen before testharness.js script", path, None))

            if all(seen_elements[name] for name in required_elements):
                break

    if source_file.testdriver_nodes:
        if len(source_file.testdriver_nodes) > 1:
            errors.append(("MULTIPLE-TESTDRIVER",
                           "More than one <script src='/resources/testdriver.js'>", path, None))

        testdriver_vendor_nodes = source_file.root.findall(".//{http://www.w3.org/1999/xhtml}script[@src='/resources/testdriver-vendor.js']")
        if not testdriver_vendor_nodes:
            errors.append(("MISSING-TESTDRIVER-VENDOR",
                           "Missing <script src='/resources/testdriver-vendor.js'>", path, None))
        else:
            if len(testdriver_vendor_nodes) > 1:
                errors.append(("MULTIPLE-TESTDRIVER-VENDOR",
                               "More than one <script src='/resources/testdriver-vendor.js'>", path, None))

    for element in source_file.root.findall(".//{http://www.w3.org/1999/xhtml}script[@src]"):
        src = element.attrib["src"]
        for name in ["testharness", "testharnessreport", "testdriver", "testdriver-vendor"]:
            if "%s.js" % name == src or ("/%s.js" % name in src and src != "/resources/%s.js" % name):
                errors.append(("%s-PATH" % name.upper(), "%s.js script seen with incorrect path" % name, path, None))

    return errors
Example #3
0
def check_parsed(repo_root, path, f, css_mode):
    source_file = SourceFile(repo_root, path, "/", contents=f.read())

    errors = []

    if css_mode or path.startswith("css/"):
        if (source_file.type == "support" and not source_file.name_is_non_test
                and not source_file.name_is_reference):
            return [("SUPPORT-WRONG-DIR",
                     "Support file not in support directory", path, None)]

    if source_file.name_is_non_test or source_file.name_is_manual:
        return []

    if source_file.markup_type is None:
        return []

    if source_file.root is None:
        return [("PARSE-FAILED", "Unable to parse file", path, None)]

    if source_file.type == "manual" and not source_file.name_is_manual:
        return [
            ("CONTENT-MANUAL",
             "Manual test whose filename doesn't end in '-manual'", path, None)
        ]

    if source_file.type == "visual" and not source_file.name_is_visual:
        return [
            ("CONTENT-VISUAL",
             "Visual test whose filename doesn't end in '-visual'", path, None)
        ]

    if len(source_file.timeout_nodes) > 1:
        errors.append(("MULTIPLE-TIMEOUT", "More than one meta name='timeout'",
                       path, None))

    for timeout_node in source_file.timeout_nodes:
        timeout_value = timeout_node.attrib.get("content", "").lower()
        if timeout_value != "long":
            errors.append(
                ("INVALID-TIMEOUT", "Invalid timeout value %s" % timeout_value,
                 path, None))

    if source_file.testharness_nodes:
        if len(source_file.testharness_nodes) > 1:
            errors.append(
                ("MULTIPLE-TESTHARNESS",
                 "More than one <script src='/resources/testharness.js'>",
                 path, None))

        testharnessreport_nodes = source_file.root.findall(
            ".//{http://www.w3.org/1999/xhtml}script[@src='/resources/testharnessreport.js']"
        )
        if not testharnessreport_nodes:
            errors.append(
                ("MISSING-TESTHARNESSREPORT",
                 "Missing <script src='/resources/testharnessreport.js'>",
                 path, None))
        else:
            if len(testharnessreport_nodes) > 1:
                errors.append((
                    "MULTIPLE-TESTHARNESSREPORT",
                    "More than one <script src='/resources/testharnessreport.js'>",
                    path, None))

        testharnesscss_nodes = source_file.root.findall(
            ".//{http://www.w3.org/1999/xhtml}link[@href='/resources/testharness.css']"
        )
        if testharnesscss_nodes:
            errors.append(
                ("PRESENT-TESTHARNESSCSS",
                 "Explicit link to testharness.css present", path, None))

        for element in source_file.variant_nodes:
            if "content" not in element.attrib:
                errors.append(
                    ("VARIANT-MISSING",
                     "<meta name=variant> missing 'content' attribute", path,
                     None))
            else:
                variant = element.attrib["content"]
                if variant != "" and variant[0] not in ("?", "#"):
                    errors.append((
                        "MALFORMED-VARIANT",
                        "%s <meta name=variant> 'content' attribute must be the empty string or start with '?' or '#'"
                        % path, None))

        seen_elements = {
            "timeout": False,
            "testharness": False,
            "testharnessreport": False
        }
        required_elements = [
            key for key, value in {
                "testharness": True,
                "testharnessreport": len(testharnessreport_nodes) > 0,
                "timeout": len(source_file.timeout_nodes) > 0
            }.items() if value
        ]

        for elem in source_file.root.iter():
            if source_file.timeout_nodes and elem == source_file.timeout_nodes[
                    0]:
                seen_elements["timeout"] = True
                if seen_elements["testharness"]:
                    errors.append((
                        "LATE-TIMEOUT",
                        "<meta name=timeout> seen after testharness.js script",
                        path, None))

            elif elem == source_file.testharness_nodes[0]:
                seen_elements["testharness"] = True

            elif testharnessreport_nodes and elem == testharnessreport_nodes[0]:
                seen_elements["testharnessreport"] = True
                if not seen_elements["testharness"]:
                    errors.append((
                        "EARLY-TESTHARNESSREPORT",
                        "testharnessreport.js script seen before testharness.js script",
                        path, None))

            if all(seen_elements[name] for name in required_elements):
                break

    for element in source_file.root.findall(
            ".//{http://www.w3.org/1999/xhtml}script[@src]"):
        src = element.attrib["src"]
        for name in ["testharness", "testharnessreport"]:
            if "%s.js" % name == src or ("/%s.js" % name in src
                                         and src != "/resources/%s.js" % name):
                errors.append(("%s-PATH" % name.upper(),
                               "%s.js script seen with incorrect path" % name,
                               path, None))

    return errors
Example #4
0
def check_parsed(path, f):
    source_file = SourceFile(repo_root, path, "/")

    errors = []

    if source_file.name_is_non_test or source_file.name_is_manual:
        return []

    if source_file.markup_type is None:
        return []

    if source_file.root is None:
        return [("PARSE-FAILED", "Unable to parse file %s" % path, None)]

    if len(source_file.timeout_nodes) > 1:
        errors.append(("MULTIPLE-TIMEOUT", "%s more than one meta name='timeout'" % path, None))

    for timeout_node in source_file.timeout_nodes:
        timeout_value = timeout_node.attrib.get("content", "").lower()
        if timeout_value != "long":
            errors.append(("INVALID-TIMEOUT", "%s invalid timeout value %s" % (path, timeout_value), None))

    if source_file.testharness_nodes:
        if len(source_file.testharness_nodes) > 1:
            errors.append(("MULTIPLE-TESTHARNESS",
                           "%s more than one <script src='/resources/testharness.js'>" % path, None))

        testharnessreport_nodes = source_file.root.findall(".//{http://www.w3.org/1999/xhtml}script[@src='/resources/testharnessreport.js']")
        if not testharnessreport_nodes:
            errors.append(("MISSING-TESTHARNESSREPORT",
                           "%s missing <script src='/resources/testharnessreport.js'>" % path, None))
        else:
            if len(testharnessreport_nodes) > 1:
                errors.append(("MULTIPLE-TESTHARNESSREPORT",
                               "%s more than one <script src='/resources/testharnessreport.js'>" % path, None))

        for element in source_file.variant_nodes:
            if "content" not in element.attrib:
                errors.append(("VARIANT-MISSING",
                               "%s has <meta name=variant> missing 'content' attribute" % path, None))
            else:
                variant = element.attrib["content"]
                if variant != "" and variant[0] not in ("?", "#"):
                    errors.append(("MALFORMED-VARIANT",
                               "%s <meta name=variant> 'content' attribute must be the empty string or start with '?' or '#'" % path, None))

        seen_elements = {"timeout": False,
                         "testharness": False,
                         "testharnessreport": False}
        required_elements = [key for key, value in {"testharness": True,
                                                    "testharnessreport": len(testharnessreport_nodes) > 0,
                                                    "timeout": len(source_file.timeout_nodes) > 0}.iteritems()
                             if value]

        for elem in source_file.root.iter():
            if source_file.timeout_nodes and elem == source_file.timeout_nodes[0]:
                seen_elements["timeout"] = True
                if seen_elements["testharness"]:
                    errors.append(("LATE-TIMEOUT",
                                   "%s <meta name=timeout> seen after testharness.js script" % path, None))

            elif elem == source_file.testharness_nodes[0]:
                seen_elements["testharness"] = True

            elif testharnessreport_nodes and elem == testharnessreport_nodes[0]:
                seen_elements["testharnessreport"] = True
                if not seen_elements["testharness"]:
                    errors.append(("EARLY-TESTHARNESSREPORT",
                                   "%s testharnessreport.js script seen before testharness.js script" % path, None))

            if all(seen_elements[name] for name in required_elements):
                break

    return errors
Example #5
0
 def __init__(self, id, path, timeout=10, contents=testharness_test):
     self.id = id
     self.url = "/" + path
     self.item_type = "testharness"
     self.timeout = timeout
     self.source_file = SourceFile("/", path, "/", contents=contents)