diff options
19 files changed, 778 insertions, 273 deletions
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index f4d36982ea4..85b062a1178 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -319097,6 +319097,11 @@ {} ] ], + "tools/lint/rules.py": [ + [ + {} + ] + ], "tools/lint/tests/__init__.py": [ [ {} @@ -649420,7 +649425,7 @@ "support" ], "generic-sensor/generic-sensor-tests.js": [ - "8168d7a39f75fc22404c8c39937723e10c372d2d", + "a48b4c59aa89d0f1a0c7855f93bd80ce0f33fbf0", "support" ], "generic-sensor/idlharness.https.window.js": [ @@ -670296,7 +670301,7 @@ "support" ], "interfaces/webaudio.idl": [ - "4f1914dbae23a5619b72b92b761bd146d1aaacf9", + "4679558023ae87655f46b10d5a57d39269c6e8c9", "support" ], "interfaces/webauthn.idl": [ @@ -704876,7 +704881,11 @@ "support" ], "tools/lint/lint.py": [ - "ccadcdc16c72a9790c7de697c6f7762f0cbe06f1", + "19d0c112186a09ab2ca5fb449faf4ea90bb66e04", + "support" + ], + "tools/lint/rules.py": [ + "78f9d072a8a71c7af0494dc3625bd7aa937a5554", "support" ], "tools/lint/tests/__init__.py": [ @@ -705016,7 +705025,7 @@ "support" ], "tools/lint/tests/test_file_lints.py": [ - "28ccacc8787c61c2a6cf34552f179ef893360fed", + "ddf03986e10f5c336ea7ce7731bbcdd2135235d0", "support" ], "tools/lint/tests/test_lint.py": [ @@ -705024,7 +705033,7 @@ "support" ], "tools/lint/tests/test_path_lints.py": [ - "bf8418d52a02e1a22b83fbb15c0b468969546dc6", + "ab44c559187e8e435a34d5e13076feb420a15270", "support" ], "tools/localpaths.py": [ @@ -722416,7 +722425,7 @@ "testharness" ], "workers/modules/resources/credentials.py": [ - "7623d849625db4df7a9a10b8edd6f5e5e3187faf", + "fb1c7fe96cba4f41ac4b32c09642aea44fe05b23", "support" ], "workers/modules/resources/dynamic-import-and-then-static-import-worker.js": [ diff --git a/tests/wpt/metadata/css/css-fonts/variations/at-font-face-font-matching.html.ini b/tests/wpt/metadata/css/css-fonts/variations/at-font-face-font-matching.html.ini index 37f7f11182a..468859377f2 100644 --- a/tests/wpt/metadata/css/css-fonts/variations/at-font-face-font-matching.html.ini +++ b/tests/wpt/metadata/css/css-fonts/variations/at-font-face-font-matching.html.ini @@ -311,3 +311,27 @@ [Matching font-style: 'oblique -10deg' should prefer 'oblique -1deg 0deg' over 'oblique -20deg -15deg'] expected: FAIL + [Matching font-weight: '430' should prefer '350 399' over '340 398'] + expected: FAIL + + [Matching font-stretch: '100%' should prefer '110% 120%' over '115% 116%'] + expected: FAIL + + [Matching font-weight: '430' should prefer '500' over '400 425'] + expected: FAIL + + [Matching font-stretch: '110%' should prefer '105%' over '100%'] + expected: FAIL + + [Matching font-style: 'oblique 0deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg'] + expected: FAIL + + [Matching font-weight: '400' should prefer '351 398' over '501 550'] + expected: FAIL + + [Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg'] + expected: FAIL + + [Matching font-style: 'oblique -10deg' should prefer 'italic' over 'oblique 0deg 10deg'] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-transitions/transitions-animatable-properties-01.html.ini b/tests/wpt/metadata/css/css-transitions/transitions-animatable-properties-01.html.ini index 8850ec200da..323528d3385 100644 --- a/tests/wpt/metadata/css/css-transitions/transitions-animatable-properties-01.html.ini +++ b/tests/wpt/metadata/css/css-transitions/transitions-animatable-properties-01.html.ini @@ -74,3 +74,6 @@ [opacity end] expected: FAIL + [letter-spacing end] + expected: FAIL + diff --git a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini index d146040e0c1..3d135f3bd66 100644 --- a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini +++ b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini @@ -2,7 +2,7 @@ type: testharness [single-byte-decoder.html?document] - expected: CRASH + expected: TIMEOUT [ISO-8859-4: iso_8859-4:1988 (document.characterSet and document.inputEncoding)] expected: FAIL @@ -32,7 +32,6 @@ [single-byte-decoder.html?XMLHttpRequest] - expected: CRASH [ISO-8859-2: iso_8859-2:1987 (XMLHttpRequest)] expected: FAIL @@ -58,67 +57,7 @@ expected: FAIL [windows-1254: iso_8859-9:1989 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: windows-1254 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1257: cp1257 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: x-cp1254 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1255: windows-1255 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1258: x-cp1258 (XMLHttpRequest)] - expected: TIMEOUT - - [x-mac-cyrillic: x-mac-cyrillic (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1258: cp1258 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1257: x-cp1257 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: iso88599 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: iso_8859-9 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1257: windows-1257 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1258: windows-1258 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1256: cp1256 (XMLHttpRequest)] - expected: TIMEOUT - - [x-mac-cyrillic: x-mac-ukrainian (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1255: x-cp1255 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1256: x-cp1256 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1256: windows-1256 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: l5 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: latin5 (XMLHttpRequest)] - expected: TIMEOUT - - [windows-1254: iso8859-9 (XMLHttpRequest)] - expected: TIMEOUT + expected: FAIL [single-byte-decoder.html?TextDecoder] diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini index 18f786d4963..72022cb4ff0 100644 --- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini @@ -22,7 +22,7 @@ expected: NOTRUN [<iframe>: combined response Content-Type: text/plain */*;charset=gbk] - expected: FAIL + expected: TIMEOUT [fetch(): separate response Content-Type: text/html;x=" text/plain] expected: NOTRUN @@ -163,7 +163,7 @@ expected: NOTRUN [<iframe>: combined response Content-Type: text/html;" " text/plain] - expected: FAIL + expected: TIMEOUT [Request: combined response Content-Type: text/plain;charset=gbk;x=foo text/plain] expected: NOTRUN @@ -172,7 +172,7 @@ expected: NOTRUN [<iframe>: combined response Content-Type: text/html;" \\" text/plain ";charset=GBK] - expected: FAIL + expected: TIMEOUT [Response: combined response Content-Type: text/html;x=" text/plain] expected: NOTRUN @@ -202,7 +202,7 @@ expected: NOTRUN [<iframe>: separate response Content-Type: text/html;" " text/plain] - expected: FAIL + expected: TIMEOUT [fetch(): separate response Content-Type: text/plain */*;charset=gbk] expected: NOTRUN @@ -286,7 +286,7 @@ expected: NOTRUN [<iframe>: separate response Content-Type: text/html;" \\" text/plain ";charset=GBK] - expected: FAIL + expected: TIMEOUT [fetch(): combined response Content-Type: text/html;" " text/plain] expected: NOTRUN @@ -310,5 +310,32 @@ expected: NOTRUN [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] + expected: TIMEOUT + + [<iframe>: combined response Content-Type: text/html;" text/plain] + expected: TIMEOUT + + [<iframe>: separate response Content-Type: text/html;" text/plain] + expected: TIMEOUT + + [<iframe>: separate response Content-Type: text/html */*;charset=gbk] + expected: TIMEOUT + + [<iframe>: separate response Content-Type: text/html */*] expected: FAIL + [<iframe>: combined response Content-Type: text/html */*;charset=gbk] + expected: TIMEOUT + + [<iframe>: separate response Content-Type: text/html;x=" text/plain] + expected: TIMEOUT + + [<iframe>: combined response Content-Type: text/html;" \\" text/plain] + expected: TIMEOUT + + [<iframe>: separate response Content-Type: text/html;" \\" text/plain] + expected: TIMEOUT + + [<iframe>: combined response Content-Type: text/html;x=" text/plain] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini index 75d75b4cda2..51f8272a6de 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini @@ -1,4 +1,4 @@ -[traverse_the_history_2.html] +[traverse_the_history_3.html] [Multiple history traversals, last would be aborted] expected: FAIL diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini index 385376c7321..dc2e45516de 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini @@ -1,4 +1,4 @@ -[traverse_the_history_4.html] +[traverse_the_history_5.html] [Multiple history traversals, last would be aborted] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini new file mode 100644 index 00000000000..8cc42056d34 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini @@ -0,0 +1,10 @@ +[non-active-document.html] + [DOMParser] + expected: FAIL + + [createHTMLDocument] + expected: FAIL + + [<template>] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini deleted file mode 100644 index 178680e5d14..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[script-onerror-insertion-point-2.html] - expected: TIMEOUT diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini index 66bd350083b..a56bad443a2 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini @@ -1,4 +1,5 @@ [realtimeanalyser-fft-scaling.html] + expected: TIMEOUT [X 2048-point FFT peak position is not equal to 64. Got 0.] expected: FAIL diff --git a/tests/wpt/metadata/workers/modules/dedicated-worker-options-credentials.html.ini b/tests/wpt/metadata/workers/modules/dedicated-worker-options-credentials.html.ini index b9bc1e26d74..c2ee9826593 100644 --- a/tests/wpt/metadata/workers/modules/dedicated-worker-options-credentials.html.ini +++ b/tests/wpt/metadata/workers/modules/dedicated-worker-options-credentials.html.ini @@ -58,10 +58,10 @@ expected: NOTRUN [new Worker() with type=module and credentials=omit should not send the credentials] - expected: NOTRUN + expected: FAIL [new Worker() with type=module and default credentials option should behave as credentials=same-origin and send the credentials for same-origin static imports] - expected: NOTRUN + expected: TIMEOUT [new Worker() with type=classic should always send the credentials regardless of the credentials option (same-origin).] expected: NOTRUN @@ -93,12 +93,3 @@ [new Worker() with type=module and credentials=include should send the credentials for same-origin dynamic imports] expected: NOTRUN - [new Worker() with type=module and credentials=same-origin should send the credentials] - expected: NOTRUN - - [new Worker() with type=module and credentials=include should send the credentials] - expected: NOTRUN - - [new Worker() with type=module and default credentials option should behave as credentials=same-origin and send the credentials] - expected: TIMEOUT - diff --git a/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini b/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini deleted file mode 100644 index dbea4f293ad..00000000000 --- a/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transition_calc_implicit.html] - expected: TIMEOUT diff --git a/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js index 8168d7a39f7..a48b4c59aa8 100644 --- a/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js +++ b/tests/wpt/web-platform-tests/generic-sensor/generic-sensor-tests.js @@ -7,7 +7,7 @@ // // --enable-blink-features=MojoJS,MojoJSTest let loadChromiumResources = Promise.resolve().then(() => { - if (!MojoInterfaceInterceptor) { + if (!window.MojoInterfaceInterceptor) { // Do nothing on non-Chromium-based browsers or when the Mojo bindings are // not present in the global namespace. return; @@ -37,7 +37,10 @@ async function initialize_generic_sensor_tests() { if (typeof GenericSensorTest === 'undefined') { await loadChromiumResources; } - assert_true(typeof GenericSensorTest !== 'undefined'); + assert_true( + typeof GenericSensorTest !== 'undefined', + 'Mojo testing interface is not available.' + ); let sensorTest = new GenericSensorTest(); await sensorTest.initialize(); return sensorTest; diff --git a/tests/wpt/web-platform-tests/interfaces/webaudio.idl b/tests/wpt/web-platform-tests/interfaces/webaudio.idl index 4f1914dbae2..4679558023a 100644 --- a/tests/wpt/web-platform-tests/interfaces/webaudio.idl +++ b/tests/wpt/web-platform-tests/interfaces/webaudio.idl @@ -551,9 +551,11 @@ dictionary WaveShaperOptions : AudioNodeOptions { interface AudioWorklet : Worklet { }; +callback AudioWorkletProcessorConstructor = AudioWorkletProcessor (object options); + [Global=(Worklet, AudioWorklet), Exposed=AudioWorklet] interface AudioWorkletGlobalScope : WorkletGlobalScope { - void registerProcessor (DOMString name, VoidFunction processorCtor); + void registerProcessor (DOMString name, AudioWorkletProcessorConstructor processorCtor); readonly attribute unsigned long long currentFrame; readonly attribute double currentTime; readonly attribute float sampleRate; diff --git a/tests/wpt/web-platform-tests/tools/lint/lint.py b/tests/wpt/web-platform-tests/tools/lint/lint.py index ccadcdc16c7..19d0c112186 100644 --- a/tests/wpt/web-platform-tests/tools/lint/lint.py +++ b/tests/wpt/web-platform-tests/tools/lint/lint.py @@ -13,6 +13,7 @@ import tempfile from collections import defaultdict from . import fnmatch +from . import rules from .. import localpaths from ..gitignore.gitignore import PathFilter from ..wpt import testfiles @@ -117,7 +118,7 @@ def _all_files_equal(paths): def check_path_length(repo_root, path): if len(path) + 1 > 150: - return [("PATH LENGTH", "/%s longer than maximum path length (%d > 150)" % (path, len(path) + 1), path, None)] + return [rules.PathLength.error(path, (path, len(path) + 1))] return [] @@ -127,10 +128,7 @@ def check_worker_collision(repo_root, path): (".worker.html", ".worker.js")] for path_ending, generated in endings: if path.endswith(path_ending): - return [("WORKER COLLISION", - "path ends with %s which collides with generated tests from %s files" % (path_ending, generated), - path, - None)] + return [rules.WorkerCollision.error(path, (path_ending, generated))] return [] @@ -150,16 +148,13 @@ def check_gitignore_file(repo_root, path): path_parts[:3] == ["css", "tools", "apiclient"]): return [] - return [("GITIGNORE", - ".gitignore found outside the root", - path, - None)] + return [rules.GitIgnoreFile.error(path)] def check_ahem_copy(repo_root, path): lpath = path.lower() if "ahem" in lpath and lpath.endswith(".ttf"): - return [("AHEM COPY", "Don't add extra copies of Ahem, use /fonts/Ahem.ttf", path, None)] + return [rules.AhemCopy.error(path)] return [] @@ -177,8 +172,7 @@ def check_git_ignore(repo_root, paths): # If the matching filter reported by check-ignore is a special-case exception, # that's fine. Otherwise, it requires a new special-case exception. if filter_string[0] != '!': - errors += [("IGNORED PATH", "%s matches an ignore filter in .gitignore - " - "please add a .gitignore exception" % path, path, None)] + errors.append(rules.IgnoredPath.error(path, (path,))) except subprocess.CalledProcessError: # Nonzero return code means that no match exists. pass @@ -264,25 +258,19 @@ def check_css_globally_unique(repo_root, paths): 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: - errors.append(("CSS-COLLIDING-TEST-NAME", - "The filename %s in the %s testsuite is shared by: %s" - % (name, - spec, - ", ".join(sorted(paths))), - x, - None)) - - for error_name, d in [("CSS-COLLIDING-REF-NAME", ref_files), - ("CSS-COLLIDING-SUPPORT-NAME", support_files)]: + 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((error_name, - "The filename %s is shared by: %s" % (name, - ", ".join(sorted(colliding))), - x, - None)) + errors.append(rule_class.error(x, context)) return errors @@ -341,102 +329,20 @@ def filter_whitelist_errors(data, errors): return [item for i, item in enumerate(errors) if not whitelisted[i]] -class Regexp(object): - pattern = None - file_extensions = None - error = None - _re = None - - def __init__(self): - self._re = re.compile(self.pattern) - - def applies(self, path): - return (self.file_extensions is None or - os.path.splitext(path)[1] in self.file_extensions) - - def search(self, line): - return self._re.search(line) - -class TrailingWhitespaceRegexp(Regexp): - pattern = b"[ \t\f\v]$" - error = "TRAILING WHITESPACE" - description = "Whitespace at EOL" - -class TabsRegexp(Regexp): - pattern = b"^\t" - error = "INDENT TABS" - description = "Tabs used for indentation" - -class CRRegexp(Regexp): - pattern = b"\r$" - error = "CR AT EOL" - description = "CR character in line separator" - -class SetTimeoutRegexp(Regexp): - pattern = br"setTimeout\s*\(" - error = "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" - error = "W3C-TEST.ORG" - description = "External w3c-test.org domain used" - -class WebPlatformTestRegexp(Regexp): - pattern = br"web\-platform\.test" - error = "WEB-PLATFORM.TEST" - description = "Internal web-platform.test domain used" - -class Webidl2Regexp(Regexp): - pattern = br"webidl2\.js" - error = "WEBIDL2.JS" - description = "Legacy webidl2.js script used" - -class ConsoleRegexp(Regexp): - pattern = br"console\.[a-zA-Z]+\s*\(" - error = "CONSOLE" - file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] - description = "Console logging API used" - -class GenerateTestsRegexp(Regexp): - pattern = br"generate_tests\s*\(" - error = "GENERATE_TESTS" - file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] - description = "generate_tests used" - -class PrintRegexp(Regexp): - pattern = br"print(?:\s|\s*\()" - error = "PRINT STATEMENT" - file_extensions = [".py"] - description = "Print function used" - -class LayoutTestsRegexp(Regexp): - pattern = br"eventSender|testRunner|window\.internals" - error = "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" - error = "SPECIALPOWERS API" - file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"] - description = "SpecialPowers used; this is gecko-specific and not supported in wpt" - regexps = [item() for item in - [TrailingWhitespaceRegexp, - TabsRegexp, - CRRegexp, - SetTimeoutRegexp, - W3CTestOrgRegexp, - WebPlatformTestRegexp, - Webidl2Regexp, - ConsoleRegexp, - GenerateTestsRegexp, - PrintRegexp, - LayoutTestsRegexp, - SpecialPowersRegexp]] + [rules.TrailingWhitespaceRegexp, + rules.TabsRegexp, + rules.CRRegexp, + rules.SetTimeoutRegexp, + rules.W3CTestOrgRegexp, + rules.WebPlatformTestRegexp, + rules.Webidl2Regexp, + rules.ConsoleRegexp, + rules.GenerateTestsRegexp, + rules.PrintRegexp, + rules.LayoutTestsRegexp, + rules.SpecialPowersRegexp]] def check_regexp_line(repo_root, path, f): errors = [] @@ -446,7 +352,7 @@ def check_regexp_line(repo_root, path, f): for i, line in enumerate(f): for regexp in applicable_regexps: if regexp.search(line): - errors.append((regexp.error, regexp.description, path, i+1)) + errors.append((regexp.name, regexp.description, path, i+1)) return errors @@ -459,12 +365,12 @@ def check_parsed(repo_root, path, f): 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)] + return [rules.SupportWrongDir.error(path)] 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)] + return [rules.MissingLink.error(path)] if source_file.name_is_non_test: return [] @@ -473,13 +379,13 @@ def check_parsed(repo_root, path, f): return [] if source_file.root is None: - return [("PARSE-FAILED", "Unable to parse file", path, None)] + return [rules.ParseFailed.error(path)] if source_file.type == "manual" and not source_file.name_is_manual: - errors.append(("CONTENT-MANUAL", "Manual test whose filename doesn't end in '-manual'", path, None)) + errors.append(rules.ContentManual.error(path)) if source_file.type == "visual" and not source_file.name_is_visual: - errors.append(("CONTENT-VISUAL", "Visual test whose filename doesn't end in '-visual'", path, None)) + errors.append(rules.ContentVisual.error(path)) about_blank_parts = urlsplit("about:blank") for reftest_node in source_file.reftest_nodes: @@ -490,18 +396,14 @@ def check_parsed(repo_root, path, f): continue if (parts.scheme or parts.netloc): - errors.append(("ABSOLUTE-URL-REF", - "Reference test with a reference file specified via an absolute URL: '%s'" % href, path, None)) + errors.append(rules.AbsoluteUrlRef.error(path, (href,))) 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)) + errors.append(rules.SameFileRef.error(path)) continue assert ref_parts.path != "" @@ -510,45 +412,39 @@ def check_parsed(repo_root, path, f): 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)) + errors.append(rules.NonexistentRef.error(path, + (reference_rel, href))) if len(source_file.timeout_nodes) > 1: - errors.append(("MULTIPLE-TIMEOUT", "More than one meta name='timeout'", path, None)) + errors.append(rules.MultipleTimeout.error(path)) 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)) + errors.append(rules.InvalidTimeout.error(path, (timeout_value,))) 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)) + errors.append(rules.MultipleTestharness.error(path)) 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)) + errors.append(rules.MissingTestharnessReport.error(path)) else: if len(testharnessreport_nodes) > 1: - errors.append(("MULTIPLE-TESTHARNESSREPORT", - "More than one <script src='/resources/testharnessreport.js'>", path, None)) + errors.append(rules.MultipleTestharnessReport.error(path)) 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)) + errors.append(rules.PresentTestharnessCSS.error(path)) 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)) + errors.append(rules.VariantMissing.error(path)) 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)) + errors.append(rules.MalformedVariant.error(path, (path,))) seen_elements = {"timeout": False, "testharness": False, @@ -562,8 +458,7 @@ def check_parsed(repo_root, path, f): 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)) + errors.append(rules.LateTimeout.error(path)) elif elem == source_file.testharness_nodes[0]: seen_elements["testharness"] = True @@ -571,46 +466,53 @@ def check_parsed(repo_root, path, f): 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)) + errors.append(rules.EarlyTestharnessReport.error(path)) 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)) + errors.append(rules.MultipleTestdriver.error(path)) 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)) + errors.append(rules.MissingTestdriverVendor.error(path)) else: if len(testdriver_vendor_nodes) > 1: - errors.append(("MULTIPLE-TESTDRIVER-VENDOR", - "More than one <script src='/resources/testdriver-vendor.js'>", path, None)) + errors.append(rules.MultipleTestdriverVendor.error(path)) 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)) + + def incorrect_path(script, src): + return (script == src or + ("/%s" % script in src and src != "/resources/%s" % script)) + + if incorrect_path("testharness.js", src): + errors.append(rules.TestharnessPath.error(path)) + + if incorrect_path("testharnessreport.js", src): + errors.append(rules.TestharnessReportPath.error(path)) + + if incorrect_path("testdriver.js", src): + errors.append(rules.TestdriverPath.error(path)) + + if incorrect_path("testdriver-vendor.js", src): + errors.append(rules.TestdriverVendorPath.error(path)) return errors class ASTCheck(object): __metaclass__ = abc.ABCMeta - error = None - description = None + rule = None @abc.abstractmethod def check(self, root): pass class OpenModeCheck(ASTCheck): - error = "OPEN-NO-MODE" - description = "File opened without providing an explicit mode (note: binary files must be read with 'b' in the mode flags)" + rule = rules.OpenNoMode def check(self, root): errors = [] @@ -631,12 +533,12 @@ def check_python_ast(repo_root, path, f): try: root = ast.parse(f.read()) except SyntaxError as e: - return [("PARSE-FAILED", "Unable to parse file", path, e.lineno)] + return [rules.ParseFailed.error(path, line_no=e.lineno)] errors = [] for checker in ast_checkers: for lineno in checker.check(root): - errors.append((checker.error, checker.description, path, lineno)) + errors.append(checker.rule.error(path, line_no=lineno)) return errors @@ -654,19 +556,21 @@ def check_global_metadata(value): if global_value.startswith(b"!"): excluded_value = global_value[1:] if not get_any_variants(excluded_value): - yield ("UNKNOWN-GLOBAL-METADATA", "Unexpected value for global metadata") + yield (rules.UnknownGlobalMetadata, ()) elif excluded_value in global_values: - yield ("BROKEN-GLOBAL-METADATA", "Cannot specify both %s and %s" % (global_value, excluded_value)) + yield (rules.BrokenGlobalMetadata, + ("Cannot specify both %s and %s" % (global_value, excluded_value))) else: excluded_variants = get_any_variants(excluded_value) if not (excluded_variants & included_variants): - yield ("BROKEN-GLOBAL-METADATA", "Cannot exclude %s if it is not included" % (excluded_value,)) + yield (rules.BrokenGlobalMetadata, + ("Cannot exclude %s if it is not included" % (excluded_value,))) else: if not get_any_variants(global_value): - yield ("UNKNOWN-GLOBAL-METADATA", "Unexpected value for global metadata") + yield (rules.UnknownGlobalMetadata, ()) def check_script_metadata(repo_root, path, f): @@ -688,10 +592,12 @@ def check_script_metadata(repo_root, path, f): if m: key, value = m.groups() if key == b"global": - errors.extend((kind, message, path, idx + 1) for (kind, message) in check_global_metadata(value)) + for rule_class, context in check_global_metadata(value): + errors.append(rule_class.error(path, context, idx + 1)) elif key == b"timeout": if value != b"long": - errors.append(("UNKNOWN-TIMEOUT-METADATA", "Unexpected value for timeout metadata", path, idx + 1)) + errors.append(rules.UnknownTimeoutMetadata.error(path, + line_no=idx + 1)) elif key == b"title": pass elif key == b"script": @@ -699,17 +605,19 @@ def check_script_metadata(repo_root, path, f): elif key == b"variant": pass else: - errors.append(("UNKNOWN-METADATA", "Unexpected kind of metadata", path, idx + 1)) + errors.append(rules.UnknownMetadata.error(path, + line_no=idx + 1)) else: done = True if done: if meta_re.match(line): - errors.append(("STRAY-METADATA", "Metadata comments should start the file", path, idx + 1)) + errors.append(rules.StrayMetadata.error(path, line_no=idx + 1)) elif meta_re.search(line): - errors.append(("INDENTED-METADATA", "Metadata comments should start the line", path, idx + 1)) + errors.append(rules.IndentedMetadata.error(path, + line_no=idx + 1)) elif broken_metadata.search(line): - errors.append(("BROKEN-METADATA", "Metadata comment is not formatted correctly", path, idx + 1)) + errors.append(rules.BrokenMetadata.error(path, line_no=idx + 1)) return errors diff --git a/tests/wpt/web-platform-tests/tools/lint/rules.py b/tests/wpt/web-platform-tests/tools/lint/rules.py new file mode 100644 index 00000000000..78f9d072a8a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/lint/rules.py @@ -0,0 +1,316 @@ +from __future__ import unicode_literals +import os +import re + +class Rule(object): + name = None + description = None + to_fix = None + + @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(Rule): + pattern = None + file_extensions = None + _re = None + + def __init__(self): + self._re = re.compile(self.pattern) + + def applies(self, path): + return (self.file_extensions is None or + os.path.splitext(path)[1] in self.file_extensions) + + def search(self, line): + 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.""" diff --git a/tests/wpt/web-platform-tests/tools/lint/tests/test_file_lints.py b/tests/wpt/web-platform-tests/tools/lint/tests/test_file_lints.py index 28ccacc8787..ddf03986e10 100644 --- a/tests/wpt/web-platform-tests/tools/lint/tests/test_file_lints.py +++ b/tests/wpt/web-platform-tests/tools/lint/tests/test_file_lints.py @@ -296,6 +296,79 @@ def test_multiple_testharnessreport(): ] +def test_multiple_testdriver(): + code = b""" +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind in ["web-lax", "web-strict"]: + assert errors == [ + ("MULTIPLE-TESTDRIVER", "More than one <script src='/resources/testdriver.js'>", filename, None), + ] + elif kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 2), + ] + + +def test_multiple_testdriver_vendor(): + code = b""" +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind in ["web-lax", "web-strict"]: + assert errors == [ + ("MULTIPLE-TESTDRIVER-VENDOR", "More than one <script src='/resources/testdriver-vendor.js'>", filename, None), + ] + elif kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 2), + ] + + +def test_missing_testdriver_vendor(): + code = b""" +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind in ["web-lax", "web-strict"]: + assert errors == [ + ("MISSING-TESTDRIVER-VENDOR", "Missing <script src='/resources/testdriver-vendor.js'>", filename, None), + ] + elif kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 2), + ] + + def test_present_testharnesscss(): code = b""" <html xmlns="http://www.w3.org/1999/xhtml"> @@ -373,12 +446,81 @@ def test_testharnessreport_path(): assert errors == expected +def test_testdriver_path(): + code = b"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="testdriver.js"></script> +<script src="/elsewhere/testdriver.js"></script> +<script src="/elsewhere/resources/testdriver.js"></script> +<script src="/resources/elsewhere/testdriver.js"></script> +<script src="../resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + expected = [] + if kind == "python": + expected.append(("PARSE-FAILED", "Unable to parse file", filename, 1)) + elif kind in ["web-lax", "web-strict"]: + expected.extend([ + ("TESTDRIVER-PATH", "testdriver.js script seen with incorrect path", filename, None), + ("TESTDRIVER-PATH", "testdriver.js script seen with incorrect path", filename, None), + ("TESTDRIVER-PATH", "testdriver.js script seen with incorrect path", filename, None), + ("TESTDRIVER-PATH", "testdriver.js script seen with incorrect path", filename, None), + ("TESTDRIVER-PATH", "testdriver.js script seen with incorrect path", filename, None) + ]) + assert errors == expected + + +def test_testdriver_vendor_path(): + code = b"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="testdriver-vendor.js"></script> +<script src="/elsewhere/testdriver-vendor.js"></script> +<script src="/elsewhere/resources/testdriver-vendor.js"></script> +<script src="/resources/elsewhere/testdriver-vendor.js"></script> +<script src="../resources/testdriver-vendor.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind == "python": + expected = set([("PARSE-FAILED", "Unable to parse file", filename, 1)]) + elif kind in ["web-lax", "web-strict"]: + expected = set([ + ("MISSING-TESTDRIVER-VENDOR", "Missing <script src='/resources/testdriver-vendor.js'>", filename, None), + ("TESTDRIVER-VENDOR-PATH", "testdriver-vendor.js script seen with incorrect path", filename, None), + ("TESTDRIVER-VENDOR-PATH", "testdriver-vendor.js script seen with incorrect path", filename, None), + ("TESTDRIVER-VENDOR-PATH", "testdriver-vendor.js script seen with incorrect path", filename, None), + ("TESTDRIVER-VENDOR-PATH", "testdriver-vendor.js script seen with incorrect path", filename, None), + ("TESTDRIVER-VENDOR-PATH", "testdriver-vendor.js script seen with incorrect path", filename, None) + ]) + else: + expected = set() + + assert set(errors) == expected + + def test_not_testharness_path(): code = b"""\ <html xmlns="http://www.w3.org/1999/xhtml"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="resources/webperftestharness.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> </html> """ error_map = check_with_files(code) @@ -394,6 +536,79 @@ def test_not_testharness_path(): assert errors == [] +def test_variant_missing(): + code = b"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> +<meta name="variant"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 1), + ] + elif kind == "web-lax": + assert errors == [ + ("VARIANT-MISSING", "<meta name=variant> missing 'content' attribute", filename, None) + ] + + +# A corresponding "positive" test cannot be written because the manifest +# SourceFile implementation raises a runtime exception for the condition this +# linting rule describes +@pytest.mark.parametrize("content", ["", + "?" + "#"]) +def test_variant_malformed_negative(content): + code = """\ +<html xmlns="http://www.w3.org/1999/xhtml"> +<meta name="variant" content="{}"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</html> +""".format(content).encode("utf-8") + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 1), + ] + elif kind == "web-lax": + assert errors == [] + + +def test_late_timeout(): + code = b"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> +<script src="/resources/testharness.js"></script> +<meta name="timeout" content="long"> +<script src="/resources/testharnessreport.js"></script> +</html> +""" + error_map = check_with_files(code) + + for (filename, (errors, kind)) in error_map.items(): + check_errors(errors) + + if kind == "python": + assert errors == [ + ("PARSE-FAILED", "Unable to parse file", filename, 1), + ] + elif kind == "web-lax": + assert errors == [ + ("LATE-TIMEOUT", "<meta name=timeout> seen after testharness.js script", filename, None) + ] + + @pytest.mark.skipif(six.PY3, reason="Cannot parse print statements from python 3") def test_print_statement(): error_map = check_with_files(b"def foo():\n print 'statement'\n print\n") diff --git a/tests/wpt/web-platform-tests/tools/lint/tests/test_path_lints.py b/tests/wpt/web-platform-tests/tools/lint/tests/test_path_lints.py index bf8418d52a0..ab44c559187 100644 --- a/tests/wpt/web-platform-tests/tools/lint/tests/test_path_lints.py +++ b/tests/wpt/web-platform-tests/tools/lint/tests/test_path_lints.py @@ -38,3 +38,61 @@ def test_forbidden_path_endings(path_ending, generated): errors = check_path("/foo/", path) check_errors(errors) assert errors == [("WORKER COLLISION", message, path, None)] + + +@pytest.mark.parametrize("path", ["ahem.ttf", + "Ahem.ttf", + "ahem.tTf", + "not-ahem.ttf", + "support/ahem.ttf", + "ahem/other.ttf"]) +def test_ahem_copy(path): + expected_error = ("AHEM COPY", + "Don't add extra copies of Ahem, use /fonts/Ahem.ttf", + path, + None) + + errors = check_path("/foo/", path) + + assert errors == [expected_error] + +@pytest.mark.parametrize("path", ["ahem.woff", + "ahem.ttff", + "support/ahem.woff", + "ahem/other.woff"]) +def test_ahem_copy_negative(path): + errors = check_path("/foo/", path) + + assert errors == [] + +@pytest.mark.parametrize("path", ["elsewhere/.gitignore", + "else/where/.gitignore" + "elsewhere/tools/.gitignore", + "elsewhere/docs/.gitignore", + "elsewhere/resources/webidl2/.gitignore", + "elsewhere/css/tools/apiclient/.gitignore"]) +def test_gitignore_file(path): + expected_error = ("GITIGNORE", + ".gitignore found outside the root", + path, + None) + + errors = check_path("/foo/", path) + + assert errors == [expected_error] + +@pytest.mark.parametrize("path", [".gitignore", + "elsewhere/.gitignores", + "elsewhere/name.gitignore", + "tools/.gitignore", + "tools/elsewhere/.gitignore", + "docs/.gitignore" + "docs/elsewhere/.gitignore", + "resources/webidl2/.gitignore", + "resources/webidl2/elsewhere/.gitignore", + "css/tools/apiclient/.gitignore", + "css/tools/apiclient/elsewhere/.gitignore"]) +def test_gitignore_negative(path): + errors = check_path("/foo/", path) + + assert errors == [] diff --git a/tests/wpt/web-platform-tests/workers/modules/resources/credentials.py b/tests/wpt/web-platform-tests/workers/modules/resources/credentials.py index 7623d849625..fb1c7fe96cb 100644 --- a/tests/wpt/web-platform-tests/workers/modules/resources/credentials.py +++ b/tests/wpt/web-platform-tests/workers/modules/resources/credentials.py @@ -2,9 +2,12 @@ def main(request, response): cookie = request.cookies.first("COOKIE_NAME", None) response_headers = [("Content-Type", "text/javascript"), - ("Access-Control-Allow-Origin", request.headers.get("Origin")), ("Access-Control-Allow-Credentials", "true")] + origin = request.headers.get("Origin", None) + if origin: + response_headers.append(("Access-Control-Allow-Origin", origin)) + cookie_value = ''; if cookie: cookie_value = cookie.value; |