diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a0ebe28 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +dist: xenial +language: python +matrix: + include: + - python: 3.7 + env: TOXENV=flake8 + - python: 3.5 + env: TOXENV=py35 + - python: 3.6 + env: TOXENV=py36 + - python: 3.7 + env: TOXENV=py37 + - python: 3.7 + env: TOXENV=upy +install: + - pip install tox +script: + - tox diff --git a/bin/micropython b/bin/micropython new file mode 100755 index 0000000..91b3b94 Binary files /dev/null and b/bin/micropython differ diff --git a/run_tests.py b/run_tests.py new file mode 100644 index 0000000..b8b8e5b --- /dev/null +++ b/run_tests.py @@ -0,0 +1,3 @@ +import unittest + +unittest.main('tests') diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..74d5e5a --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +from tests.test_microdot import TestMicrodot diff --git a/tests/test_microdot.py b/tests/test_microdot.py new file mode 100644 index 0000000..8d7a0aa --- /dev/null +++ b/tests/test_microdot.py @@ -0,0 +1,6 @@ +import unittest + + +class TestMicrodot(unittest.TestCase): + def test_foo(self): + pass diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..22dff1b --- /dev/null +++ b/tox.ini @@ -0,0 +1,26 @@ +[tox] +envlist=flake8,py35,py36,py37,upy +skip_missing_interpreters=True + +[testenv] +commands=python run_tests.py +basepython= + flake8: python3.7 + py35: python3.5 + py36: python3.6 + py37: python3.7 + upy: python3.7 + +[testenv:flake8] +deps= + flake8 +commands= + flake8 microdot.py tests + +[testenv:upy] +whitelist_externals=sh +commands=sh -c "bin/micropython run_tests.py" + +[testenv:upy-mac] +whitelist_externals=micropython +commands=micropython run_tests.py diff --git a/unittest.py b/unittest.py new file mode 100644 index 0000000..0361c86 --- /dev/null +++ b/unittest.py @@ -0,0 +1,224 @@ +import sys + + +class SkipTest(Exception): + pass + + +class AssertRaisesContext: + + def __init__(self, exc): + self.expected = exc + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_type is None: + assert False, "%r not raised" % self.expected + if issubclass(exc_type, self.expected): + return True + return False + + +class TestCase: + + def fail(self, msg=''): + assert False, msg + + def assertEqual(self, x, y, msg=''): + if not msg: + msg = "%r vs (expected) %r" % (x, y) + assert x == y, msg + + def assertNotEqual(self, x, y, msg=''): + if not msg: + msg = "%r not expected to be equal %r" % (x, y) + assert x != y, msg + + def assertAlmostEqual(self, x, y, places=None, msg='', delta=None): + if x == y: + return + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + + if delta is not None: + if abs(x - y) <= delta: + return + if not msg: + msg = '%r != %r within %r delta' % (x, y, delta) + else: + if places is None: + places = 7 + if round(abs(y-x), places) == 0: + return + if not msg: + msg = '%r != %r within %r places' % (x, y, places) + + assert False, msg + + def assertNotAlmostEqual(self, x, y, places=None, msg='', delta=None): + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + + if delta is not None: + if not (x == y) and abs(x - y) > delta: + return + if not msg: + msg = '%r == %r within %r delta' % (x, y, delta) + else: + if places is None: + places = 7 + if not (x == y) and round(abs(y-x), places) != 0: + return + if not msg: + msg = '%r == %r within %r places' % (x, y, places) + + assert False, msg + + def assertIs(self, x, y, msg=''): + if not msg: + msg = "%r is not %r" % (x, y) + assert x is y, msg + + def assertIsNot(self, x, y, msg=''): + if not msg: + msg = "%r is %r" % (x, y) + assert x is not y, msg + + def assertIsNone(self, x, msg=''): + if not msg: + msg = "%r is not None" % x + assert x is None, msg + + def assertIsNotNone(self, x, msg=''): + if not msg: + msg = "%r is None" % x + assert x is not None, msg + + def assertTrue(self, x, msg=''): + if not msg: + msg = "Expected %r to be True" % x + assert x, msg + + def assertFalse(self, x, msg=''): + if not msg: + msg = "Expected %r to be False" % x + assert not x, msg + + def assertIn(self, x, y, msg=''): + if not msg: + msg = "Expected %r to be in %r" % (x, y) + assert x in y, msg + + def assertIsInstance(self, x, y, msg=''): + assert isinstance(x, y), msg + + def assertRaises(self, exc, func=None, *args, **kwargs): + if func is None: + return AssertRaisesContext(exc) + + try: + func(*args, **kwargs) + assert False, "%r not raised" % exc + except Exception as e: + if isinstance(e, exc): + return + raise + + + +def skip(msg): + def _decor(fun): + # We just replace original fun with _inner + def _inner(self): + raise SkipTest(msg) + return _inner + return _decor + +def skipIf(cond, msg): + if not cond: + return lambda x: x + return skip(msg) + +def skipUnless(cond, msg): + if cond: + return lambda x: x + return skip(msg) + + +class TestSuite: + def __init__(self): + self.tests = [] + def addTest(self, cls): + self.tests.append(cls) + +class TestRunner: + def run(self, suite): + res = TestResult() + for c in suite.tests: + run_class(c, res) + + 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 + print(msg) + + return res + +class TestResult: + def __init__(self): + self.errorsNum = 0 + self.failuresNum = 0 + self.skippedNum = 0 + self.testsRun = 0 + + def wasSuccessful(self): + return self.errorsNum == 0 and self.failuresNum == 0 + +# TODO: Uncompliant +def run_class(c, test_result): + o = c() + set_up = getattr(o, "setUp", lambda: None) + tear_down = getattr(o, "tearDown", lambda: None) + 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 + continue + finally: + tear_down() + + +def main(module="__main__"): + def test_cases(m): + for tn in dir(m): + c = getattr(m, tn) + if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase): + yield c + + m = __import__(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)