| from __future__ import unicode_literals |
| |
| import abc |
| import os |
| import re |
| |
| import six |
| |
| MYPY = False |
| if MYPY: |
| # MYPY is set to True when run under Mypy. |
| from typing import List, Optional, Pattern, Text, Match |
| |
| |
| class Rule(six.with_metaclass(abc.ABCMeta)): |
| @abc.abstractproperty |
| def name(self): |
| # type: () -> Text |
| pass |
| |
| @abc.abstractproperty |
| def description(self): |
| # type: () -> Text |
| pass |
| |
| to_fix = None # type: Optional[Text] |
| |
| @classmethod |
| def error(cls, path, context=(), line_no=None): |
| description = cls.description % context |
| return (cls.name, description, path, line_no) |
| |
| |
| class MissingLink(Rule): |
| name = "MISSING-LINK" |
| description = "Testcase file must have a link to a spec" |
| to_fix = """ |
| Ensure that there is a `<link rel="help" href="[url]">` for the spec. |
| `MISSING-LINK` is designed to ensure that the CSS build tool can find |
| the tests. Note that the CSS build system is primarily used by |
| [test.csswg.org/](http://test.csswg.org/), which doesn't use |
| `wptserve`, so `*.any.js` and similar tests won't work there; stick |
| with the `.html` equivalent. |
| """ |
| |
| |
| class PathLength(Rule): |
| name = "PATH LENGTH" |
| description = "/%s longer than maximum path length (%d > 150)" |
| |
| |
| class WorkerCollision(Rule): |
| name = "WORKER COLLISION" |
| description = ("path ends with %s which collides with generated tests " |
| "from %s files") |
| |
| |
| class GitIgnoreFile(Rule): |
| name = "GITIGNORE" |
| description = ".gitignore found outside the root" |
| |
| |
| class AhemCopy(Rule): |
| name = "AHEM COPY" |
| description = "Don't add extra copies of Ahem, use /fonts/Ahem.ttf" |
| |
| |
| # TODO: Add tests for this rule |
| class IgnoredPath(Rule): |
| name = "IGNORED PATH" |
| description = ("%s matches an ignore filter in .gitignore - " |
| "please add a .gitignore exception") |
| |
| |
| class CSSCollidingTestName(Rule): |
| name = "CSS-COLLIDING-TEST-NAME" |
| description = "The filename %s in the %s testsuite is shared by: %s" |
| |
| |
| class CSSCollidingRefName(Rule): |
| name = "CSS-COLLIDING-REF-NAME" |
| description = "The filename %s is shared by: %s" |
| |
| |
| class CSSCollidingSupportName(Rule): |
| name = "CSS-COLLIDING-SUPPORT-NAME" |
| description = "The filename %s is shared by: %s" |
| |
| |
| class SupportWrongDir(Rule): |
| name = "SUPPORT-WRONG-DIR" |
| description = "Support file not in support directory" |
| |
| |
| class ParseFailed(Rule): |
| name = "PARSE-FAILED" |
| description = "Unable to parse file" |
| |
| |
| class ContentManual(Rule): |
| name = "CONTENT-MANUAL" |
| description = "Manual test whose filename doesn't end in '-manual'" |
| |
| |
| class ContentVisual(Rule): |
| name = "CONTENT-VISUAL" |
| description = "Visual test whose filename doesn't end in '-visual'" |
| |
| |
| class AbsoluteUrlRef(Rule): |
| name = "ABSOLUTE-URL-REF" |
| description = ("Reference test with a reference file specified via an " |
| "absolute URL: '%s'") |
| |
| |
| class SameFileRef(Rule): |
| name = "SAME-FILE-REF" |
| description = "Reference test which points at itself as a reference" |
| |
| |
| class NonexistentRef(Rule): |
| name = "NON-EXISTENT-REF" |
| description = ("Reference test with a non-existent '%s' relationship " |
| "reference: '%s'") |
| |
| |
| class MultipleTimeout(Rule): |
| name = "MULTIPLE-TIMEOUT" |
| description = "More than one meta name='timeout'" |
| |
| |
| class InvalidTimeout(Rule): |
| name = "INVALID-TIMEOUT" |
| description = "Invalid timeout value %s" |
| |
| |
| class MultipleTestharness(Rule): |
| name = "MULTIPLE-TESTHARNESS" |
| description = "More than one <script src='/resources/testharness.js'>" |
| |
| |
| class MissingTestharnessReport(Rule): |
| name = "MISSING-TESTHARNESSREPORT" |
| description = "Missing <script src='/resources/testharnessreport.js'>" |
| |
| |
| class MultipleTestharnessReport(Rule): |
| name = "MULTIPLE-TESTHARNESSREPORT" |
| description = "More than one <script src='/resources/testharnessreport.js'>" |
| |
| |
| class PresentTestharnessCSS(Rule): |
| name = "PRESENT-TESTHARNESSCSS" |
| description = "Explicit link to testharness.css present" |
| |
| |
| class VariantMissing(Rule): |
| name = "VARIANT-MISSING" |
| description = "<meta name=variant> missing 'content' attribute" |
| |
| |
| class MalformedVariant(Rule): |
| name = "MALFORMED-VARIANT" |
| description = ("%s <meta name=variant> 'content' attribute must be the " |
| "empty string or start with '?' or '#'") |
| |
| |
| class LateTimeout(Rule): |
| name = "LATE-TIMEOUT" |
| description = "<meta name=timeout> seen after testharness.js script" |
| |
| |
| class EarlyTestharnessReport(Rule): |
| name = "EARLY-TESTHARNESSREPORT" |
| description = "testharnessreport.js script seen before testharness.js script" |
| |
| |
| class MultipleTestdriver(Rule): |
| name = "MULTIPLE-TESTDRIVER" |
| description = "More than one <script src='/resources/testdriver.js'>" |
| |
| |
| class MissingTestdriverVendor(Rule): |
| name = "MISSING-TESTDRIVER-VENDOR" |
| description = "Missing <script src='/resources/testdriver-vendor.js'>" |
| |
| |
| class MultipleTestdriverVendor(Rule): |
| name = "MULTIPLE-TESTDRIVER-VENDOR" |
| description = "More than one <script src='/resources/testdriver-vendor.js'>" |
| |
| |
| class TestharnessPath(Rule): |
| name = "TESTHARNESS-PATH" |
| description = "testharness.js script seen with incorrect path" |
| |
| |
| class TestharnessReportPath(Rule): |
| name = "TESTHARNESSREPORT-PATH" |
| description = "testharnessreport.js script seen with incorrect path" |
| |
| |
| class TestdriverPath(Rule): |
| name = "TESTDRIVER-PATH" |
| description = "testdriver.js script seen with incorrect path" |
| |
| |
| class TestdriverVendorPath(Rule): |
| name = "TESTDRIVER-VENDOR-PATH" |
| description = "testdriver-vendor.js script seen with incorrect path" |
| |
| |
| class OpenNoMode(Rule): |
| name = "OPEN-NO-MODE" |
| description = "File opened without providing an explicit mode (note: binary files must be read with 'b' in the mode flags)" |
| |
| |
| class UnknownGlobalMetadata(Rule): |
| name = "UNKNOWN-GLOBAL-METADATA" |
| description = "Unexpected value for global metadata" |
| |
| |
| class BrokenGlobalMetadata(Rule): |
| name = "BROKEN-GLOBAL-METADATA" |
| description = "Invalid global metadata: %s" |
| |
| |
| class UnknownTimeoutMetadata(Rule): |
| name = "UNKNOWN-TIMEOUT-METADATA" |
| description = "Unexpected value for timeout metadata" |
| |
| |
| class UnknownMetadata(Rule): |
| name = "UNKNOWN-METADATA" |
| description = "Unexpected kind of metadata" |
| |
| |
| class StrayMetadata(Rule): |
| name = "STRAY-METADATA" |
| description = "Metadata comments should start the file" |
| |
| |
| class IndentedMetadata(Rule): |
| name = "INDENTED-METADATA" |
| description = "Metadata comments should start the line" |
| |
| |
| class BrokenMetadata(Rule): |
| name = "BROKEN-METADATA" |
| description = "Metadata comment is not formatted correctly" |
| |
| |
| class Regexp(six.with_metaclass(abc.ABCMeta)): |
| @abc.abstractproperty |
| def pattern(self): |
| # type: () -> bytes |
| pass |
| |
| @abc.abstractproperty |
| def description(self): |
| # type: () -> Text |
| pass |
| |
| file_extensions = None # type: Optional[List[Text]] |
| |
| def __init__(self): |
| # type: () -> None |
| self._re = re.compile(self.pattern) # type: Pattern |
| |
| def applies(self, path): |
| # type: (str) -> bool |
| return (self.file_extensions is None or |
| os.path.splitext(path)[1] in self.file_extensions) |
| |
| def search(self, line): |
| # type: (bytes) -> Optional[Match[bytes]] |
| return self._re.search(line) |
| |
| |
| class TabsRegexp(Regexp): |
| pattern = b"^\t" |
| name = "INDENT TABS" |
| description = "Tabs used for indentation" |
| |
| class CRRegexp(Regexp): |
| pattern = b"\r$" |
| name = "CR AT EOL" |
| description = "CR character in line separator" |
| |
| class SetTimeoutRegexp(Regexp): |
| pattern = br"setTimeout\s*\(" |
| name = "SET TIMEOUT" |
| file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] |
| description = "setTimeout used; step_timeout should typically be used instead" |
| |
| class W3CTestOrgRegexp(Regexp): |
| pattern = br"w3c\-test\.org" |
| name = "W3C-TEST.ORG" |
| description = "External w3c-test.org domain used" |
| |
| class WebPlatformTestRegexp(Regexp): |
| pattern = br"web\-platform\.test" |
| name = "WEB-PLATFORM.TEST" |
| description = "Internal web-platform.test domain used" |
| |
| class Webidl2Regexp(Regexp): |
| pattern = br"webidl2\.js" |
| name = "WEBIDL2.JS" |
| description = "Legacy webidl2.js script used" |
| |
| class ConsoleRegexp(Regexp): |
| pattern = br"console\.[a-zA-Z]+\s*\(" |
| name = "CONSOLE" |
| file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] |
| description = "Console logging API used" |
| |
| class GenerateTestsRegexp(Regexp): |
| pattern = br"generate_tests\s*\(" |
| name = "GENERATE_TESTS" |
| file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] |
| description = "generate_tests used" |
| |
| class PrintRegexp(Regexp): |
| pattern = br"print(?:\s|\s*\()" |
| name = "PRINT STATEMENT" |
| file_extensions = [".py"] |
| description = "Print function used" |
| |
| class LayoutTestsRegexp(Regexp): |
| pattern = br"eventSender|testRunner|window\.internals" |
| name = "LAYOUTTESTS APIS" |
| file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] |
| description = "eventSender/testRunner/window.internals used; these are LayoutTests-specific APIs (WebKit/Blink)" |
| |
| class SpecialPowersRegexp(Regexp): |
| pattern = b"SpecialPowers" |
| name = "SPECIALPOWERS API" |
| file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] |
| description = "SpecialPowers used; this is gecko-specific and not supported in wpt" |
| |
| class TrailingWhitespaceRegexp(Regexp): |
| name = "TRAILING WHITESPACE" |
| description = "Whitespace at EOL" |
| pattern = b"[ \t\f\v]$" |
| to_fix = """Remove trailing whitespace from all lines in the file.""" |