Update web-platform-tests to revision dc5cbf088edcdb266541d4e5a76149a2c6e716a0

This commit is contained in:
Ms2ger 2016-09-09 09:40:35 +02:00
parent 1d40075f03
commit 079092dfea
2381 changed files with 90360 additions and 17722 deletions

View file

@ -1,4 +1,8 @@
*#
.coverage*
htmlcov/
coverage.xml
.tox
*.py[co]
*.sw[po]
*~

View file

@ -1,12 +1,35 @@
language: python
python:
- "2.7"
- "3.5"
sudo: false
cache:
directories:
- $HOME/.cache/pip
matrix:
include:
- python: 2.7
env: TOXENV=py27
- python: 3.5
env: TOXENV=py35
- python: pypy
env: TOXENV=pypy
# An ugly hack needed to make py.test believe our top level can be
# imported (on Travis CI, we end up in a wpt-tools directory, and of
# course you cannot import a name including a hyphen in Python, so it
# ignores the fact we have a __init__.py at the top level).
before_install:
- mv `pwd` /tmp/tools
- cd /tmp/tools
- export TRAVIS_BUILD_DIR=/tmp/tools
install:
- pip install flake8
- pip install pytest
- pip install ./html5lib
- pip install pytest-travis-fold
- pip install -U tox codecov
script:
- py.test manifest
- flake8
- tox
after_success:
- coverage combine
- codecov

View file

@ -1,6 +1,8 @@
from __future__ import print_function, unicode_literals
import abc
import argparse
import ast
import fnmatch
import json
import os
@ -43,29 +45,26 @@ def check_path_length(repo_root, path):
return [("PATH LENGTH", "/%s longer than maximum path length (%d > 150)" % (path, len(path) + 1), None)]
return []
def set_type(error_type, errors):
return [(error_type,) + error for error in errors]
def parse_whitelist_file(filename):
def parse_whitelist(f):
"""
Parse the whitelist file at `filename`, and return the parsed structure.
Parse the whitelist file given by `f`, and return the parsed structure.
"""
data = defaultdict(lambda:defaultdict(set))
with open(filename) as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = [item.strip() for item in line.split(":")]
if len(parts) == 2:
parts.append(None)
else:
parts[-1] = int(parts[-1])
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = [item.strip() for item in line.split(":")]
if len(parts) == 2:
parts.append(None)
else:
parts[-1] = int(parts[-1])
error_type, file_match, line_number = parts
data[file_match][error_type].add(line_number)
error_type, file_match, line_number = parts
data[file_match][error_type].add(line_number)
return data
@ -133,7 +132,7 @@ class Webidl2Regexp(Regexp):
class ConsoleRegexp(Regexp):
pattern = b"console\.[a-zA-Z]+\s*\("
error = "CONSOLE"
file_extensions = [".html", ".htm", ".js", ".xht", ".html", ".svg"]
file_extensions = [".html", ".htm", ".js", ".xht", ".xhtml", ".svg"]
description = "Console logging API used"
class PrintRegexp(Regexp):
@ -164,7 +163,7 @@ def check_regexp_line(repo_root, path, f):
return errors
def check_parsed(repo_root, path, f):
source_file = SourceFile(repo_root, path, "/")
source_file = SourceFile(repo_root, path, "/", contents=f.read())
errors = []
@ -199,6 +198,11 @@ def check_parsed(repo_root, path, f):
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",
@ -238,6 +242,79 @@ def check_parsed(repo_root, path, f):
return errors
class ASTCheck(object):
__metaclass__ = abc.ABCMeta
error = None
description = 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)"
def check(self, root):
errors = []
for node in ast.walk(root):
if isinstance(node, ast.Call):
if hasattr(node.func, "id") and node.func.id in ("open", "file"):
if (len(node.args) < 2 and
all(item.arg != "mode" for item in node.keywords)):
errors.append(node.lineno)
return errors
ast_checkers = [item() for item in [OpenModeCheck]]
def check_python_ast(repo_root, path, f):
if not path.endswith(".py"):
return []
try:
root = ast.parse(f.read())
except SyntaxError as e:
return [("PARSE-FAILED", "Unable to parse file", path, e.lineno)]
errors = []
for checker in ast_checkers:
for lineno in checker.check(root):
errors.append((checker.error, checker.description, path, lineno))
return errors
def check_path(repo_root, path):
"""
Runs lints that check the file path.
:param repo_root: the repository root
:param path: the path of the file within the repository
:returns: a list of errors found in ``path``
"""
errors = []
for path_fn in path_lints:
errors.extend(path_fn(repo_root, path))
return errors
def check_file_contents(repo_root, path, f):
"""
Runs lints that check the file contents.
:param repo_root: the repository root
:param path: the path of the file within the repository
:param f: a file-like object with the file contents
:returns: a list of errors found in ``f``
"""
errors = []
for file_fn in file_lints:
errors.extend(file_fn(repo_root, path, f))
f.seek(0)
return errors
def output_errors_text(errors):
for error_type, description, path, line_number in errors:
pos_string = path
@ -279,35 +356,47 @@ def lint(repo_root, paths, output_json):
error_count = defaultdict(int)
last = None
whitelist = parse_whitelist_file(os.path.join(repo_root, "lint.whitelist"))
with open(os.path.join(repo_root, "lint.whitelist")) as f:
whitelist = parse_whitelist(f)
if output_json:
output_errors = output_errors_json
else:
output_errors = output_errors_text
def run_lint(path, fn, last, *args):
errors = filter_whitelist_errors(whitelist, path, fn(repo_root, path, *args))
if errors:
last = (errors[-1][0], path)
def process_errors(path, errors):
"""
Filters and prints the errors, and updates the ``error_count`` object.
:param path: the path of the file that contains the errors
:param errors: a list of error tuples (error type, message, path, line number)
:returns: ``None`` if there were no errors, or
a tuple of the error type and the path otherwise
"""
errors = filter_whitelist_errors(whitelist, path, errors)
if not errors:
return None
output_errors(errors)
for error_type, error, path, line in errors:
error_count[error_type] += 1
return last
return (errors[-1][0], path)
for path in paths:
abs_path = os.path.join(repo_root, path)
if not os.path.exists(abs_path):
continue
for path_fn in path_lints:
last = run_lint(path, path_fn, last)
errors = check_path(repo_root, path)
last = process_errors(path, errors) or last
if not os.path.isdir(abs_path):
with open(abs_path) as f:
for file_fn in file_lints:
last = run_lint(path, file_fn, last, f)
f.seek(0)
errors = check_file_contents(repo_root, path, f)
last = process_errors(path, errors) or last
if not output_json:
output_error_count(error_count)
@ -316,7 +405,7 @@ def lint(repo_root, paths, output_json):
return sum(error_count.itervalues())
path_lints = [check_path_length]
file_lints = [check_regexp_line, check_parsed]
file_lints = [check_regexp_line, check_parsed, check_python_ast]
if __name__ == "__main__":
error_count = main()

