Source code

Revision control

Copy as Markdown

Other Tools

# 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 functools
import types
from unittest.case import SkipTest
def parameterized(func_suffix, *args, **kwargs):
r"""Decorator which generates methods given a base method and some data.
**func_suffix** is used as a suffix for the new created method and must be
unique given a base method. if **func_suffix** countains characters that
are not allowed in normal python function name, these characters will be
replaced with "_".
This decorator can be used more than once on a single base method. The class
must have a metaclass of :class:`MetaParameterized`.
Example::
# This example will generate two methods:
#
# - MyTestCase.test_it_1
# - MyTestCase.test_it_2
#
class MyTestCase(MarionetteTestCase):
@parameterized("1", 5, named='name')
@parameterized("2", 6, named='name2')
def test_it(self, value, named=None):
print value, named
:param func_suffix: will be used as a suffix for the new method
:param \*args: arguments to pass to the new method
:param \*\*kwargs: named arguments to pass to the new method
"""
def wrapped(func):
if not hasattr(func, "metaparameters"):
func.metaparameters = []
func.metaparameters.append((func_suffix, args, kwargs))
return func
return wrapped
def run_if_manage_instance(reason):
"""Decorator which runs a test if Marionette manages the application instance."""
def decorator(test_item):
if not isinstance(test_item, types.FunctionType):
raise Exception("Decorator only supported for functions")
@functools.wraps(test_item)
def skip_wrapper(self, *args, **kwargs):
if self.marionette.instance is None:
raise SkipTest(reason)
return test_item(self, *args, **kwargs)
return skip_wrapper
return decorator
def skip_if_chrome(reason):
"""Decorator which skips a test if chrome context is active."""
def decorator(test_item):
if not isinstance(test_item, types.FunctionType):
raise Exception("Decorator only supported for functions")
@functools.wraps(test_item)
def skip_wrapper(self, *args, **kwargs):
if self.marionette._send_message("getContext", key="value") == "chrome":
raise SkipTest(reason)
return test_item(self, *args, **kwargs)
return skip_wrapper
return decorator
def skip_if_desktop(reason):
"""Decorator which skips a test if run on desktop."""
def decorator(test_item):
if not isinstance(test_item, types.FunctionType):
raise Exception("Decorator only supported for functions")
@functools.wraps(test_item)
def skip_wrapper(self, *args, **kwargs):
if self.marionette.session_capabilities.get("browserName") == "firefox":
raise SkipTest(reason)
return test_item(self, *args, **kwargs)
return skip_wrapper
return decorator
def skip_unless_browser_pref(reason, pref, predicate=bool):
"""Decorator which skips a test based on the value of a browser preference.
:param reason: Message describing why the test need to be skipped.
:param pref: the preference name
:param predicate: a function that should return false to skip the test.
The function takes one parameter, the preference value.
Defaults to the python built-in bool function.
Note that the preference must exist, else a failure is raised.
Example: ::
class TestSomething(MarionetteTestCase):
@skip_unless_browser_pref("Sessionstore needs to be enabled for crashes",
"browser.sessionstore.resume_from_crash",
lambda value: value is True,
)
def test_foo(self):
pass # test implementation here
"""
def decorator(test_item):
if not isinstance(test_item, types.FunctionType):
raise Exception("Decorator only supported for functions")
if not callable(predicate):
raise ValueError("predicate must be callable")
@functools.wraps(test_item)
def skip_wrapper(self, *args, **kwargs):
value = self.marionette.get_pref(pref)
if value is None:
self.fail("No such browser preference: {0!r}".format(pref))
if not predicate(value):
raise SkipTest(reason)
return test_item(self, *args, **kwargs)
return skip_wrapper
return decorator
def skip_unless_protocol(reason, predicate):
"""Decorator which skips a test if the predicate does not match the current protocol level."""
def decorator(test_item):
if not isinstance(test_item, types.FunctionType):
raise Exception("Decorator only supported for functions")
if not callable(predicate):
raise ValueError("predicate must be callable")
@functools.wraps(test_item)
def skip_wrapper(self, *args, **kwargs):
level = self.marionette.client.protocol
if not predicate(level):
raise SkipTest(reason)
return test_item(self, *args, **kwargs)
return skip_wrapper
return decorator
def with_parameters(parameters):
"""Decorator which generates methods given a base method and some data.
Acts like :func:`parameterized`, but define all methods in one call.
Example::
# This example will generate two methods:
#
# - MyTestCase.test_it_1
# - MyTestCase.test_it_2
#
DATA = [("1", [5], {'named':'name'}), ("2", [6], {'named':'name2'})]
class MyTestCase(MarionetteTestCase):
@with_parameters(DATA)
def test_it(self, value, named=None):
print value, named
:param parameters: list of tuples (**func_suffix**, **args**, **kwargs**)
defining parameters like in :func:`todo`.
"""
def wrapped(func):
func.metaparameters = parameters
return func
return wrapped