unittest.py
1 """Based on https://raw.githubusercontent.com/micropython/micropython-lib/cfa1b9cce0c93a3115bbff3886c9bbcddd9e8047/unittest/unittest.py """ 2 import sys 3 4 5 class SkipTest(Exception): 6 pass 7 8 9 raiseException = False 10 raiseBaseException = True 11 12 13 class AssertRaisesContext: 14 def __init__(self, exc): 15 self.expected = exc 16 17 def __enter__(self): 18 return self 19 20 def __exit__(self, exc_type, exc_value, tb): 21 if exc_type is None: 22 assert False, "%r not raised" % self.expected 23 if issubclass(exc_type, self.expected): 24 return True 25 return False 26 27 28 class TestCase: 29 def fail(self, msg=""): 30 assert False, msg 31 32 def assertEqual(self, x, y, msg=""): 33 if not msg: 34 msg = "%r vs (expected) %r" % (x, y) 35 assert x == y, msg 36 37 def assertNotEqual(self, x, y, msg=""): 38 if not msg: 39 msg = "%r not expected to be equal %r" % (x, y) 40 assert x != y, msg 41 42 def assertAlmostEqual(self, x, y, places=None, msg="", delta=None): 43 if x == y: 44 return 45 if delta is not None and places is not None: 46 raise TypeError("specify delta or places not both") 47 48 if delta is not None: 49 if abs(x - y) <= delta: 50 return 51 if not msg: 52 msg = "%r != %r within %r delta" % (x, y, delta) 53 else: 54 if places is None: 55 places = 7 56 if round(abs(y - x), places) == 0: 57 return 58 if not msg: 59 msg = "%r != %r within %r places" % (x, y, places) 60 61 assert False, msg 62 63 def assertNotAlmostEqual(self, x, y, places=None, msg="", delta=None): 64 if delta is not None and places is not None: 65 raise TypeError("specify delta or places not both") 66 67 if delta is not None: 68 if not (x == y) and abs(x - y) > delta: 69 return 70 if not msg: 71 msg = "%r == %r within %r delta" % (x, y, delta) 72 else: 73 if places is None: 74 places = 7 75 if not (x == y) and round(abs(y - x), places) != 0: 76 return 77 if not msg: 78 msg = "%r == %r within %r places" % (x, y, places) 79 80 assert False, msg 81 82 def assertIs(self, x, y, msg=""): 83 if not msg: 84 msg = "%r is not %r" % (x, y) 85 assert x is y, msg 86 87 def assertIsNot(self, x, y, msg=""): 88 if not msg: 89 msg = "%r is %r" % (x, y) 90 assert x is not y, msg 91 92 def assertIsNone(self, x, msg=""): 93 if not msg: 94 msg = "%r is not None" % x 95 assert x is None, msg 96 97 def assertIsNotNone(self, x, msg=""): 98 if not msg: 99 msg = "%r is None" % x 100 assert x is not None, msg 101 102 def assertTrue(self, x, msg=""): 103 if not msg: 104 msg = "Expected %r to be True" % x 105 assert x, msg 106 107 def assertFalse(self, x, msg=""): 108 if not msg: 109 msg = "Expected %r to be False" % x 110 assert not x, msg 111 112 def assertIn(self, x, y, msg=""): 113 if not msg: 114 msg = "Expected %r to be in %r" % (x, y) 115 assert x in y, msg 116 117 def assertIsInstance(self, x, y, msg=""): 118 assert isinstance(x, y), msg 119 120 def assertRaises(self, exc, func=None, *args, **kwargs): 121 if func is None: 122 return AssertRaisesContext(exc) 123 124 try: 125 func(*args, **kwargs) 126 assert False, "%r not raised" % exc 127 except Exception as e: 128 if isinstance(e, exc): 129 return 130 raise 131 132 133 def skip(msg): 134 def _decor(fun): 135 # We just replace original fun with _inner 136 def _inner(self): 137 raise SkipTest(msg) 138 139 return _inner 140 141 return _decor 142 143 144 def skipIf(cond, msg): 145 if not cond: 146 return lambda x: x 147 return skip(msg) 148 149 150 def skipUnless(cond, msg): 151 if cond: 152 return lambda x: x 153 return skip(msg) 154 155 156 class TestSuite: 157 def __init__(self): 158 self.tests = [] 159 160 def addTest(self, cls): 161 self.tests.append(cls) 162 163 164 class TestRunner: 165 def run(self, suite): 166 res = TestResult() 167 for c in suite.tests: 168 run_class(c, res) 169 170 print("Ran %d tests\n" % res.testsRun) 171 if res.failuresNum > 0 or res.errorsNum > 0: 172 print("FAILED (failures=%d, errors=%d)" % (res.failuresNum, res.errorsNum)) 173 else: 174 msg = "OK" 175 if res.skippedNum > 0: 176 msg += " (%d skipped)" % res.skippedNum 177 print(msg) 178 179 return res 180 181 182 class TestResult: 183 def __init__(self): 184 self.errorsNum = 0 185 self.failuresNum = 0 186 self.skippedNum = 0 187 self.testsRun = 0 188 189 def wasSuccessful(self): 190 return self.errorsNum == 0 and self.failuresNum == 0 191 192 193 # TODO: Uncompliant 194 def run_class(c, test_result): 195 o = c() 196 set_up = getattr(o, "setUp", lambda: None) 197 tear_down = getattr(o, "tearDown", lambda: None) 198 for name in dir(o): 199 if name.startswith("test"): 200 print("%s (%s) ..." % (name, c.__qualname__), end="") 201 m = getattr(o, name) 202 set_up() 203 try: 204 test_result.testsRun += 1 205 m() 206 print(" ok") 207 except SkipTest as e: 208 print(" skipped:", e.args[0]) 209 test_result.skippedNum += 1 210 except Exception as e: # user exception 211 print(" FAIL") 212 if raiseException: 213 raise 214 else: 215 print(e) 216 test_result.failuresNum += 1 217 continue 218 except BaseException as e: # system exception 219 print(" FAIL") 220 if raiseBaseException: 221 raise 222 else: 223 print(e) 224 test_result.failuresNum += 1 225 continue 226 finally: 227 tear_down() 228 229 230 def main(module="__main__"): 231 def test_cases(m): 232 for tn in dir(m): 233 c = getattr(m, tn) 234 if ( 235 isinstance(c, object) 236 and isinstance(c, type) 237 and issubclass(c, TestCase) 238 ): 239 yield c 240 241 m = __import__(module) # changed to permit non-top-level testing modules 242 suite = TestSuite() 243 for c in test_cases(m): 244 suite.addTest(c) 245 runner = TestRunner() 246 result = runner.run(suite)