View file

@ -0,0 +1,287 @@
from __future__ import unicode_literals
from ..lint import check_file_contents
import os
import pytest
import six
INTERESTING_FILE_NAMES = {
"python": [
"test.py",
],
"js": [
"test.js",
],
"web-lax": [
"test.htm",
"test.html",
],
"web-strict": [
"test.svg",
"test.xht",
"test.xhtml",
],
}
def check_with_files(input_bytes):
return {
filename: (check_file_contents("", filename, six.BytesIO(input_bytes)), kind)
for (filename, kind) in
(
(os.path.join("html", filename), kind)
for (kind, filenames) in INTERESTING_FILE_NAMES.items()
for filename in filenames
)
}
def test_trailing_whitespace():
error_map = check_with_files(b"test; ")
for (filename, (errors, kind)) in error_map.items():
expected = [("TRAILING WHITESPACE", "Whitespace at EOL", filename, 1)]
if kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_indent_tabs():
error_map = check_with_files(b"def foo():\n\x09pass")
for (filename, (errors, kind)) in error_map.items():
expected = [("INDENT TABS", "Tabs used for indentation", filename, 2)]
if kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_cr_not_at_eol():
error_map = check_with_files(b"line1\rline2\r")
for (filename, (errors, kind)) in error_map.items():
expected = [("CR AT EOL", "CR character in line separator", filename, 1)]
if kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_cr_at_eol():
error_map = check_with_files(b"line1\r\nline2\r\n")
for (filename, (errors, kind)) in error_map.items():
expected = [
("CR AT EOL", "CR character in line separator", filename, 1),
("CR AT EOL", "CR character in line separator", filename, 2),
]
if kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_w3c_test_org():
error_map = check_with_files(b"import('http://www.w3c-test.org/')")
for (filename, (errors, kind)) in error_map.items():
expected = [("W3C-TEST.ORG", "External w3c-test.org domain used", filename, 1)]
if kind == "python":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, 1))
elif kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_webidl2_js():
error_map = check_with_files(b"<script src=/resources/webidl2.js>")
for (filename, (errors, kind)) in error_map.items():
expected = [("WEBIDL2.JS", "Legacy webidl2.js script used", filename, 1)]
if kind == "python":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, 1))
elif kind == "web-strict":
expected.append(("PARSE-FAILED", "Unable to parse file", filename, None))
assert errors == expected
def test_console():
error_map = check_with_files(b"<script>\nconsole.log('error');\nconsole.error ('log')\n</script>")
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict", "js"]:
assert errors == [
("CONSOLE", "Console logging API used", filename, 2),
("CONSOLE", "Console logging API used", filename, 3),
]
else:
assert errors == [("PARSE-FAILED", "Unable to parse file", filename, 1)]
def test_meta_timeout():
code = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<meta name="timeout" />
<meta name="timeout" content="short" />
<meta name="timeout" content="long" />
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict"]:
assert errors == [
("MULTIPLE-TIMEOUT", "More than one meta name='timeout'", filename, None),
("INVALID-TIMEOUT", "Invalid timeout value ", filename, None),
("INVALID-TIMEOUT", "Invalid timeout value short", filename, None),
]
elif kind == "python":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, 2),
]
def test_early_testharnessreport():
code = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testharness.js"></script>
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict"]:
assert errors == [
("EARLY-TESTHARNESSREPORT", "testharnessreport.js script seen before testharness.js script", filename, None),
]
elif kind == "python":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, 2),
]
def test_multiple_testharness():
code = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharness.js"></script>
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict"]:
assert errors == [
("MULTIPLE-TESTHARNESS", "More than one <script src='/resources/testharness.js'>", filename, None),
("MISSING-TESTHARNESSREPORT", "Missing <script src='/resources/testharnessreport.js'>", filename, None),
]
elif kind == "python":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, 2),
]
def test_multiple_testharnessreport():
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/testharnessreport.js"></script>
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict"]:
assert errors == [
("MULTIPLE-TESTHARNESSREPORT", "More than one <script src='/resources/testharnessreport.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">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="stylesheet" href="/resources/testharness.css"/>
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
if kind in ["web-lax", "web-strict"]:
assert errors == [
("PRESENT-TESTHARNESSCSS", "Explicit link to testharness.css present", filename, None),
]
elif kind == "python":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, 2),
]
@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")
for (filename, (errors, kind)) in error_map.items():
if kind == "python":
assert errors == [
("PRINT STATEMENT", "Print function used", filename, 2),
("PRINT STATEMENT", "Print function used", filename, 3),
]
elif kind == "web-strict":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, None),
]
else:
assert errors == []
def test_print_function():
error_map = check_with_files(b"def foo():\n print('function')\n")
for (filename, (errors, kind)) in error_map.items():
if kind == "python":
assert errors == [
("PRINT STATEMENT", "Print function used", filename, 2),
]
elif kind == "web-strict":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, None),
]
else:
assert errors == []
open_mode_code = """
def first():
return {0}("test.png")
def second():
return {0}("test.png", "r")
def third():
return {0}("test.png", "rb")
def fourth():
return {0}("test.png", encoding="utf-8")
def fifth():
return {0}("test.png", mode="rb")
"""
def test_open_mode():
for method in ["open", "file"]:
code = open_mode_code.format(method).encode("utf-8")
errors = check_file_contents("", "test.py", six.BytesIO(code))
message = ("File opened without providing an explicit mode (note: " +
"binary files must be read with 'b' in the mode flags)")
assert errors == [
("OPEN-NO-MODE", message, "test.py", 3),
("OPEN-NO-MODE", message, "test.py", 12),
]

