kopia lustrzana https://github.com/micropython/micropython-lib
unittest: Add discover function.
rodzic
9d9ca3d59b
commit
a7b2f63117
|
@ -1,3 +1,4 @@
|
||||||
srctype = micropython-lib
|
srctype = micropython-lib
|
||||||
type = module
|
type = module
|
||||||
version = 0.3.2
|
version = 0.3.2
|
||||||
|
depends = argparse, fnmatch
|
||||||
|
|
|
@ -21,4 +21,5 @@ setup(
|
||||||
license="MIT",
|
license="MIT",
|
||||||
cmdclass={"sdist": sdist_upip.sdist},
|
cmdclass={"sdist": sdist_upip.sdist},
|
||||||
py_modules=["unittest"],
|
py_modules=["unittest"],
|
||||||
|
install_requires=["micropython-argparse", "micropython-fnmatch"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import sys
|
import sys
|
||||||
|
import uos
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import io
|
import io
|
||||||
|
@ -280,6 +281,15 @@ class TestResult:
|
||||||
self.failuresNum,
|
self.failuresNum,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
self.errorsNum += other.errorsNum
|
||||||
|
self.failuresNum += other.failuresNum
|
||||||
|
self.skippedNum += other.skippedNum
|
||||||
|
self.testsRun += other.testsRun
|
||||||
|
self.errors.extend(other.errors)
|
||||||
|
self.failures.extend(other.failures)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
def capture_exc(e):
|
def capture_exc(e):
|
||||||
buf = io.StringIO()
|
buf = io.StringIO()
|
||||||
|
@ -290,7 +300,6 @@ def capture_exc(e):
|
||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|
||||||
|
|
||||||
# TODO: Uncompliant
|
|
||||||
def run_suite(c, test_result, suite_name=""):
|
def run_suite(c, test_result, suite_name=""):
|
||||||
if isinstance(c, TestSuite):
|
if isinstance(c, TestSuite):
|
||||||
c.run(test_result)
|
c.run(test_result)
|
||||||
|
@ -343,7 +352,7 @@ def run_suite(c, test_result, suite_name=""):
|
||||||
return
|
return
|
||||||
|
|
||||||
for name in dir(o):
|
for name in dir(o):
|
||||||
if name.startswith("test_"):
|
if name.startswith("test"):
|
||||||
m = getattr(o, name)
|
m = getattr(o, name)
|
||||||
if not callable(m):
|
if not callable(m):
|
||||||
continue
|
continue
|
||||||
|
@ -356,20 +365,65 @@ def run_suite(c, test_result, suite_name=""):
|
||||||
return exceptions
|
return exceptions
|
||||||
|
|
||||||
|
|
||||||
def main(module="__main__"):
|
def _test_cases(mod):
|
||||||
def test_cases(m):
|
for tn in dir(mod):
|
||||||
for tn in dir(m):
|
c = getattr(mod, tn)
|
||||||
c = getattr(m, tn)
|
|
||||||
if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
|
if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
|
||||||
yield c
|
yield c
|
||||||
elif tn.startswith("test_") and callable(c):
|
elif tn.startswith("test_") and callable(c):
|
||||||
yield c
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
def run_module(runner, module, path, top):
|
||||||
|
sys_path_initial = sys.path[:]
|
||||||
|
# Add script dir and top dir to import path
|
||||||
|
sys.path.insert(0, str(path))
|
||||||
|
if top:
|
||||||
|
sys.path.insert(1, top)
|
||||||
|
try:
|
||||||
|
suite = TestSuite(module)
|
||||||
m = __import__(module) if isinstance(module, str) else module
|
m = __import__(module) if isinstance(module, str) else module
|
||||||
suite = TestSuite(m.__name__)
|
for c in _test_cases(m):
|
||||||
for c in test_cases(m):
|
|
||||||
suite.addTest(c)
|
suite.addTest(c)
|
||||||
runner = TestRunner()
|
|
||||||
result = runner.run(suite)
|
result = runner.run(suite)
|
||||||
|
return result
|
||||||
|
|
||||||
|
finally:
|
||||||
|
sys.path[:] = sys_path_initial
|
||||||
|
|
||||||
|
|
||||||
|
def discover(runner: TestRunner):
|
||||||
|
from unittest_discover import discover
|
||||||
|
|
||||||
|
return discover(runner=runner)
|
||||||
|
|
||||||
|
|
||||||
|
def main(module="__main__"):
|
||||||
|
runner = TestRunner()
|
||||||
|
|
||||||
|
if len(sys.argv) <= 1:
|
||||||
|
result = discover(runner)
|
||||||
|
elif sys.argv[0].split(".")[0] == "unittest" and sys.argv[1] == "discover":
|
||||||
|
result = discover(runner)
|
||||||
|
else:
|
||||||
|
for test_spec in sys.argv[1:]:
|
||||||
|
try:
|
||||||
|
uos.stat(test_spec)
|
||||||
|
# test_spec is a local file, run it directly
|
||||||
|
if "/" in test_spec:
|
||||||
|
path, fname = test_spec.rsplit("/", 1)
|
||||||
|
else:
|
||||||
|
path, fname = ".", test_spec
|
||||||
|
modname = fname.rsplit(".", 1)[0]
|
||||||
|
result = run_module(runner, modname, path, None)
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
# Not a file, treat as import name
|
||||||
|
result = run_module(runner, test_spec, ".", None)
|
||||||
|
|
||||||
# Terminate with non zero return code in case of failures
|
# Terminate with non zero return code in case of failures
|
||||||
sys.exit(result.failuresNum or result.errorsNum)
|
sys.exit(result.failuresNum or result.errorsNum)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import uos
|
||||||
|
from fnmatch import fnmatch
|
||||||
|
|
||||||
|
from unittest import TestRunner, TestResult, run_module
|
||||||
|
|
||||||
|
|
||||||
|
def discover(runner: TestRunner):
|
||||||
|
"""
|
||||||
|
Implements discover function inspired by https://docs.python.org/3/library/unittest.html#test-discovery
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
# parser.add_argument(
|
||||||
|
# "-v",
|
||||||
|
# "--verbose",
|
||||||
|
# action="store_true",
|
||||||
|
# help="Verbose output",
|
||||||
|
# )
|
||||||
|
parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--start-directory",
|
||||||
|
dest="start",
|
||||||
|
default=".",
|
||||||
|
help="Directory to start discovery",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--pattern ",
|
||||||
|
dest="pattern",
|
||||||
|
default="test*.py",
|
||||||
|
help="Pattern to match test files",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--top-level-directory",
|
||||||
|
dest="top",
|
||||||
|
help="Top level directory of project (defaults to start directory)",
|
||||||
|
)
|
||||||
|
args = parser.parse_args(args=sys.argv[2:])
|
||||||
|
|
||||||
|
path = args.start
|
||||||
|
top = args.top or path
|
||||||
|
|
||||||
|
return run_all_in_dir(
|
||||||
|
runner=runner,
|
||||||
|
path=path,
|
||||||
|
pattern=args.pattern,
|
||||||
|
top=top,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_all_in_dir(runner: TestRunner, path: str, pattern: str, top: str):
|
||||||
|
DIR_TYPE = 0x4000
|
||||||
|
|
||||||
|
result = TestResult()
|
||||||
|
for fname, type, *_ in uos.ilistdir(path):
|
||||||
|
if fname in ("..", "."):
|
||||||
|
continue
|
||||||
|
if type == DIR_TYPE:
|
||||||
|
result += run_all_in_dir(
|
||||||
|
runner=runner,
|
||||||
|
path="/".join((path, fname)),
|
||||||
|
pattern=pattern,
|
||||||
|
top=top,
|
||||||
|
)
|
||||||
|
if fnmatch(fname, pattern):
|
||||||
|
modname = fname[: fname.rfind(".")]
|
||||||
|
result += run_module(runner, modname, path, top)
|
||||||
|
return result
|
Ładowanie…
Reference in New Issue