From f4754a10fd9e76e8b39e011c05a742e83dc5d59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Th=C3=B6rngren?= Date: Thu, 19 Nov 2015 14:52:26 -0800 Subject: [PATCH 1/4] Corrected name of program and spelling. --- python/cmdtest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/cmdtest.py b/python/cmdtest.py index 3c4ba77..fbe22b5 100755 --- a/python/cmdtest.py +++ b/python/cmdtest.py @@ -608,8 +608,8 @@ class Tfile: #---------------------------------------------------------------------- -def parse_otions(): - parser = argparse.ArgumentParser('jcons') +def parse_options(): + parser = argparse.ArgumentParser('cmdtest') parser.add_argument("-v", "--verbose", action="store_true", help="be more verbose") parser.add_argument("arg", nargs="*", @@ -631,7 +631,7 @@ def parse_otions(): return options, py_files, selected_methods def main(): - options, py_files, selected_methods = parse_otions() + options, py_files, selected_methods = parse_options() statistics = Statistics() for py_file in py_files: tfile = Tfile(py_file) From f486a15f66c77f0586b4d936e86e5f9f507c49b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Th=C3=B6rngren?= Date: Wed, 9 Dec 2015 20:49:13 -0800 Subject: [PATCH 2/4] Allow Python cmdtest to be used as a library. Added cmdtest_in_dir(path) to allow Python cmdtest to be used as part of another Python script. Factored out most of the functionality from main() to the common function test_files(). --- python/cmdtest.py | 51 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/python/cmdtest.py b/python/cmdtest.py index fbe22b5..5d7d21c 100755 --- a/python/cmdtest.py +++ b/python/cmdtest.py @@ -23,6 +23,7 @@ # This is a minimal Python version of "cmdtest". import argparse +import contextlib import copy import glob import hashlib @@ -47,7 +48,7 @@ if sys.platform == 'win32': class AssertFailed(Exception): pass -ORIG_CWD = os.getcwd() +ROOT_WD = os.getcwd() class Statistics: def __init__(self): @@ -92,6 +93,16 @@ def mkdir_for(filepath): if dirpath: os.makedirs(dirpath, exist_ok=True) +@contextlib.contextmanager +def temp_chdir(path): + global ROOT_WD + starting_directory = os.getcwd() + try: + os.chdir(path) + ROOT_WD = os.getcwd() + yield + finally: + os.chdir(starting_directory) def progress(*args): print("###", "-" * 50, *args) @@ -361,7 +372,7 @@ class TestCase: pass def prepend_path(self, dirpath): - os.environ['PATH'] = os.pathsep.join((os.path.join(ORIG_CWD, dirpath), + os.environ['PATH'] = os.pathsep.join((os.path.join(ROOT_WD, dirpath), os.environ['PATH'])) def prepend_local_path(self, dirpath): @@ -370,7 +381,7 @@ class TestCase: def import_file(self, src, tgt): mkdir_for(tgt) - shutil.copy(os.path.join(ORIG_CWD, src), tgt) + shutil.copy(os.path.join(ROOT_WD, src), tgt) def create_file(self, fname, content, encoding='utf-8'): mkdir_for(fname) @@ -608,6 +619,27 @@ class Tfile: #---------------------------------------------------------------------- +# Run cmdtest in given directory +def cmdtest_in_dir(path): + with temp_chdir(path): + py_files = glob.glob("CMDTEST_*.py") + return test_files(py_files) + +def test_files(py_files, selected_methods = set()): + statistics = Statistics() + for py_file in py_files: + tfile = Tfile(py_file) + tmpdir = Tmpdir() + for tclass in tfile.tclasses(): + statistics.classes += 1 + progress(tclass.name()) + for tmethod in tclass.tmethods(): + if not selected_methods or tmethod.name() in selected_methods: + statistics.methods += 1 + progress(tmethod.name()) + tmethod.run(tmpdir, statistics) + return statistics + def parse_options(): parser = argparse.ArgumentParser('cmdtest') parser.add_argument("-v", "--verbose", action="store_true", @@ -632,18 +664,7 @@ def parse_options(): def main(): options, py_files, selected_methods = parse_options() - statistics = Statistics() - for py_file in py_files: - tfile = Tfile(py_file) - tmpdir = Tmpdir() - for tclass in tfile.tclasses(): - statistics.classes += 1 - progress(tclass.name()) - for tmethod in tclass.tmethods(): - if not selected_methods or tmethod.name() in selected_methods: - statistics.methods += 1 - progress(tmethod.name()) - tmethod.run(tmpdir, statistics) + statistics = test_files(py_files, selected_methods) print() print(statistics) print() From af287466484c1a3d32685a710117c5b822aa8de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Th=C3=B6rngren?= Date: Sat, 2 Jan 2016 20:14:27 -0800 Subject: [PATCH 3/4] Preserve files for failed tests. In the Python version, preserve the work directory in work-save/class_name to make it possible to examine it afterwards. Before running tests, remove the entire old work-save directory hierarchy to ensure we only leave those behind that actually are relevant. --- python/cmdtest.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/python/cmdtest.py b/python/cmdtest.py index 5d7d21c..59ceafc 100755 --- a/python/cmdtest.py +++ b/python/cmdtest.py @@ -212,7 +212,7 @@ class ExpectPattern: #---------------------------------------------------------------------- class Result: - def __init__(self, err, before, after, stdout, stderr, tmpdir): + def __init__(self, err, before, after, stdout, stderr, tmpdir, test_class_name): self._err = err self._before = before self._after = after @@ -225,6 +225,9 @@ class Result: self._checked_files = set() self._nerrors = 0 + self.tmpdir = tmpdir + self.test_class_name = test_class_name + def __enter__(self, *args): return self @@ -241,6 +244,7 @@ class Result: if not self._checked_stderr: self.stderr_equal([]) if self._nerrors > 0: + self.tmpdir.preserve(self.test_class_name) raise AssertFailed("...") def _error(self, name, actual, expect): @@ -420,7 +424,7 @@ class TestCase: return Result(err, before, after, File(stdout_log), File(stderr_log), - tmpdir) + tmpdir, type(self).__name__) def _wait_for_new_second(self): newest = self._newest_file_time() @@ -518,9 +522,11 @@ class FsSnapshot: class Tmpdir: def __init__(self): self.top = os.path.abspath("tmp-cmdtest-python/work") + self.top_save = self.top + "-save" self.logdir = os.path.dirname(self.top) self.environ_path = os.environ['PATH'] self.old_cwds = [] + self.remove_all_preserve() def stdout_log(self): return os.path.join(self.logdir, "tmp.stdout") @@ -539,6 +545,13 @@ class Tmpdir: shutil.rmtree(self.top) os.makedirs(self.top) + def remove_all_preserve(self): + if os.path.exists(self.top_save): + shutil.rmtree(self.top_save) + + def preserve(self, name): + shutil.move(self.top, os.path.join(self.top_save, name)) + def __enter__(self): self.old_cwds.append(os.getcwd()) os.chdir(self.top) @@ -627,9 +640,9 @@ def cmdtest_in_dir(path): def test_files(py_files, selected_methods = set()): statistics = Statistics() + tmpdir = Tmpdir() for py_file in py_files: tfile = Tfile(py_file) - tmpdir = Tmpdir() for tclass in tfile.tclasses(): statistics.classes += 1 progress(tclass.name()) From 5075c7b38bed076b161783446e97ea1d24df4f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Th=C3=B6rngren?= Date: Sun, 3 Jan 2016 19:53:00 -0800 Subject: [PATCH 4/4] Combine class and method name when saving work dir In the Python version when saving the work directory for a failed test case, create a path based on both the class and method name. --- python/cmdtest.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/python/cmdtest.py b/python/cmdtest.py index 59ceafc..43b7cbe 100755 --- a/python/cmdtest.py +++ b/python/cmdtest.py @@ -527,6 +527,7 @@ class Tmpdir: self.environ_path = os.environ['PATH'] self.old_cwds = [] self.remove_all_preserve() + self.test_method_name = None def stdout_log(self): return os.path.join(self.logdir, "tmp.stdout") @@ -540,6 +541,10 @@ class Tmpdir: def snapshot(self): return FsSnapshot(self.top) + def prepare_for_test(self, test_method_name): + self.clear() + self.test_method_name = test_method_name + def clear(self): if os.path.exists(self.top): shutil.rmtree(self.top) @@ -549,8 +554,10 @@ class Tmpdir: if os.path.exists(self.top_save): shutil.rmtree(self.top_save) - def preserve(self, name): - shutil.move(self.top, os.path.join(self.top_save, name)) + def preserve(self, test_class_name): + shutil.move(self.top, os.path.join(self.top_save, + test_class_name, + self.test_method_name)) def __enter__(self): self.old_cwds.append(os.getcwd()) @@ -575,7 +582,7 @@ class Tmethod: def run(self, tmpdir, statistics): obj = self.tclass.klass(tmpdir, statistics) - tmpdir.clear() + tmpdir.prepare_for_test(self.name()) with tmpdir: try: obj.setup()