View file

@ -1,5 +1,54 @@
from lint.lint import filter_whitelist_errors
from __future__ import unicode_literals
from ..lint import filter_whitelist_errors, parse_whitelist
import six
def test_lint():
filtered = filter_whitelist_errors({}, '', [])
assert filtered == []
def test_parse_whitelist():
input_buffer = six.StringIO("""
# Comment
CR AT EOL: svg/import/*
CR AT EOL: streams/resources/test-utils.js
INDENT TABS: .gitmodules
INDENT TABS: app-uri/*
INDENT TABS: svg/*
TRAILING WHITESPACE: app-uri/*
CONSOLE:streams/resources/test-utils.js: 12
*:*.pdf
*:resources/*
""")
expected = {
'*.pdf': {
'*': {None},
},
'.gitmodules': {
'INDENT TABS': {None},
},
'app-uri/*': {
'TRAILING WHITESPACE': {None},
'INDENT TABS': {None},
},
'resources/*': {
'*': {None},
},
'streams/resources/test-utils.js': {
'CONSOLE': {12},
'CR AT EOL': {None},
},
'svg/*': {
'INDENT TABS': {None},
},
'svg/import/*': {
'CR AT EOL': {None},
},
}
assert parse_whitelist(input_buffer) == expected

View file

@ -0,0 +1,25 @@
from __future__ import unicode_literals
from ..lint import check_path
import pytest
import six
def test_allowed_path_length():
basename = 29 * "test/"
for idx in range(5):
filename = basename + idx * "a"
errors = check_path("/foo/", filename)
assert errors == []
def test_forbidden_path_length():
basename = 29 * "test/"
for idx in range(5, 10):
filename = basename + idx * "a"
message = "/%s longer than maximum path length (%s > 150)" % (filename, 146 + idx)
errors = check_path("/foo/", filename)
assert errors == [("PATH LENGTH", message, None)]

