diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2013-02-02 11:15:11 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2013-02-02 11:15:11 -0500 |
commit | c19232a9d2be2bde30e446311f32e9dcdd5d4774 (patch) | |
tree | c2a9afb49cb74d9e041058c0275e1896dc0ecd0c /tests/test_farm.py | |
parent | c359cea1408c410a4c770debeddf3aed0abd43fe (diff) | |
download | python-coveragepy-git-c19232a9d2be2bde30e446311f32e9dcdd5d4774.tar.gz |
Move the test directory to tests to avoid conflicts with the stdlib test package.
--HG--
rename : test/__init__.py => tests/__init__.py
rename : test/backtest.py => tests/backtest.py
rename : test/backunittest.py => tests/backunittest.py
rename : test/coveragetest.py => tests/coveragetest.py
rename : test/covmodzip1.py => tests/covmodzip1.py
rename : test/eggsrc/egg1/__init__.py => tests/eggsrc/egg1/__init__.py
rename : test/eggsrc/egg1/egg1.py => tests/eggsrc/egg1/egg1.py
rename : test/eggsrc/setup.py => tests/eggsrc/setup.py
rename : test/farm/annotate/annotate_dir.py => tests/farm/annotate/annotate_dir.py
rename : test/farm/annotate/gold/white.py,cover => tests/farm/annotate/gold/white.py,cover
rename : test/farm/annotate/gold_anno_dir/a___init__.py,cover => tests/farm/annotate/gold_anno_dir/a___init__.py,cover
rename : test/farm/annotate/gold_anno_dir/a_a.py,cover => tests/farm/annotate/gold_anno_dir/a_a.py,cover
rename : test/farm/annotate/gold_anno_dir/b___init__.py,cover => tests/farm/annotate/gold_anno_dir/b___init__.py,cover
rename : test/farm/annotate/gold_anno_dir/b_b.py,cover => tests/farm/annotate/gold_anno_dir/b_b.py,cover
rename : test/farm/annotate/gold_anno_dir/multi.py,cover => tests/farm/annotate/gold_anno_dir/multi.py,cover
rename : test/farm/annotate/gold_multi/a/__init__.py,cover => tests/farm/annotate/gold_multi/a/__init__.py,cover
rename : test/farm/annotate/gold_multi/a/a.py,cover => tests/farm/annotate/gold_multi/a/a.py,cover
rename : test/farm/annotate/gold_multi/b/__init__.py,cover => tests/farm/annotate/gold_multi/b/__init__.py,cover
rename : test/farm/annotate/gold_multi/b/b.py,cover => tests/farm/annotate/gold_multi/b/b.py,cover
rename : test/farm/annotate/gold_multi/multi.py,cover => tests/farm/annotate/gold_multi/multi.py,cover
rename : test/farm/annotate/gold_v24/white.py,cover => tests/farm/annotate/gold_v24/white.py,cover
rename : test/farm/annotate/run.py => tests/farm/annotate/run.py
rename : test/farm/annotate/run_multi.py => tests/farm/annotate/run_multi.py
rename : test/farm/annotate/src/a/__init__.py => tests/farm/annotate/src/a/__init__.py
rename : test/farm/annotate/src/a/a.py => tests/farm/annotate/src/a/a.py
rename : test/farm/annotate/src/b/__init__.py => tests/farm/annotate/src/b/__init__.py
rename : test/farm/annotate/src/b/b.py => tests/farm/annotate/src/b/b.py
rename : test/farm/annotate/src/multi.py => tests/farm/annotate/src/multi.py
rename : test/farm/annotate/src/white.py => tests/farm/annotate/src/white.py
rename : test/farm/html/gold_a/a.html => tests/farm/html/gold_a/a.html
rename : test/farm/html/gold_a/index.html => tests/farm/html/gold_a/index.html
rename : test/farm/html/gold_b_branch/b.html => tests/farm/html/gold_b_branch/b.html
rename : test/farm/html/gold_b_branch/index.html => tests/farm/html/gold_b_branch/index.html
rename : test/farm/html/gold_bom/bom.html => tests/farm/html/gold_bom/bom.html
rename : test/farm/html/gold_bom/index.html => tests/farm/html/gold_bom/index.html
rename : test/farm/html/gold_isolatin1/index.html => tests/farm/html/gold_isolatin1/index.html
rename : test/farm/html/gold_isolatin1/isolatin1.html => tests/farm/html/gold_isolatin1/isolatin1.html
rename : test/farm/html/gold_omit_1/index.html => tests/farm/html/gold_omit_1/index.html
rename : test/farm/html/gold_omit_1/m1.html => tests/farm/html/gold_omit_1/m1.html
rename : test/farm/html/gold_omit_1/m2.html => tests/farm/html/gold_omit_1/m2.html
rename : test/farm/html/gold_omit_1/m3.html => tests/farm/html/gold_omit_1/m3.html
rename : test/farm/html/gold_omit_1/main.html => tests/farm/html/gold_omit_1/main.html
rename : test/farm/html/gold_omit_2/index.html => tests/farm/html/gold_omit_2/index.html
rename : test/farm/html/gold_omit_2/m2.html => tests/farm/html/gold_omit_2/m2.html
rename : test/farm/html/gold_omit_2/m3.html => tests/farm/html/gold_omit_2/m3.html
rename : test/farm/html/gold_omit_2/main.html => tests/farm/html/gold_omit_2/main.html
rename : test/farm/html/gold_omit_3/index.html => tests/farm/html/gold_omit_3/index.html
rename : test/farm/html/gold_omit_3/m3.html => tests/farm/html/gold_omit_3/m3.html
rename : test/farm/html/gold_omit_3/main.html => tests/farm/html/gold_omit_3/main.html
rename : test/farm/html/gold_omit_4/index.html => tests/farm/html/gold_omit_4/index.html
rename : test/farm/html/gold_omit_4/m1.html => tests/farm/html/gold_omit_4/m1.html
rename : test/farm/html/gold_omit_4/m3.html => tests/farm/html/gold_omit_4/m3.html
rename : test/farm/html/gold_omit_4/main.html => tests/farm/html/gold_omit_4/main.html
rename : test/farm/html/gold_omit_5/index.html => tests/farm/html/gold_omit_5/index.html
rename : test/farm/html/gold_omit_5/m1.html => tests/farm/html/gold_omit_5/m1.html
rename : test/farm/html/gold_omit_5/main.html => tests/farm/html/gold_omit_5/main.html
rename : test/farm/html/gold_other/blah_blah_other.html => tests/farm/html/gold_other/blah_blah_other.html
rename : test/farm/html/gold_other/here.html => tests/farm/html/gold_other/here.html
rename : test/farm/html/gold_other/index.html => tests/farm/html/gold_other/index.html
rename : test/farm/html/gold_partial/index.html => tests/farm/html/gold_partial/index.html
rename : test/farm/html/gold_partial/partial.html => tests/farm/html/gold_partial/partial.html
rename : test/farm/html/gold_styled/a.html => tests/farm/html/gold_styled/a.html
rename : test/farm/html/gold_styled/extra.css => tests/farm/html/gold_styled/extra.css
rename : test/farm/html/gold_styled/index.html => tests/farm/html/gold_styled/index.html
rename : test/farm/html/gold_styled/style.css => tests/farm/html/gold_styled/style.css
rename : test/farm/html/gold_unicode/index.html => tests/farm/html/gold_unicode/index.html
rename : test/farm/html/gold_unicode/unicode.html => tests/farm/html/gold_unicode/unicode.html
rename : test/farm/html/gold_x_xml/coverage.xml => tests/farm/html/gold_x_xml/coverage.xml
rename : test/farm/html/gold_y_xml_branch/coverage.xml => tests/farm/html/gold_y_xml_branch/coverage.xml
rename : test/farm/html/othersrc/other.py => tests/farm/html/othersrc/other.py
rename : test/farm/html/run_a.py => tests/farm/html/run_a.py
rename : test/farm/html/run_a_xml_1.py => tests/farm/html/run_a_xml_1.py
rename : test/farm/html/run_a_xml_2.py => tests/farm/html/run_a_xml_2.py
rename : test/farm/html/run_b_branch.py => tests/farm/html/run_b_branch.py
rename : test/farm/html/run_bom.py => tests/farm/html/run_bom.py
rename : test/farm/html/run_isolatin1.py => tests/farm/html/run_isolatin1.py
rename : test/farm/html/run_omit_1.py => tests/farm/html/run_omit_1.py
rename : test/farm/html/run_omit_2.py => tests/farm/html/run_omit_2.py
rename : test/farm/html/run_omit_3.py => tests/farm/html/run_omit_3.py
rename : test/farm/html/run_omit_4.py => tests/farm/html/run_omit_4.py
rename : test/farm/html/run_omit_5.py => tests/farm/html/run_omit_5.py
rename : test/farm/html/run_other.py => tests/farm/html/run_other.py
rename : test/farm/html/run_partial.py => tests/farm/html/run_partial.py
rename : test/farm/html/run_styled.py => tests/farm/html/run_styled.py
rename : test/farm/html/run_tabbed.py => tests/farm/html/run_tabbed.py
rename : test/farm/html/run_unicode.py => tests/farm/html/run_unicode.py
rename : test/farm/html/run_y_xml_branch.py => tests/farm/html/run_y_xml_branch.py
rename : test/farm/html/src/a.py => tests/farm/html/src/a.py
rename : test/farm/html/src/b.py => tests/farm/html/src/b.py
rename : test/farm/html/src/bom.py => tests/farm/html/src/bom.py
rename : test/farm/html/src/coverage.xml => tests/farm/html/src/coverage.xml
rename : test/farm/html/src/extra.css => tests/farm/html/src/extra.css
rename : test/farm/html/src/here.py => tests/farm/html/src/here.py
rename : test/farm/html/src/isolatin1.py => tests/farm/html/src/isolatin1.py
rename : test/farm/html/src/m1.py => tests/farm/html/src/m1.py
rename : test/farm/html/src/m2.py => tests/farm/html/src/m2.py
rename : test/farm/html/src/m3.py => tests/farm/html/src/m3.py
rename : test/farm/html/src/main.py => tests/farm/html/src/main.py
rename : test/farm/html/src/omit4.ini => tests/farm/html/src/omit4.ini
rename : test/farm/html/src/omit5.ini => tests/farm/html/src/omit5.ini
rename : test/farm/html/src/partial.py => tests/farm/html/src/partial.py
rename : test/farm/html/src/run_a_xml_2.ini => tests/farm/html/src/run_a_xml_2.ini
rename : test/farm/html/src/tabbed.py => tests/farm/html/src/tabbed.py
rename : test/farm/html/src/unicode.py => tests/farm/html/src/unicode.py
rename : test/farm/html/src/y.py => tests/farm/html/src/y.py
rename : test/farm/run/run_chdir.py => tests/farm/run/run_chdir.py
rename : test/farm/run/run_timid.py => tests/farm/run/run_timid.py
rename : test/farm/run/run_xxx.py => tests/farm/run/run_xxx.py
rename : test/farm/run/src/chdir.py => tests/farm/run/src/chdir.py
rename : test/farm/run/src/showtrace.py => tests/farm/run/src/showtrace.py
rename : test/farm/run/src/subdir/placeholder => tests/farm/run/src/subdir/placeholder
rename : test/farm/run/src/xxx => tests/farm/run/src/xxx
rename : test/js/index.html => tests/js/index.html
rename : test/js/tests.js => tests/js/tests.js
rename : test/modules/aa/__init__.py => tests/modules/aa/__init__.py
rename : test/modules/aa/afile.odd.py => tests/modules/aa/afile.odd.py
rename : test/modules/aa/afile.py => tests/modules/aa/afile.py
rename : test/modules/aa/bb.odd/bfile.py => tests/modules/aa/bb.odd/bfile.py
rename : test/modules/aa/bb/__init__.py => tests/modules/aa/bb/__init__.py
rename : test/modules/aa/bb/bfile.odd.py => tests/modules/aa/bb/bfile.odd.py
rename : test/modules/aa/bb/bfile.py => tests/modules/aa/bb/bfile.py
rename : test/modules/aa/bb/cc/__init__.py => tests/modules/aa/bb/cc/__init__.py
rename : test/modules/aa/bb/cc/cfile.py => tests/modules/aa/bb/cc/cfile.py
rename : test/modules/aa/zfile.py => tests/modules/aa/zfile.py
rename : test/modules/covmod1.py => tests/modules/covmod1.py
rename : test/modules/pkg1/__init__.py => tests/modules/pkg1/__init__.py
rename : test/modules/pkg1/__main__.py => tests/modules/pkg1/__main__.py
rename : test/modules/pkg1/p1a.py => tests/modules/pkg1/p1a.py
rename : test/modules/pkg1/p1b.py => tests/modules/pkg1/p1b.py
rename : test/modules/pkg1/p1c.py => tests/modules/pkg1/p1c.py
rename : test/modules/pkg1/runmod2.py => tests/modules/pkg1/runmod2.py
rename : test/modules/pkg1/sub/__init__.py => tests/modules/pkg1/sub/__init__.py
rename : test/modules/pkg1/sub/__main__.py => tests/modules/pkg1/sub/__main__.py
rename : test/modules/pkg1/sub/ps1a.py => tests/modules/pkg1/sub/ps1a.py
rename : test/modules/pkg1/sub/runmod3.py => tests/modules/pkg1/sub/runmod3.py
rename : test/modules/pkg2/__init__.py => tests/modules/pkg2/__init__.py
rename : test/modules/pkg2/p2a.py => tests/modules/pkg2/p2a.py
rename : test/modules/pkg2/p2b.py => tests/modules/pkg2/p2b.py
rename : test/modules/runmod1.py => tests/modules/runmod1.py
rename : test/modules/usepkgs.py => tests/modules/usepkgs.py
rename : test/moremodules/othermods/__init__.py => tests/moremodules/othermods/__init__.py
rename : test/moremodules/othermods/othera.py => tests/moremodules/othermods/othera.py
rename : test/moremodules/othermods/otherb.py => tests/moremodules/othermods/otherb.py
rename : test/moremodules/othermods/sub/__init__.py => tests/moremodules/othermods/sub/__init__.py
rename : test/moremodules/othermods/sub/osa.py => tests/moremodules/othermods/sub/osa.py
rename : test/moremodules/othermods/sub/osb.py => tests/moremodules/othermods/sub/osb.py
rename : test/osinfo.py => tests/osinfo.py
rename : test/qunit/jquery.tmpl.min.js => tests/qunit/jquery.tmpl.min.js
rename : test/qunit/qunit.css => tests/qunit/qunit.css
rename : test/qunit/qunit.js => tests/qunit/qunit.js
rename : test/stress_phystoken.tok => tests/stress_phystoken.tok
rename : test/stress_phystoken_dos.tok => tests/stress_phystoken_dos.tok
rename : test/test_api.py => tests/test_api.py
rename : test/test_arcs.py => tests/test_arcs.py
rename : test/test_cmdline.py => tests/test_cmdline.py
rename : test/test_codeunit.py => tests/test_codeunit.py
rename : test/test_config.py => tests/test_config.py
rename : test/test_coverage.py => tests/test_coverage.py
rename : test/test_data.py => tests/test_data.py
rename : test/test_execfile.py => tests/test_execfile.py
rename : test/test_farm.py => tests/test_farm.py
rename : test/test_files.py => tests/test_files.py
rename : test/test_html.py => tests/test_html.py
rename : test/test_misc.py => tests/test_misc.py
rename : test/test_oddball.py => tests/test_oddball.py
rename : test/test_parser.py => tests/test_parser.py
rename : test/test_phystokens.py => tests/test_phystokens.py
rename : test/test_process.py => tests/test_process.py
rename : test/test_results.py => tests/test_results.py
rename : test/test_summary.py => tests/test_summary.py
rename : test/test_templite.py => tests/test_templite.py
rename : test/test_testing.py => tests/test_testing.py
rename : test/test_xml.py => tests/test_xml.py
rename : test/try_execfile.py => tests/try_execfile.py
Diffstat (limited to 'tests/test_farm.py')
-rw-r--r-- | tests/test_farm.py | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/tests/test_farm.py b/tests/test_farm.py new file mode 100644 index 00000000..f25d6109 --- /dev/null +++ b/tests/test_farm.py @@ -0,0 +1,366 @@ +"""Run tests in the farm subdirectory. Designed for nose.""" + +import difflib, filecmp, fnmatch, glob, os, re, shutil, sys +from nose.plugins.skip import SkipTest + +from test.backtest import run_command, execfile # pylint: disable=W0622 + +from coverage.control import _TEST_NAME_FILE + + +def test_farm(clean_only=False): + """A test-generating function for nose to find and run.""" + for fname in glob.glob("test/farm/*/*.py"): + case = FarmTestCase(fname, clean_only) + yield (case,) + + +class FarmTestCase(object): + """A test case from the farm tree. + + Tests are short Python script files, often called run.py: + + copy("src", "out") + run(''' + coverage -x white.py + coverage -a white.py + ''', rundir="out") + compare("out", "gold", "*,cover") + clean("out") + + Verbs (copy, run, compare, clean) are methods in this class. FarmTestCase + has options to allow various uses of the test cases (normal execution, + cleaning-only, or run and leave the results for debugging). + + """ + def __init__(self, runpy, clean_only=False, dont_clean=False): + """Create a test case from a run.py file. + + `clean_only` means that only the clean() action is executed. + `dont_clean` means that the clean() action is not executed. + + """ + self.description = runpy + self.dir, self.runpy = os.path.split(runpy) + self.clean_only = clean_only + self.dont_clean = dont_clean + + def cd(self, newdir): + """Change the current directory, and return the old one.""" + cwd = os.getcwd() + os.chdir(newdir) + return cwd + + def addtopath(self, directory): + """Add `directory` to the path, and return the old path.""" + oldpath = sys.path[:] + if directory is not None: + sys.path.insert(0, directory) + return oldpath + + def restorepath(self, path): + """Restore the system path to `path`.""" + sys.path = path + + def __call__(self): + """Execute the test from the run.py file. + + """ + if _TEST_NAME_FILE: + f = open(_TEST_NAME_FILE, "w") + f.write(self.description.replace("/", "_")) + f.close() + + cwd = self.cd(self.dir) + + # Prepare a dictionary of globals for the run.py files to use. + fns = """ + copy run runfunc compare contains doesnt_contain clean skip + """.split() + if self.clean_only: + glo = dict([(fn, self.noop) for fn in fns]) + glo['clean'] = self.clean + else: + glo = dict([(fn, getattr(self, fn)) for fn in fns]) + if self.dont_clean: # pragma: not covered + glo['clean'] = self.noop + + old_mods = dict(sys.modules) + try: + execfile(self.runpy, glo) + finally: + self.cd(cwd) + # Remove any new modules imported during the test run. This lets us + # import the same source files for more than one test. + to_del = [m for m in sys.modules if m not in old_mods] + for m in to_del: + del sys.modules[m] + + def run_fully(self): # pragma: not covered + """Run as a full test case, with setUp and tearDown.""" + self.setUp() + try: + self() + finally: + self.tearDown() + + def fnmatch_list(self, files, file_pattern): + """Filter the list of `files` to only those that match `file_pattern`. + + If `file_pattern` is None, then return the entire list of files. + + Returns a list of the filtered files. + + """ + if file_pattern: + files = [f for f in files if fnmatch.fnmatch(f, file_pattern)] + return files + + def setUp(self): + """Test set up, run by nose before __call__.""" + + # Modules should be importable from the current directory. + self.old_syspath = sys.path[:] + sys.path.insert(0, '') + + def tearDown(self): + """Test tear down, run by nose after __call__.""" + # Make sure no matter what, the test is cleaned up. + if not self.dont_clean: # pragma: part covered + self.clean_only = True + self() + + # Restore the original sys.path + sys.path = self.old_syspath + + # Functions usable inside farm run.py files + + def noop(self, *args, **kwargs): + """A no-op function to stub out run, copy, etc, when only cleaning.""" + pass + + def copy(self, src, dst): + """Copy a directory.""" + + if os.path.exists(dst): + shutil.rmtree(dst) + shutil.copytree(src, dst) + + def run(self, cmds, rundir="src", outfile=None): + """Run a list of commands. + + `cmds` is a string, commands separated by newlines. + `rundir` is the directory in which to run the commands. + `outfile` is a filename to redirect stdout to. + + """ + cwd = self.cd(rundir) + if outfile: + fout = open(outfile, "a+") + try: + for cmd in cmds.split("\n"): + cmd = cmd.strip() + if not cmd: + continue + retcode, output = run_command(cmd) + print(output.rstrip()) + if outfile: + fout.write(output) + if retcode: + raise Exception("command exited abnormally") + finally: + if outfile: + fout.close() + self.cd(cwd) + + def runfunc(self, fn, rundir="src", addtopath=None): + """Run a function. + + `fn` is a callable. + `rundir` is the directory in which to run the function. + + """ + + cwd = self.cd(rundir) + oldpath = self.addtopath(addtopath) + try: + fn() + finally: + self.cd(cwd) + self.restorepath(oldpath) + + def compare(self, dir1, dir2, file_pattern=None, size_within=0, + left_extra=False, right_extra=False, scrubs=None + ): + """Compare files matching `file_pattern` in `dir1` and `dir2`. + + `dir2` is interpreted as a prefix, with Python version numbers appended + to find the actual directory to compare with. "foo" will compare against + "foo_v241", "foo_v24", "foo_v2", or "foo", depending on which directory + is found first. + + `size_within` is a percentage delta for the file sizes. If non-zero, + then the file contents are not compared (since they are expected to + often be different), but the file sizes must be within this amount. + For example, size_within=10 means that the two files' sizes must be + within 10 percent of each other to compare equal. + + `left_extra` true means the left directory can have extra files in it + without triggering an assertion. `right_extra` means the right + directory can. + + `scrubs` is a list of pairs, regex find and replace patterns to use to + scrub the files of unimportant differences. + + An assertion will be raised if the directories fail one of their + matches. + + """ + # Search for a dir2 with a version suffix. + version_suff = ''.join(map(str, sys.version_info[:3])) + while version_suff: + trydir = dir2 + '_v' + version_suff + if os.path.exists(trydir): + dir2 = trydir + break + version_suff = version_suff[:-1] + + assert os.path.exists(dir1), "Left directory missing: %s" % dir1 + assert os.path.exists(dir2), "Right directory missing: %s" % dir2 + + dc = filecmp.dircmp(dir1, dir2) + diff_files = self.fnmatch_list(dc.diff_files, file_pattern) + left_only = self.fnmatch_list(dc.left_only, file_pattern) + right_only = self.fnmatch_list(dc.right_only, file_pattern) + + if size_within: + # The files were already compared, use the diff_files list as a + # guide for size comparison. + wrong_size = [] + for f in diff_files: + left = open(os.path.join(dir1, f), "rb").read() + right = open(os.path.join(dir2, f), "rb").read() + size_l, size_r = len(left), len(right) + big, little = max(size_l, size_r), min(size_l, size_r) + if (big - little) / float(little) > size_within/100.0: + # print "%d %d" % (big, little) + # print "Left: ---\n%s\n-----\n%s" % (left, right) + wrong_size.append(f) + assert not wrong_size, ( + "File sizes differ between %s and %s: %s" % ( + dir1, dir2, wrong_size + )) + else: + # filecmp only compares in binary mode, but we want text mode. So + # look through the list of different files, and compare them + # ourselves. + text_diff = [] + for f in diff_files: + left = open(os.path.join(dir1, f), "rU").readlines() + right = open(os.path.join(dir2, f), "rU").readlines() + if scrubs: + left = self._scrub(left, scrubs) + right = self._scrub(right, scrubs) + if left != right: + text_diff.append(f) + print("".join(list(difflib.Differ().compare(left, right)))) + assert not text_diff, "Files differ: %s" % text_diff + + if not left_extra: + assert not left_only, "Files in %s only: %s" % (dir1, left_only) + if not right_extra: + assert not right_only, "Files in %s only: %s" % (dir2, right_only) + + def _scrub(self, strlist, scrubs): + """Scrub uninteresting data from the strings in `strlist`. + + `scrubs is a list of (find, replace) pairs of regexes that are used on + each string in `strlist`. A list of scrubbed strings is returned. + + """ + scrubbed = [] + for s in strlist: + for rgx_find, rgx_replace in scrubs: + s = re.sub(rgx_find, rgx_replace, s) + scrubbed.append(s) + return scrubbed + + def contains(self, filename, *strlist): + """Check that the file contains all of a list of strings. + + An assert will be raised if one of the arguments in `strlist` is + missing in `filename`. + + """ + text = open(filename, "r").read() + for s in strlist: + assert s in text, "Missing content in %s: %r" % (filename, s) + + def doesnt_contain(self, filename, *strlist): + """Check that the file contains none of a list of strings. + + An assert will be raised if any of the strings in strlist appears in + `filename`. + + """ + text = open(filename, "r").read() + for s in strlist: + assert s not in text, "Forbidden content in %s: %r" % (filename, s) + + def clean(self, cleandir): + """Clean `cleandir` by removing it and all its children completely.""" + # rmtree gives mysterious failures on Win7, so retry a "few" times. + # I've seen it take over 100 tries, so, 1000! This is probably the + # most unpleasant hack I've written in a long time... + tries = 1000 + while tries: # pragma: part covered + if os.path.exists(cleandir): + try: + shutil.rmtree(cleandir) + except OSError: # pragma: not covered + if tries == 1: + raise + else: + tries -= 1 + continue + break + + def skip(self, msg=None): + """Skip the current test.""" + raise SkipTest(msg) + + +def main(): # pragma: not covered + """Command-line access to test_farm. + + Commands: + + run testcase - Run a single test case. + out testcase - Run a test case, but don't clean up, to see the output. + clean - Clean all the output for all tests. + + """ + op = 'help' + try: + op = sys.argv[1] + except IndexError: + pass + + if op == 'run': + # Run the test for real. + case = FarmTestCase(sys.argv[2]) + case.run_fully() + elif op == 'out': + # Run the test, but don't clean up, so we can examine the output. + case = FarmTestCase(sys.argv[2], dont_clean=True) + case.run_fully() + elif op == 'clean': + # Run all the tests, but just clean. + for test in test_farm(clean_only=True): + test[0].run_fully() + else: + print(main.__doc__) + +# So that we can run just one farm run.py at a time. +if __name__ == '__main__': + main() |