From 86dd99a5e295772273c076b0ed1e25011a804dbb Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 1 Nov 2018 16:25:38 +1100 Subject: [PATCH 01/37] unittest: Allow passing module name or instance into unittest.main() --- python-stdlib/unittest/unittest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 2b00fbddb..3aed90c72 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -219,7 +219,7 @@ 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) From 96007cfaf920d5cedee2991ac2d2997fba4402ef Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 31 Oct 2018 11:49:45 +1100 Subject: [PATCH 02/37] unittest: Log failure tracebacks at test end. Store traceback details for each test failure and log to console at the end of the test, like CPython version of the module does. --- python-stdlib/unittest/unittest.py | 31 ++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 3aed90c72..55468b548 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 @@ -160,7 +168,7 @@ class TestRunner: def run(self, suite): res = TestResult() for c in suite.tests: - run_class(c, res) + res.exceptions.extend(run_class(c, res)) print("Ran %d tests\n" % res.testsRun) if res.failuresNum > 0 or res.errorsNum > 0: @@ -180,16 +188,27 @@ def __init__(self): self.failuresNum = 0 self.skippedNum = 0 self.testsRun = 0 + self.exceptions = [] def wasSuccessful(self): return self.errorsNum == 0 and self.failuresNum == 0 +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() set_up = getattr(o, "setUp", lambda: None) tear_down = getattr(o, "tearDown", lambda: None) + exceptions = [] for name in dir(o): if name.startswith("test"): print("%s (%s) ..." % (name, c.__qualname__), end="") @@ -202,14 +221,14 @@ def run_class(c, test_result): except SkipTest as e: print(" skipped:", e.args[0]) test_result.skippedNum += 1 - except: + except Exception as ex: + exceptions.append(capture_exc(ex)) print(" FAIL") test_result.failuresNum += 1 - # Uncomment to investigate failure in detail - # raise continue finally: tear_down() + return exceptions def main(module="__main__"): @@ -225,5 +244,9 @@ def test_cases(m): suite.addTest(c) runner = TestRunner() result = runner.run(suite) + if result.exceptions: + sep = "\n----------------------------------------------------------------------\n" + print(sep) + print(sep.join(result.exceptions)) # Terminate with non zero return code in case of failures sys.exit(result.failuresNum > 0) From 209da35652dc60556cc1694e1f61de3f7165bfc7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Nov 2018 10:30:45 +0300 Subject: [PATCH 03/37] unittest: Release 0.4. --- python-stdlib/unittest/metadata.txt | 2 +- python-stdlib/unittest/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index f3c23ccee..980e21f52 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.4 diff --git a/python-stdlib/unittest/setup.py b/python-stdlib/unittest/setup.py index 74b985e81..009d4b0c5 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.4", 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", From 81e6b6e2389ab5bd5c74568a9326a575239679c9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Dec 2018 00:36:08 +0300 Subject: [PATCH 04/37] unittest: test_unittest.py: Fix typo in method name. --- python-stdlib/unittest/test_unittest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/test_unittest.py b/python-stdlib/unittest/test_unittest.py index 4651cf852..78c3dc9e8 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) From d098bc635447d595e2fa4be577cf5228e22f264e Mon Sep 17 00:00:00 2001 From: sss Date: Wed, 31 Oct 2018 15:59:56 +1100 Subject: [PATCH 05/37] unittest: Allow to catch AssertionError with assertRaises(). Without this change, current implementaiton produces a false positive result for AssertionError type. Example of falsely passing test code: def test(a, b): assert a > 10 assert b > 10 self.assertRaises(AssertionError, test, 20, 20) --- python-stdlib/unittest/unittest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 55468b548..f6772ddbe 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -126,12 +126,13 @@ 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 skip(msg): def _decor(fun): From 0f495dfdb2e4dc0625b98d21293c02be10dd4fd3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Jan 2019 02:42:30 +0300 Subject: [PATCH 06/37] unittest: test_unittest: Add test for .assertRaises(AssertionError). Make sure that not raising AssertionError from tested function is properly caught. --- python-stdlib/unittest/test_unittest.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/python-stdlib/unittest/test_unittest.py b/python-stdlib/unittest/test_unittest.py index 78c3dc9e8..645363cee 100644 --- a/python-stdlib/unittest/test_unittest.py +++ b/python-stdlib/unittest/test_unittest.py @@ -111,6 +111,21 @@ def testRaises(self): def testSkip(self): self.assertFail("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") + if __name__ == "__main__": unittest.main() From c2c761a8c3bf5e110efecd9ff1ca28839b99e308 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Jan 2019 02:45:11 +0300 Subject: [PATCH 07/37] unittest: Release 0.4.1. --- python-stdlib/unittest/metadata.txt | 2 +- python-stdlib/unittest/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 980e21f52..693abdc06 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.4 +version = 0.4.1 diff --git a/python-stdlib/unittest/setup.py b/python-stdlib/unittest/setup.py index 009d4b0c5..b1a9429fc 100644 --- a/python-stdlib/unittest/setup.py +++ b/python-stdlib/unittest/setup.py @@ -10,7 +10,7 @@ setup( name="micropython-unittest", - version="0.4", + version="0.4.1", 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", From 6d9ab14b15b81208b89b570a888f4c28bb897b59 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Mar 2019 23:40:09 +0300 Subject: [PATCH 08/37] unittest: test_unittest: Typo fix. --- python-stdlib/unittest/test_unittest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/test_unittest.py b/python-stdlib/unittest/test_unittest.py index 645363cee..8188def9e 100644 --- a/python-stdlib/unittest/test_unittest.py +++ b/python-stdlib/unittest/test_unittest.py @@ -109,7 +109,7 @@ 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): From 21138970648e5ba27be89ed6134032878d284572 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 27 Jul 2019 07:14:45 +0300 Subject: [PATCH 09/37] unittest: AssertRaisesContext: Store exception value as self.exception. For tests to check. This feature is used by CPython stdlib tests. --- python-stdlib/unittest/unittest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index f6772ddbe..061a0b0b4 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -21,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): From bb06989263a17a130179ef890b02b873932f9780 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 27 Jul 2019 07:15:36 +0300 Subject: [PATCH 10/37] unittest: Release 0.4.2. --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 693abdc06..ab95981de 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.4.1 +version = 0.4.2 From e6d950e25975bea4d25edc280be799ac2d7ddca9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 13 Aug 2019 08:29:50 +0300 Subject: [PATCH 11/37] unittest: Add assertLessEqual, assertGreaterEqual methods. As used by CPython testsuite. --- python-stdlib/unittest/unittest.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 061a0b0b4..a22880d5a 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -43,6 +43,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 From 9a8d644d397822da7474672bb0c3d22e82ea031e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 13 Aug 2019 08:30:31 +0300 Subject: [PATCH 12/37] unittest: Release 0.4.3. --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index ab95981de..756708af5 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.4.2 +version = 0.4.3 From 74f6b452bb40f0fa946b9a2267b787d144a87b70 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 14 Dec 2019 22:17:02 +0300 Subject: [PATCH 13/37] unittest: Reinstate useful debugger helper. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index a22880d5a..a3e058b1b 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -237,6 +237,8 @@ def run_class(c, test_result): exceptions.append(capture_exc(ex)) print(" FAIL") test_result.failuresNum += 1 + # Uncomment to investigate failure in detail + # raise continue finally: tear_down() From 06ee16e8f54b2cb2e19268994d6f724cad376086 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 15 Dec 2019 15:05:18 +0300 Subject: [PATCH 14/37] unittest: TestSuite: Add undescore to internal field, self._tests. To avoid possible name clashes. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index a3e058b1b..e0c463fff 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -170,16 +170,16 @@ def skipUnless(cond, msg): class TestSuite: def __init__(self): - self.tests = [] + self._tests = [] def addTest(self, cls): - self.tests.append(cls) + self._tests.append(cls) class TestRunner: def run(self, suite): res = TestResult() - for c in suite.tests: + for c in suite._tests: res.exceptions.extend(run_class(c, res)) print("Ran %d tests\n" % res.testsRun) From 1629f67b9d4975f935b3ad504871786d4f1f9999 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 15 Dec 2019 16:13:47 +0300 Subject: [PATCH 15/37] unittest: Only treat callable fields as test methods. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index e0c463fff..066ad3613 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -223,8 +223,10 @@ def run_class(c, test_result): exceptions = [] for name in dir(o): if name.startswith("test"): - print("%s (%s) ..." % (name, c.__qualname__), end="") m = getattr(o, name) + if not callable(m): + continue + print("%s (%s) ..." % (name, c.__qualname__), end="") set_up() try: test_result.testsRun += 1 From 9f72618b4bbac7823ff228698ae0913942f15112 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 15 Dec 2019 16:14:12 +0300 Subject: [PATCH 16/37] unittest: Release 0.4.4. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 756708af5..d6433743d 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.4.3 +version = 0.4.4 From 096beea1941ccdc9b0d383600468080be3d7437c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 26 Feb 2020 15:03:46 +0200 Subject: [PATCH 17/37] unittest: Support both test classes and class instances. And for clarity, rename runner function run_class() -> run_suite(). Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 066ad3613..55d002f42 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -180,7 +180,7 @@ class TestRunner: def run(self, suite): res = TestResult() for c in suite._tests: - res.exceptions.extend(run_class(c, res)) + res.exceptions.extend(run_suite(c, res)) print("Ran %d tests\n" % res.testsRun) if res.failuresNum > 0 or res.errorsNum > 0: @@ -216,8 +216,11 @@ def capture_exc(e): # TODO: Uncompliant -def run_class(c, test_result): - o = c() +def run_suite(c, test_result): + if isinstance(c, type): + o = c() + else: + o = c set_up = getattr(o, "setUp", lambda: None) tear_down = getattr(o, "tearDown", lambda: None) exceptions = [] From de45d3430f3a11a9635db86a1ff16da07c0a14ba Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 27 Feb 2020 17:17:48 +0200 Subject: [PATCH 18/37] unittest: TestCase: Add (dummy) __init__. Mostly to workaround inherited MicroPython's issues with inheritance. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 55d002f42..fb6c61254 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -30,6 +30,9 @@ def __exit__(self, exc_type, exc_value, tb): class TestCase: + def __init__(self): + pass + def fail(self, msg=""): assert False, msg From 375ad10e9bca2486c737858fd2057282d505ceb6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 28 Feb 2020 08:19:09 +0200 Subject: [PATCH 19/37] unittest: Release 0.5. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index d6433743d..016cd6854 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.4.4 +version = 0.5 From 73238f6e5d610710ee1d5c7f17a92d0db3663245 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 8 Aug 2020 11:42:24 +0300 Subject: [PATCH 20/37] unittest: Add TestCase.skipTest() method. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index fb6c61254..70da2ce16 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -33,6 +33,9 @@ class TestCase: def __init__(self): pass + def skipTest(self, reason): + raise SkipTest(reason) + def fail(self, msg=""): assert False, msg From 5a8b3fe666fadfb9de794e70b2ec8bce192f0e37 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 9 Aug 2020 11:58:19 +0300 Subject: [PATCH 21/37] unittest: Add dummy TestCase.subTest() context manager. Just runs "subtests" in the scope of the main TestCase. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 70da2ce16..deb678b9d 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -29,10 +29,21 @@ 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 subTest(self, msg=None, **params): + return NullContext() + def skipTest(self, reason): raise SkipTest(reason) From cd0e67f4f5f7ce0115dd6a876b0726f7984d2574 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 10 Aug 2020 20:54:49 +0300 Subject: [PATCH 22/37] unittest: Add dummy TestCase.assertWarns() context manager. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index deb678b9d..5911117c2 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -161,6 +161,9 @@ def assertRaises(self, exc, func=None, *args, **kwargs): assert False, "%r not raised" % exc + def assertWarns(self, warn): + return NullContext() + def skip(msg): def _decor(fun): From 68409a12a734f127ca9d5047c68228e2c2c23727 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 11 Aug 2020 23:03:38 +0300 Subject: [PATCH 23/37] unittest: Release 0.5.1. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 016cd6854..19dae5df9 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.5 +version = 0.5.1 From c2d27fae7d188da8cdc9f847e7b1b6aaed6a039b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 15 Nov 2020 11:52:23 +0300 Subject: [PATCH 24/37] unittest: TestSuite: Add run() method. For CPython compatibility. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 5911117c2..4e428204d 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -195,12 +195,16 @@ def __init__(self): def addTest(self, cls): self._tests.append(cls) + def run(self, result): + for c in self._tests: + result.exceptions.extend(run_suite(c, result)) + return result + class TestRunner: def run(self, suite): res = TestResult() - for c in suite._tests: - res.exceptions.extend(run_suite(c, res)) + suite.run(res) print("Ran %d tests\n" % res.testsRun) if res.failuresNum > 0 or res.errorsNum > 0: From 4f0e2a2eee69951a264c4050a712e8a5be7292db Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 16 Nov 2020 23:30:28 +0300 Subject: [PATCH 25/37] unittest: Release 0.5.2. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 19dae5df9..7fdf0ed2a 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.5.1 +version = 0.5.2 From e2ce11085cfaf0aac80da42ab0c7d309c44f6c9a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 13 May 2021 01:30:32 +0300 Subject: [PATCH 26/37] unittest: Implement basic addCleanup()/doCleanup(). Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 4e428204d..8c092a31d 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -41,6 +41,17 @@ 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() @@ -271,6 +282,7 @@ def run_suite(c, test_result): continue finally: tear_down() + o.doCleanups() return exceptions From 8b1eed7555f135c4041a84da9d279be1c9b8f3e6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 14 May 2021 17:15:24 +0300 Subject: [PATCH 27/37] unittest: Properly handle failures vs errors. Also, rework result printing to be more compatible with CPython. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 46 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 8c092a31d..ac1ff5fc3 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -208,7 +208,7 @@ def addTest(self, cls): def run(self, result): for c in self._tests: - result.exceptions.extend(run_suite(c, result)) + run_suite(c, result) return result @@ -217,6 +217,8 @@ def run(self, suite): res = TestResult() 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)) @@ -235,11 +237,33 @@ def __init__(self): self.failuresNum = 0 self.skippedNum = 0 self.testsRun = 0 - self.exceptions = [] + 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() @@ -274,9 +298,15 @@ def run_suite(c, test_result): print(" skipped:", e.args[0]) test_result.skippedNum += 1 except Exception as ex: - exceptions.append(capture_exc(ex)) - print(" FAIL") - test_result.failuresNum += 1 + 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 continue @@ -299,9 +329,5 @@ def test_cases(m): suite.addTest(c) runner = TestRunner() result = runner.run(suite) - if result.exceptions: - sep = "\n----------------------------------------------------------------------\n" - print(sep) - print(sep.join(result.exceptions)) # Terminate with non zero return code in case of failures - sys.exit(result.failuresNum > 0) + sys.exit(result.failuresNum or result.errorsNum) From 166ac7136cb03b60b3b84df9dffac4a6fc21cf97 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 15 May 2021 10:35:25 +0300 Subject: [PATCH 28/37] unittest: Support recursive TestSuite's. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index ac1ff5fc3..dcdc5a1c1 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -276,6 +276,10 @@ def capture_exc(e): # TODO: Uncompliant def run_suite(c, test_result): + if isinstance(c, TestSuite): + c.run(test_result) + return + if isinstance(c, type): o = c() else: From 6b431aa2cc1c9a82bcb5dbe4ddb4cd5d9ba203c8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 16 May 2021 08:37:25 +0300 Subject: [PATCH 29/37] unittest: Release 0.6. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 7fdf0ed2a..e4ccfffdf 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.5.2 +version = 0.6 From 5e094882169554eb22bbd46157551a02cfe1b990 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 19 Jul 2021 17:28:35 +0300 Subject: [PATCH 30/37] unittest: Add expectedFailure decorator. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index dcdc5a1c1..e6793809c 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -199,6 +199,18 @@ 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 = [] From 8cdd3c09395d2b48fc273e7d09dd4fb58090a4fa Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 20 Jul 2021 22:06:52 +0300 Subject: [PATCH 31/37] unittest: test_unittest: Add tests for expectedFailure decorator. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/test_unittest.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/python-stdlib/unittest/test_unittest.py b/python-stdlib/unittest/test_unittest.py index 8188def9e..7d7e4ca27 100644 --- a/python-stdlib/unittest/test_unittest.py +++ b/python-stdlib/unittest/test_unittest.py @@ -126,6 +126,22 @@ def func_under_test(a): 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__": unittest.main() From df5ef9909d7e59096de07e5c864e66a30b7b3825 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 21 Jul 2021 10:17:34 +0300 Subject: [PATCH 32/37] unittest: Release 0.6.1. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index e4ccfffdf..3906d1bd8 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.6 +version = 0.6.1 From 0d586446957e081cca1b3e14c9367128f51d1ab0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 12 Oct 2021 08:57:23 +0300 Subject: [PATCH 33/37] unittest: Print no. of skipped tests in a way compatible with CPython. Perhaps, modern CPython (3.8). Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index e6793809c..b5e2090a0 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -237,7 +237,7 @@ def run(self, suite): else: msg = "OK" if res.skippedNum > 0: - msg += " (%d skipped)" % res.skippedNum + msg += " (skipped=%d)" % res.skippedNum print(msg) return res From 86a5de6a780b3e84dc391505f232bdac91f94057 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Oct 2021 22:22:20 +0300 Subject: [PATCH 34/37] unittest: Add TextTestRunner as alias for TestRunner. For CPython compatibility. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index b5e2090a0..2fbe97583 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -243,6 +243,9 @@ def run(self, suite): return res +TextTestRunner = TestRunner + + class TestResult: def __init__(self): self.errorsNum = 0 From 865bc6d425c4fa5f2e78953a80cac834e8f7ea2c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Oct 2021 13:30:52 +0300 Subject: [PATCH 35/37] unittest: Release 0.6.2. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index 3906d1bd8..a2ad65a92 100644 --- a/python-stdlib/unittest/metadata.txt +++ b/python-stdlib/unittest/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.6.1 +version = 0.6.2 From 621738b03ea06e6f167d945d6faec5c8bcadc10b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Oct 2021 18:09:32 +0300 Subject: [PATCH 36/37] unittest: Support TestCase subclasses with own runTest() method. E.g. for doctest. Signed-off-by: Paul Sokolovsky --- python-stdlib/unittest/unittest.py | 58 +++++++++++++++++------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 2fbe97583..02a94d04d 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -302,36 +302,44 @@ def run_suite(c, test_result): 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"): m = getattr(o, name) if not callable(m): continue - 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 - continue - finally: - tear_down() - o.doCleanups() + run_one(m) return exceptions From f6ad093e0a5ca65d5504d72dfb1ff62d581bba9e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Oct 2021 09:17:03 +0300 Subject: [PATCH 37/37] unittest: Release 0.7. --- python-stdlib/unittest/metadata.txt | 2 +- python-stdlib/unittest/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python-stdlib/unittest/metadata.txt b/python-stdlib/unittest/metadata.txt index a2ad65a92..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.6.2 +version = 0.7 diff --git a/python-stdlib/unittest/setup.py b/python-stdlib/unittest/setup.py index b1a9429fc..982245bff 100644 --- a/python-stdlib/unittest/setup.py +++ b/python-stdlib/unittest/setup.py @@ -10,7 +10,7 @@ setup( name="micropython-unittest", - version="0.4.1", + 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",