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