Commits

Floris Bruynooghe committed 229f321 Merge

Merge pull request #158, fixes issue 504

  • Participants
  • Parent commits 9572842, 6fa216b

Comments (0)

Files changed (8)

 Marc Schlaich
 Christopher Gilling
 Daniel Grana
+Andy Freeland
 NEXT (2.6)
 -----------------------------------
 
+- change -v output to include full node IDs of tests.  Users can copy
+  a node ID from a test run, including line number, and use it as a
+  positional argument in order to run only a single test.
+
 - fix issue 475: fail early and comprehensible if calling
   pytest.raises with wrong exception type.
 

File _pytest/config.py

 
 import py
 # DON't import pytest here because it causes import cycle troubles
+import re
 import sys, os
 from _pytest import hookspec # the extension point definitions
 from _pytest.core import PluginManager
                     a = option.attrs()
                     arggroup.add_argument(*n, **a)
         # bash like autocompletion for dirs (appending '/')
-        optparser.add_argument(FILE_OR_DIR, nargs='*'
+        optparser.add_argument(FILE_OR_DIR, nargs='*', type=node_with_line_number,
                                ).completer=filescompleter
         return optparser
 
         except ConftestImportFailure:
             e = sys.exc_info()[1]
             if ns.help or ns.version:
-                # we don't want to prevent --help/--version to work 
+                # we don't want to prevent --help/--version to work
                 # so just let is pass and print a warning at the end
                 self.pluginmanager._warnings.append(
                         "could not load initial conftests (%s)\n" % e.path)
     return {}
 
 
+def node_with_line_number(string):
+    split = string.split('[')
+    split[0] = re.sub(r'@\d+', '', split[0])
+    return '['.join(split)
+
+
 def setns(obj, dic):
     import pytest
     for name, value in dic.items():

File _pytest/terminal.py

             line = str(fspath)
             if lineno is not None:
                 lineno += 1
-                line += ":" + str(lineno)
+                line += "@" + str(lineno)
             if domain:
-                line += ": " + str(domain)
+                split = str(domain).split('[')
+                split[0] = split[0].replace('.', '::')  # don't replace '.' in params
+                line += "::" + '['.join(split)
         else:
             line = "[location]"
         return line + " "

File testing/python/fixture.py

         """)
         result = testdir.runpytest("-v")
         result.stdout.fnmatch_lines("""
-            test_mod1.py:1: test_func[s1] PASSED
-            test_mod2.py:1: test_func2[s1] PASSED
-            test_mod2.py:3: test_func3[s1-m1] PASSED
-            test_mod2.py:5: test_func3b[s1-m1] PASSED
-            test_mod2.py:3: test_func3[s1-m2] PASSED
-            test_mod2.py:5: test_func3b[s1-m2] PASSED
-            test_mod1.py:1: test_func[s2] PASSED
-            test_mod2.py:1: test_func2[s2] PASSED
-            test_mod2.py:3: test_func3[s2-m1] PASSED
-            test_mod2.py:5: test_func3b[s2-m1] PASSED
-            test_mod2.py:7: test_func4[m1] PASSED
-            test_mod2.py:3: test_func3[s2-m2] PASSED
-            test_mod2.py:5: test_func3b[s2-m2] PASSED
-            test_mod2.py:7: test_func4[m2] PASSED
-            test_mod1.py:3: test_func1[m1] PASSED
-            test_mod1.py:3: test_func1[m2] PASSED
+            test_mod1.py@1::test_func[s1] PASSED
+            test_mod2.py@1::test_func2[s1] PASSED
+            test_mod2.py@3::test_func3[s1-m1] PASSED
+            test_mod2.py@5::test_func3b[s1-m1] PASSED
+            test_mod2.py@3::test_func3[s1-m2] PASSED
+            test_mod2.py@5::test_func3b[s1-m2] PASSED
+            test_mod1.py@1::test_func[s2] PASSED
+            test_mod2.py@1::test_func2[s2] PASSED
+            test_mod2.py@3::test_func3[s2-m1] PASSED
+            test_mod2.py@5::test_func3b[s2-m1] PASSED
+            test_mod2.py@7::test_func4[m1] PASSED
+            test_mod2.py@3::test_func3[s2-m2] PASSED
+            test_mod2.py@5::test_func3b[s2-m2] PASSED
+            test_mod2.py@7::test_func4[m2] PASSED
+            test_mod1.py@3::test_func1[m1] PASSED
+            test_mod1.py@3::test_func1[m2] PASSED
         """)
 
     def test_class_ordering(self, testdir):
         """)
         result = testdir.runpytest("-vs")
         result.stdout.fnmatch_lines("""
-            test_class_ordering.py:4: TestClass2.test_1[1-a] PASSED
-            test_class_ordering.py:4: TestClass2.test_1[2-a] PASSED
-            test_class_ordering.py:6: TestClass2.test_2[1-a] PASSED
-            test_class_ordering.py:6: TestClass2.test_2[2-a] PASSED
-            test_class_ordering.py:4: TestClass2.test_1[1-b] PASSED
-            test_class_ordering.py:4: TestClass2.test_1[2-b] PASSED
-            test_class_ordering.py:6: TestClass2.test_2[1-b] PASSED
-            test_class_ordering.py:6: TestClass2.test_2[2-b] PASSED
-            test_class_ordering.py:9: TestClass.test_3[1-a] PASSED
-            test_class_ordering.py:9: TestClass.test_3[2-a] PASSED
-            test_class_ordering.py:9: TestClass.test_3[1-b] PASSED
-            test_class_ordering.py:9: TestClass.test_3[2-b] PASSED
+            test_class_ordering.py@4::TestClass2::test_1[1-a] PASSED
+            test_class_ordering.py@4::TestClass2::test_1[2-a] PASSED
+            test_class_ordering.py@6::TestClass2::test_2[1-a] PASSED
+            test_class_ordering.py@6::TestClass2::test_2[2-a] PASSED
+            test_class_ordering.py@4::TestClass2::test_1[1-b] PASSED
+            test_class_ordering.py@4::TestClass2::test_1[2-b] PASSED
+            test_class_ordering.py@6::TestClass2::test_2[1-b] PASSED
+            test_class_ordering.py@6::TestClass2::test_2[2-b] PASSED
+            test_class_ordering.py@9::TestClass::test_3[1-a] PASSED
+            test_class_ordering.py@9::TestClass::test_3[2-a] PASSED
+            test_class_ordering.py@9::TestClass::test_3[1-b] PASSED
+            test_class_ordering.py@9::TestClass::test_3[2-b] PASSED
         """)
 
     def test_parametrize_separated_order_higher_scope_first(self, testdir):
             def fix1(request):
                 def f():
                     raise KeyError
