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