summaryrefslogtreecommitdiffstats
path: root/testing/addtest.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/addtest.py')
-rw-r--r--testing/addtest.py358
1 files changed, 358 insertions, 0 deletions
diff --git a/testing/addtest.py b/testing/addtest.py
new file mode 100644
index 0000000000..bb44f1b454
--- /dev/null
+++ b/testing/addtest.py
@@ -0,0 +1,358 @@
+import io
+import os
+
+import manifestparser
+
+
+class Creator(object):
+ def __init__(self, topsrcdir, test, suite, doc, **kwargs):
+ self.topsrcdir = topsrcdir
+ self.test = test
+ self.suite = suite
+ self.doc = doc
+ self.kwargs = kwargs
+
+ def check_args(self):
+ """Perform any validation required for suite-specific arguments"""
+ return True
+
+ def __iter__(self):
+ """Iterate over a list of (path, data) tuples corresponding to the files
+ to be created"""
+ yield (self.test, self._get_template_contents())
+
+ def _get_template_contents(self, **kwargs):
+ raise NotImplementedError
+
+ def update_manifest(self):
+ """Perform any manifest updates required to register the added tests"""
+ raise NotImplementedError
+
+
+class XpcshellCreator(Creator):
+ template_body = """/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_TODO() {
+ ok(true, "TODO: implement the test");
+});
+"""
+
+ def _get_template_contents(self):
+ return self.template_body
+
+ def update_manifest(self):
+ update_toml_or_ini("xpcshell", self.test)
+
+
+class MochitestCreator(Creator):
+ templates = {
+ "mochitest-browser-chrome": "browser.template.txt",
+ "mochitest-plain": "plain%(doc)s.template.txt",
+ "mochitest-chrome": "chrome%(doc)s.template.txt",
+ }
+
+ def _get_template_contents(self):
+ mochitest_templates = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), "mochitest", "static")
+ )
+ template_file_name = None
+
+ template_file_name = self.templates.get(self.suite)
+
+ if template_file_name is None:
+ print(
+ "Sorry, `addtest` doesn't currently know how to add {}".format(
+ self.suite
+ )
+ )
+ return None
+
+ template_file_name = template_file_name % {"doc": self.doc}
+
+ template_file = os.path.join(mochitest_templates, template_file_name)
+ if not os.path.isfile(template_file):
+ print(
+ "Sorry, `addtest` doesn't currently know how to add {} with document type {}".format( # NOQA: E501
+ self.suite, self.doc
+ )
+ )
+ return None
+
+ with open(template_file) as f:
+ return f.read()
+
+ def update_manifest(self):
+ # attempt to insert into the appropriate manifest
+ guessed_prefix = {
+ "mochitest-plain": "mochitest",
+ "mochitest-chrome": "chrome",
+ "mochitest-browser-chrome": "browser",
+ }[self.suite]
+
+ update_toml_or_ini(guessed_prefix, self.test)
+
+
+class WebPlatformTestsCreator(Creator):
+ template_prefix = """<!doctype html>
+%(documentElement)s<meta charset=utf-8>
+"""
+ template_long_timeout = "<meta name=timeout content=long>\n"
+
+ template_body_th = """<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+</script>
+"""
+
+ template_body_reftest = """<title></title>
+<link rel=%(match)s href=%(ref)s>
+"""
+
+ template_body_reftest_wait = """<script src="/common/reftest-wait.js"></script>
+"""
+
+ template_js = ""
+ template_js_long_timeout = "//META: timeout=long\n"
+
+ upstream_path = os.path.join("testing", "web-platform", "tests")
+ local_path = os.path.join("testing", "web-platform", "mozilla", "tests")
+
+ def __init__(self, *args, **kwargs):
+ super(WebPlatformTestsCreator, self).__init__(*args, **kwargs)
+ self.reftest = self.suite == "web-platform-tests-reftest"
+
+ @classmethod
+ def get_parser(cls, parser):
+ parser.add_argument(
+ "--long-timeout",
+ action="store_true",
+ help="Test should be given a long timeout "
+ "(typically 60s rather than 10s, but varies depending on environment)",
+ )
+ parser.add_argument(
+ "-m", "--reference", dest="ref", help="Path to the reference file"
+ )
+ parser.add_argument(
+ "--mismatch", action="store_true", help="Create a mismatch reftest"
+ )
+ parser.add_argument(
+ "--wait",
+ action="store_true",
+ help="Create a reftest that waits until takeScreenshot() is called",
+ )
+
+ def check_args(self):
+ if self.wpt_type(self.test) is None:
+ print(
+ """Test path %s is not in wpt directories:
+testing/web-platform/tests for tests that may be shared
+testing/web-platform/mozilla/tests for Gecko-only tests"""
+ % self.test
+ )
+ return False
+
+ if not self.reftest:
+ if self.kwargs["ref"]:
+ print("--ref only makes sense for a reftest")
+ return False
+
+ if self.kwargs["mismatch"]:
+ print("--mismatch only makes sense for a reftest")
+ return False
+
+ if self.kwargs["wait"]:
+ print("--wait only makes sense for a reftest")
+ return False
+ else:
+ # Set the ref to a url relative to the test
+ if self.kwargs["ref"]:
+ if self.ref_path(self.kwargs["ref"]) is None:
+ print("--ref doesn't refer to a path inside web-platform-tests")
+ return False
+
+ def __iter__(self):
+ yield (self.test, self._get_template_contents())
+
+ if self.reftest and self.kwargs["ref"]:
+ ref_path = self.ref_path(self.kwargs["ref"])
+ yield (ref_path, self._get_template_contents(reference=True))
+
+ def _get_template_contents(self, reference=False):
+ args = {
+ "documentElement": "<html class=reftest-wait>\n"
+ if self.kwargs["wait"]
+ else ""
+ }
+
+ if self.test.rsplit(".", 1)[1] == "js":
+ template = self.template_js
+ if self.kwargs["long_timeout"]:
+ template += self.template_js_long_timeout
+ else:
+ template = self.template_prefix % args
+ if self.kwargs["long_timeout"]:
+ template += self.template_long_timeout
+
+ if self.reftest:
+ if not reference:
+ args = {
+ "match": "match" if not self.kwargs["mismatch"] else "mismatch",
+ "ref": (
+ self.ref_url(self.kwargs["ref"])
+ if self.kwargs["ref"]
+ else '""'
+ ),
+ }
+ template += self.template_body_reftest % args
+ if self.kwargs["wait"]:
+ template += self.template_body_reftest_wait
+ else:
+ template += "<title></title>"
+ else:
+ template += self.template_body_th
+
+ return template
+
+ def update_manifest(self):
+ pass
+
+ def src_rel_path(self, path):
+ if path is None:
+ return
+
+ abs_path = os.path.normpath(os.path.abspath(path))
+ return os.path.relpath(abs_path, self.topsrcdir)
+
+ def wpt_type(self, path):
+ path = self.src_rel_path(path)
+ if path.startswith(self.upstream_path):
+ return "upstream"
+ elif path.startswith(self.local_path):
+ return "local"
+ return None
+
+ def ref_path(self, path):
+ # The ref parameter can be one of several things
+ # 1. An absolute path to a reference file
+ # 2. A path to a file relative to the topsrcdir
+ # 3. A path relative to the test file
+ # These are not unambiguous, so it's somewhat best effort
+
+ if os.path.isabs(path):
+ path = os.path.normpath(path)
+ if not path.startswith(self.topsrcdir):
+ # Path is an absolute URL relative to the tests root
+ if path.startswith("/_mozilla/"):
+ base = self.local_path
+ path = path[len("/_mozilla/") :]
+ else:
+ base = self.upstream_path
+ path = path[1:]
+ path = path.replace("/", os.sep)
+ return os.path.join(base, path)
+ else:
+ return self.src_rel_path(path)
+ else:
+ if self.wpt_type(path) is not None:
+ return path
+ else:
+ test_rel_path = self.src_rel_path(
+ os.path.join(os.path.dirname(self.test), path)
+ )
+ if self.wpt_type(test_rel_path) is not None:
+ return test_rel_path
+ # Returning None indicates that the path wasn't valid
+
+ def ref_url(self, path):
+ ref_path = self.ref_path(path)
+ if not ref_path:
+ return
+
+ if path[0] == "/" and len(path) < len(ref_path):
+ # This is an absolute url
+ return path
+
+ # Othewise it's a file path
+ wpt_type_ref = self.wpt_type(ref_path)
+ wpt_type_test = self.wpt_type(self.test)
+ if wpt_type_ref == wpt_type_test:
+ return os.path.relpath(ref_path, os.path.dirname(self.test))
+
+ # If we have a local test referencing an upstream ref,
+ # or vice-versa use absolute paths
+ if wpt_type_ref == "upstream":
+ rel_path = os.path.relpath(ref_path, self.upstream_path)
+ url_base = "/"
+ elif wpt_type_ref == "local":
+ rel_path = os.path.relpath(ref_path, self.local_path)
+ url_base = "/_mozilla/"
+ else:
+ return None
+ return url_base + rel_path.replace(os.path.sep, "/")
+
+
+# Insert a new test in the right place
+def update_toml_or_ini(manifest_prefix, testpath):
+ basedir = os.path.dirname(testpath)
+ manifest_file = os.path.join(basedir, manifest_prefix + ".toml")
+ if not os.path.isfile(manifest_file):
+ manifest_file = os.path.join(basedir, manifest_prefix + ".ini")
+ if not os.path.isfile(manifest_file):
+ print("Could not open manifest file {}".format(manifest_file))
+ return
+ filename = os.path.basename(testpath)
+ write_to_manifest_file(manifest_file, filename)
+
+
+# Insert a new test in the right place within a given manifest file
+def write_to_manifest_file(manifest_file, filename):
+ use_toml = manifest_file.endswith(".toml")
+ manifest = manifestparser.TestManifest(manifests=[manifest_file], use_toml=use_toml)
+ insert_before = None
+
+ if any(t["name"] == filename for t in manifest.tests):
+ print("{} is already in the manifest.".format(filename))
+ return
+
+ for test in manifest.tests:
+ if test.get("name") > filename:
+ insert_before = test.get("name")
+ break
+
+ with open(manifest_file, "r") as f:
+ contents = f.readlines()
+
+ entry_line = '["{}"]\n' if use_toml else "[{}]"
+ filename = (entry_line + "\n").format(filename)
+
+ if not insert_before:
+ contents.append(filename)
+ else:
+ insert_before = entry_line.format(insert_before)
+ for i in range(len(contents)):
+ if contents[i].startswith(insert_before):
+ contents.insert(i, filename)
+ break
+
+ with io.open(manifest_file, "w", newline="\n") as f:
+ f.write("".join(contents))
+
+
+TEST_CREATORS = {
+ "mochitest": MochitestCreator,
+ "web-platform-tests": WebPlatformTestsCreator,
+ "xpcshell": XpcshellCreator,
+}
+
+
+def creator_for_suite(suite):
+ if suite.split("-")[0] == "mochitest":
+ base_suite = "mochitest"
+ else:
+ base_suite = suite.rsplit("-", 1)[0]
+ return TEST_CREATORS.get(base_suite)