implement index-based mechanizm for collection of parametrized tests
--HG-- branch : parametrize-hashable
This commit is contained in:
parent
d30ad3f5ce
commit
0cfd873abe
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue