/ test / src / unittest.py
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)