Bug 1641886 [wpt PR 23851] - Support interpolating contain-intrinsic-size, a=testonly
[gecko.git] / testing / addtest.py
blob9a18fce86a170e6d83b224126ac6daa7ef589cb8
2 from __future__ import absolute_import, unicode_literals, print_function
4 import io
5 import os
6 import manifestparser
9 class Creator(object):
10 def __init__(self, topsrcdir, test, suite, doc, **kwargs):
11 self.topsrcdir = topsrcdir
12 self.test = test
13 self.suite = suite
14 self.doc = doc
15 self.kwargs = kwargs
17 def check_args(self):
18 """Perform any validation required for suite-specific arguments"""
19 return True
21 def __iter__(self):
22 """Iterate over a list of (path, data) tuples corresponding to the files
23 to be created"""
24 yield (self.test, self._get_template_contents())
26 def _get_template_contents(self, **kwargs):
27 raise NotImplementedError
29 def update_manifest(self):
30 """Perform any manifest updates required to register the added tests"""
31 raise NotImplementedError
34 class XpcshellCreator(Creator):
35 template_body = """/* Any copyright is dedicated to the Public Domain.
36 http://creativecommons.org/publicdomain/zero/1.0/ */
38 "use strict";
40 add_task(async function test_TODO() {
41 ok(true, "TODO: implement the test");
42 });
43 """
45 def _get_template_contents(self):
46 return self.template_body
48 def update_manifest(self):
49 manifest_file = os.path.join(os.path.dirname(self.test), "xpcshell.ini")
50 filename = os.path.basename(self.test)
52 if not os.path.isfile(manifest_file):
53 print('Could not open manifest file {}'.format(manifest_file))
54 return
55 write_to_ini_file(manifest_file, filename)
58 class MochitestCreator(Creator):
59 templates = {
60 "mochitest-browser-chrome": "browser.template.txt",
61 "mochitest-plain": "plain%(doc)s.template.txt",
62 "mochitest-chrome": "chrome%(doc)s.template.txt",
65 def _get_template_contents(self):
66 mochitest_templates = os.path.abspath(
67 os.path.join(os.path.dirname(__file__), 'mochitest', 'static')
69 template_file_name = None
71 template_file_name = self.templates.get(self.suite)
73 if template_file_name is None:
74 print("Sorry, `addtest` doesn't currently know how to add {}".format(self.suite))
75 return None
77 template_file_name = template_file_name % {"doc": self.doc}
79 template_file = os.path.join(mochitest_templates, template_file_name)
80 if not os.path.isfile(template_file):
81 print("Sorry, `addtest` doesn't currently know how to add {} with document type {}"
82 .format(self.suite, self.doc))
83 return None
85 with open(template_file) as f:
86 return f.read()
88 def update_manifest(self):
89 # attempt to insert into the appropriate manifest
90 guessed_ini = {
91 "mochitest-plain": "mochitest.ini",
92 "mochitest-chrome": "chrome.ini",
93 "mochitest-browser-chrome": "browser.ini"
94 }[self.suite]
95 manifest_file = os.path.join(os.path.dirname(self.test), guessed_ini)
96 filename = os.path.basename(self.test)
98 if not os.path.isfile(manifest_file):
99 print('Could not open manifest file {}'.format(manifest_file))
100 return
102 write_to_ini_file(manifest_file, filename)
105 class WebPlatformTestsCreator(Creator):
106 template_prefix = """<!doctype html>
107 %(documentElement)s<meta charset=utf-8>
109 template_long_timeout = "<meta name=timeout content=long>\n"
111 template_body_th = """<title></title>
112 <script src=/resources/testharness.js></script>
113 <script src=/resources/testharnessreport.js></script>
114 <script>
116 </script>
119 template_body_reftest = """<title></title>
120 <link rel=%(match)s href=%(ref)s>
123 template_body_reftest_wait = """<script src="/common/reftest-wait.js"></script>
126 template_js = ""
127 template_js_long_timeout = "//META: timeout=long\n"
129 upstream_path = os.path.join("testing", "web-platform", "tests")
130 local_path = os.path.join("testing", "web-platform", "mozilla", "tests")
132 def __init__(self, *args, **kwargs):
133 super(WebPlatformTestsCreator, self).__init__(*args, **kwargs)
134 self.reftest = self.suite == "web-platform-tests-reftest"
136 @classmethod
137 def get_parser(cls, parser):
138 parser.add_argument("--long-timeout", action="store_true",
139 help="Test should be given a long timeout "
140 "(typically 60s rather than 10s, but varies depending on environment)")
141 parser.add_argument("-m", "--reference", dest="ref", help="Path to the reference file")
142 parser.add_argument("--mismatch", action="store_true",
143 help="Create a mismatch reftest")
144 parser.add_argument("--wait", action="store_true",
145 help="Create a reftest that waits until takeScreenshot() is called")
147 def check_args(self):
148 if self.wpt_type(self.test) is None:
149 print("""Test path %s is not in wpt directories:
150 testing/web-platform/tests for tests that may be shared
151 testing/web-platform/mozilla/tests for Gecko-only tests""" % self.test)
152 return False
154 if not self.reftest:
155 if self.kwargs["ref"]:
156 print("--ref only makes sense for a reftest")
157 return False
159 if self.kwargs["mismatch"]:
160 print("--mismatch only makes sense for a reftest")
161 return False
163 if self.kwargs["wait"]:
164 print("--wait only makes sense for a reftest")
165 return False
166 else:
167 # Set the ref to a url relative to the test
168 if self.kwargs["ref"]:
169 if self.ref_path(self.kwargs["ref"]) is None:
170 print("--ref doesn't refer to a path inside web-platform-tests")
171 return False
173 def __iter__(self):
174 yield (self.test, self._get_template_contents())
176 if self.reftest and self.kwargs["ref"]:
177 ref_path = self.ref_path(self.kwargs["ref"])
178 yield (ref_path, self._get_template_contents(reference=True))
180 def _get_template_contents(self, reference=False):
181 args = {"documentElement": "<html class=reftest-wait>\n"
182 if self.kwargs["wait"] else ""}
184 if self.test.rsplit(".", 1)[1] == "js":
185 template = self.template_js
186 if self.kwargs["long_timeout"]:
187 template += self.template_js_long_timeout
188 else:
189 template = self.template_prefix % args
190 if self.kwargs["long_timeout"]:
191 template += self.template_long_timeout
193 if self.reftest:
194 if not reference:
195 args = {"match": "match" if not self.kwargs["mismatch"] else "mismatch",
196 "ref": (self.ref_url(self.kwargs["ref"])
197 if self.kwargs["ref"] else '""')}
198 template += self.template_body_reftest % args
199 if self.kwargs["wait"]:
200 template += self.template_body_reftest_wait
201 else:
202 template += "<title></title>"
203 else:
204 template += self.template_body_th
206 return template
208 def update_manifest(self):
209 pass
211 def src_rel_path(self, path):
212 if path is None:
213 return
215 abs_path = os.path.normpath(os.path.abspath(path))
216 return os.path.relpath(abs_path, self.topsrcdir)
218 def wpt_type(self, path):
219 path = self.src_rel_path(path)
220 if path.startswith(self.upstream_path):
221 return "upstream"
222 elif path.startswith(self.local_path):
223 return "local"
224 return None
226 def ref_path(self, path):
227 # The ref parameter can be one of several things
228 # 1. An absolute path to a reference file
229 # 2. A path to a file relative to the topsrcdir
230 # 3. A path relative to the test file
231 # These are not unambiguous, so it's somewhat best effort
233 if os.path.isabs(path):
234 path = os.path.normpath(path)
235 if not path.startswith(self.topsrcdir):
236 # Path is an absolute URL relative to the tests root
237 if path.startswith("/_mozilla/"):
238 base = self.local_path
239 path = path[len("/_mozilla/"):]
240 else:
241 base = self.upstream_path
242 path = path[1:]
243 path = path.replace("/", os.sep)
244 return os.path.join(base, path)
245 else:
246 return self.src_rel_path(path)
247 else:
248 if self.wpt_type(path) is not None:
249 return path
250 else:
251 test_rel_path = self.src_rel_path(
252 os.path.join(os.path.dirname(self.test), path))
253 if self.wpt_type(test_rel_path) is not None:
254 return test_rel_path
255 # Returning None indicates that the path wasn't valid
257 def ref_url(self, path):
258 ref_path = self.ref_path(path)
259 if not ref_path:
260 return
262 if path[0] == "/" and len(path) < len(ref_path):
263 # This is an absolute url
264 return path
266 # Othewise it's a file path
267 wpt_type_ref = self.wpt_type(ref_path)
268 wpt_type_test = self.wpt_type(self.test)
269 if wpt_type_ref == wpt_type_test:
270 return os.path.relpath(ref_path, os.path.dirname(self.test))
272 # If we have a local test referencing an upstream ref,
273 # or vice-versa use absolute paths
274 if wpt_type_ref == "upstream":
275 rel_path = os.path.relpath(ref_path, self.upstream_path)
276 url_base = "/"
277 elif wpt_type_ref == "local":
278 rel_path = os.path.relpath(ref_path, self.local_path)
279 url_base = "/_mozilla/"
280 else:
281 return None
282 return url_base + rel_path.replace(os.path.sep, "/")
285 # Insert a new test in the right place within a given manifest file
286 def write_to_ini_file(manifest_file, filename):
287 # Insert a new test in the right place within a given manifest file
288 manifest = manifestparser.TestManifest(manifests=[manifest_file])
289 insert_before = None
291 if any(t['name'] == filename for t in manifest.tests):
292 print("{} is already in the manifest.".format(filename))
293 return
295 for test in manifest.tests:
296 if test.get('name') > filename:
297 insert_before = test.get('name')
298 break
300 with open(manifest_file, "r") as f:
301 contents = f.readlines()
303 filename = '[{}]\n'.format(filename)
305 if not insert_before:
306 contents.append(filename)
307 else:
308 insert_before = '[{}]'.format(insert_before)
309 for i in range(len(contents)):
310 if contents[i].startswith(insert_before):
311 contents.insert(i, filename)
312 break
314 with io.open(manifest_file, "w", newline='\n') as f:
315 f.write("".join(contents))
318 TEST_CREATORS = {"mochitest": MochitestCreator,
319 "web-platform-tests": WebPlatformTestsCreator,
320 "xpcshell": XpcshellCreator}
323 def creator_for_suite(suite):
324 if suite.split("-")[0] == "mochitest":
325 base_suite = "mochitest"
326 else:
327 base_suite = suite.rsplit("-", 1)[0]
328 return TEST_CREATORS.get(base_suite)