implement index-based mechanizm for collection of parametrized tests

--HG--
branch : parametrize-hashable
This commit is contained in:
Anatoly Bubenkov 2013-12-03 21:05:19 +01:00
parent d30ad3f5ce
commit 0cfd873abe
3 changed files with 47 additions and 10 deletions

View File

@ -1,6 +1,9 @@
Unreleased Unreleased
----------------------------------- -----------------------------------
- fix issue244 by implementing special index for parameters to only use
indices for paramentrized test ids
- fix issue287 by running all finalizers but saving the exception - fix issue287 by running all finalizers but saving the exception
from the first failing finalizer and re-raising it so teardown will from the first failing finalizer and re-raising it so teardown will
still have failed. We reraise the first failing exception because still have failed. We reraise the first failing exception because

View File

@ -594,12 +594,14 @@ class CallSpec2(object):
self._globalparam = _notexists self._globalparam = _notexists
self._arg2scopenum = {} # used for sorting parametrized resources self._arg2scopenum = {} # used for sorting parametrized resources
self.keywords = {} self.keywords = {}
self.indices = {}
def copy(self, metafunc): def copy(self, metafunc):
cs = CallSpec2(self.metafunc) cs = CallSpec2(self.metafunc)
cs.funcargs.update(self.funcargs) cs.funcargs.update(self.funcargs)
cs.params.update(self.params) cs.params.update(self.params)
cs.keywords.update(self.keywords) cs.keywords.update(self.keywords)
cs.indices.update(self.indices)
cs._arg2scopenum.update(self._arg2scopenum) cs._arg2scopenum.update(self._arg2scopenum)
cs._idlist = list(self._idlist) cs._idlist = list(self._idlist)
cs._globalid = self._globalid cs._globalid = self._globalid
@ -623,7 +625,8 @@ class CallSpec2(object):
def id(self): def id(self):
return "-".join(map(str, filter(None, self._idlist))) return "-".join(map(str, filter(None, self._idlist)))
def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0): def setmulti(self, valtype, argnames, valset, id, keywords, scopenum,
param_index):
for arg,val in zip(argnames, valset): for arg,val in zip(argnames, valset):
self._checkargnotcontained(arg) self._checkargnotcontained(arg)
getattr(self, valtype)[arg] = val getattr(self, valtype)[arg] = val
@ -631,6 +634,7 @@ class CallSpec2(object):
# parametrize_sorted() which groups tests by params/scope # parametrize_sorted() which groups tests by params/scope
if valtype == "funcargs": if valtype == "funcargs":
self.params[arg] = id self.params[arg] = id
self.indices[arg] = param_index
self._arg2scopenum[arg] = scopenum self._arg2scopenum[arg] = scopenum
if val is _notexists: if val is _notexists:
self._emptyparamspecified = True self._emptyparamspecified = True
@ -740,11 +744,12 @@ class Metafunc(FuncargnamesCompatAttr):
ids = idmaker(argnames, argvalues) ids = idmaker(argnames, argvalues)
newcalls = [] newcalls = []
for callspec in self._calls or [CallSpec2(self)]: for callspec in self._calls or [CallSpec2(self)]:
for i, valset in enumerate(argvalues): for param_index, valset in enumerate(argvalues):
assert len(valset) == len(argnames) assert len(valset) == len(argnames)
newcallspec = callspec.copy(self) newcallspec = callspec.copy(self)
newcallspec.setmulti(valtype, argnames, valset, ids[i], newcallspec.setmulti(valtype, argnames, valset, ids[param_index],
newkeywords.get(i, {}), scopenum) newkeywords.get(param_index, {}), scopenum,
param_index)
newcalls.append(newcallspec) newcalls.append(newcallspec)
self._calls = newcalls self._calls = newcalls
@ -1862,19 +1867,19 @@ def getfuncargparams(item, ignore, scopenum, cache):
except AttributeError: except AttributeError:
return [] return []
if scopenum == 0: if scopenum == 0:
argparams = [x for x in cs.params.items() if x not in ignore argparams = [x for x in cs.indices.items() if x not in ignore
and cs._arg2scopenum[x[0]] == scopenum] and cs._arg2scopenum[x[0]] == scopenum]
elif scopenum == 1: # module elif scopenum == 1: # module
argparams = [] argparams = []
for argname, param in cs.params.items(): for argname, valindex in cs.indices.items():
if cs._arg2scopenum[argname] == scopenum: if cs._arg2scopenum[argname] == scopenum:
key = (argname, param, item.fspath) key = (argname, valindex, item.fspath)
if key in ignore: if key in ignore:
continue continue
argparams.append(key) argparams.append(key)
elif scopenum == 2: # class elif scopenum == 2: # class
argparams = [] argparams = []
for argname, param in cs.params.items(): for argname, valindex in cs.indices.items():
if cs._arg2scopenum[argname] == scopenum: if cs._arg2scopenum[argname] == scopenum:
l = cache.setdefault(item.fspath, []) l = cache.setdefault(item.fspath, [])
try: try:
@ -1882,13 +1887,13 @@ def getfuncargparams(item, ignore, scopenum, cache):
except ValueError: except ValueError:
i = len(l) i = len(l)
l.append(item.cls) l.append(item.cls)
key = (argname, param, item.fspath, i) key = (argname, valindex, item.fspath, i)
if key in ignore: if key in ignore:
continue continue
argparams.append(key) argparams.append(key)
#elif scopenum == 3: #elif scopenum == 3:
# argparams = [] # argparams = []
# for argname, param in cs.params.items(): # for argname, param in cs.indices.items():
# if cs._arg2scopenum[argname] == scopenum: # if cs._arg2scopenum[argname] == scopenum:
# key = (argname, param, getfslineno(item.obj)) # key = (argname, param, getfslineno(item.obj))
# if key in ignore: # if key in ignore:

View File

@ -355,6 +355,35 @@ class TestFunction:
rec = testdir.inline_run() rec = testdir.inline_run()
rec.assertoutcome(passed=2) rec.assertoutcome(passed=2)
def test_parametrize_with_non_hashable_values_indirect(self, testdir):
"""Test parametrization with non-hashable values with indirect parametrization."""
testdir.makepyfile("""
archival_mapping = {
'1.0': {'tag': '1.0'},
'1.2.2a1': {'tag': 'release-1.2.2a1'},
}
import pytest
@pytest.fixture
def key(request):
return request.param
@pytest.fixture
def value(request):
return request.param
@pytest.mark.parametrize('key value'.split(),
archival_mapping.items(), indirect=True)
def test_archival_to_version(key, value):
assert key in archival_mapping
assert value == archival_mapping[key]
""")
rec = testdir.inline_run()
rec.assertoutcome(passed=2)
def test_parametrize_with_mark(selfself, testdir): def test_parametrize_with_mark(selfself, testdir):
items = testdir.getitems(""" items = testdir.getitems("""
import pytest import pytest