Index: third_party/typ/typ/runner.py |
diff --git a/third_party/typ/typ/runner.py b/third_party/typ/typ/runner.py |
index 01e414c883ba5eab1a911f4cc0c2f428a1dbfc3e..62d92c7fce33e6a4f8b98df228ce2bc97ced63eb 100644 |
--- a/third_party/typ/typ/runner.py |
+++ b/third_party/typ/typ/runner.py |
@@ -111,6 +111,7 @@ class Runner(object): |
self.stats = None |
self.teardown_fn = None |
self.top_level_dir = None |
+ self.top_level_dirs = [] |
self.win_multiprocessing = WinMultiprocessing.spawn |
self.final_responses = [] |
@@ -159,7 +160,7 @@ class Runner(object): |
return self._spawn(test_set) |
ret = self._set_up_runner() |
- if ret: # pragma: no cover |
+ if ret: |
return ret, None, None |
find_start = h.time() |
@@ -289,24 +290,39 @@ class Runner(object): |
self.printer = Printer( |
self.print_, args.overwrite, args.terminal_width) |
- self.top_level_dir = args.top_level_dir |
- if not self.top_level_dir: |
- if args.tests and h.isdir(args.tests[0]): |
- # TODO: figure out what to do if multiple files are |
- # specified and they don't all have the same correct |
- # top level dir. |
- d = h.realpath(h.dirname(args.tests[0])) |
- if h.exists(d, '__init__.py'): |
- top_dir = d |
+ if self.args.top_level_dirs and self.args.top_level_dir: |
+ self.print_( |
+ 'Cannot specify both --top-level-dir and --top-level-dirs', |
+ stream=h.stderr) |
+ return 1 |
+ |
+ self.top_level_dirs = args.top_level_dirs |
+ if not self.top_level_dirs and args.top_level_dir: |
+ self.top_level_dirs = [args.top_level_dir] |
+ |
+ if not self.top_level_dirs: |
+ for test in [t for t in args.tests if h.exists(t)]: |
+ if h.isdir(test): |
+ top_dir = test |
else: |
- top_dir = args.tests[0] |
- else: |
- top_dir = h.getcwd() |
+ top_dir = h.dirname(test) |
+ while h.exists(top_dir, '__init__.py'): |
+ top_dir = h.dirname(top_dir) |
+ top_dir = h.realpath(top_dir) |
+ if not top_dir in self.top_level_dirs: |
+ self.top_level_dirs.append(top_dir) |
+ if not self.top_level_dirs: |
+ top_dir = h.getcwd() |
while h.exists(top_dir, '__init__.py'): |
top_dir = h.dirname(top_dir) |
- self.top_level_dir = h.realpath(top_dir) |
+ top_dir = h.realpath(top_dir) |
+ self.top_level_dirs.append(top_dir) |
- h.add_to_path(self.top_level_dir) |
+ if not self.top_level_dir and self.top_level_dirs: |
+ self.top_level_dir = self.top_level_dirs[0] |
+ |
+ for path in self.top_level_dirs: |
+ h.add_to_path(path) |
for path in args.path: |
h.add_to_path(path) |
@@ -315,11 +331,11 @@ class Runner(object): |
try: |
import coverage |
except ImportError: |
- h.print_("Error: coverage is not installed") |
return 1 |
+ |
source = self.args.coverage_source |
if not source: |
- source = [self.top_level_dir] + self.args.path |
+ source = self.top_level_dirs + self.args.path |
self.coverage_source = source |
self.cov = coverage.coverage(source=self.coverage_source, |
data_suffix=True) |
@@ -342,7 +358,7 @@ class Runner(object): |
for name in names: |
try: |
self._add_tests_to_set(test_set, args.suffixes, |
- self.top_level_dir, classifier, |
+ self.top_level_dirs, classifier, |
name) |
except (AttributeError, ImportError, SyntaxError) as e: |
ex_str = traceback.format_exc() |
@@ -385,33 +401,47 @@ class Runner(object): |
s = self.host.read_text_file(args.file_list) |
names = [line.strip() for line in s.splitlines()] |
else: |
- names = [self.top_level_dir] |
+ names = self.top_level_dirs |
return names |
- def _add_tests_to_set(self, test_set, suffixes, top_level_dir, classifier, |
+ def _add_tests_to_set(self, test_set, suffixes, top_level_dirs, classifier, |
name): |
h = self.host |
loader = self.loader |
add_tests = _test_adder(test_set, classifier) |
- if h.isfile(name): |
- rpath = h.relpath(name, top_level_dir) |
- if rpath.endswith('.py'): |
- rpath = rpath[:-3] |
- module = rpath.replace(h.sep, '.') |
- add_tests(loader.loadTestsFromName(module)) |
- elif h.isdir(name): |
- for suffix in suffixes: |
- add_tests(loader.discover(name, suffix, top_level_dir)) |
- else: |
- possible_dir = name.replace('.', h.sep) |
- if h.isdir(top_level_dir, possible_dir): |
+ found = set() |
+ for d in top_level_dirs: |
+ if h.isfile(name): |
+ rpath = h.relpath(name, d) |
+ if rpath.startswith('..'): |
+ continue |
+ if rpath.endswith('.py'): |
+ rpath = rpath[:-3] |
+ module = rpath.replace(h.sep, '.') |
+ if module not in found: |
+ found.add(module) |
+ add_tests(loader.loadTestsFromName(module)) |
+ elif h.isdir(name): |
+ rpath = h.relpath(name, d) |
+ if rpath.startswith('..'): |
+ continue |
for suffix in suffixes: |
- path = h.join(top_level_dir, possible_dir) |
- suite = loader.discover(path, suffix, top_level_dir) |
- add_tests(suite) |
+ if not name in found: |
+ found.add(name + '/' + suffix) |
+ add_tests(loader.discover(name, suffix, d)) |
else: |
- add_tests(loader.loadTestsFromName(name)) |
+ possible_dir = name.replace('.', h.sep) |
+ if h.isdir(d, possible_dir): |
+ for suffix in suffixes: |
+ path = h.join(d, possible_dir) |
+ if not path in found: |
+ found.add(path + '/' + suffix) |
+ suite = loader.discover(path, suffix, d) |
+ add_tests(suite) |
+ elif not name in found: |
+ found.add(name) |
+ add_tests(loader.loadTestsFromName(name)) |
# pylint: disable=no-member |
if hasattr(loader, 'errors') and loader.errors: # pragma: python3 |
@@ -755,6 +785,7 @@ class _Child(object): |
self.teardown_fn = parent.teardown_fn |
self.context_after_setup = None |
self.top_level_dir = parent.top_level_dir |
+ self.top_level_dirs = parent.top_level_dirs |
self.loaded_suites = {} |
self.cov = None |