7 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/191ff82647ca/ Changeset: 191ff82647ca User: Wouter van Ackooy Date: 2013-05-20 14:37:58 Summary: Fixed issue #306: Keywords and markers are now matched in a defined way. Also applied some pep8 formatting while fixing. Affected #: 3 files
diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r 191ff82647ca3e61116861483efb8fe2c2985e82 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -216,6 +216,9 @@ #: keywords/markers collected from all scopes self.keywords = NodeKeywords(self) + #: allow adding of extra keywords to use for matching + self.extra_keyword_matches = [] + #self.extrainit() @property @@ -307,6 +310,15 @@ chain.reverse() return chain + def listextrakeywords(self): + """ Return a list of all extra keywords in self and any parents.""" + extra_keywords = [] + item = self + while item is not None: + extra_keywords.extend(item.extra_keyword_matches) + item = item.parent + return extra_keywords + def listnames(self): return [x.name for x in self.listchain()] diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r 191ff82647ca3e61116861483efb8fe2c2985e82 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -1,44 +1,56 @@ """ generic mechanism for marking and selecting python functions. """ import pytest, py + def pytest_namespace(): return {'mark': MarkGenerator()} + def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('-k', + group._addoption( + '-k', action="store", dest="keyword", default='', metavar="EXPRESSION", help="only run tests which match the given substring expression. " "An expression is a python evaluatable expression " - "where all names are substring-matched against test names " - "and keywords. Example: -k 'test_method or test_other' " - "matches all test functions whose name contains " - "'test_method' or 'test_other'.") + "where all names are substring-matched against test names" + "and their parent classes. Example: -k 'test_method or test " + "other' matches all test functions and classes whose name " + "contains 'test_method' or 'test_other'. " + "Additionally keywords are matched to classes and functions " + "containing extra names in their 'extra_keyword_matches' list, " + "as well as functions which have names assigned directly to them." + ) - group._addoption("-m", + group._addoption( + "-m", action="store", dest="markexpr", default="", metavar="MARKEXPR", help="only run tests matching given mark expression. " "example: -m 'mark1 and not mark2'." - ) + ) - group.addoption("--markers", action="store_true", help= - "show markers (builtin, plugin and per-project ones).") + group.addoption( + "--markers", action="store_true", + help="show markers (builtin, plugin and per-project ones)." + ) parser.addini("markers", "markers for test functions", 'linelist') + def pytest_cmdline_main(config): if config.option.markers: config.pluginmanager.do_configure(config) tw = py.io.TerminalWriter() for line in config.getini("markers"): name, rest = line.split(":", 1) - tw.write("@pytest.mark.%s:" % name, bold=True) + tw.write("@pytest.mark.%s:" % name, bold=True) tw.line(rest) tw.line() config.pluginmanager.do_unconfigure(config) return 0 pytest_cmdline_main.tryfirst = True + def pytest_collection_modifyitems(items, config): keywordexpr = config.option.keyword matchexpr = config.option.markexpr @@ -67,32 +79,76 @@ config.hook.pytest_deselected(items=deselected) items[:] = remaining -class BoolDict: - def __init__(self, mydict): - self._mydict = mydict - def __getitem__(self, name): - return name in self._mydict -class SubstringDict: - def __init__(self, mydict): - self._mydict = mydict - def __getitem__(self, name): - for key in self._mydict: - if name in key: +class MarkMapping: + """Provides a local mapping for markers. + Only the marker names from the given :class:`NodeKeywords` will be mapped, + so the names are taken only from :class:`MarkInfo` or + :class:`MarkDecorator` items. + """ + def __init__(self, keywords): + mymarks = [] + for key, value in keywords.items(): + if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator): + mymarks.append(key) + self._mymarks = mymarks + + def __getitem__(self, markname): + return markname in self._mymarks + + +class KeywordMapping: + """Provides a local mapping for keywords. + Given a list of names, map any substring of one of these names to True. + """ + def __init__(self, names): + self._names = names + + def __getitem__(self, subname): + for name in self._names: + if subname in name: return True return False -def matchmark(colitem, matchexpr): - return eval(matchexpr, {}, BoolDict(colitem.keywords)) + +def matchmark(colitem, markexpr): + """Tries to match on any marker names, attached to the given colitem.""" + return eval(markexpr, {}, MarkMapping(colitem.keywords)) + def matchkeyword(colitem, keywordexpr): + """Tries to match given keyword expression to given collector item. + + Will match on the name of colitem, including the names of its parents. + Only matches names of items which are either a :class:`Class` or a + :class:`Function`. + Additionally, matches on names in the 'extra_keyword_matches' list of + any item, as well as names directly assigned to test functions. + """ keywordexpr = keywordexpr.replace("-", "not ") - return eval(keywordexpr, {}, SubstringDict(colitem.keywords)) + mapped_names = [] + + # Add the names of the current item and any parent items + for item in colitem.listchain(): + if isinstance(item, pytest.Class) or isinstance(item, pytest.Function): + mapped_names.append(item.name) + + # Add the names added as extra keywords to current or parent items + for name in colitem.listextrakeywords(): + mapped_names.append(name) + + # Add the names attached to the current function through direct assignment + for name in colitem.function.func_dict: + mapped_names.append(name) + + return eval(keywordexpr, {}, KeywordMapping(mapped_names)) + def pytest_configure(config): if config.option.strict: pytest.mark._config = config + class MarkGenerator: """ Factory for :class:`MarkDecorator` objects - exposed as a ``py.test.mark`` singleton instance. Example:: @@ -126,6 +182,7 @@ if name not in self._markers: raise AttributeError("%r not a registered marker" % (name,)) + class MarkDecorator: """ A decorator for test functions and test classes. When applied it will create :class:`MarkInfo` objects which may be @@ -149,7 +206,7 @@ def __repr__(self): d = self.__dict__.copy() name = d.pop('markname') - return "<MarkDecorator %r %r>" %(name, d) + return "<MarkDecorator %r %r>" % (name, d) def __call__(self, *args, **kwargs): """ if passed a single callable argument: decorate it with mark info. @@ -162,15 +219,17 @@ if hasattr(func, 'pytestmark'): l = func.pytestmark if not isinstance(l, list): - func.pytestmark = [l, self] + func.pytestmark = [l, self] else: - l.append(self) + l.append(self) else: - func.pytestmark = [self] + func.pytestmark = [self] else: holder = getattr(func, self.markname, None) if holder is None: - holder = MarkInfo(self.markname, self.args, self.kwargs) + holder = MarkInfo( + self.markname, self.args, self.kwargs + ) setattr(func, self.markname, holder) else: holder.add(self.args, self.kwargs) @@ -180,6 +239,7 @@ args = self.args + args return self.__class__(self.markname, args=args, kwargs=kw) + class MarkInfo: """ Marking object created by :class:`MarkDecorator` instances. """ def __init__(self, name, args, kwargs): @@ -193,7 +253,8 @@ def __repr__(self): return "<MarkInfo %r args=%r kwargs=%r>" % ( - self.name, self.args, self.kwargs) + self.name, self.args, self.kwargs + ) def add(self, args, kwargs): """ add a MarkInfo with the given args and kwargs. """ @@ -205,4 +266,3 @@ """ yield MarkInfo objects each relating to a marking-call. """ for args, kwargs in self._arglist: yield MarkInfo(self.name, args, kwargs) - diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r 191ff82647ca3e61116861483efb8fe2c2985e82 testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -382,7 +382,6 @@ 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 and test', 'test_method_one') @@ -401,7 +400,7 @@ def pytest_pycollect_makeitem(__multicall__, name): if name == "TestClass": item = __multicall__.execute() - item.keywords["xxx"] = True + item.extra_keyword_matches.append("xxx") return item """) reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword) https://bitbucket.org/hpk42/pytest/commits/64a8b6828ebc/ Changeset: 64a8b6828ebc User: Wouter van Ackooy Date: 2013-05-22 07:41:46 Summary: Added lost space. Affected #: 1 file diff -r 191ff82647ca3e61116861483efb8fe2c2985e82 -r 64a8b6828ebcf2e8cd9066bd44c6c83b7b89a9b1 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -13,7 +13,7 @@ action="store", dest="keyword", default='', metavar="EXPRESSION", help="only run tests which match the given substring expression. " "An expression is a python evaluatable expression " - "where all names are substring-matched against test names" + "where all names are substring-matched against test names " "and their parent classes. Example: -k 'test_method or test " "other' matches all test functions and classes whose name " "contains 'test_method' or 'test_other'. " https://bitbucket.org/hpk42/pytest/commits/88815889e4a3/ Changeset: 88815889e4a3 User: Wouter van Ackooy Date: 2013-05-23 09:12:50 Summary: Added a test to check there is no matching on magic values. Affected #: 1 file diff -r 64a8b6828ebcf2e8cd9066bd44c6c83b7b89a9b1 -r 88815889e4a3dd27082f20187232050f17f05424 testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -439,3 +439,21 @@ reprec = testdir.inline_run("-k", "mykeyword", p) passed, skipped, failed = reprec.countoutcomes() assert failed == 1 + + def test_no_magic_values(self, testdir): + """Make sure the tests do not match on magic values, + no double underscored values, like '__dict__', + and no instance values, like '()'. + """ + p = testdir.makepyfile(""" + def test_one(): assert 1 + """) + def assert_test_is_not_selected(keyword): + reprec = testdir.inline_run("-k", keyword, p) + passed, skipped, failed = reprec.countoutcomes() + dlist = reprec.getcalls("pytest_deselected") + assert passed + skipped + failed == 0 + assert len(dlist) == 1 + + assert_test_is_not_selected("__") + assert_test_is_not_selected("()") https://bitbucket.org/hpk42/pytest/commits/13c86754a55e/ Changeset: 13c86754a55e User: Wouter van Ackooy Date: 2013-05-23 12:21:40 Summary: Added new test to check on matching markers to full test names, which was possible before. Also adjusted check on number of deselected tests. Affected #: 1 file diff -r 88815889e4a3dd27082f20187232050f17f05424 -r 13c86754a55e774c40cff5c2d256c7f3cba56b3d testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -345,6 +345,24 @@ assert l[0].args == ("pos0",) assert l[1].args == ("pos1",) + def test_no_marker_match_on_unmarked_names(self, testdir): + p = testdir.makepyfile(""" + import pytest + @pytest.mark.shouldmatch + def test_marked(): + assert 1 + + def test_unmarked(): + assert 1 + """) + reprec = testdir.inline_run("-m", "test_unmarked", p) + passed, skipped, failed = reprec.listoutcomes() + assert len(passed) + len(skipped) + len(failed) == 0 + dlist = reprec.getcalls("pytest_deselected") + deselected_tests = dlist[0].items + assert len(deselected_tests) == 2 + + def test_keywords_at_node_level(self, testdir): p = testdir.makepyfile(""" import pytest @@ -453,7 +471,8 @@ passed, skipped, failed = reprec.countoutcomes() dlist = reprec.getcalls("pytest_deselected") assert passed + skipped + failed == 0 - assert len(dlist) == 1 + deselected_tests = dlist[0].items + assert len(deselected_tests) == 1 assert_test_is_not_selected("__") assert_test_is_not_selected("()") https://bitbucket.org/hpk42/pytest/commits/1a919511ae4f/ Changeset: 1a919511ae4f User: Wouter van Ackooy Date: 2013-05-27 17:58:39 Summary: Issue 306: Use the names of all the parents in the chain for matching, except the Instance objects. Affected #: 1 file diff -r 13c86754a55e774c40cff5c2d256c7f3cba56b3d -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -130,7 +130,7 @@ # Add the names of the current item and any parent items for item in colitem.listchain(): - if isinstance(item, pytest.Class) or isinstance(item, pytest.Function): + if not isinstance(item, pytest.Instance): mapped_names.append(item.name) # Add the names added as extra keywords to current or parent items https://bitbucket.org/hpk42/pytest/commits/c3bc70bc6704/ Changeset: c3bc70bc6704 User: Wouter van Ackooy Date: 2013-05-27 18:14:35 Summary: Issue 306: Used a set for the extra_keywords, and used listchain for parent iteration. Affected #: 3 files diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r c3bc70bc6704b95ed26b1072ab719c696cde68a4 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -217,7 +217,7 @@ self.keywords = NodeKeywords(self) #: allow adding of extra keywords to use for matching - self.extra_keyword_matches = [] + self.extra_keyword_matches = set() #self.extrainit() @@ -311,12 +311,11 @@ return chain def listextrakeywords(self): - """ Return a list of all extra keywords in self and any parents.""" - extra_keywords = [] + """ Return a set of all extra keywords in self and any parents.""" + extra_keywords = set() item = self - while item is not None: - extra_keywords.extend(item.extra_keyword_matches) - item = item.parent + for item in self.listchain(): + extra_keywords.update(item.extra_keyword_matches) return extra_keywords def listnames(self): diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r c3bc70bc6704b95ed26b1072ab719c696cde68a4 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -18,7 +18,7 @@ "other' matches all test functions and classes whose name " "contains 'test_method' or 'test_other'. " "Additionally keywords are matched to classes and functions " - "containing extra names in their 'extra_keyword_matches' list, " + "containing extra names in their 'extra_keyword_matches' set, " "as well as functions which have names assigned directly to them." ) @@ -87,10 +87,10 @@ :class:`MarkDecorator` items. """ def __init__(self, keywords): - mymarks = [] + mymarks = set() for key, value in keywords.items(): if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator): - mymarks.append(key) + mymarks.add(key) self._mymarks = mymarks def __getitem__(self, markname): @@ -122,24 +122,24 @@ Will match on the name of colitem, including the names of its parents. Only matches names of items which are either a :class:`Class` or a :class:`Function`. - Additionally, matches on names in the 'extra_keyword_matches' list of + Additionally, matches on names in the 'extra_keyword_matches' set of any item, as well as names directly assigned to test functions. """ keywordexpr = keywordexpr.replace("-", "not ") - mapped_names = [] + mapped_names = set() # Add the names of the current item and any parent items for item in colitem.listchain(): if not isinstance(item, pytest.Instance): - mapped_names.append(item.name) + mapped_names.add(item.name) # Add the names added as extra keywords to current or parent items for name in colitem.listextrakeywords(): - mapped_names.append(name) + mapped_names.add(name) # Add the names attached to the current function through direct assignment for name in colitem.function.func_dict: - mapped_names.append(name) + mapped_names.add(name) return eval(keywordexpr, {}, KeywordMapping(mapped_names)) diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r c3bc70bc6704b95ed26b1072ab719c696cde68a4 testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -418,7 +418,7 @@ def pytest_pycollect_makeitem(__multicall__, name): if name == "TestClass": item = __multicall__.execute() - item.extra_keyword_matches.append("xxx") + item.extra_keyword_matches.add("xxx") return item """) reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword) https://bitbucket.org/hpk42/pytest/commits/5ce621f0b3d2/ Changeset: 5ce621f0b3d2 User: hpk42 Date: 2013-05-27 21:40:41 Summary: Merged in w00t0r/pytest-fixes (pull request #35) Fixed issue #306: Keywords and markers are now matched in a defined way. Also applied some pep8 formatting while fixing. Affected #: 3 files diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r 5ce621f0b3d2857ce7035b765cd18836ec8ea73f _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -216,6 +216,9 @@ #: keywords/markers collected from all scopes self.keywords = NodeKeywords(self) + #: allow adding of extra keywords to use for matching + self.extra_keyword_matches = set() + #self.extrainit() @property @@ -307,6 +310,14 @@ chain.reverse() return chain + def listextrakeywords(self): + """ Return a set of all extra keywords in self and any parents.""" + extra_keywords = set() + item = self + for item in self.listchain(): + extra_keywords.update(item.extra_keyword_matches) + return extra_keywords + def listnames(self): return [x.name for x in self.listchain()] diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r 5ce621f0b3d2857ce7035b765cd18836ec8ea73f _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -1,44 +1,56 @@ """ generic mechanism for marking and selecting python functions. """ import pytest, py + def pytest_namespace(): return {'mark': MarkGenerator()} + def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('-k', + group._addoption( + '-k', action="store", dest="keyword", default='', metavar="EXPRESSION", help="only run tests which match the given substring expression. " "An expression is a python evaluatable expression " "where all names are substring-matched against test names " - "and keywords. Example: -k 'test_method or test_other' " - "matches all test functions whose name contains " - "'test_method' or 'test_other'.") + "and their parent classes. Example: -k 'test_method or test " + "other' matches all test functions and classes whose name " + "contains 'test_method' or 'test_other'. " + "Additionally keywords are matched to classes and functions " + "containing extra names in their 'extra_keyword_matches' set, " + "as well as functions which have names assigned directly to them." + ) - group._addoption("-m", + group._addoption( + "-m", action="store", dest="markexpr", default="", metavar="MARKEXPR", help="only run tests matching given mark expression. " "example: -m 'mark1 and not mark2'." - ) + ) - group.addoption("--markers", action="store_true", help= - "show markers (builtin, plugin and per-project ones).") + group.addoption( + "--markers", action="store_true", + help="show markers (builtin, plugin and per-project ones)." + ) parser.addini("markers", "markers for test functions", 'linelist') + def pytest_cmdline_main(config): if config.option.markers: config.pluginmanager.do_configure(config) tw = py.io.TerminalWriter() for line in config.getini("markers"): name, rest = line.split(":", 1) - tw.write("@pytest.mark.%s:" % name, bold=True) + tw.write("@pytest.mark.%s:" % name, bold=True) tw.line(rest) tw.line() config.pluginmanager.do_unconfigure(config) return 0 pytest_cmdline_main.tryfirst = True + def pytest_collection_modifyitems(items, config): keywordexpr = config.option.keyword matchexpr = config.option.markexpr @@ -67,32 +79,76 @@ config.hook.pytest_deselected(items=deselected) items[:] = remaining -class BoolDict: - def __init__(self, mydict): - self._mydict = mydict - def __getitem__(self, name): - return name in self._mydict -class SubstringDict: - def __init__(self, mydict): - self._mydict = mydict - def __getitem__(self, name): - for key in self._mydict: - if name in key: +class MarkMapping: + """Provides a local mapping for markers. + Only the marker names from the given :class:`NodeKeywords` will be mapped, + so the names are taken only from :class:`MarkInfo` or + :class:`MarkDecorator` items. + """ + def __init__(self, keywords): + mymarks = set() + for key, value in keywords.items(): + if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator): + mymarks.add(key) + self._mymarks = mymarks + + def __getitem__(self, markname): + return markname in self._mymarks + + +class KeywordMapping: + """Provides a local mapping for keywords. + Given a list of names, map any substring of one of these names to True. + """ + def __init__(self, names): + self._names = names + + def __getitem__(self, subname): + for name in self._names: + if subname in name: return True return False -def matchmark(colitem, matchexpr): - return eval(matchexpr, {}, BoolDict(colitem.keywords)) + +def matchmark(colitem, markexpr): + """Tries to match on any marker names, attached to the given colitem.""" + return eval(markexpr, {}, MarkMapping(colitem.keywords)) + def matchkeyword(colitem, keywordexpr): + """Tries to match given keyword expression to given collector item. + + Will match on the name of colitem, including the names of its parents. + Only matches names of items which are either a :class:`Class` or a + :class:`Function`. + Additionally, matches on names in the 'extra_keyword_matches' set of + any item, as well as names directly assigned to test functions. + """ keywordexpr = keywordexpr.replace("-", "not ") - return eval(keywordexpr, {}, SubstringDict(colitem.keywords)) + mapped_names = set() + + # Add the names of the current item and any parent items + for item in colitem.listchain(): + if not isinstance(item, pytest.Instance): + mapped_names.add(item.name) + + # Add the names added as extra keywords to current or parent items + for name in colitem.listextrakeywords(): + mapped_names.add(name) + + # Add the names attached to the current function through direct assignment + for name in colitem.function.func_dict: + mapped_names.add(name) + + return eval(keywordexpr, {}, KeywordMapping(mapped_names)) + def pytest_configure(config): if config.option.strict: pytest.mark._config = config + class MarkGenerator: """ Factory for :class:`MarkDecorator` objects - exposed as a ``py.test.mark`` singleton instance. Example:: @@ -126,6 +182,7 @@ if name not in self._markers: raise AttributeError("%r not a registered marker" % (name,)) + class MarkDecorator: """ A decorator for test functions and test classes. When applied it will create :class:`MarkInfo` objects which may be @@ -149,7 +206,7 @@ def __repr__(self): d = self.__dict__.copy() name = d.pop('markname') - return "<MarkDecorator %r %r>" %(name, d) + return "<MarkDecorator %r %r>" % (name, d) def __call__(self, *args, **kwargs): """ if passed a single callable argument: decorate it with mark info. @@ -162,15 +219,17 @@ if hasattr(func, 'pytestmark'): l = func.pytestmark if not isinstance(l, list): - func.pytestmark = [l, self] + func.pytestmark = [l, self] else: - l.append(self) + l.append(self) else: - func.pytestmark = [self] + func.pytestmark = [self] else: holder = getattr(func, self.markname, None) if holder is None: - holder = MarkInfo(self.markname, self.args, self.kwargs) + holder = MarkInfo( + self.markname, self.args, self.kwargs + ) setattr(func, self.markname, holder) else: holder.add(self.args, self.kwargs) @@ -180,6 +239,7 @@ args = self.args + args return self.__class__(self.markname, args=args, kwargs=kw) + class MarkInfo: """ Marking object created by :class:`MarkDecorator` instances. """ def __init__(self, name, args, kwargs): @@ -193,7 +253,8 @@ def __repr__(self): return "<MarkInfo %r args=%r kwargs=%r>" % ( - self.name, self.args, self.kwargs) + self.name, self.args, self.kwargs + ) def add(self, args, kwargs): """ add a MarkInfo with the given args and kwargs. """ @@ -205,4 +266,3 @@ """ yield MarkInfo objects each relating to a marking-call. """ for args, kwargs in self._arglist: yield MarkInfo(self.name, args, kwargs) - diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r 5ce621f0b3d2857ce7035b765cd18836ec8ea73f testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -345,6 +345,24 @@ assert l[0].args == ("pos0",) assert l[1].args == ("pos1",) + def test_no_marker_match_on_unmarked_names(self, testdir): + p = testdir.makepyfile(""" + import pytest + @pytest.mark.shouldmatch + def test_marked(): + assert 1 + + def test_unmarked(): + assert 1 + """) + reprec = testdir.inline_run("-m", "test_unmarked", p) + passed, skipped, failed = reprec.listoutcomes() + assert len(passed) + len(skipped) + len(failed) == 0 + dlist = reprec.getcalls("pytest_deselected") + deselected_tests = dlist[0].items + assert len(deselected_tests) == 2 + + def test_keywords_at_node_level(self, testdir): p = testdir.makepyfile(""" import pytest @@ -382,7 +400,6 @@ 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 and test', 'test_method_one') @@ -401,7 +418,7 @@ def pytest_pycollect_makeitem(__multicall__, name): if name == "TestClass": item = __multicall__.execute() - item.keywords["xxx"] = True + item.extra_keyword_matches.add("xxx") return item """) reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword) @@ -440,3 +457,22 @@ reprec = testdir.inline_run("-k", "mykeyword", p) passed, skipped, failed = reprec.countoutcomes() assert failed == 1 + + def test_no_magic_values(self, testdir): + """Make sure the tests do not match on magic values, + no double underscored values, like '__dict__', + and no instance values, like '()'. + """ + p = testdir.makepyfile(""" + def test_one(): assert 1 + """) + def assert_test_is_not_selected(keyword): + reprec = testdir.inline_run("-k", keyword, p) + passed, skipped, failed = reprec.countoutcomes() + dlist = reprec.getcalls("pytest_deselected") + assert passed + skipped + failed == 0 + deselected_tests = dlist[0].items + assert len(deselected_tests) == 1 + + assert_test_is_not_selected("__") + assert_test_is_not_selected("()") Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org http://mail.python.org/mailman/listinfo/pytest-commit