1 from inspect
import isabstract
2 from six
import iteritems
, with_metaclass
3 from six
.moves
.urllib
.parse
import urljoin
, urlparse
4 from abc
import ABCMeta
, abstractproperty
6 from .utils
import to_os_path
10 # MYPY is set to True when run under Mypy.
11 from typing
import Optional
12 from typing
import Text
13 from typing
import Dict
14 from typing
import Tuple
15 from typing
import List
16 from typing
import Union
17 from typing
import Type
18 from typing
import Any
19 from typing
import Sequence
20 from typing
import Hashable
21 from .manifest
import Manifest
22 Fuzzy
= Dict
[Optional
[Tuple
[Text
, Text
, Text
]], List
[int]]
24 item_types
= {} # type: Dict[str, Type[ManifestItem]]
27 class ManifestItemMeta(ABCMeta
):
28 """Custom metaclass that registers all the subclasses in the
29 item_types dictionary according to the value of their item_type
30 attribute, and otherwise behaves like an ABCMeta."""
32 def __new__(cls
, name
, bases
, attrs
):
33 # type: (Type[ManifestItemMeta], str, Tuple[ManifestItemMeta, ...], Dict[str, Any]) -> ManifestItemMeta
34 rv
= super(ManifestItemMeta
, cls
).__new
__(cls
, name
, bases
, attrs
)
35 if not isabstract(rv
):
36 assert issubclass(rv
, ManifestItem
)
37 assert isinstance(rv
.item_type
, str)
38 item_types
[rv
.item_type
] = rv
40 return rv
# type: ignore
43 class ManifestItem(with_metaclass(ManifestItemMeta
)):
44 __slots__
= ("_tests_root", "path")
46 def __init__(self
, tests_root
, path
):
47 # type: (Text, Text) -> None
48 self
._tests
_root
= tests_root
54 """The test's id (usually its url)"""
64 # type: () -> Hashable
65 """A unique identifier for the test"""
66 return (self
.item_type
, self
.id)
68 def __eq__(self
, other
):
70 if not hasattr(other
, "key"):
72 return bool(self
.key() == other
.key())
76 return hash(self
.key())
80 return "<%s.%s id=%r, path=%r>" % (self
.__module
__, self
.__class
__.__name
__, self
.id, self
.path
)
83 # type: () -> Tuple[Any, ...]
88 manifest
, # type: Manifest
92 # type: (...) -> ManifestItem
93 path
= to_os_path(path
)
94 tests_root
= manifest
.tests_root
95 assert tests_root
is not None
96 return cls(tests_root
, path
)
99 class URLManifestItem(ManifestItem
):
100 __slots__
= ("url_base", "_url", "_extras")
103 tests_root
, # type: Text
105 url_base
, # type: Text
109 # type: (...) -> None
110 super(URLManifestItem
, self
).__init
__(tests_root
, path
)
111 assert url_base
[0] == "/"
112 self
.url_base
= url_base
115 self
._extras
= extras
125 # we can outperform urljoin, because we know we just have path relative URLs
126 if self
.url_base
== "/":
127 return "/" + self
._url
128 return urljoin(self
.url_base
, self
._url
)
133 flags
= set(urlparse(self
.url
).path
.rsplit("/", 1)[1].split(".")[1:-1])
134 return "https" in flags
or "serviceworker" in flags
139 flags
= set(urlparse(self
.url
).path
.rsplit("/", 1)[1].split(".")[1:-1])
143 # type: () -> Tuple[Text, Dict[Any, Any]]
144 rv
= (self
._url
, {}) # type: Tuple[Text, Dict[Any, Any]]
149 manifest
, # type: Manifest
151 obj
# type: Tuple[Text, Dict[Any, Any]]
153 # type: (...) -> URLManifestItem
154 path
= to_os_path(path
)
156 tests_root
= manifest
.tests_root
157 assert tests_root
is not None
158 return cls(tests_root
,
165 class TestharnessTest(URLManifestItem
):
168 item_type
= "testharness"
172 # type: () -> Optional[Text]
173 return self
._extras
.get("timeout")
176 def testdriver(self
):
177 # type: () -> Optional[Text]
178 return self
._extras
.get("testdriver")
182 # type: () -> Optional[Text]
183 return self
._extras
.get("jsshell")
186 def script_metadata(self
):
187 # type: () -> Optional[Text]
188 return self
._extras
.get("script_metadata")
191 # type: () -> Tuple[Text, Dict[Text, Any]]
192 rv
= super(TestharnessTest
, self
).to_json()
193 if self
.timeout
is not None:
194 rv
[-1]["timeout"] = self
.timeout
196 rv
[-1]["testdriver"] = self
.testdriver
198 rv
[-1]["jsshell"] = True
199 if self
.script_metadata
:
200 rv
[-1]["script_metadata"] = self
.script_metadata
204 class RefTest(URLManifestItem
):
205 __slots__
= ("references",)
207 item_type
= "reftest"
210 tests_root
, # type: Text
212 url_base
, # type: Text
214 references
=None, # type: Optional[List[Tuple[Text, Text]]]
217 super(RefTest
, self
).__init
__(tests_root
, path
, url_base
, url
, **extras
)
218 if references
is None:
219 self
.references
= [] # type: List[Tuple[Text, Text]]
221 self
.references
= references
225 # type: () -> Optional[Text]
226 return self
._extras
.get("timeout")
229 def viewport_size(self
):
230 # type: () -> Optional[Text]
231 return self
._extras
.get("viewport_size")
235 # type: () -> Optional[Text]
236 return self
._extras
.get("dpi")
241 fuzzy
= self
._extras
.get("fuzzy", {}) # type: Union[Fuzzy, List[Tuple[Optional[Sequence[Text]], List[int]]]]
242 if not isinstance(fuzzy
, list):
245 rv
= {} # type: Fuzzy
246 for k
, v
in fuzzy
: # type: Tuple[Optional[Sequence[Text]], List[int]]
248 key
= None # type: Optional[Tuple[Text, Text, Text]]
250 # mypy types this as Tuple[Text, ...]
252 key
= tuple(k
) # type: ignore
256 def to_json(self
): # type: ignore
257 # type: () -> Tuple[Text, List[Tuple[Text, Text]], Dict[Text, Any]]
258 rv
= (self
._url
, self
.references
, {}) # type: Tuple[Text, List[Tuple[Text, Text]], Dict[Text, Any]]
260 if self
.timeout
is not None:
261 extras
["timeout"] = self
.timeout
262 if self
.viewport_size
is not None:
263 extras
["viewport_size"] = self
.viewport_size
264 if self
.dpi
is not None:
265 extras
["dpi"] = self
.dpi
267 extras
["fuzzy"] = list(iteritems(self
.fuzzy
))
271 def from_json(cls
, # type: ignore
272 manifest
, # type: Manifest
274 obj
# type: Tuple[Text, List[Tuple[Text, Text]], Dict[Any, Any]]
276 # type: (...) -> RefTest
277 tests_root
= manifest
.tests_root
278 assert tests_root
is not None
279 path
= to_os_path(path
)
280 url
, references
, extras
= obj
281 return cls(tests_root
,
289 class ManualTest(URLManifestItem
):
295 class ConformanceCheckerTest(URLManifestItem
):
298 item_type
= "conformancechecker"
301 class VisualTest(URLManifestItem
):
307 class CrashTest(URLManifestItem
):
310 item_type
= "crashtest"
314 # type: () -> Optional[Text]
318 class WebDriverSpecTest(URLManifestItem
):
325 # type: () -> Optional[Text]
326 return self
._extras
.get("timeout")
329 # type: () -> Tuple[Text, Dict[Text, Any]]
330 rv
= super(WebDriverSpecTest
, self
).to_json()
331 if self
.timeout
is not None:
332 rv
[-1]["timeout"] = self
.timeout
336 class SupportFile(ManifestItem
):
339 item_type
= "support"