Source code for mobly.asserts

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import unittest

from mobly import signals


# Have an instance of unittest.TestCase so we could reuse some logic from
# python's own unittest.
# _ProxyTest is required because py2 does not allow instantiating
# unittest.TestCase directly.
class _ProxyTest(unittest.TestCase):
    def runTest(self):
        pass


_pyunit_proxy = _ProxyTest()


[docs]def assert_equal(first, second, msg=None, extras=None): """Assert the equality of objects, otherwise fail the test. Error message is "first != second" by default. Additional explanation can be supplied in the message. Args: first: The first object to compare. second: The second object to compare. msg: A string that adds additional info about the failure. extras: An optional field for extra information to be included in test result. """ my_msg = None try: _pyunit_proxy.assertEqual(first, second) except AssertionError as e: my_msg = str(e) if msg: my_msg = "%s %s" % (my_msg, msg) # This raise statement is outside of the above except statement to prevent # Python3's exception message from having two tracebacks. if my_msg is not None: raise signals.TestFailure(my_msg, extras=extras)
[docs]def assert_raises(expected_exception, extras=None, *args, **kwargs): """Assert that an exception is raised when a function is called. If no exception is raised, test fail. If an exception is raised but not of the expected type, the exception is let through. This should only be used as a context manager: with assert_raises(Exception): func() Args: expected_exception: An exception class that is expected to be raised. extras: An optional field for extra information to be included in test result. """ context = _AssertRaisesContext(expected_exception, extras=extras) return context
[docs]def assert_raises_regex(expected_exception, expected_regex, extras=None, *args, **kwargs): """Assert that an exception is raised when a function is called. If no exception is raised, test fail. If an exception is raised but not of the expected type, the exception is let through. If an exception of the expected type is raised but the error message does not match the expected_regex, test fail. This should only be used as a context manager: with assert_raises(Exception): func() Args: expected_exception: An exception class that is expected to be raised. extras: An optional field for extra information to be included in test result. """ context = _AssertRaisesContext(expected_exception, expected_regex, extras=extras) return context
[docs]def assert_true(expr, msg, extras=None): """Assert an expression evaluates to true, otherwise fail the test. Args: expr: The expression that is evaluated. msg: A string explaining the details in case of failure. extras: An optional field for extra information to be included in test result. """ if not expr: fail(msg, extras)
[docs]def assert_false(expr, msg, extras=None): """Assert an expression evaluates to false, otherwise fail the test. Args: expr: The expression that is evaluated. msg: A string explaining the details in case of failure. extras: An optional field for extra information to be included in test result. """ if expr: fail(msg, extras)
[docs]def skip_if(expr, reason, extras=None): """Skip a test if expression evaluates to True. Args: expr: The expression that is evaluated. reason: The reason this test is skipped. extras: An optional field for extra information to be included in test result. """ if expr: skip(reason, extras)
[docs]def abort_class(reason, extras=None): """Abort all subsequent tests within the same test class in one iteration. If one test class is requested multiple times in a test run, this can only abort one of the requested executions, NOT all. Args: reason: The reason to abort. extras: An optional field for extra information to be included in test result. Raises: signals.TestAbortClass: Abort all subsequent tests in a test class. """ raise signals.TestAbortClass(reason, extras)
[docs]def abort_class_if(expr, reason, extras=None): """Abort all subsequent tests within the same test class in one iteration, if expression evaluates to True. If one test class is requested multiple times in a test run, this can only abort one of the requested executions, NOT all. Args: expr: The expression that is evaluated. reason: The reason to abort. extras: An optional field for extra information to be included in test result. Raises: signals.TestAbortClass: Abort all subsequent tests in a test class. """ if expr: abort_class(reason, extras)
[docs]def abort_all(reason, extras=None): """Abort all subsequent tests, including the ones not in this test class or iteration. Args: reason: The reason to abort. extras: An optional field for extra information to be included in test result. Raises: signals.TestAbortAll: Abort all subsequent tests. """ raise signals.TestAbortAll(reason, extras)
[docs]def abort_all_if(expr, reason, extras=None): """Abort all subsequent tests, if the expression evaluates to True. Args: expr: The expression that is evaluated. reason: The reason to abort. extras: An optional field for extra information to be included in test result. Raises: signals.TestAbortAll: Abort all subsequent tests. """ if expr: abort_all(reason, extras)
[docs]def fail(msg, extras=None): """Explicitly fail a test. Args: msg: A string explaining the details of the failure. extras: An optional field for extra information to be included in test result. Raises: signals.TestFailure: Mark a test as failed. """ raise signals.TestFailure(msg, extras)
[docs]def explicit_pass(msg, extras=None): """Explicitly pass a test. This will pass the test explicitly regardless of any other error happened in the test body. E.g. even if errors have been recorded with `expects`, the test will still be marked pass if this is called. A test without uncaught exception will pass implicitly so this should be used scarcely. Args: msg: A string explaining the details of the passed test. extras: An optional field for extra information to be included in test result. Raises: signals.TestPass: Mark a test as passed. """ raise signals.TestPass(msg, extras)
class _AssertRaisesContext(object): """A context manager used to implement TestCase.assertRaises* methods.""" def __init__(self, expected, expected_regexp=None, extras=None): self.expected = expected self.failureException = signals.TestFailure self.expected_regexp = expected_regexp self.extras = extras def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): if exc_type is None: try: exc_name = self.expected.__name__ except AttributeError: exc_name = str(self.expected) raise signals.TestFailure('%s not raised' % exc_name, extras=self.extras) if not issubclass(exc_type, self.expected): # let unexpected exceptions pass through return False self.exception = exc_value # store for later retrieval if self.expected_regexp is None: return True expected_regexp = self.expected_regexp if isinstance(expected_regexp, str): expected_regexp = re.compile(expected_regexp) if not expected_regexp.search(str(exc_value)): raise signals.TestFailure( '"%s" does not match "%s"' % (expected_regexp.pattern, str(exc_value)), extras=self.extras) return True