refine lsof/FD leakage testing and rework test setup and some of pytest own tests. Note that the actual diff to non-test code is small. Also remove some redundant tests (introduced by a copy-paste-error apparently in test_mark.py).
This commit is contained in:
parent
077c468589
commit
a2f4a11301
|
@ -1,7 +1,7 @@
|
|||
Changes between 2.1.3 and [next version]
|
||||
----------------------------------------
|
||||
|
||||
- fix pytest's own test suite to not leak FDs
|
||||
- fix and cleanup pytest's own test suite to not leak FDs
|
||||
- fix issue83: link to generated funcarg list
|
||||
- fix issue74: pyarg module names are now checked against imp.find_module false positives
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#
|
||||
__version__ = '2.1.4.dev2'
|
||||
__version__ = '2.1.4.dev3'
|
||||
|
|
|
@ -11,20 +11,23 @@ def pytest_addoption(parser):
|
|||
group._addoption('-s', action="store_const", const="no", dest="capture",
|
||||
help="shortcut for --capture=no.")
|
||||
|
||||
@pytest.mark.tryfirst
|
||||
def pytest_cmdline_parse(pluginmanager, args):
|
||||
# we want to perform capturing already for plugin/conftest loading
|
||||
if '-s' in args or "--capture=no" in args:
|
||||
method = "no"
|
||||
elif hasattr(os, 'dup') and '--capture=sys' not in args:
|
||||
method = "fd"
|
||||
else:
|
||||
method = "sys"
|
||||
capman = CaptureManager(method)
|
||||
pluginmanager.register(capman, "capturemanager")
|
||||
|
||||
def addouterr(rep, outerr):
|
||||
for secname, content in zip(["out", "err"], outerr):
|
||||
if content:
|
||||
rep.sections.append(("Captured std%s" % secname, content))
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
# registered in config.py during early conftest.py loading
|
||||
capman = config.pluginmanager.getplugin('capturemanager')
|
||||
while capman._method2capture:
|
||||
name, cap = capman._method2capture.popitem()
|
||||
# XXX logging module may wants to close it itself on process exit
|
||||
# otherwise we could do finalization here and call "reset()".
|
||||
cap.suspend()
|
||||
|
||||
class NoCapture:
|
||||
def startall(self):
|
||||
pass
|
||||
|
@ -36,8 +39,9 @@ class NoCapture:
|
|||
return "", ""
|
||||
|
||||
class CaptureManager:
|
||||
def __init__(self):
|
||||
def __init__(self, defaultmethod=None):
|
||||
self._method2capture = {}
|
||||
self._defaultmethod = defaultmethod
|
||||
|
||||
def _maketempfile(self):
|
||||
f = py.std.tempfile.TemporaryFile()
|
||||
|
@ -62,14 +66,6 @@ class CaptureManager:
|
|||
else:
|
||||
raise ValueError("unknown capturing method: %r" % method)
|
||||
|
||||
def _getmethod_preoptionparse(self, args):
|
||||
if '-s' in args or "--capture=no" in args:
|
||||
return "no"
|
||||
elif hasattr(os, 'dup') and '--capture=sys' not in args:
|
||||
return "fd"
|
||||
else:
|
||||
return "sys"
|
||||
|
||||
def _getmethod(self, config, fspath):
|
||||
if config.option.capture:
|
||||
method = config.option.capture
|
||||
|
@ -82,16 +78,22 @@ class CaptureManager:
|
|||
method = "sys"
|
||||
return method
|
||||
|
||||
def reset_capturings(self):
|
||||
for name, cap in self._method2capture.items():
|
||||
cap.reset()
|
||||
|
||||
def resumecapture_item(self, item):
|
||||
method = self._getmethod(item.config, item.fspath)
|
||||
if not hasattr(item, 'outerr'):
|
||||
item.outerr = ('', '') # we accumulate outerr on the item
|
||||
return self.resumecapture(method)
|
||||
|
||||
def resumecapture(self, method):
|
||||
def resumecapture(self, method=None):
|
||||
if hasattr(self, '_capturing'):
|
||||
raise ValueError("cannot resume, already capturing with %r" %
|
||||
(self._capturing,))
|
||||
if method is None:
|
||||
method = self._defaultmethod
|
||||
cap = self._method2capture.get(method)
|
||||
self._capturing = method
|
||||
if cap is None:
|
||||
|
|
|
@ -11,8 +11,12 @@ def pytest_cmdline_parse(pluginmanager, args):
|
|||
return config
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
for func in config._cleanup:
|
||||
func()
|
||||
while 1:
|
||||
try:
|
||||
fin = config._cleanup.pop()
|
||||
except IndexError:
|
||||
break
|
||||
fin()
|
||||
|
||||
class Parser:
|
||||
""" Parser for command line arguments. """
|
||||
|
@ -254,11 +258,14 @@ class Config(object):
|
|||
self.hook = self.pluginmanager.hook
|
||||
self._inicache = {}
|
||||
self._cleanup = []
|
||||
|
||||
|
||||
@classmethod
|
||||
def fromdictargs(cls, option_dict, args):
|
||||
""" constructor useable for subprocesses. """
|
||||
config = cls()
|
||||
# XXX slightly crude way to initialize capturing
|
||||
import _pytest.capture
|
||||
_pytest.capture.pytest_cmdline_parse(config.pluginmanager, args)
|
||||
config._preparse(args, addopts=False)
|
||||
config.option.__dict__.update(option_dict)
|
||||
for x in config.option.plugins:
|
||||
|
@ -283,11 +290,10 @@ class Config(object):
|
|||
|
||||
def _setinitialconftest(self, args):
|
||||
# capture output during conftest init (#issue93)
|
||||
from _pytest.capture import CaptureManager
|
||||
capman = CaptureManager()
|
||||
self.pluginmanager.register(capman, 'capturemanager')
|
||||
# will be unregistered in capture.py's unconfigure()
|
||||
capman.resumecapture(capman._getmethod_preoptionparse(args))
|
||||
# XXX introduce load_conftest hook to avoid needing to know
|
||||
# about capturing plugin here
|
||||
capman = self.pluginmanager.getplugin("capturemanager")
|
||||
capman.resumecapture()
|
||||
try:
|
||||
try:
|
||||
self._conftest.setinitial(args)
|
||||
|
|
|
@ -431,10 +431,7 @@ _preinit = []
|
|||
def _preloadplugins():
|
||||
_preinit.append(PluginManager(load=True))
|
||||
|
||||
def main(args=None, plugins=None):
|
||||
""" returned exit code integer, after an in-process testing run
|
||||
with the given command line arguments, preloading an optional list
|
||||
of passed in plugin objects. """
|
||||
def _prepareconfig(args=None, plugins=None):
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
elif isinstance(args, py.path.local):
|
||||
|
@ -448,13 +445,19 @@ def main(args=None, plugins=None):
|
|||
else: # subsequent calls to main will create a fresh instance
|
||||
_pluginmanager = PluginManager(load=True)
|
||||
hook = _pluginmanager.hook
|
||||
if plugins:
|
||||
for plugin in plugins:
|
||||
_pluginmanager.register(plugin)
|
||||
return hook.pytest_cmdline_parse(
|
||||
pluginmanager=_pluginmanager, args=args)
|
||||
|
||||
def main(args=None, plugins=None):
|
||||
""" returned exit code integer, after an in-process testing run
|
||||
with the given command line arguments, preloading an optional list
|
||||
of passed in plugin objects. """
|
||||
try:
|
||||
if plugins:
|
||||
for plugin in plugins:
|
||||
_pluginmanager.register(plugin)
|
||||
config = hook.pytest_cmdline_parse(
|
||||
pluginmanager=_pluginmanager, args=args)
|
||||
exitstatus = hook.pytest_cmdline_main(config=config)
|
||||
config = _prepareconfig(args, plugins)
|
||||
exitstatus = config.hook.pytest_cmdline_main(config=config)
|
||||
except UsageError:
|
||||
e = sys.exc_info()[1]
|
||||
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
|
||||
|
|
|
@ -56,6 +56,7 @@ def pytest_cmdline_main(config):
|
|||
elif config.option.help:
|
||||
config.pluginmanager.do_configure(config)
|
||||
showhelp(config)
|
||||
config.pluginmanager.do_unconfigure(config)
|
||||
return 0
|
||||
|
||||
def showhelp(config):
|
||||
|
@ -113,7 +114,7 @@ def pytest_report_header(config):
|
|||
verinfo = getpluginversioninfo(config)
|
||||
if verinfo:
|
||||
lines.extend(verinfo)
|
||||
|
||||
|
||||
if config.option.traceconfig:
|
||||
lines.append("active plugins:")
|
||||
plugins = []
|
||||
|
|
|
@ -50,7 +50,7 @@ def pytest_addoption(parser):
|
|||
def pytest_namespace():
|
||||
collect = dict(Item=Item, Collector=Collector, File=File, Session=Session)
|
||||
return dict(collect=collect)
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
py.test.config = config # compatibiltiy
|
||||
if config.option.exitfirst:
|
||||
|
@ -134,7 +134,7 @@ def compatproperty(name):
|
|||
return getattr(pytest, name)
|
||||
return property(fget, None, None,
|
||||
"deprecated attribute %r, use pytest.%s" % (name,name))
|
||||
|
||||
|
||||
class Node(object):
|
||||
""" base class for all Nodes in the collection tree.
|
||||
Collector subclasses have children, Items are terminal nodes."""
|
||||
|
@ -145,13 +145,13 @@ class Node(object):
|
|||
|
||||
#: the parent collector node.
|
||||
self.parent = parent
|
||||
|
||||
|
||||
#: the test config object
|
||||
self.config = config or parent.config
|
||||
|
||||
#: the collection this node is part of
|
||||
self.session = session or parent.session
|
||||
|
||||
|
||||
#: filesystem path where this node was collected from
|
||||
self.fspath = getattr(parent, 'fspath', None)
|
||||
self.ihook = self.session.gethookproxy(self.fspath)
|
||||
|
@ -488,7 +488,7 @@ class Session(FSCollector):
|
|||
else:
|
||||
if fd is not None:
|
||||
fd.close()
|
||||
|
||||
|
||||
if type_[2] != imp.PKG_DIRECTORY:
|
||||
path = [os.path.dirname(mod)]
|
||||
else:
|
||||
|
@ -511,7 +511,7 @@ class Session(FSCollector):
|
|||
raise pytest.UsageError(msg + arg)
|
||||
parts[0] = path
|
||||
return parts
|
||||
|
||||
|
||||
def matchnodes(self, matching, names):
|
||||
self.trace("matchnodes", matching, names)
|
||||
self.trace.root.indent += 1
|
||||
|
|
|
@ -314,16 +314,6 @@ class TmpTestdir:
|
|||
result.extend(session.genitems(colitem))
|
||||
return result
|
||||
|
||||
def inline_genitems(self, *args):
|
||||
#config = self.parseconfig(*args)
|
||||
config = self.parseconfigure(*args)
|
||||
rec = self.getreportrecorder(config)
|
||||
session = Session(config)
|
||||
config.hook.pytest_sessionstart(session=session)
|
||||
session.perform_collect()
|
||||
config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK)
|
||||
return session.items, rec
|
||||
|
||||
def runitem(self, source):
|
||||
# used from runner functional tests
|
||||
item = self.getitem(source)
|
||||
|
@ -347,70 +337,52 @@ class TmpTestdir:
|
|||
assert len(reports) == 1, reports
|
||||
return reports[0]
|
||||
|
||||
def inline_run(self, *args):
|
||||
args = ("-s", ) + args # otherwise FD leakage
|
||||
config = self.parseconfig(*args)
|
||||
reprec = self.getreportrecorder(config)
|
||||
#config.pluginmanager.do_configure(config)
|
||||
config.hook.pytest_cmdline_main(config=config)
|
||||
#config.pluginmanager.do_unconfigure(config)
|
||||
return reprec
|
||||
def inline_genitems(self, *args):
|
||||
return self.inprocess_run(list(args) + ['--collectonly'])
|
||||
|
||||
def config_preparse(self):
|
||||
config = self.Config()
|
||||
for plugin in self.plugins:
|
||||
if isinstance(plugin, str):
|
||||
config.pluginmanager.import_plugin(plugin)
|
||||
else:
|
||||
if isinstance(plugin, dict):
|
||||
plugin = PseudoPlugin(plugin)
|
||||
if not config.pluginmanager.isregistered(plugin):
|
||||
config.pluginmanager.register(plugin)
|
||||
return config
|
||||
def inline_run(self, *args):
|
||||
items, rec = self.inprocess_run(args)
|
||||
return rec
|
||||
|
||||
def inprocess_run(self, args, plugins=None):
|
||||
rec = []
|
||||
items = []
|
||||
class Collect:
|
||||
def pytest_configure(x, config):
|
||||
rec.append(self.getreportrecorder(config))
|
||||
def pytest_itemcollected(self, item):
|
||||
items.append(item)
|
||||
if not plugins:
|
||||
plugins = []
|
||||
plugins.append(Collect())
|
||||
self.pytestmain(list(args), plugins=[Collect()])
|
||||
assert len(rec) == 1
|
||||
return items, rec[0]
|
||||
|
||||
def parseconfig(self, *args):
|
||||
if not args:
|
||||
args = (self.tmpdir,)
|
||||
config = self.config_preparse()
|
||||
args = list(args)
|
||||
args = map(str, args)
|
||||
for x in args:
|
||||
if str(x).startswith('--basetemp'):
|
||||
break
|
||||
else:
|
||||
args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp'))
|
||||
config.parse(args)
|
||||
import _pytest.core
|
||||
config = _pytest.core._prepareconfig(args, self.plugins)
|
||||
# the in-process pytest invocation needs to avoid leaking FDs
|
||||
# so we register a "reset_capturings" callmon the capturing manager
|
||||
# and make sure it gets called
|
||||
config._cleanup.append(
|
||||
config.pluginmanager.getplugin("capturemanager").reset_capturings)
|
||||
import _pytest.config
|
||||
self.request.addfinalizer(
|
||||
lambda: _pytest.config.pytest_unconfigure(config))
|
||||
return config
|
||||
|
||||
def reparseconfig(self, args=None):
|
||||
""" this is used from tests that want to re-invoke parse(). """
|
||||
if not args:
|
||||
args = [self.tmpdir]
|
||||
oldconfig = getattr(py.test, 'config', None)
|
||||
try:
|
||||
c = py.test.config = self.Config()
|
||||
c.basetemp = py.path.local.make_numbered_dir(prefix="reparse",
|
||||
keep=0, rootdir=self.tmpdir, lock_timeout=None)
|
||||
c.parse(args)
|
||||
c.pluginmanager.do_configure(c)
|
||||
self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c))
|
||||
return c
|
||||
finally:
|
||||
py.test.config = oldconfig
|
||||
|
||||
def parseconfigure(self, *args):
|
||||
config = self.parseconfig(*args)
|
||||
config.pluginmanager.do_configure(config)
|
||||
self.request.addfinalizer(lambda:
|
||||
config.pluginmanager.do_unconfigure(config))
|
||||
# XXX we need to additionally reset FDs to prevent pen FDs
|
||||
# during our test suite. see also capture.py's unconfigure XXX
|
||||
# comment about logging
|
||||
def finalize_capman():
|
||||
capman = config.pluginmanager.getplugin('capturemanager')
|
||||
while capman._method2capture:
|
||||
name, cap = capman._method2capture.popitem()
|
||||
cap.reset()
|
||||
self.request.addfinalizer(finalize_capman)
|
||||
config.pluginmanager.do_unconfigure(config))
|
||||
return config
|
||||
|
||||
def getitem(self, source, funcname="test_func"):
|
||||
|
@ -430,7 +402,6 @@ class TmpTestdir:
|
|||
self.makepyfile(__init__ = "#")
|
||||
self.config = config = self.parseconfigure(path, *configargs)
|
||||
node = self.getnode(config, path)
|
||||
#config.pluginmanager.do_unconfigure(config)
|
||||
return node
|
||||
|
||||
def collect_by_name(self, modcol, name):
|
||||
|
@ -447,9 +418,16 @@ class TmpTestdir:
|
|||
return py.std.subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw)
|
||||
|
||||
def pytestmain(self, *args, **kwargs):
|
||||
ret = pytest.main(*args, **kwargs)
|
||||
if ret == 2:
|
||||
raise KeyboardInterrupt()
|
||||
class ResetCapturing:
|
||||
@pytest.mark.trylast
|
||||
def pytest_unconfigure(self, config):
|
||||
capman = config.pluginmanager.getplugin("capturemanager")
|
||||
capman.reset_capturings()
|
||||
plugins = kwargs.setdefault("plugins", [])
|
||||
rc = ResetCapturing()
|
||||
plugins.append(rc)
|
||||
return pytest.main(*args, **kwargs)
|
||||
|
||||
def run(self, *cmdargs):
|
||||
return self._run(*cmdargs)
|
||||
|
||||
|
@ -550,10 +528,6 @@ def getdecoded(out):
|
|||
return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
|
||||
py.io.saferepr(out),)
|
||||
|
||||
class PseudoPlugin:
|
||||
def __init__(self, vars):
|
||||
self.__dict__.update(vars)
|
||||
|
||||
class ReportRecorder(object):
|
||||
def __init__(self, hook):
|
||||
self.hook = hook
|
||||
|
|
|
@ -43,7 +43,8 @@ def pytest_configure(config):
|
|||
pass
|
||||
else:
|
||||
stdout = os.fdopen(newfd, stdout.mode, 1)
|
||||
config._toclose = stdout
|
||||
config._cleanup.append(lambda: stdout.close())
|
||||
|
||||
reporter = TerminalReporter(config, stdout)
|
||||
config.pluginmanager.register(reporter, 'terminalreporter')
|
||||
if config.option.debug or config.option.traceconfig:
|
||||
|
@ -52,11 +53,6 @@ def pytest_configure(config):
|
|||
reporter.write_line("[traceconfig] " + msg)
|
||||
config.trace.root.setprocessor("pytest:config", mywriter)
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
if hasattr(config, '_toclose'):
|
||||
#print "closing", config._toclose, config._toclose.fileno()
|
||||
config._toclose.close()
|
||||
|
||||
def getreportopt(config):
|
||||
reportopts = ""
|
||||
optvalue = config.option.report
|
||||
|
|
2
setup.py
2
setup.py
|
@ -24,7 +24,7 @@ def main():
|
|||
name='pytest',
|
||||
description='py.test: simple powerful testing with Python',
|
||||
long_description = long_description,
|
||||
version='2.1.4.dev2',
|
||||
version='2.1.4.dev3',
|
||||
url='http://pytest.org',
|
||||
license='MIT license',
|
||||
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
||||
|
|
|
@ -13,6 +13,12 @@ class TestGeneralUsage:
|
|||
'*ERROR: hello'
|
||||
])
|
||||
|
||||
def test_root_conftest_syntax_error(self, testdir):
|
||||
p = testdir.makepyfile(conftest="raise SyntaxError\n")
|
||||
result = testdir.runpytest()
|
||||
result.stderr.fnmatch_lines(["*raise SyntaxError*"])
|
||||
assert result.ret != 0
|
||||
|
||||
def test_early_hook_error_issue38_1(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_sessionstart():
|
||||
|
@ -354,24 +360,24 @@ class TestInvocationVariants:
|
|||
def test_equivalence_pytest_pytest(self):
|
||||
assert pytest.main == py.test.cmdline.main
|
||||
|
||||
def test_invoke_with_string(self, capsys):
|
||||
retcode = pytest.main("-h")
|
||||
def test_invoke_with_string(self, testdir, capsys):
|
||||
retcode = testdir.pytestmain("-h")
|
||||
assert not retcode
|
||||
out, err = capsys.readouterr()
|
||||
assert "--help" in out
|
||||
pytest.raises(ValueError, lambda: pytest.main(retcode))
|
||||
pytest.raises(ValueError, lambda: pytest.main(0))
|
||||
|
||||
def test_invoke_with_path(self, testdir, capsys):
|
||||
retcode = testdir.pytestmain(testdir.tmpdir)
|
||||
assert not retcode
|
||||
out, err = capsys.readouterr()
|
||||
|
||||
def test_invoke_plugin_api(self, capsys):
|
||||
def test_invoke_plugin_api(self, testdir, capsys):
|
||||
class MyPlugin:
|
||||
def pytest_addoption(self, parser):
|
||||
parser.addoption("--myopt")
|
||||
|
||||
pytest.main(["-h"], plugins=[MyPlugin()])
|
||||
testdir.pytestmain(["-h"], plugins=[MyPlugin()])
|
||||
out, err = capsys.readouterr()
|
||||
assert "--myopt" in out
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ def pytest_configure(config):
|
|||
except py.process.cmdexec.Error:
|
||||
pass
|
||||
else:
|
||||
config._numfiles = getopenfiles(out)
|
||||
config._numfiles = len(getopenfiles(out))
|
||||
|
||||
#def pytest_report_header():
|
||||
# return "pid: %s" % os.getpid()
|
||||
|
@ -26,23 +26,31 @@ def pytest_configure(config):
|
|||
def getopenfiles(out):
|
||||
def isopen(line):
|
||||
return ("REG" in line or "CHR" in line) and (
|
||||
"deleted" not in line and 'mem' not in line)
|
||||
return len([x for x in out.split("\n") if isopen(x)])
|
||||
"deleted" not in line and 'mem' not in line and "txt" not in line)
|
||||
return [x for x in out.split("\n") if isopen(x)]
|
||||
|
||||
def pytest_unconfigure(config, __multicall__):
|
||||
if not hasattr(config, '_numfiles'):
|
||||
return
|
||||
__multicall__.execute()
|
||||
def check_open_files(config):
|
||||
out2 = py.process.cmdexec("lsof -p %d" % pid)
|
||||
len2 = getopenfiles(out2)
|
||||
assert len2 < config._numfiles + 15, out2
|
||||
|
||||
lines2 = getopenfiles(out2)
|
||||
if len(lines2) > config._numfiles + 1:
|
||||
error = []
|
||||
error.append("***** %s FD leackage detected" %
|
||||
(len(lines2)-config._numfiles))
|
||||
error.extend(lines2)
|
||||
error.append(error[0])
|
||||
# update numfile so that the overall test run continuess
|
||||
config._numfiles = len(lines2)
|
||||
raise AssertionError("\n".join(error))
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
item._oldir = py.path.local()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
def pytest_runtest_teardown(item, __multicall__):
|
||||
item._oldir.chdir()
|
||||
if hasattr(item.config, '_numfiles'):
|
||||
x = __multicall__.execute()
|
||||
check_open_files(item.config)
|
||||
return x
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
multi = getattr(metafunc.function, 'multi', None)
|
||||
|
|
|
@ -16,7 +16,6 @@ class TestCaptureManager:
|
|||
|
||||
def test_configure_per_fspath(self, testdir):
|
||||
config = testdir.parseconfig(testdir.tmpdir)
|
||||
assert config.getvalue("capture") is None
|
||||
capman = CaptureManager()
|
||||
hasfd = hasattr(os, 'dup')
|
||||
if hasfd:
|
||||
|
@ -53,6 +52,7 @@ class TestCaptureManager:
|
|||
capman.resumecapture(method)
|
||||
out, err = capman.suspendcapture()
|
||||
assert not out and not err
|
||||
capman.reset_capturings()
|
||||
finally:
|
||||
capouter.reset()
|
||||
|
||||
|
@ -60,20 +60,23 @@ class TestCaptureManager:
|
|||
def test_juggle_capturings(self, testdir):
|
||||
capouter = py.io.StdCaptureFD()
|
||||
try:
|
||||
config = testdir.parseconfig(testdir.tmpdir)
|
||||
#config = testdir.parseconfig(testdir.tmpdir)
|
||||
capman = CaptureManager()
|
||||
capman.resumecapture("fd")
|
||||
pytest.raises(ValueError, 'capman.resumecapture("fd")')
|
||||
pytest.raises(ValueError, 'capman.resumecapture("sys")')
|
||||
os.write(1, "hello\n".encode('ascii'))
|
||||
out, err = capman.suspendcapture()
|
||||
assert out == "hello\n"
|
||||
capman.resumecapture("sys")
|
||||
os.write(1, "hello\n".encode('ascii'))
|
||||
py.builtin.print_("world", file=sys.stderr)
|
||||
out, err = capman.suspendcapture()
|
||||
assert not out
|
||||
assert err == "world\n"
|
||||
try:
|
||||
capman.resumecapture("fd")
|
||||
pytest.raises(ValueError, 'capman.resumecapture("fd")')
|
||||
pytest.raises(ValueError, 'capman.resumecapture("sys")')
|
||||
os.write(1, "hello\n".encode('ascii'))
|
||||
out, err = capman.suspendcapture()
|
||||
assert out == "hello\n"
|
||||
capman.resumecapture("sys")
|
||||
os.write(1, "hello\n".encode('ascii'))
|
||||
py.builtin.print_("world", file=sys.stderr)
|
||||
out, err = capman.suspendcapture()
|
||||
assert not out
|
||||
assert err == "world\n"
|
||||
finally:
|
||||
capman.reset_capturings()
|
||||
finally:
|
||||
capouter.reset()
|
||||
|
||||
|
|
|
@ -313,7 +313,8 @@ class TestSession:
|
|||
def test_collect_topdir(self, testdir):
|
||||
p = testdir.makepyfile("def test_func(): pass")
|
||||
id = "::".join([p.basename, "test_func"])
|
||||
config = testdir.parseconfigure(id)
|
||||
# XXX migrate to inline_genitems? (see below)
|
||||
config = testdir.parseconfig(id)
|
||||
topdir = testdir.tmpdir
|
||||
rcol = Session(config)
|
||||
assert topdir == rcol.fspath
|
||||
|
@ -328,15 +329,9 @@ class TestSession:
|
|||
def test_collect_protocol_single_function(self, testdir):
|
||||
p = testdir.makepyfile("def test_func(): pass")
|
||||
id = "::".join([p.basename, "test_func"])
|
||||
config = testdir.parseconfigure(id)
|
||||
topdir = testdir.tmpdir
|
||||
rcol = Session(config)
|
||||
assert topdir == rcol.fspath
|
||||
hookrec = testdir.getreportrecorder(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
assert len(items) == 1
|
||||
item = items[0]
|
||||
items, hookrec = testdir.inline_genitems(id)
|
||||
item, = items
|
||||
assert item.name == "test_func"
|
||||
newid = item.nodeid
|
||||
assert newid == id
|
||||
|
@ -363,10 +358,7 @@ class TestSession:
|
|||
p.basename + "::TestClass::()",
|
||||
normid,
|
||||
]:
|
||||
config = testdir.parseconfigure(id)
|
||||
rcol = Session(config=config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
items, hookrec = testdir.inline_genitems(id)
|
||||
assert len(items) == 1
|
||||
assert items[0].name == "test_method"
|
||||
newid = items[0].nodeid
|
||||
|
@ -388,11 +380,7 @@ class TestSession:
|
|||
""" % p.basename)
|
||||
id = p.basename
|
||||
|
||||
config = testdir.parseconfigure(id)
|
||||
rcol = Session(config)
|
||||
hookrec = testdir.getreportrecorder(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
items, hookrec = testdir.inline_genitems(id)
|
||||
py.std.pprint.pprint(hookrec.hookrecorder.calls)
|
||||
assert len(items) == 2
|
||||
hookrec.hookrecorder.contains([
|
||||
|
@ -413,11 +401,8 @@ class TestSession:
|
|||
aaa = testdir.mkpydir("aaa")
|
||||
test_aaa = aaa.join("test_aaa.py")
|
||||
p.move(test_aaa)
|
||||
config = testdir.parseconfigure()
|
||||
rcol = Session(config)
|
||||
hookrec = testdir.getreportrecorder(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
|
||||
items, hookrec = testdir.inline_genitems()
|
||||
assert len(items) == 1
|
||||
py.std.pprint.pprint(hookrec.hookrecorder.calls)
|
||||
hookrec.hookrecorder.contains([
|
||||
|
@ -437,11 +422,8 @@ class TestSession:
|
|||
p.move(test_bbb)
|
||||
|
||||
id = "."
|
||||
config = testdir.parseconfigure(id)
|
||||
rcol = Session(config)
|
||||
hookrec = testdir.getreportrecorder(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
|
||||
items, hookrec = testdir.inline_genitems(id)
|
||||
assert len(items) == 2
|
||||
py.std.pprint.pprint(hookrec.hookrecorder.calls)
|
||||
hookrec.hookrecorder.contains([
|
||||
|
@ -455,19 +437,13 @@ class TestSession:
|
|||
|
||||
def test_serialization_byid(self, testdir):
|
||||
p = testdir.makepyfile("def test_func(): pass")
|
||||
config = testdir.parseconfigure()
|
||||
rcol = Session(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
items, hookrec = testdir.inline_genitems()
|
||||
assert len(items) == 1
|
||||
item, = items
|
||||
rcol.config.pluginmanager.unregister(name="session")
|
||||
newcol = Session(config)
|
||||
item2, = newcol.perform_collect([item.nodeid], genitems=False)
|
||||
items2, hookrec = testdir.inline_genitems(item.nodeid)
|
||||
item2, = items2
|
||||
assert item2.name == item.name
|
||||
assert item2.fspath == item.fspath
|
||||
item2b, = newcol.perform_collect([item.nodeid], genitems=False)
|
||||
assert item2b == item2
|
||||
|
||||
def test_find_byid_without_instance_parents(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
|
@ -476,10 +452,7 @@ class TestSession:
|
|||
pass
|
||||
""")
|
||||
arg = p.basename + ("::TestClass::test_method")
|
||||
config = testdir.parseconfigure(arg)
|
||||
rcol = Session(config)
|
||||
rcol.perform_collect()
|
||||
items = rcol.items
|
||||
items, hookrec = testdir.inline_genitems(arg)
|
||||
assert len(items) == 1
|
||||
item, = items
|
||||
assert item.nodeid.endswith("TestClass::()::test_method")
|
||||
|
@ -487,7 +460,7 @@ class TestSession:
|
|||
class Test_getinitialnodes:
|
||||
def test_global_file(self, testdir, tmpdir):
|
||||
x = tmpdir.ensure("x.py")
|
||||
config = testdir.reparseconfig([x])
|
||||
config = testdir.parseconfigure(x)
|
||||
col = testdir.getnode(config, x)
|
||||
assert isinstance(col, pytest.Module)
|
||||
assert col.name == 'x.py'
|
||||
|
@ -502,7 +475,7 @@ class Test_getinitialnodes:
|
|||
subdir = tmpdir.join("subdir")
|
||||
x = subdir.ensure("x.py")
|
||||
subdir.ensure("__init__.py")
|
||||
config = testdir.reparseconfig([x])
|
||||
config = testdir.parseconfigure(x)
|
||||
col = testdir.getnode(config, x)
|
||||
assert isinstance(col, pytest.Module)
|
||||
assert col.name == 'subdir/x.py'
|
||||
|
@ -528,12 +501,6 @@ class Test_genitems:
|
|||
assert hash(i) != hash(j)
|
||||
assert i != j
|
||||
|
||||
def test_root_conftest_syntax_error(self, testdir):
|
||||
# do we want to unify behaviour with
|
||||
# test_subdir_conftest_error?
|
||||
p = testdir.makepyfile(conftest="raise SyntaxError\n")
|
||||
pytest.raises(SyntaxError, testdir.inline_genitems, p.dirpath())
|
||||
|
||||
def test_example_items1(self, testdir):
|
||||
p = testdir.makepyfile('''
|
||||
def testone():
|
||||
|
@ -597,6 +564,6 @@ def test_matchnodes_two_collections_same_file(testdir):
|
|||
res.stdout.fnmatch_lines([
|
||||
"*1 passed*",
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import py, pytest
|
||||
|
||||
from _pytest.config import getcfg, Config
|
||||
from _pytest.config import getcfg
|
||||
|
||||
class TestParseIni:
|
||||
def test_getcfg_and_config(self, tmpdir):
|
||||
def test_getcfg_and_config(self, testdir, tmpdir):
|
||||
sub = tmpdir.mkdir("sub")
|
||||
sub.chdir()
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
|
@ -12,25 +12,23 @@ class TestParseIni:
|
|||
"""))
|
||||
cfg = getcfg([sub], ["setup.cfg"])
|
||||
assert cfg['name'] == "value"
|
||||
config = Config()
|
||||
config._preparse([sub])
|
||||
config = testdir.parseconfigure(sub)
|
||||
assert config.inicfg['name'] == 'value'
|
||||
|
||||
def test_getcfg_empty_path(self, tmpdir):
|
||||
cfg = getcfg([''], ['setup.cfg']) #happens on py.test ""
|
||||
|
||||
def test_append_parse_args(self, tmpdir):
|
||||
def test_append_parse_args(self, testdir, tmpdir):
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
[pytest]
|
||||
addopts = --verbose
|
||||
"""))
|
||||
config = Config()
|
||||
config.parse([tmpdir])
|
||||
config = testdir.parseconfig(tmpdir)
|
||||
assert config.option.verbose
|
||||
config = Config()
|
||||
args = [tmpdir,]
|
||||
config._preparse(args, addopts=False)
|
||||
assert len(args) == 1
|
||||
#config = testdir.Config()
|
||||
#args = [tmpdir,]
|
||||
#config._preparse(args, addopts=False)
|
||||
#assert len(args) == 1
|
||||
|
||||
def test_tox_ini_wrong_version(self, testdir):
|
||||
p = testdir.makefile('.ini', tox="""
|
||||
|
@ -49,8 +47,7 @@ class TestParseIni:
|
|||
[pytest]
|
||||
minversion = 1.0
|
||||
"""))
|
||||
config = Config()
|
||||
config.parse([testdir.tmpdir])
|
||||
config = testdir.parseconfig()
|
||||
assert config.getini("minversion") == "1.0"
|
||||
|
||||
def test_toxini_before_lower_pytestini(self, testdir):
|
||||
|
@ -63,8 +60,7 @@ class TestParseIni:
|
|||
[pytest]
|
||||
minversion = 1.5
|
||||
"""))
|
||||
config = Config()
|
||||
config.parse([sub])
|
||||
config = testdir.parseconfigure(sub)
|
||||
assert config.getini("minversion") == "2.0"
|
||||
|
||||
@pytest.mark.xfail(reason="probably not needed")
|
||||
|
@ -77,10 +73,10 @@ class TestParseIni:
|
|||
""")
|
||||
result = testdir.runpytest("--confcutdir=.")
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
class TestConfigCmdlineParsing:
|
||||
def test_parsing_again_fails(self, testdir):
|
||||
config = testdir.reparseconfig([testdir.tmpdir])
|
||||
config = testdir.parseconfig()
|
||||
pytest.raises(AssertionError, "config.parse([])")
|
||||
|
||||
|
||||
|
@ -101,7 +97,7 @@ class TestConfigAPI:
|
|||
assert config.getvalue("x") == 1
|
||||
assert config.getvalue("x", o.join('sub')) == 2
|
||||
pytest.raises(KeyError, "config.getvalue('y')")
|
||||
config = testdir.reparseconfig([str(o.join('sub'))])
|
||||
config = testdir.parseconfigure(str(o.join('sub')))
|
||||
assert config.getvalue("x") == 2
|
||||
assert config.getvalue("y") == 3
|
||||
assert config.getvalue("x", o) == 1
|
||||
|
@ -127,18 +123,18 @@ class TestConfigAPI:
|
|||
def test_config_overwrite(self, testdir):
|
||||
o = testdir.tmpdir
|
||||
o.ensure("conftest.py").write("x=1")
|
||||
config = testdir.reparseconfig([str(o)])
|
||||
config = testdir.parseconfig(str(o))
|
||||
assert config.getvalue('x') == 1
|
||||
config.option.x = 2
|
||||
assert config.getvalue('x') == 2
|
||||
config = testdir.reparseconfig([str(o)])
|
||||
config = testdir.parseconfig([str(o)])
|
||||
assert config.getvalue('x') == 1
|
||||
|
||||
def test_getconftest_pathlist(self, testdir, tmpdir):
|
||||
somepath = tmpdir.join("x", "y", "z")
|
||||
p = tmpdir.join("conftest.py")
|
||||
p.write("pathlist = ['.', %r]" % str(somepath))
|
||||
config = testdir.reparseconfig([p])
|
||||
config = testdir.parseconfigure(p)
|
||||
assert config._getconftest_pathlist('notexist') is None
|
||||
pl = config._getconftest_pathlist('pathlist')
|
||||
print(pl)
|
||||
|
|
|
@ -332,17 +332,6 @@ class TestPytestPluginInteractions:
|
|||
"*did not find*sys*"
|
||||
])
|
||||
|
||||
def test_do_option_conftestplugin(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--test123', action="store_true")
|
||||
""")
|
||||
config = testdir.Config()
|
||||
config._conftest.importconftest(p)
|
||||
print(config.pluginmanager.getplugins())
|
||||
config.parse([])
|
||||
assert not config.option.test123
|
||||
|
||||
def test_namespace_early_from_import(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
from pytest import Item
|
||||
|
@ -370,9 +359,7 @@ class TestPytestPluginInteractions:
|
|||
])
|
||||
|
||||
def test_do_option_postinitialize(self, testdir):
|
||||
config = testdir.Config()
|
||||
config.parse([])
|
||||
config.pluginmanager.do_configure(config=config)
|
||||
config = testdir.parseconfigure()
|
||||
assert not hasattr(config.option, 'test123')
|
||||
p = testdir.makepyfile("""
|
||||
def pytest_addoption(parser):
|
||||
|
@ -640,7 +627,7 @@ class TestTracer:
|
|||
log2("seen")
|
||||
tags, args = l2[0]
|
||||
assert args == ("seen",)
|
||||
|
||||
|
||||
|
||||
def test_setmyprocessor(self):
|
||||
from _pytest.core import TagTracer
|
||||
|
|
|
@ -189,58 +189,6 @@ class TestFunctional:
|
|||
])
|
||||
|
||||
|
||||
class Test_genitems:
|
||||
def test_check_collect_hashes(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
def test_1():
|
||||
pass
|
||||
|
||||
def test_2():
|
||||
pass
|
||||
""")
|
||||
p.copy(p.dirpath(p.purebasename + "2" + ".py"))
|
||||
items, reprec = testdir.inline_genitems(p.dirpath())
|
||||
assert len(items) == 4
|
||||
for numi, i in enumerate(items):
|
||||
for numj, j in enumerate(items):
|
||||
if numj != numi:
|
||||
assert hash(i) != hash(j)
|
||||
assert i != j
|
||||
|
||||
def test_root_conftest_syntax_error(self, testdir):
|
||||
# do we want to unify behaviour with
|
||||
# test_subdir_conftest_error?
|
||||
p = testdir.makepyfile(conftest="raise SyntaxError\n")
|
||||
pytest.raises(SyntaxError, testdir.inline_genitems, p.dirpath())
|
||||
|
||||
def test_example_items1(self, testdir):
|
||||
p = testdir.makepyfile('''
|
||||
def testone():
|
||||
pass
|
||||
|
||||
class TestX:
|
||||
def testmethod_one(self):
|
||||
pass
|
||||
|
||||
class TestY(TestX):
|
||||
pass
|
||||
''')
|
||||
items, reprec = testdir.inline_genitems(p)
|
||||
assert len(items) == 3
|
||||
assert items[0].name == 'testone'
|
||||
assert items[1].name == 'testmethod_one'
|
||||
assert items[2].name == 'testmethod_one'
|
||||
|
||||
# let's also test getmodpath here
|
||||
assert items[0].getmodpath() == "testone"
|
||||
assert items[1].getmodpath() == "TestX.testmethod_one"
|
||||
assert items[2].getmodpath() == "TestY.testmethod_one"
|
||||
|
||||
s = items[0].getmodpath(stopatmodule=False)
|
||||
assert s.endswith("test_example_items1.testone")
|
||||
print(s)
|
||||
|
||||
|
||||
class TestKeywordSelection:
|
||||
def test_select_simple(self, testdir):
|
||||
file_test = testdir.makepyfile("""
|
||||
|
|
|
@ -257,7 +257,7 @@ class TestFunction:
|
|||
assert hasattr(modcol.obj, 'test_func')
|
||||
|
||||
def test_function_equality(self, testdir, tmpdir):
|
||||
config = testdir.reparseconfig()
|
||||
config = testdir.parseconfigure()
|
||||
session = testdir.Session(config)
|
||||
f1 = pytest.Function(name="name", config=config,
|
||||
args=(1,), callobj=isinstance, session=session)
|
||||
|
@ -279,7 +279,7 @@ class TestFunction:
|
|||
assert not f1 != f1_b
|
||||
|
||||
def test_function_equality_with_callspec(self, testdir, tmpdir):
|
||||
config = testdir.reparseconfig()
|
||||
config = testdir.parseconfigure()
|
||||
class callspec1:
|
||||
param = 1
|
||||
funcargs = {}
|
||||
|
@ -783,7 +783,7 @@ class TestRequestCachedSetup:
|
|||
req2 = funcargs.FuncargRequest(item2)
|
||||
ret2 = req2.cached_setup(setup, scope="class")
|
||||
assert ret2 == "hello"
|
||||
|
||||
|
||||
req3 = funcargs.FuncargRequest(item3)
|
||||
ret3a = req3.cached_setup(setup, scope="class")
|
||||
ret3b = req3.cached_setup(setup, scope="class")
|
||||
|
@ -1320,7 +1320,7 @@ def test_customized_python_discovery(testdir):
|
|||
"*CheckMyApp*",
|
||||
"*check_meth*",
|
||||
])
|
||||
|
||||
|
||||
result = testdir.runpytest()
|
||||
assert result.ret == 0
|
||||
result.stdout.fnmatch_lines([
|
||||
|
@ -1354,7 +1354,7 @@ def test_customize_through_attributes(testdir):
|
|||
Function = MyFunction
|
||||
class MyClass(pytest.Class):
|
||||
Instance = MyInstance
|
||||
|
||||
|
||||
def pytest_pycollect_makeitem(collector, name, obj):
|
||||
if name.startswith("MyTestClass"):
|
||||
return MyClass(name, parent=collector)
|
||||
|
|
|
@ -54,17 +54,6 @@ class TestConfigTmpdir:
|
|||
assert b2.check()
|
||||
assert not h.check()
|
||||
|
||||
def test_reparse(self, testdir):
|
||||
config2 = testdir.reparseconfig([])
|
||||
config3 = testdir.reparseconfig([])
|
||||
assert config2.basetemp != config3.basetemp
|
||||
assert not config2.basetemp.relto(config3.basetemp)
|
||||
assert not config3.basetemp.relto(config2.basetemp)
|
||||
|
||||
def test_reparse_filename_too_long(self, testdir):
|
||||
config = testdir.reparseconfig(["--basetemp=%s" % ("123"*300)])
|
||||
|
||||
|
||||
def test_basetemp(testdir):
|
||||
mytemp = testdir.tmpdir.mkdir("mytemp")
|
||||
p = testdir.makepyfile("""
|
||||
|
|
Loading…
Reference in New Issue