unittest framework kickoff
svn: r9301
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
2007-11-05 Jim Sack <jgsack@san.rr.com>
|
||||||
|
* src/test directory added
|
||||||
|
* src/test/{__init__,regrtest,test_init}.py added
|
||||||
|
* src/test/test/test_util_test.py added
|
||||||
|
First steps in a new unittest framework
|
||||||
|
|
||||||
2007-11-05 Jim Sack <jgsack@san.rr.com>
|
2007-11-05 Jim Sack <jgsack@san.rr.com>
|
||||||
* remove 2 files from version control: config.guess and config.sub
|
* remove 2 files from version control: config.guess and config.sub
|
||||||
These are generated by configure (via autogen.sh).
|
These are generated by configure (via autogen.sh).
|
||||||
|
46
src/test/__init__.py
Normal file
46
src/test/__init__.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#
|
||||||
|
# Gramps - a GTK+/GNOME based genealogy program
|
||||||
|
#
|
||||||
|
# Copyright (C) 2004-2006 Donald N. Allingham
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
# $Id:$
|
||||||
|
|
||||||
|
"""
|
||||||
|
This package implements unittest support for GRAMPS
|
||||||
|
|
||||||
|
It includes a test-running program regrtest.py,
|
||||||
|
and various test support utility modules
|
||||||
|
(first one created being test_util.py)
|
||||||
|
|
||||||
|
Also includes tests for code in the parent (src) directory
|
||||||
|
and other tests that may be considered top-level tests
|
||||||
|
|
||||||
|
Note: tests for utility code in this directory would be in a
|
||||||
|
subdirectory also named test by convention for gramps testing.
|
||||||
|
|
||||||
|
Note: test subdirectories do not normally need to have a
|
||||||
|
package-enabling module __init__.py, but this one (src/test) does
|
||||||
|
because it contains utilities used by other test modules.
|
||||||
|
Thus, this package would allow test code like
|
||||||
|
from test import test_util
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# This file does not presently contain any code.
|
||||||
|
|
||||||
|
#===eof===
|
155
src/test/regrtest.py
Executable file
155
src/test/regrtest.py
Executable file
@@ -0,0 +1,155 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
#
|
||||||
|
# Gramps - a GTK+/GNOME based genealogy program
|
||||||
|
#
|
||||||
|
# Copyright (C) 2000-2005 Donald N. Allingham
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Original: RunAllTests.py Written by Richard Taylor
|
||||||
|
# (jgs: revised for embedded "test" subdirs as regrtest.py )
|
||||||
|
|
||||||
|
"""
|
||||||
|
Testing framework for performing a variety of unttests for GRAMPS.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO: review whether logging is really useful for unittest
|
||||||
|
# it does seem to work .. try -v5
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
from test import test_util as tu
|
||||||
|
gramps_root=tu.path_append_parent()
|
||||||
|
|
||||||
|
def make_parser():
|
||||||
|
usage = "usage: %prog [options]"
|
||||||
|
parser = OptionParser(usage)
|
||||||
|
parser.add_option("-v", "--verbosity", type="int",
|
||||||
|
dest="verbose_level", default=0,
|
||||||
|
help="Level of verboseness")
|
||||||
|
parser.add_option("-p", "--performance", action="store_true",
|
||||||
|
dest="performance", default=False,
|
||||||
|
help="Run the performance tests.")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def getTestSuites(loc=gramps_root):
|
||||||
|
# in a developer's checkout, it is worth filtering-out .svn
|
||||||
|
# and we only need to look inside test subdirs
|
||||||
|
# (this might change)
|
||||||
|
# this is not so performance critical that we can't afford
|
||||||
|
# a couple of function calls to make it readable
|
||||||
|
# TODO: handle parts of a module (see unittest.py)
|
||||||
|
|
||||||
|
ldr= unittest.defaultTestLoader
|
||||||
|
|
||||||
|
test_dirname = "test"
|
||||||
|
test_suffix = "_test.py"
|
||||||
|
def test_mod(p,ds):
|
||||||
|
""" test for path p=test dir; removes a dir '.svn' in ds """
|
||||||
|
if ".svn" in ds:
|
||||||
|
ds.remove(".svn")
|
||||||
|
return os.path.basename(p) == test_dirname
|
||||||
|
def match_mod(fs):
|
||||||
|
""" test for any test modules; deletes all non-tests """
|
||||||
|
# NB: do not delete fs elements within a "for f in fs"
|
||||||
|
dels= [f for f in fs if not f.endswith(test_suffix)]
|
||||||
|
for f in dels:
|
||||||
|
fs.remove(f)
|
||||||
|
return len(fs) > 0
|
||||||
|
|
||||||
|
test_suites = []
|
||||||
|
perf_suites = []
|
||||||
|
# note that test_mod and match_mod modify passed-in lists
|
||||||
|
paths = [(path,files) for path,dirs,files in os.walk(loc) \
|
||||||
|
if test_mod(path,dirs) and match_mod(files)]
|
||||||
|
|
||||||
|
oldpath = list(sys.path)
|
||||||
|
for (dir,test_modules) in paths:
|
||||||
|
sys.path.append(dir)
|
||||||
|
|
||||||
|
for module in test_modules:
|
||||||
|
if not module.endswith(test_suffix):
|
||||||
|
raise ValueError
|
||||||
|
mod = __import__(module[:-len(".py")])
|
||||||
|
if getattr(mod,"suite",None):
|
||||||
|
test_suites.append(mod.suite())
|
||||||
|
else:
|
||||||
|
test_suites.append(ldr.loadTestsFromModule(mod))
|
||||||
|
try:
|
||||||
|
perf_suites.append(mod.perfSuite())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# remove temporary paths added
|
||||||
|
sys.path = list(oldpath)
|
||||||
|
return (test_suites,perf_suites)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
def logging_init():
|
||||||
|
global logger
|
||||||
|
global console
|
||||||
|
console = logging.StreamHandler()
|
||||||
|
console.setLevel(logging.INFO)
|
||||||
|
console.setFormatter(logging.Formatter(
|
||||||
|
'%(name)-12s: %(levelname)-8s %(message)s'))
|
||||||
|
logger = logging.getLogger('Gramps')
|
||||||
|
logger.addHandler(console)
|
||||||
|
return console, logger
|
||||||
|
|
||||||
|
def logging_adjust(verbose_level):
|
||||||
|
if verbose_level == 1:
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
console.setLevel(logging.INFO)
|
||||||
|
elif verbose_level == 2:
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
console.setLevel(logging.DEBUG)
|
||||||
|
elif verbose_level == 3:
|
||||||
|
logger.setLevel(logging.NOTSET)
|
||||||
|
console.setLevel(logging.NOTSET)
|
||||||
|
elif verbose_level >= 4:
|
||||||
|
logger.setLevel(logging.NOTSET)
|
||||||
|
console.setLevel(logging.NOTSET)
|
||||||
|
os.environ['GRAMPS_SIGNAL'] = "1"
|
||||||
|
else:
|
||||||
|
logger.setLevel(logging.ERROR)
|
||||||
|
console.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
console,logger = logging_init()
|
||||||
|
options,args = make_parser().parse_args()
|
||||||
|
logging_adjust(options.verbose_level)
|
||||||
|
|
||||||
|
# TODO allow multiple subdirs, modules, or testnames
|
||||||
|
# (see unittest.py)
|
||||||
|
# hmmm this is starting to look like a unittest.Testprog
|
||||||
|
# (maybe with a custom TestLoader)
|
||||||
|
if args and os.path.isdir(args[0]):
|
||||||
|
loc = args[0]
|
||||||
|
else:
|
||||||
|
loc = gramps_root
|
||||||
|
|
||||||
|
utests, ptests = getTestSuites(loc)
|
||||||
|
if options.performance:
|
||||||
|
suite = unittest.TestSuite(ptests)
|
||||||
|
else:
|
||||||
|
suite = unittest.TestSuite(utests)
|
||||||
|
|
||||||
|
unittest.TextTestRunner(verbosity=options.verbose_level).run(suite)
|
||||||
|
|
||||||
|
#===eof===
|
167
src/test/test/test_util_test.py
Normal file
167
src/test/test/test_util_test.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
"""unittest (test_util_test.py) for test_util.py"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import unittest as U
|
||||||
|
|
||||||
|
usage_note="""
|
||||||
|
**************************************************************
|
||||||
|
Testing (and runing) Gramps requires that PYTHONPATH include
|
||||||
|
the path to the top Gramps directory (where gramps.py resides).
|
||||||
|
|
||||||
|
For example, in bash, a shell export would look like
|
||||||
|
export PYTHONPATH=/.../src
|
||||||
|
with the ... filled in appropriately.
|
||||||
|
**************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
# **************************************************************
|
||||||
|
#
|
||||||
|
# Since this module is used by other test modules, it is
|
||||||
|
# strongly advised to test this module to 100% coverage,
|
||||||
|
# and in all calling variations, eg:
|
||||||
|
# run directly, from this dir with and without ./ prefix
|
||||||
|
# run from other dirs (with path prefix)
|
||||||
|
# run from within regrtest.py
|
||||||
|
# run from regrtest.py with other test modules present
|
||||||
|
# which use the test_util module itself
|
||||||
|
#
|
||||||
|
# **************************************************************
|
||||||
|
|
||||||
|
try:
|
||||||
|
from test import test_util as tu
|
||||||
|
##here = tu.absdir()
|
||||||
|
except ImportError:
|
||||||
|
print "Cannot import 'test_util'from package 'test'" + usage_note
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# grouping into multiple TestCases (classes) is not required,
|
||||||
|
# but may be useful for various reasons, such as collecting
|
||||||
|
# tests that share a setUp/tearDown mechanism or that share
|
||||||
|
# some test data, or just because they're related.
|
||||||
|
#
|
||||||
|
# The test function name should not have docstrings, but should
|
||||||
|
# have names which add to the value of failure reporting, and
|
||||||
|
# which make it easy to find them within the source.
|
||||||
|
|
||||||
|
|
||||||
|
# some enabling infrastructure features
|
||||||
|
class Test1(U.TestCase):
|
||||||
|
def test1a_custom_exception(s):
|
||||||
|
tmsg = "testing"
|
||||||
|
try:
|
||||||
|
err = None
|
||||||
|
raise tu.TestError(tmsg)
|
||||||
|
except tu.TestError,e:
|
||||||
|
emsg = e.value
|
||||||
|
s.assertEqual(emsg, tmsg,
|
||||||
|
"raising TestError: g=%r e=%r" % (emsg, tmsg))
|
||||||
|
|
||||||
|
def test1b_msg_reporting_utility(s):
|
||||||
|
g,e = "got this", "expected that"
|
||||||
|
m,p = "your message here", "pfx"
|
||||||
|
tmsg0 = m + "\n .....got:'" + g + \
|
||||||
|
"'\n expected:'" + e +"'"
|
||||||
|
tmsg1 = p + ": " + tmsg0
|
||||||
|
s.assertEqual(tu.msg(g,e,m), tmsg0, "non-prefix message")
|
||||||
|
s.assertEqual(tu.msg(g,e,m,p), tmsg1, "prefix message")
|
||||||
|
|
||||||
|
|
||||||
|
# path-related features (note use of tu.msg tested above)
|
||||||
|
class Test2(U.TestCase):
|
||||||
|
def test2a_context_via_traceback(s):
|
||||||
|
e = __file__.rstrip(".co") # eg in *.py[co]
|
||||||
|
g = tu._caller_context()[0]
|
||||||
|
g.rstrip('c')
|
||||||
|
s.assertEqual(g,e, tu.msg(g,e, "_caller_context"))
|
||||||
|
|
||||||
|
def test2b_absdir(s):
|
||||||
|
here = tu.absdir();
|
||||||
|
g=tu.absdir(__file__)
|
||||||
|
s.assertEqual(g,here, tu.msg(g,here, "absdir"))
|
||||||
|
|
||||||
|
def test2c_path_append_parent(s):
|
||||||
|
here = tu.absdir();
|
||||||
|
par = os.path.dirname(here)
|
||||||
|
was_there = par in sys.path
|
||||||
|
if was_there:
|
||||||
|
while par in sys.path:
|
||||||
|
sys.path.remove(par)
|
||||||
|
np = len(sys.path)
|
||||||
|
|
||||||
|
for p in (None, __file__):
|
||||||
|
s.assertFalse(par in sys.path, "par not in initial path")
|
||||||
|
if not p:
|
||||||
|
g = tu.path_append_parent()
|
||||||
|
else:
|
||||||
|
g = tu.path_append_parent(p)
|
||||||
|
s.assertEqual(g,par, tu.msg(g,par, "path_append_parent return"))
|
||||||
|
s.assertTrue(par in sys.path, "actually appends")
|
||||||
|
sys.path.remove(par)
|
||||||
|
l= len(sys.path)
|
||||||
|
s.assertEqual(l,np, tu.msg(l,np,"numpaths"))
|
||||||
|
if was_there:
|
||||||
|
# restore entry state (but no multiples needed!)
|
||||||
|
sys.path.append(par)
|
||||||
|
|
||||||
|
# make and remove test dirs
|
||||||
|
class Test3(U.TestCase):
|
||||||
|
here = tu.absdir()
|
||||||
|
bases = (here, tempfile.gettempdir())
|
||||||
|
asubs = map(lambda b: os.path.join(b,"test_sub"), bases)
|
||||||
|
home= os.environ["HOME"]
|
||||||
|
if home:
|
||||||
|
home_junk = os.path.join(home,"test_junk")
|
||||||
|
def _rmsubs(s):
|
||||||
|
import shutil
|
||||||
|
for sub in s.asubs:
|
||||||
|
if os.path.isdir(sub):
|
||||||
|
shutil.rmtree(sub)
|
||||||
|
|
||||||
|
def setUp(s):
|
||||||
|
s._rmsubs()
|
||||||
|
if s.home and not os.path.isdir(s.home_junk):
|
||||||
|
os.mkdir(s.home_junk)
|
||||||
|
|
||||||
|
def tearDown(s):
|
||||||
|
s._rmsubs()
|
||||||
|
if s.home and os.path.isdir(s.home_junk):
|
||||||
|
os.rmdir(s.home_junk)
|
||||||
|
|
||||||
|
def test3a_subdir(s):
|
||||||
|
for sub in s.asubs:
|
||||||
|
s.assertFalse(os.path.isdir(sub), "init: no dir %r" % sub)
|
||||||
|
b,d = os.path.dirname(sub), os.path.basename(sub)
|
||||||
|
md = tu.make_subdir(d, b)
|
||||||
|
s.assertTrue(os.path.isdir(sub), "made dir %r" % sub)
|
||||||
|
s.assertEqual(md,sub, tu.msg(md,sub,
|
||||||
|
"make_subdir returns path"))
|
||||||
|
|
||||||
|
s2 = os.path.join(sub,"sub2")
|
||||||
|
tu.make_subdir("sub2", sub)
|
||||||
|
s.assertTrue(os.path.isdir(s2), "made dir %r" % s2)
|
||||||
|
f = os.path.join(s2,"test_file")
|
||||||
|
|
||||||
|
open(f,"w").write("testing..")
|
||||||
|
s.assertTrue(os.path.isfile(f), "file %r exists" % f)
|
||||||
|
tu.delete_tree(sub)
|
||||||
|
s.assertFalse(os.path.isdir(sub),
|
||||||
|
"delete_tree removes subdir %r" % sub )
|
||||||
|
|
||||||
|
def test3b_delete_tree_constraint(s):
|
||||||
|
if s.home:
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
tu.delete_tree(s.home_junk)
|
||||||
|
except tu.TestError, e:
|
||||||
|
err = e.value
|
||||||
|
s.assertFalse(err is None,
|
||||||
|
"deltree on %r raises TestError" % (s.home_junk))
|
||||||
|
else:
|
||||||
|
s.fail("Skip deltree constraint test, no '$HOME' var")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
U.main()
|
||||||
|
#===eof===
|
143
src/test/test_util.py
Normal file
143
src/test/test_util.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
"""unittest support utility module"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
# _caller_context is primarily here to support and document the process
|
||||||
|
# of determining the test-module's directory.
|
||||||
|
#
|
||||||
|
# NB: the traceback 0-element is 'limit'-levels back, or earliest calling
|
||||||
|
# context if that is less than limit.
|
||||||
|
# The -1 element is this very function; -2 is its caller, etc.
|
||||||
|
# A traceback context tuple is:
|
||||||
|
# (file, line, active function, text of the call-line)
|
||||||
|
def _caller_context():
|
||||||
|
"""Return context of first caller outside this module"""
|
||||||
|
lim = 5 # 1 for this function, plus futrher chain within this module
|
||||||
|
st = traceback.extract_stack(limit=lim)
|
||||||
|
thisfile = __file__.rstrip("co") # eg, in ".py[co]
|
||||||
|
while st and st[-1][0] == thisfile:
|
||||||
|
del(st[-1])
|
||||||
|
if not st:
|
||||||
|
raise TestError("Unexpected function call chain length!")
|
||||||
|
return st[-1]
|
||||||
|
|
||||||
|
|
||||||
|
# NB: tb[0] differs between running 'XYZ_test.py' and './XYZ_test.py'
|
||||||
|
# so, always take the abspath.
|
||||||
|
def _caller_dir():
|
||||||
|
"""Return directory of caller function (caller outside this module)"""
|
||||||
|
tb = _caller_context()
|
||||||
|
return os.path.dirname(os.path.abspath(tb[0]))
|
||||||
|
|
||||||
|
|
||||||
|
class TestError(Exception):
|
||||||
|
"""Exception for use by test modules
|
||||||
|
|
||||||
|
Use this, for example, to distuinguish testing errors.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
def msg(got, exp, msg, pfx=""):
|
||||||
|
"""Error-report message formatting utility
|
||||||
|
|
||||||
|
This improves unittest failure messages by showing data values
|
||||||
|
Usage:
|
||||||
|
assertEqual(got,exp, msg(got,exp,"mess" [,prefix])
|
||||||
|
The failure message will show as
|
||||||
|
[prefix: ] mess
|
||||||
|
.....got:repr(value-of-got)
|
||||||
|
expected:repr(value-of-exp)
|
||||||
|
|
||||||
|
"""
|
||||||
|
if pfx:
|
||||||
|
pfx += ": "
|
||||||
|
return "%s%s\n .....got:%r\n expected:%r" % (pfx, msg, got, exp)
|
||||||
|
|
||||||
|
|
||||||
|
def absdir(path=None):
|
||||||
|
"""Return absolute dir of the specified path
|
||||||
|
|
||||||
|
The path parm may be dir or file or missing.
|
||||||
|
If a file, the dir of the file is used.
|
||||||
|
If missing, the dir of test-module caller is used
|
||||||
|
|
||||||
|
Common usage is
|
||||||
|
here = absdir()
|
||||||
|
here = absdir(__file__)
|
||||||
|
These 2 return the same result
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not path:
|
||||||
|
path = _caller_dir()
|
||||||
|
loc = os.path.abspath(path)
|
||||||
|
if os.path.isfile(loc):
|
||||||
|
loc = os.path.dirname(loc)
|
||||||
|
return loc
|
||||||
|
|
||||||
|
|
||||||
|
def path_append_parent(path=None):
|
||||||
|
"""Append (if required) the parent of a path to the python system path,
|
||||||
|
and return the abspath to the parent as a possible convenience
|
||||||
|
|
||||||
|
The path parm may be a dir or a file or missing.
|
||||||
|
If a file, the the dir of the file is used.
|
||||||
|
If missing the test-module caller's dir is used.
|
||||||
|
And then the parent of that dir is appended (if not already present)
|
||||||
|
|
||||||
|
Common usage is
|
||||||
|
path_append_parent()
|
||||||
|
path_append_parent(__file__)
|
||||||
|
These 2 produce the same result
|
||||||
|
|
||||||
|
"""
|
||||||
|
pdir = os.path.dirname(absdir(path))
|
||||||
|
if not pdir in sys.path:
|
||||||
|
sys.path.append(pdir)
|
||||||
|
return pdir
|
||||||
|
|
||||||
|
|
||||||
|
def make_subdir(dir, parent=None):
|
||||||
|
"""Make (if required) a subdir to a given parent and return its path
|
||||||
|
|
||||||
|
The parent parm may be dir or file or missing
|
||||||
|
If a file, the dir of the file us used
|
||||||
|
If missing, the test-module caller's dir is used
|
||||||
|
Then the subdir dir in the parent dir is created if not already present
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not parent:
|
||||||
|
parent = _caller_dir()
|
||||||
|
sdir = os.path.join(parent,dir)
|
||||||
|
if not os.path.exists(sdir):
|
||||||
|
os.mkdir(sdir)
|
||||||
|
return sdir
|
||||||
|
|
||||||
|
def delete_tree(dir):
|
||||||
|
"""Recursively delete directory and content
|
||||||
|
|
||||||
|
WARNING: this is clearly dangerous
|
||||||
|
it will only operate on subdirs of the test module dir or of /tmp
|
||||||
|
|
||||||
|
Test writers may explicitly use shutil.rmtree if really needed
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not os.path.isdir(dir):
|
||||||
|
raise TestError("%r is not a dir" % dir)
|
||||||
|
sdir = os.path.abspath(dir)
|
||||||
|
here = _caller_dir() + os.path.sep
|
||||||
|
tmp = tempfile.gettempdir() + os.path.sep
|
||||||
|
if not (sdir.startswith(here) or sdir.startswith(tmp)):
|
||||||
|
raise TestError("%r is not a subdir of here (%r) or %r"
|
||||||
|
% (dir, here, tmp))
|
||||||
|
shutil.rmtree(sdir)
|
||||||
|
|
||||||
|
#===eof===
|
Reference in New Issue
Block a user