View file

@ -14,16 +14,26 @@ import html5lib
from . import vcs
from .item import Stub, ManualTest, WebdriverSpecTest, RefTest, TestharnessTest
from .utils import rel_path_to_url, is_blacklisted, ContextManagerStringIO, cached_property
from .utils import rel_path_to_url, is_blacklisted, ContextManagerBytesIO, cached_property
wd_pattern = "*.py"
def replace_end(s, old, new):
"""
Given a string `s` that ends with `old`, replace that occurrence of `old`
with `new`.
"""
assert s.endswith(old)
return s[:-len(old)] + new
class SourceFile(object):
parsers = {"html":lambda x:html5lib.parse(x, treebuilder="etree"),
"xhtml":ElementTree.parse,
"svg":ElementTree.parse}
def __init__(self, tests_root, rel_path, url_base, use_committed=False):
def __init__(self, tests_root, rel_path, url_base, use_committed=False,
contents=None):
"""Object representing a file in a source tree.
:param tests_root: Path to the root of the source tree
@ -31,12 +41,16 @@ class SourceFile(object):
:param url_base: Base URL used when converting file paths to urls
:param use_committed: Work with the last committed version of the file
rather than the on-disk version.
:param contents: Byte array of the contents of the file or ``None``.
"""
assert not (use_committed and contents is not None)
self.tests_root = tests_root
self.rel_path = rel_path
self.url_base = url_base
self.use_committed = use_committed
self.contents = contents
self.url = rel_path_to_url(rel_path, url_base)
self.path = os.path.join(tests_root, rel_path)
@ -68,15 +82,27 @@ class SourceFile(object):
:param prefix: The prefix to check"""
return self.name.startswith(prefix)
def open(self):
"""Return a File object opened for reading the file contents,
or the contents of the file when last committed, if
use_comitted is true."""
def is_dir(self):
"""Return whether this file represents a directory."""
if self.contents is not None:
return False
if self.use_committed:
return os.path.isdir(self.rel_path)
def open(self):
"""
Return either
* the contents specified in the constructor, if any;
* the contents of the file when last committed, if use_committed is true; or
* a File object opened for reading the file contents.
"""
if self.contents is not None:
file_obj = ContextManagerBytesIO(self.contents)
elif self.use_committed:
git = vcs.get_git_func(os.path.dirname(__file__))
blob = git("show", "HEAD:%s" % self.rel_path)
file_obj = ContextManagerStringIO(blob)
file_obj = ContextManagerBytesIO(blob)
else:
file_obj = open(self.path, 'rb')
return file_obj
@ -85,7 +111,7 @@ class SourceFile(object):
def name_is_non_test(self):
"""Check if the file name matches the conditions for the file to
be a non-test file"""
return (os.path.isdir(self.rel_path) or
return (self.is_dir() or
self.name_prefix("MANIFEST") or
self.filename.startswith(".") or
is_blacklisted(self.url))
@ -102,6 +128,12 @@ class SourceFile(object):
be a manual test file"""
return self.type_flag == "manual"
@property
def name_is_multi_global(self):
"""Check if the file name matches the conditions for the file to
be a multi-global js test file"""
return "any" in self.meta_flags and self.ext == ".js"
@property
def name_is_worker(self):
"""Check if the file name matches the conditions for the file to
@ -296,8 +328,14 @@ class SourceFile(object):
elif self.name_is_manual:
rv = [ManualTest(self, self.url)]
elif self.name_is_multi_global:
rv = [
TestharnessTest(self, replace_end(self.url, ".any.js", ".any.html")),
TestharnessTest(self, replace_end(self.url, ".any.js", ".any.worker")),
]
elif self.name_is_worker:
rv = [TestharnessTest(self, self.url[:-3])]
rv = [TestharnessTest(self, replace_end(self.url, ".worker.js", ".worker"))]
elif self.name_is_webdriver:
rv = [WebdriverSpecTest(self, self.url)]

View file

@ -0,0 +1,239 @@
from ..sourcefile import SourceFile
def create(filename, contents=b""):
assert isinstance(contents, bytes)
return SourceFile("/", filename, "/", contents=contents)
def items(s):
return [
(item.item_type, item.url)
for item in s.manifest_items()
]
def test_name_is_non_test():
non_tests = [
".gitignore",
".travis.yml",
"MANIFEST.json",
"tools/test.html",
"resources/test.html",
"common/test.html",
"conformance-checkers/test.html",
]
for rel_path in non_tests:
s = create(rel_path)
assert s.name_is_non_test
assert not s.content_is_testharness
assert items(s) == []
def test_name_is_manual():
manual_tests = [
"html/test-manual.html",
"html/test-manual.xhtml",
]
for rel_path in manual_tests:
s = create(rel_path)
assert not s.name_is_non_test
assert s.name_is_manual
assert not s.content_is_testharness
assert items(s) == [("manual", "/" + rel_path)]
def test_worker():
s = create("html/test.worker.js")
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert s.name_is_worker
assert not s.name_is_reference
assert not s.content_is_testharness
assert items(s) == [("testharness", "/html/test.worker")]
def test_multi_global():
s = create("html/test.any.js")
assert not s.name_is_non_test
assert not s.name_is_manual
assert s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert not s.content_is_testharness
assert items(s) == [
("testharness", "/html/test.any.html"),
("testharness", "/html/test.any.worker"),
]
def test_testharness():
content = b"<script src=/resources/testharness.js></script>"
for ext in ["htm", "html"]:
filename = "html/test." + ext
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert s.content_is_testharness
assert items(s) == [("testharness", "/" + filename)]
def test_relative_testharness():
content = b"<script src=../resources/testharness.js></script>"
for ext in ["htm", "html"]:
filename = "html/test." + ext
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert not s.content_is_testharness
assert items(s) == []
def test_testharness_xhtml():
content = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body/>
</html>
"""
for ext in ["xhtml", "xht", "xml"]:
filename = "html/test." + ext
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert s.content_is_testharness
assert items(s) == [("testharness", "/" + filename)]
def test_relative_testharness_xhtml():
content = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
</head>
<body/>
</html>
"""
for ext in ["xhtml", "xht", "xml"]:
filename = "html/test." + ext
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert not s.content_is_testharness
assert items(s) == []
def test_testharness_svg():
content = b"""\
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
version="1.1"
width="100%" height="100%" viewBox="0 0 400 400">
<title>Null test</title>
<h:script src="/resources/testharness.js"/>
<h:script src="/resources/testharnessreport.js"/>
</svg>
"""
filename = "html/test.svg"
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert s.root
assert s.content_is_testharness
assert items(s) == [("testharness", "/" + filename)]
def test_relative_testharness_svg():
content = b"""\
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
version="1.1"
width="100%" height="100%" viewBox="0 0 400 400">
<title>Null test</title>
<h:script src="../resources/testharness.js"/>
<h:script src="../resources/testharnessreport.js"/>
</svg>
"""
filename = "html/test.svg"
s = create(filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert s.root
assert not s.content_is_testharness
assert items(s) == []
def test_testharness_ext():
content = b"<script src=/resources/testharness.js></script>"
for filename in ["test", "test.test"]:
s = create("html/" + filename, content)
assert not s.name_is_non_test
assert not s.name_is_manual
assert not s.name_is_multi_global
assert not s.name_is_worker
assert not s.name_is_reference
assert not s.root
assert not s.content_is_testharness
assert items(s) == []

View file

@ -1,5 +1,5 @@
import os
from six import StringIO
from six import BytesIO
blacklist = ["/", "/tools/", "/resources/", "/common/", "/conformance-checkers/", "_certs"]
@ -26,7 +26,7 @@ def from_os_path(path):
def to_os_path(path):
return path.replace("/", os.path.sep)
class ContextManagerStringIO(StringIO):
class ContextManagerBytesIO(BytesIO):
def __enter__(self):
return self

View file

@ -0,0 +1,2 @@
[pytest]
norecursedirs = .* {arch} *.egg html5lib py pytest pywebsocket six webdriver wptserve

View file

@ -74,6 +74,12 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Count of matching tests</label>
<div class="col-sm-9" id="testcount">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-success toggleStart" disabled>Start</button>

View file

@ -1,3 +1,5 @@
from __future__ import print_function
import argparse
import json
import sys
@ -88,10 +90,10 @@ class HTML(object):
e.g.
h = HTML()
print h.html(
print(h.html(
html.head(),
html.body([html.h1("Hello World!")], class_="body-class")
)
))
Would give
<!DOCTYPE html><html><head></head><body class="body-class"><h1>Hello World!</h1></body></html>"""
def __getattr__(self, name):
@ -299,7 +301,7 @@ def main(filenames):
if __name__ == "__main__":
if not sys.argv[1:]:
print """Please supply a list of UA name, filename pairs e.g.
print("""Please supply a list of UA name, filename pairs e.g.
python report.py Firefox firefox.json Chrome chrome.json IE internet_explorer.json"""
print main(sys.argv[1:])
python report.py Firefox firefox.json Chrome chrome.json IE internet_explorer.json""")
print(main(sys.argv[1:]))

