parent
9555d427ae
commit
07c835fdf3
|
@ -4,7 +4,7 @@ import sys, os
|
||||||
default_plugins = (
|
default_plugins = (
|
||||||
"session terminal python runner pdb capture mark skipping tmpdir monkeypatch "
|
"session terminal python runner pdb capture mark skipping tmpdir monkeypatch "
|
||||||
"recwarn pastebin unittest helpconfig nose assertion genscript "
|
"recwarn pastebin unittest helpconfig nose assertion genscript "
|
||||||
"junitxml doctest keyword").split()
|
"junitxml doctest").split()
|
||||||
|
|
||||||
def main(args=None):
|
def main(args=None):
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
|
||||||
group = parser.getgroup("general")
|
|
||||||
group._addoption('-k',
|
|
||||||
action="store", dest="keyword", default='',
|
|
||||||
help="only run test items matching the given "
|
|
||||||
"space separated keywords. precede a keyword with '-' to negate. "
|
|
||||||
"Terminate the expression with ':' to treat a match as a signal "
|
|
||||||
"to run all subsequent tests. ")
|
|
||||||
|
|
||||||
def pytest_collection_modifyitems(items, config):
|
|
||||||
keywordexpr = config.option.keyword
|
|
||||||
if not keywordexpr:
|
|
||||||
return
|
|
||||||
selectuntil = False
|
|
||||||
if keywordexpr[-1] == ":":
|
|
||||||
selectuntil = True
|
|
||||||
keywordexpr = keywordexpr[:-1]
|
|
||||||
|
|
||||||
remaining = []
|
|
||||||
deselected = []
|
|
||||||
for colitem in items:
|
|
||||||
if keywordexpr and skipbykeyword(colitem, keywordexpr):
|
|
||||||
deselected.append(colitem)
|
|
||||||
else:
|
|
||||||
remaining.append(colitem)
|
|
||||||
if selectuntil:
|
|
||||||
keywordexpr = None
|
|
||||||
|
|
||||||
if deselected:
|
|
||||||
config.hook.pytest_deselected(items=deselected)
|
|
||||||
items[:] = remaining
|
|
||||||
|
|
||||||
def skipbykeyword(colitem, keywordexpr):
|
|
||||||
""" return True if they given keyword expression means to
|
|
||||||
skip this collector/item.
|
|
||||||
"""
|
|
||||||
if not keywordexpr:
|
|
||||||
return
|
|
||||||
chain = colitem.listchain()
|
|
||||||
for key in filter(None, keywordexpr.split()):
|
|
||||||
eor = key[:1] == '-'
|
|
||||||
if eor:
|
|
||||||
key = key[1:]
|
|
||||||
if not (eor ^ matchonekeyword(key, chain)):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def matchonekeyword(key, chain):
|
|
||||||
elems = key.split(".")
|
|
||||||
# XXX O(n^2), anyone cares?
|
|
||||||
chain = [item.keywords for item in chain if item.keywords]
|
|
||||||
for start, _ in enumerate(chain):
|
|
||||||
if start + len(elems) > len(chain):
|
|
||||||
return False
|
|
||||||
for num, elem in enumerate(elems):
|
|
||||||
for keyword in chain[num + start]:
|
|
||||||
ok = False
|
|
||||||
if elem in keyword:
|
|
||||||
ok = True
|
|
||||||
break
|
|
||||||
if not ok:
|
|
||||||
break
|
|
||||||
if num == len(elems) - 1 and ok:
|
|
||||||
return True
|
|
||||||
return False
|
|
|
@ -87,6 +87,71 @@ import py
|
||||||
def pytest_namespace():
|
def pytest_namespace():
|
||||||
return {'mark': MarkGenerator()}
|
return {'mark': MarkGenerator()}
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
group = parser.getgroup("general")
|
||||||
|
group._addoption('-k',
|
||||||
|
action="store", dest="keyword", default='',
|
||||||
|
help="only run test items matching the given "
|
||||||
|
"space separated keywords. precede a keyword with '-' to negate. "
|
||||||
|
"Terminate the expression with ':' to treat a match as a signal "
|
||||||
|
"to run all subsequent tests. ")
|
||||||
|
|
||||||
|
def pytest_collection_modifyitems(items, config):
|
||||||
|
keywordexpr = config.option.keyword
|
||||||
|
if not keywordexpr:
|
||||||
|
return
|
||||||
|
selectuntil = False
|
||||||
|
if keywordexpr[-1] == ":":
|
||||||
|
selectuntil = True
|
||||||
|
keywordexpr = keywordexpr[:-1]
|
||||||
|
|
||||||
|
remaining = []
|
||||||
|
deselected = []
|
||||||
|
for colitem in items:
|
||||||
|
if keywordexpr and skipbykeyword(colitem, keywordexpr):
|
||||||
|
deselected.append(colitem)
|
||||||
|
else:
|
||||||
|
remaining.append(colitem)
|
||||||
|
if selectuntil:
|
||||||
|
keywordexpr = None
|
||||||
|
|
||||||
|
if deselected:
|
||||||
|
config.hook.pytest_deselected(items=deselected)
|
||||||
|
items[:] = remaining
|
||||||
|
|
||||||
|
def skipbykeyword(colitem, keywordexpr):
|
||||||
|
""" return True if they given keyword expression means to
|
||||||
|
skip this collector/item.
|
||||||
|
"""
|
||||||
|
if not keywordexpr:
|
||||||
|
return
|
||||||
|
chain = colitem.listchain()
|
||||||
|
for key in filter(None, keywordexpr.split()):
|
||||||
|
eor = key[:1] == '-'
|
||||||
|
if eor:
|
||||||
|
key = key[1:]
|
||||||
|
if not (eor ^ matchonekeyword(key, chain)):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def matchonekeyword(key, chain):
|
||||||
|
elems = key.split(".")
|
||||||
|
# XXX O(n^2), anyone cares?
|
||||||
|
chain = [item.keywords for item in chain if item.keywords]
|
||||||
|
for start, _ in enumerate(chain):
|
||||||
|
if start + len(elems) > len(chain):
|
||||||
|
return False
|
||||||
|
for num, elem in enumerate(elems):
|
||||||
|
for keyword in chain[num + start]:
|
||||||
|
ok = False
|
||||||
|
if elem in keyword:
|
||||||
|
ok = True
|
||||||
|
break
|
||||||
|
if not ok:
|
||||||
|
break
|
||||||
|
if num == len(elems) - 1 and ok:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class MarkGenerator:
|
class MarkGenerator:
|
||||||
""" non-underscore attributes of this object can be used as decorators for
|
""" non-underscore attributes of this object can be used as decorators for
|
||||||
marking test functions. Example: @py.test.mark.slowtest in front of a
|
marking test functions. Example: @py.test.mark.slowtest in front of a
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
import py
|
|
||||||
|
|
||||||
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")
|
|
||||||
py.test.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("""
|
|
||||||
def test_one(): assert 0
|
|
||||||
class TestClass(object):
|
|
||||||
def test_method_one(self):
|
|
||||||
assert 42 == 43
|
|
||||||
""")
|
|
||||||
def check(keyword, name):
|
|
||||||
reprec = testdir.inline_run("-s", "-k", keyword, file_test)
|
|
||||||
passed, skipped, failed = reprec.listoutcomes()
|
|
||||||
assert len(failed) == 1
|
|
||||||
assert failed[0].nodeid.split("::")[-1] == name
|
|
||||||
assert len(reprec.getcalls('pytest_deselected')) == 1
|
|
||||||
|
|
||||||
for keyword in ['test_one', 'est_on']:
|
|
||||||
#yield check, keyword, 'test_one'
|
|
||||||
check(keyword, 'test_one')
|
|
||||||
check('TestClass.test', 'test_method_one')
|
|
||||||
|
|
||||||
def test_select_extra_keywords(self, testdir):
|
|
||||||
p = testdir.makepyfile(test_select="""
|
|
||||||
def test_1():
|
|
||||||
pass
|
|
||||||
class TestClass:
|
|
||||||
def test_2(self):
|
|
||||||
pass
|
|
||||||
""")
|
|
||||||
testdir.makepyfile(conftest="""
|
|
||||||
import py
|
|
||||||
class Class(py.test.collect.Class):
|
|
||||||
def _keywords(self):
|
|
||||||
return ['xxx', self.name]
|
|
||||||
""")
|
|
||||||
for keyword in ('xxx', 'xxx test_2', 'TestClass', 'xxx -test_1',
|
|
||||||
'TestClass test_2', 'xxx TestClass test_2',):
|
|
||||||
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
|
|
||||||
py.builtin.print_("keyword", repr(keyword))
|
|
||||||
passed, skipped, failed = reprec.listoutcomes()
|
|
||||||
assert len(passed) == 1
|
|
||||||
assert passed[0].nodeid.endswith("test_2")
|
|
||||||
dlist = reprec.getcalls("pytest_deselected")
|
|
||||||
assert len(dlist) == 1
|
|
||||||
assert dlist[0].items[0].name == 'test_1'
|
|
||||||
|
|
||||||
def test_select_starton(self, testdir):
|
|
||||||
threepass = testdir.makepyfile(test_threepass="""
|
|
||||||
def test_one(): assert 1
|
|
||||||
def test_two(): assert 1
|
|
||||||
def test_three(): assert 1
|
|
||||||
""")
|
|
||||||
reprec = testdir.inline_run("-k", "test_two:", threepass)
|
|
||||||
passed, skipped, failed = reprec.listoutcomes()
|
|
||||||
assert len(passed) == 2
|
|
||||||
assert not failed
|
|
||||||
dlist = reprec.getcalls("pytest_deselected")
|
|
||||||
assert len(dlist) == 1
|
|
||||||
item = dlist[0].items[0]
|
|
||||||
assert item.name == "test_one"
|
|
||||||
|
|
||||||
|
|
||||||
def test_keyword_extra(self, testdir):
|
|
||||||
p = testdir.makepyfile("""
|
|
||||||
def test_one():
|
|
||||||
assert 0
|
|
||||||
test_one.mykeyword = True
|
|
||||||
""")
|
|
||||||
reprec = testdir.inline_run("-k", "-mykeyword", p)
|
|
||||||
passed, skipped, failed = reprec.countoutcomes()
|
|
||||||
assert passed + skipped + failed == 0
|
|
||||||
reprec = testdir.inline_run("-k", "mykeyword", p)
|
|
||||||
passed, skipped, failed = reprec.countoutcomes()
|
|
||||||
assert failed == 1
|
|
|
@ -173,3 +173,130 @@ class TestFunctional:
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"keyword: *hello*"
|
"keyword: *hello*"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
py.test.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("""
|
||||||
|
def test_one(): assert 0
|
||||||
|
class TestClass(object):
|
||||||
|
def test_method_one(self):
|
||||||
|
assert 42 == 43
|
||||||
|
""")
|
||||||
|
def check(keyword, name):
|
||||||
|
reprec = testdir.inline_run("-s", "-k", keyword, file_test)
|
||||||
|
passed, skipped, failed = reprec.listoutcomes()
|
||||||
|
assert len(failed) == 1
|
||||||
|
assert failed[0].nodeid.split("::")[-1] == name
|
||||||
|
assert len(reprec.getcalls('pytest_deselected')) == 1
|
||||||
|
|
||||||
|
for keyword in ['test_one', 'est_on']:
|
||||||
|
#yield check, keyword, 'test_one'
|
||||||
|
check(keyword, 'test_one')
|
||||||
|
check('TestClass.test', 'test_method_one')
|
||||||
|
|
||||||
|
def test_select_extra_keywords(self, testdir):
|
||||||
|
p = testdir.makepyfile(test_select="""
|
||||||
|
def test_1():
|
||||||
|
pass
|
||||||
|
class TestClass:
|
||||||
|
def test_2(self):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
testdir.makepyfile(conftest="""
|
||||||
|
import py
|
||||||
|
class Class(py.test.collect.Class):
|
||||||
|
def _keywords(self):
|
||||||
|
return ['xxx', self.name]
|
||||||
|
""")
|
||||||
|
for keyword in ('xxx', 'xxx test_2', 'TestClass', 'xxx -test_1',
|
||||||
|
'TestClass test_2', 'xxx TestClass test_2',):
|
||||||
|
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
|
||||||
|
py.builtin.print_("keyword", repr(keyword))
|
||||||
|
passed, skipped, failed = reprec.listoutcomes()
|
||||||
|
assert len(passed) == 1
|
||||||
|
assert passed[0].nodeid.endswith("test_2")
|
||||||
|
dlist = reprec.getcalls("pytest_deselected")
|
||||||
|
assert len(dlist) == 1
|
||||||
|
assert dlist[0].items[0].name == 'test_1'
|
||||||
|
|
||||||
|
def test_select_starton(self, testdir):
|
||||||
|
threepass = testdir.makepyfile(test_threepass="""
|
||||||
|
def test_one(): assert 1
|
||||||
|
def test_two(): assert 1
|
||||||
|
def test_three(): assert 1
|
||||||
|
""")
|
||||||
|
reprec = testdir.inline_run("-k", "test_two:", threepass)
|
||||||
|
passed, skipped, failed = reprec.listoutcomes()
|
||||||
|
assert len(passed) == 2
|
||||||
|
assert not failed
|
||||||
|
dlist = reprec.getcalls("pytest_deselected")
|
||||||
|
assert len(dlist) == 1
|
||||||
|
item = dlist[0].items[0]
|
||||||
|
assert item.name == "test_one"
|
||||||
|
|
||||||
|
|
||||||
|
def test_keyword_extra(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
def test_one():
|
||||||
|
assert 0
|
||||||
|
test_one.mykeyword = True
|
||||||
|
""")
|
||||||
|
reprec = testdir.inline_run("-k", "-mykeyword", p)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert passed + skipped + failed == 0
|
||||||
|
reprec = testdir.inline_run("-k", "mykeyword", p)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 1
|
||||||
|
|
Loading…
Reference in New Issue