-                request.addfinalizer(f) 
+                request.addfinalizer(f)
                 return object()
 
             l = []
             *KeyError*
             *3 pass*2 error*
         """)
-        
+
 
 
     def test_setupfunc_missing_funcarg(self, testdir):

File testing/test_parseopt.py

         assert args.R == True
         assert args.S == False
 
+    def test_parse_removes_line_number_from_positional_arguments(self, parser):
+        args = parser.parse(['path@2::func', 'path2@5::func2[param with @]'])
+        assert getattr(args, parseopt.FILE_OR_DIR) == ['path::func', 'path2::func2[param with @]']
+
     def test_parse_defaultgetter(self):
         def defaultget(option):
             if not hasattr(option, 'type'):

File testing/test_terminal.py

         result = testdir.runpytest(*option.args)
         if option.verbose:
             result.stdout.fnmatch_lines([
-                "*test_pass_skip_fail.py:2: *test_ok*PASS*",
-                "*test_pass_skip_fail.py:4: *test_skip*SKIP*",
-                "*test_pass_skip_fail.py:6: *test_func*FAIL*",
+                "*test_pass_skip_fail.py@2::test_ok PASS*",
+                "*test_pass_skip_fail.py@4::test_skip SKIP*",
+                "*test_pass_skip_fail.py@6::test_func FAIL*",
             ])
         else:
             result.stdout.fnmatch_lines([
         ])
         result = testdir.runpytest("-v", p2)
         result.stdout.fnmatch_lines([
-            "*test_p2.py <- *test_p1.py:2: TestMore.test_p1*",
+            "*test_p2.py <- *test_p1.py@2::TestMore::test_p1*",
         ])
 
     def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir):
         """)
         result = testdir.runpytest(p1, '-v')
         result.stdout.fnmatch_lines([
-            "*test_verbose_reporting.py:2: test_fail*FAIL*",
-            "*test_verbose_reporting.py:4: test_pass*PASS*",
-            "*test_verbose_reporting.py:7: TestClass.test_skip*SKIP*",
-            "*test_verbose_reporting.py:10: test_gen*FAIL*",
+            "*test_verbose_reporting.py@2::test_fail *FAIL*",
+            "*test_verbose_reporting.py@4::test_pass *PASS*",
+            "*test_verbose_reporting.py@7::TestClass::test_skip *SKIP*",
+            "*test_verbose_reporting.py@10::test_gen*0* *FAIL*",
         ])
         assert result.ret == 1
 
         pytestconfig.pluginmanager.skipifmissing("xdist")
         result = testdir.runpytest(p1, '-v', '-n 1')
         result.stdout.fnmatch_lines([
-            "*FAIL*test_verbose_reporting.py:2: test_fail*",
+            "*FAIL*test_verbose_reporting.py@2::test_fail*",
         ])
         assert result.ret == 1
 

File testing/test_unittest.py

         """)
     result = testdir.runpytest("-v")
     result.stdout.fnmatch_lines("""
-        *MyTestCaseWithRunTest.runTest*
-        *MyTestCaseWithoutRunTest.test_something*
+        *MyTestCaseWithRunTest::runTest*
+        *MyTestCaseWithoutRunTest::test_something*
         *2 passed*
     """)