diff options
Diffstat (limited to 'testing/web-platform/harness/wptrunner/manifestexpected.py')
-rw-r--r-- | testing/web-platform/harness/wptrunner/manifestexpected.py | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/testing/web-platform/harness/wptrunner/manifestexpected.py b/testing/web-platform/harness/wptrunner/manifestexpected.py new file mode 100644 index 000000000..c0e22a843 --- /dev/null +++ b/testing/web-platform/harness/wptrunner/manifestexpected.py @@ -0,0 +1,256 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import urlparse + +from wptmanifest.backends import static +from wptmanifest.backends.static import ManifestItem + +import expected + +"""Manifest structure used to store expected results of a test. + +Each manifest file is represented by an ExpectedManifest that +has one or more TestNode children, one per test in the manifest. +Each TestNode has zero or more SubtestNode children, one for each +known subtest of the test. +""" + +def data_cls_getter(output_node, visited_node): + # visited_node is intentionally unused + if output_node is None: + return ExpectedManifest + if isinstance(output_node, ExpectedManifest): + return TestNode + if isinstance(output_node, TestNode): + return SubtestNode + raise ValueError + + +def bool_prop(name, node): + """Boolean property""" + try: + return node.get(name) + except KeyError: + return None + + +def tags(node): + """Set of tags that have been applied to the test""" + try: + value = node.get("tags") + if isinstance(value, (str, unicode)): + return {value} + return set(value) + except KeyError: + return set() + + +def prefs(node): + def value(ini_value): + if isinstance(ini_value, (str, unicode)): + return tuple(ini_value.split(":", 1)) + else: + return (ini_value, None) + + try: + node_prefs = node.get("prefs") + if type(node_prefs) in (str, unicode): + prefs = {value(node_prefs)} + rv = dict(value(item) for item in node_prefs) + except KeyError: + rv = {} + return rv + + +class ExpectedManifest(ManifestItem): + def __init__(self, name, test_path, url_base): + """Object representing all the tests in a particular manifest + + :param name: Name of the AST Node associated with this object. + Should always be None since this should always be associated with + the root node of the AST. + :param test_path: Path of the test file associated with this manifest. + :param url_base: Base url for serving the tests in this manifest + """ + if name is not None: + raise ValueError("ExpectedManifest should represent the root node") + if test_path is None: + raise ValueError("ExpectedManifest requires a test path") + if url_base is None: + raise ValueError("ExpectedManifest requires a base url") + ManifestItem.__init__(self, name) + self.child_map = {} + self.test_path = test_path + self.url_base = url_base + + def append(self, child): + """Add a test to the manifest""" + ManifestItem.append(self, child) + self.child_map[child.id] = child + + def _remove_child(self, child): + del self.child_map[child.id] + ManifestItem.remove_child(self, child) + assert len(self.child_map) == len(self.children) + + def get_test(self, test_id): + """Get a test from the manifest by ID + + :param test_id: ID of the test to return.""" + return self.child_map.get(test_id) + + @property + def url(self): + return urlparse.urljoin(self.url_base, + "/".join(self.test_path.split(os.path.sep))) + + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + +class DirectoryManifest(ManifestItem): + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + +class TestNode(ManifestItem): + def __init__(self, name): + """Tree node associated with a particular test in a manifest + + :param name: name of the test""" + assert name is not None + ManifestItem.__init__(self, name) + self.updated_expected = [] + self.new_expected = [] + self.subtests = {} + self.default_status = None + self._from_file = True + + @property + def is_empty(self): + required_keys = set(["type"]) + if set(self._data.keys()) != required_keys: + return False + return all(child.is_empty for child in self.children) + + @property + def test_type(self): + return self.get("type") + + @property + def id(self): + return urlparse.urljoin(self.parent.url, self.name) + + @property + def disabled(self): + return bool_prop("disabled", self) + + @property + def restart_after(self): + return bool_prop("restart-after", self) + + @property + def tags(self): + return tags(self) + + @property + def prefs(self): + return prefs(self) + + def append(self, node): + """Add a subtest to the current test + + :param node: AST Node associated with the subtest""" + child = ManifestItem.append(self, node) + self.subtests[child.name] = child + + def get_subtest(self, name): + """Get the SubtestNode corresponding to a particular subtest, by name + + :param name: Name of the node to return""" + if name in self.subtests: + return self.subtests[name] + return None + + +class SubtestNode(TestNode): + def __init__(self, name): + """Tree node associated with a particular subtest in a manifest + + :param name: name of the subtest""" + TestNode.__init__(self, name) + + @property + def is_empty(self): + if self._data: + return False + return True + + +def get_manifest(metadata_root, test_path, url_base, run_info): + """Get the ExpectedManifest for a particular test path, or None if there is no + metadata stored for that test path. + + :param metadata_root: Absolute path to the root of the metadata directory + :param test_path: Path to the test(s) relative to the test root + :param url_base: Base url for serving the tests in this manifest + :param run_info: Dictionary of properties of the test run for which the expectation + values should be computed. + """ + manifest_path = expected.expected_path(metadata_root, test_path) + try: + with open(manifest_path) as f: + return static.compile(f, + run_info, + data_cls_getter=data_cls_getter, + test_path=test_path, + url_base=url_base) + except IOError: + return None + +def get_dir_manifest(metadata_root, path, run_info): + """Get the ExpectedManifest for a particular test path, or None if there is no + metadata stored for that test path. + + :param metadata_root: Absolute path to the root of the metadata directory + :param path: Path to the ini file relative to the metadata root + :param run_info: Dictionary of properties of the test run for which the expectation + values should be computed. + """ + full_path = os.path.join(metadata_root, path) + try: + with open(full_path) as f: + return static.compile(f, + run_info, + data_cls_getter=lambda x,y: DirectoryManifest) + except IOError: + return None |