• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3.4
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import re
18import unittest
19
20from acts import signals
21
22# Have an instance of unittest.TestCase so we could reuse some logic from
23# python's own unittest.
24# _ProxyTest is required because py2 does not allow instantiating
25# unittest.TestCase directly.
26class _ProxyTest(unittest.TestCase):
27    def runTest(self):
28        pass
29_pyunit_proxy = _ProxyTest()
30
31def assert_equal(first, second, msg=None, extras=None):
32    """Assert an expression evaluates to true, otherwise fail the test.
33
34    Error message is "first != second" by default. Additional explanation can
35    be supplied in the message.
36
37    Args:
38        expr: The expression that is evaluated.
39        msg: A string that adds additional info about the failure.
40        extras: An optional field for extra information to be included in
41                test result.
42    """
43    try:
44        _pyunit_proxy.assertEqual(first, second)
45    except AssertionError as e:
46        my_msg = str(e)
47        if msg:
48            my_msg = "%s %s" % (my_msg, msg)
49        fail(my_msg, extras=extras)
50
51def assert_raises(expected_exception, extras=None, *args, **kwargs):
52    """Assert that an exception is raised when a function is called.
53
54    If no exception is raised, test fail. If an exception is raised but not
55    of the expected type, the exception is let through.
56
57    This should only be used as a context manager:
58        with assert_raises(Exception):
59            func()
60
61    Args:
62        expected_exception: An exception class that is expected to be
63                            raised.
64        extras: An optional field for extra information to be included in
65                test result.
66    """
67    context = _AssertRaisesContext(expected_exception, extras=extras)
68    return context
69
70def assert_raises_regex(expected_exception, expected_regex, extras=None, *args,
71                        **kwargs):
72    """Assert that an exception is raised when a function is called.
73
74    If no exception is raised, test fail. If an exception is raised but not
75    of the expected type, the exception is let through. If an exception of the
76    expected type is raised but the error message does not match the
77    expected_regex, test fail.
78
79    This should only be used as a context manager:
80        with assert_raises(Exception):
81            func()
82
83    Args:
84        expected_exception: An exception class that is expected to be
85                            raised.
86        extras: An optional field for extra information to be included in
87                test result.
88    """
89    context = _AssertRaisesContext(expected_exception, expected_regex,
90                                   extras=extras)
91    return context
92
93def assert_true(expr, msg, extras=None):
94    """Assert an expression evaluates to true, otherwise fail the test.
95
96    Args:
97        expr: The expression that is evaluated.
98        msg: A string explaining the details in case of failure.
99        extras: An optional field for extra information to be included in
100                test result.
101    """
102    if not expr:
103        fail(msg, extras)
104
105def skip(reason, extras=None):
106    """Skip a test case.
107
108    Args:
109        reason: The reason this test is skipped.
110        extras: An optional field for extra information to be included in
111                test result.
112
113    Raises:
114        signals.TestSkip is raised to mark a test case as skipped.
115    """
116    raise signals.TestSkip(reason, extras)
117
118def skip_if(expr, reason, extras=None):
119    """Skip a test case if expression evaluates to True.
120
121    Args:
122        expr: The expression that is evaluated.
123        reason: The reason this test is skipped.
124        extras: An optional field for extra information to be included in
125                test result.
126    """
127    if expr:
128        skip(reason, extras)
129
130def abort_class(reason, extras=None):
131    """Abort all subsequent test cases within the same test class in one
132    iteration.
133
134    If one test class is requested multiple times in a test run, this can
135    only abort one of the requested executions, NOT all.
136
137    Args:
138        reason: The reason to abort.
139        extras: An optional field for extra information to be included in
140                test result.
141
142    Raises:
143        signals.TestAbortClass is raised to abort all subsequent tests in a
144        test class.
145    """
146    raise signals.TestAbortClass(reason, extras)
147
148def abort_class_if(expr, reason, extras=None):
149    """Abort all subsequent test cases within the same test class in one
150    iteration, if expression evaluates to True.
151
152    If one test class is requested multiple times in a test run, this can
153    only abort one of the requested executions, NOT all.
154
155    Args:
156        expr: The expression that is evaluated.
157        reason: The reason to abort.
158        extras: An optional field for extra information to be included in
159                test result.
160
161    Raises:
162        signals.TestAbortClass is raised to abort all subsequent tests in a
163        test class.
164    """
165    if expr:
166        abort_class(reason, extras)
167
168def abort_all(reason, extras=None):
169    """Abort all subsequent test cases, including the ones not in this test
170    class or iteration.
171
172    Args:
173        reason: The reason to abort.
174        extras: An optional field for extra information to be included in
175                test result.
176
177    Raises:
178        signals.TestAbortAll is raised to abort all subsequent tests.
179    """
180    raise signals.TestAbortAll(reason, extras)
181
182def abort_all_if(expr, reason, extras=None):
183    """Abort all subsequent test cases, if the expression evaluates to
184    True.
185
186    Args:
187        expr: The expression that is evaluated.
188        reason: The reason to abort.
189        extras: An optional field for extra information to be included in
190                test result.
191
192    Raises:
193        signals.TestAbortAll is raised to abort all subsequent tests.
194    """
195    if expr:
196        abort_all(reason, extras)
197
198def fail(msg, extras=None):
199    """Explicitly fail a test case.
200
201    Args:
202        msg: A string explaining the details of the failure.
203        extras: An optional field for extra information to be included in
204                test result.
205
206    Raises:
207        signals.TestFailure is raised to mark a test case as failed.
208    """
209    raise signals.TestFailure(msg, extras)
210
211def explicit_pass(msg, extras=None):
212    """Explicitly pass a test case.
213
214    A test with not uncaught exception will pass implicitly so the usage of
215    this is optional. It is intended for reporting extra information when a
216    test passes.
217
218    Args:
219        msg: A string explaining the details of the passed test.
220        extras: An optional field for extra information to be included in
221                test result.
222
223    Raises:
224        signals.TestPass is raised to mark a test case as passed.
225    """
226    raise signals.TestPass(msg, extras)
227
228class _AssertRaisesContext(object):
229    """A context manager used to implement TestCase.assertRaises* methods."""
230
231    def __init__(self, expected, expected_regexp=None, extras=None):
232        self.expected = expected
233        self.failureException = signals.TestFailure
234        self.expected_regexp = expected_regexp
235        self.extras = extras
236
237    def __enter__(self):
238        return self
239
240    def __exit__(self, exc_type, exc_value, tb):
241        if exc_type is None:
242            try:
243                exc_name = self.expected.__name__
244            except AttributeError:
245                exc_name = str(self.expected)
246            raise signals.TestFailure("{} not raised".format(exc_name),
247                                      extras=self.extras)
248        if not issubclass(exc_type, self.expected):
249            # let unexpected exceptions pass through
250            return False
251        self.exception = exc_value # store for later retrieval
252        if self.expected_regexp is None:
253            return True
254
255        expected_regexp = self.expected_regexp
256        if isinstance(expected_regexp, str):
257            expected_regexp = re.compile(expected_regexp)
258        if not expected_regexp.search(str(exc_value)):
259            raise signals.TestFailure('"%s" does not match "%s"' %
260                     (expected_regexp.pattern, str(exc_value)),
261                      extras=self.extras)
262        return True
263