View file

@ -90,7 +90,8 @@ html.done section + section {
#manualUI {
position: fixed;
top: 100px;
z-index: 2000;
top: -20px;
left: 0;
right: 0;
display: block;
@ -121,6 +122,10 @@ body {
max-width: 800px;
}
.navbar-brand > img {
display: inline;
}
.navbar-inverse .navbar-brand {
color: #fff;
}

View file

@ -461,22 +461,35 @@ ManualUI.prototype = {
function TestControl(elem, runner) {
this.elem = elem;
this.path_input = this.elem.querySelector(".path");
this.path_input.addEventListener("change", function() {
this.set_counts();
}.bind(this), false);
this.use_regex_input = this.elem.querySelector("#use_regex");
this.use_regex_input.addEventListener("change", function() {
this.set_counts();
}.bind(this), false);
this.pause_button = this.elem.querySelector("button.togglePause");
this.start_button = this.elem.querySelector("button.toggleStart");
this.type_checkboxes = Array.prototype.slice.call(
this.elem.querySelectorAll("input[type=checkbox].test-type"));
this.type_checkboxes.forEach(function(elem) {
elem.addEventListener("change", function() {
this.set_counts();
}.bind(this),
false);
elem.addEventListener("click", function() {
this.start_button.disabled = this.get_test_types().length < 1;
}.bind(this),
false);
}.bind(this));
this.timeout_input = this.elem.querySelector(".timeout_multiplier");
this.render_checkbox = this.elem.querySelector(".render");
this.testcount_area = this.elem.querySelector("#testcount");
this.runner = runner;
this.runner.done_callbacks.push(this.on_done.bind(this));
this.set_start();
this.set_counts();
}
TestControl.prototype = {
@ -530,6 +543,21 @@ TestControl.prototype = {
},
set_counts: function() {
if (this.runner.manifest_loading) {
setTimeout(function() {
this.set_counts();
}.bind(this), 1000);
return;
}
var path = this.get_path();
var test_types = this.get_test_types();
var use_regex = this.get_use_regex();
var iterator = new ManifestIterator(this.runner.manifest, path, test_types, use_regex);
var count = iterator.count();
this.testcount_area.textContent = count;
},
get_path: function() {
return this.path_input.value;
},
@ -622,6 +650,7 @@ function Runner(manifest_path) {
this.results = new Results(this);
this.start_after_manifest_load = false;
this.manifest_loading = true;
this.manifest.load(this.manifest_loaded.bind(this));
}
@ -637,6 +666,7 @@ Runner.prototype = {
},
manifest_loaded: function() {
this.manifest_loading = false;
if (this.start_after_manifest_load) {
this.do_start();
}

View file

@ -1,4 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import argparse
import json
import os
@ -23,6 +26,15 @@ from mod_pywebsocket import standalone as pywebsocket
repo_root = localpaths.repo_root
def replace_end(s, old, new):
"""
Given a string `s` that ends with `old`, replace that occurrence of `old`
with `new`.
"""
assert s.endswith(old)
return s[:-len(old)] + new
class WorkersHandler(object):
def __init__(self):
self.handler = handlers.handler(self.handle_request)
@ -31,7 +43,7 @@ class WorkersHandler(object):
return self.handler(request, response)
def handle_request(self, request, response):
worker_path = request.url_parts.path.replace(".worker", ".worker.js")
worker_path = replace_end(request.url_parts.path, ".worker", ".worker.js")
return """<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
@ -42,6 +54,52 @@ fetch_tests_from_worker(new Worker("%s"));
</script>
""" % (worker_path,)
class AnyHtmlHandler(object):
def __init__(self):
self.handler = handlers.handler(self.handle_request)
def __call__(self, request, response):
return self.handler(request, response)
def handle_request(self, request, response):
test_path = replace_end(request.url_parts.path, ".any.html", ".any.js")
return """\
<!doctype html>
<meta charset=utf-8>
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
};
</script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script src="%s"></script>
""" % (test_path,)
class AnyWorkerHandler(object):
def __init__(self):
self.handler = handlers.handler(self.handle_request)
def __call__(self, request, response):
return self.handler(request, response)
def handle_request(self, request, response):
test_path = replace_end(request.url_parts.path, ".any.worker.js", ".any.js")
return """\
self.GLOBAL = {
isWindow: function() { return false; },
isWorker: function() { return true; },
};
importScripts("/resources/testharness.js");
importScripts("%s");
done();
""" % (test_path,)
rewrites = [("GET", "/resources/WebIDLParser.js", "/resources/webidl2/lib/webidl2.js")]
subdomains = [u"www",
@ -61,7 +119,11 @@ class RoutesBuilder(object):
("*", "{spec}/tools/*", handlers.ErrorHandler(404)),
("*", "/serve.py", handlers.ErrorHandler(404))]
self.static = [("GET", "*.worker", WorkersHandler())]
self.static = [
("GET", "*.worker", WorkersHandler()),
("GET", "*.any.html", AnyHtmlHandler()),
("GET", "*.any.worker.js", AnyWorkerHandler()),
]
self.mountpoint_routes = OrderedDict()
@ -145,10 +207,10 @@ class ServerProc(object):
self.daemon = init_func(host, port, paths, routes, bind_hostname, external_config,
ssl_config, **kwargs)
except socket.error:
print >> sys.stderr, "Socket error on port %s" % port
print("Socket error on port %s" % port, file=sys.stderr)
raise
except:
print >> sys.stderr, traceback.format_exc()
print(traceback.format_exc(), file=sys.stderr)
raise
if self.daemon:
@ -159,7 +221,7 @@ class ServerProc(object):
except KeyboardInterrupt:
pass
except:
print >> sys.stderr, traceback.format_exc()
print(traceback.format_exc(), file=sys.stderr)
raise
def wait(self):
@ -284,7 +346,7 @@ class WebSocketDaemon(object):
elif pywebsocket._import_pyopenssl():
tls_module = pywebsocket._TLS_BY_PYOPENSSL
else:
print "No SSL module available"
print("No SSL module available")
sys.exit(1)
cmd_args += ["--tls",

View file

@ -1,4 +0,0 @@
[flake8]
ignore = E128,E221,E226,E231,E251,E265,E302,E303,E402,E901,F401,F821,F841
max-line-length = 141
exclude = html5lib,py,pytest,pywebsocket,six,webdriver,wptserve

View file

@ -0,0 +1,21 @@
[tox]
envlist = py27,py35,pypy
skipsdist=True
[testenv]
deps =
flake8
{toxinidir}/py
{toxinidir}/pytest
{toxinidir}/html5lib
pytest-travis-fold
coverage
commands =
coverage run -m pytest
flake8
[flake8]
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E402,E901,F401,F821,F841
max-line-length = 141
exclude = .tox,html5lib,py,pytest,pywebsocket,six,webdriver,wptserve