diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index f3c23ccee..29a804880 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.3.2 +version = 0.7 diff --git a/python-stdlib/unittest/setup.py b/python-stdlib/unittest/setup.py index 74b985e81..982245bff 100644 --- a/python-stdlib/unittest/setup.py +++ b/python-stdlib/unittest/setup.py @@ -10,7 +10,7 @@ setup( name="micropython-unittest", - version="0.3.2", + version="0.7.0", description="unittest module for MicroPython", long_description="This is a module reimplemented specifically for MicroPython standard library,\nwith efficient and lean design in mind. Note that this module is likely work\nin progress and likely supports just a subset of CPython's corresponding\nmodule. Please help with the development if you are interested in this\nmodule.", url="https://github.com/micropython/micropython-lib", diff --git a/python-stdlib/unittest/test_unittest.py b/python-stdlib/unittest/test_unittest.py index 4651cf852..7d7e4ca27 100644 --- a/python-stdlib/unittest/test_unittest.py +++ b/python-stdlib/unittest/test_unittest.py @@ -37,7 +37,7 @@ def test_AlmostEqual(self): with self.assertRaises(AssertionError): self.assertNotAlmostEqual(float("inf"), float("inf")) - def test_AmostEqualWithDelta(self): + def test_AlmostEqualWithDelta(self): self.assertAlmostEqual(1.1, 1.0, delta=0.5) self.assertAlmostEqual(1.0, 1.1, delta=0.5) self.assertNotAlmostEqual(1.1, 1.0, delta=0.05) @@ -109,7 +109,38 @@ def testRaises(self): @unittest.skip("test of skipping") def testSkip(self): - self.assertFail("this should be skipped") + self.fail("this should be skipped") + + def testAssert(self): + + e1 = None + try: + + def func_under_test(a): + assert a > 10 + + self.assertRaises(AssertionError, func_under_test, 20) + except AssertionError as e: + e1 = e + + if not e1 or "not raised" not in e1.args[0]: + self.fail("Expected to catch lack of AssertionError from assert in func_under_test") + + @unittest.expectedFailure + def testExpectedFailure(self): + self.assertEqual(1, 0) + + def testExpectedFailureNot(self): + @unittest.expectedFailure + def testInner(): + self.assertEqual(1, 1) + + try: + testInner() + except: + pass + else: + self.fail("Unexpected success was not detected") if __name__ == "__main__": diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 2b00fbddb..02a94d04d 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -1,5 +1,13 @@ import sys +try: + import io + import traceback +except ImportError: + import uio as io + + traceback = None + class SkipTest(Exception): pass @@ -13,6 +21,7 @@ def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): + self.exception = exc_value if exc_type is None: assert False, "%r not raised" % self.expected if issubclass(exc_type, self.expected): @@ -20,7 +29,35 @@ def __exit__(self, exc_type, exc_value, tb): return False +class NullContext: + def __enter__(self): + pass + + def __exit__(self, a, b, c): + pass + + class TestCase: + def __init__(self): + pass + + def addCleanup(self, func, *args, **kwargs): + if not hasattr(self, "_cleanups"): + self._cleanups = [] + self._cleanups.append((func, args, kwargs)) + + def doCleanups(self): + if hasattr(self, "_cleanups"): + while self._cleanups: + func, args, kwargs = self._cleanups.pop() + func(*args, **kwargs) + + def subTest(self, msg=None, **params): + return NullContext() + + def skipTest(self, reason): + raise SkipTest(reason) + def fail(self, msg=""): assert False, msg @@ -34,6 +71,16 @@ def assertNotEqual(self, x, y, msg=""): msg = "%r not expected to be equal %r" % (x, y) assert x != y, msg + def assertLessEqual(self, x, y, msg=None): + if msg is None: + msg = "%r is expected to be <= %r" % (x, y) + assert x <= y, msg + + def assertGreaterEqual(self, x, y, msg=None): + if msg is None: + msg = "%r is expected to be >= %r" % (x, y) + assert x >= y, msg + def assertAlmostEqual(self, x, y, places=None, msg="", delta=None): if x == y: return @@ -118,12 +165,16 @@ def assertRaises(self, exc, func=None, *args, **kwargs): try: func(*args, **kwargs) - assert False, "%r not raised" % exc except Exception as e: if isinstance(e, exc): return raise + assert False, "%r not raised" % exc + + def assertWarns(self, warn): + return NullContext() + def skip(msg): def _decor(fun): @@ -148,68 +199,148 @@ def skipUnless(cond, msg): return skip(msg) +def expectedFailure(test): + def test_exp_fail(*args, **kwargs): + try: + test(*args, **kwargs) + except: + pass + else: + assert False, "unexpected success" + + return test_exp_fail + + class TestSuite: def __init__(self): - self.tests = [] + self._tests = [] def addTest(self, cls): - self.tests.append(cls) + self._tests.append(cls) + + def run(self, result): + for c in self._tests: + run_suite(c, result) + return result class TestRunner: def run(self, suite): res = TestResult() - for c in suite.tests: - run_class(c, res) + suite.run(res) + res.printErrors() + print("----------------------------------------------------------------------") print("Ran %d tests\n" % res.testsRun) if res.failuresNum > 0 or res.errorsNum > 0: print("FAILED (failures=%d, errors=%d)" % (res.failuresNum, res.errorsNum)) else: msg = "OK" if res.skippedNum > 0: - msg += " (%d skipped)" % res.skippedNum + msg += " (skipped=%d)" % res.skippedNum print(msg) return res +TextTestRunner = TestRunner + + class TestResult: def __init__(self): self.errorsNum = 0 self.failuresNum = 0 self.skippedNum = 0 self.testsRun = 0 + self.errors = [] + self.failures = [] def wasSuccessful(self): return self.errorsNum == 0 and self.failuresNum == 0 + def printErrors(self): + print() + self.printErrorList(self.errors) + self.printErrorList(self.failures) + + def printErrorList(self, lst): + sep = "----------------------------------------------------------------------" + for c, e in lst: + print("======================================================================") + print(c) + print(sep) + print(e) + + def __repr__(self): + # Format is compatible with CPython. + return "" % ( + self.testsRun, + self.errorsNum, + self.failuresNum, + ) + + +def capture_exc(e): + buf = io.StringIO() + if hasattr(sys, "print_exception"): + sys.print_exception(e, buf) + elif traceback is not None: + traceback.print_exception(None, e, sys.exc_info()[2], file=buf) + return buf.getvalue() + # TODO: Uncompliant -def run_class(c, test_result): - o = c() +def run_suite(c, test_result): + if isinstance(c, TestSuite): + c.run(test_result) + return + + if isinstance(c, type): + o = c() + else: + o = c set_up = getattr(o, "setUp", lambda: None) tear_down = getattr(o, "tearDown", lambda: None) + exceptions = [] + + def run_one(m): + print("%s (%s) ..." % (name, c.__qualname__), end="") + set_up() + try: + test_result.testsRun += 1 + m() + print(" ok") + except SkipTest as e: + print(" skipped:", e.args[0]) + test_result.skippedNum += 1 + except Exception as ex: + ex_str = capture_exc(ex) + if isinstance(ex, AssertionError): + test_result.failuresNum += 1 + test_result.failures.append(((name, c), ex_str)) + print(" FAIL") + else: + test_result.errorsNum += 1 + test_result.errors.append(((name, c), ex_str)) + print(" ERROR") + # Uncomment to investigate failure in detail + # raise + finally: + tear_down() + o.doCleanups() + + if hasattr(o, "runTest"): + name = str(o) + run_one(o.runTest) + return + for name in dir(o): if name.startswith("test"): - print("%s (%s) ..." % (name, c.__qualname__), end="") m = getattr(o, name) - set_up() - try: - test_result.testsRun += 1 - m() - print(" ok") - except SkipTest as e: - print(" skipped:", e.args[0]) - test_result.skippedNum += 1 - except: - print(" FAIL") - test_result.failuresNum += 1 - # Uncomment to investigate failure in detail - # raise + if not callable(m): continue - finally: - tear_down() + run_one(m) + return exceptions def main(module="__main__"): @@ -219,11 +350,11 @@ def test_cases(m): if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase): yield c - m = __import__(module) + m = __import__(module) if isinstance(module, str) else module suite = TestSuite() for c in test_cases(m): suite.addTest(c) runner = TestRunner() result = runner.run(suite) # Terminate with non zero return code in case of failures - sys.exit(result.failuresNum > 0) + sys.exit(result.failuresNum or result.errorsNum) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy