<rdar://problem/12362092>
authorEnrico Granata <egranata@apple.com>
Sat, 23 Feb 2013 01:05:23 +0000 (01:05 +0000)
committerEnrico Granata <egranata@apple.com>
Sat, 23 Feb 2013 01:05:23 +0000 (01:05 +0000)
The decorators @expectedFailure (plain and special-case like i386, clang, ...) are modified to optionally take a bugnumber argument
If such an argument is specified, the failure report (or unexpected success report) will include the information passed in as part of the message
This is mostly useful for associating failures to issue IDs in issue management systems (e.g. the LLVM bugzilla)

llvm-svn: 175942

lldb/test/dotest.py
lldb/test/lang/objc/foundation/TestObjCMethods2.py
lldb/test/lldbtest.py
lldb/test/unittest2/case.py
lldb/test/unittest2/result.py
lldb/test/unittest2/runner.py

index 8ed13da..e5e2fdf 100755 (executable)
@@ -1459,14 +1459,14 @@ for ia in range(len(archs) if iterArchs else 1):
                         else:
                             failuresPerCategory[category] = 1
 
-            def addExpectedFailure(self, test, err):
+            def addExpectedFailure(self, test, err, bugnumber):
                 global sdir_has_content
                 global parsable
                 sdir_has_content = True
-                super(LLDBTestResult, self).addExpectedFailure(test, err)
+                super(LLDBTestResult, self).addExpectedFailure(test, err, bugnumber)
                 method = getattr(test, "markExpectedFailure", None)
                 if method:
-                    method()
+                    method(err, bugnumber)
                 if parsable:
                     self.stream.write("XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
 
@@ -1481,14 +1481,14 @@ for ia in range(len(archs) if iterArchs else 1):
                 if parsable:
                     self.stream.write("UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % (self._config_string(test), str(test), reason))
 
-            def addUnexpectedSuccess(self, test):
+            def addUnexpectedSuccess(self, test, bugnumber):
                 global sdir_has_content
                 global parsable
                 sdir_has_content = True
-                super(LLDBTestResult, self).addUnexpectedSuccess(test)
+                super(LLDBTestResult, self).addUnexpectedSuccess(test, bugnumber)
                 method = getattr(test, "markUnexpectedSuccess", None)
                 if method:
-                    method()
+                    method(bugnumber)
                 if parsable:
                     self.stream.write("XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
 
index 4ed2c9b..37e3f1e 100644 (file)
@@ -133,8 +133,7 @@ class FoundationTestCase2(TestBase):
 
         self.runCmd("process continue")
 
-    @unittest2.expectedFailure
-    # <rdar://problem/8741897> Expressions should support properties
+    @unittest2.expectedFailure(8741897)
     def NSArray_expr(self):
         """Test expression commands for NSArray."""
         exe = os.path.join(os.getcwd(), "a.out")
@@ -160,8 +159,7 @@ class FoundationTestCase2(TestBase):
             patterns = ["\(int\) \$.* = 3"])
         self.runCmd("process continue")
 
-    @unittest2.expectedFailure
-    # <rdar://problem/8741897> Expressions should support properties
+    @unittest2.expectedFailure(8741897)
     def NSString_expr(self):
         """Test expression commands for NSString."""
         exe = os.path.join(os.getcwd(), "a.out")
index d45e6d4..fa18b86 100644 (file)
@@ -368,27 +368,41 @@ def dwarf_test(func):
     wrapper.__dwarf_test__ = True
     return wrapper
 
-def expectedFailureCompiler(func, compiler):
-    """Decorate the item as an expectedFailure if the test compiler matches parameter compiler."""
-    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
-        raise Exception("@expectedFailureClang can only be used to decorate a test method")
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        from unittest2 import case
-        self = args[0]
-        test_compiler = self.getCompiler()
-        try:
-            func(*args, **kwargs)
-        except Exception:
-            if compiler in test_compiler:
-                raise case._ExpectedFailure(sys.exc_info())
-            else:
-                raise
-
-        if compiler in test_compiler:
-            raise case._UnexpectedSuccess
-    return wrapper
-
+def expectedFailureCompiler(bugnumber=None):
+     if callable(bugnumber):
+        @wraps(bugnumber)
+        def expectedFailureCompiler_easy_wrapper(*args, **kwargs):
+               from unittest2 import case
+               self = args[0]
+               test_compiler = self.getCompiler()
+               try:
+                   bugnumber(*args, **kwargs)
+               except Exception:
+                   if compiler in test_compiler:
+                       raise _ExpectedFailure(sys.exc_info(),None)
+                   else:
+                       raise
+               if compiler in test_compiler:
+                   raise case._UnexpectedSuccess(sys.exc_info(),None)
+        return expectedFailureCompiler_easy_wrapper
+     else:
+        def expectedFailureCompiler_impl(func):
+              @wraps(func)
+              def wrapper(*args, **kwargs):
+                       from unittest2 import case
+                       self = args[0]
+                       test_compiler = self.getCompiler()
+                       try:
+                           func(*args, **kwargs)
+                       except Exception:
+                           if compiler in test_compiler:
+                               raise _ExpectedFailure(sys.exc_info(),None)
+                           else:
+                               raise
+                       if compiler in test_compiler:
+                           raise case._UnexpectedSuccess(sys.exc_info(),None)
+              return wrapper
+        return expectedFailureCompiler_impl
 
 def expectedFailureGcc(func):
     """Decorate the item as a GCC only expectedFailure."""
@@ -402,47 +416,77 @@ def expectedFailureClang(func):
         raise Exception("@expectedFailureClang can only be used to decorate a test method")
     return expectedFailureCompiler(func, "clang")
 
-def expectedFailurei386(func):
-    """Decorate the item as an i386 only expectedFailure."""
-    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
-        raise Exception("@expectedFailurei386 can only be used to decorate a test method")
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        from unittest2 import case
-        self = args[0]
-        arch = self.getArchitecture()
-        try:
-            func(*args, **kwargs)
-        except Exception:
-            if "i386" in arch:
-                raise case._ExpectedFailure(sys.exc_info())
-            else:
-                raise
-
-        if "i386" in arch:
-            raise case._UnexpectedSuccess
-    return wrapper
-
-def expectedFailureLinux(func):
-    """Decorate the item as a Linux only expectedFailure."""
-    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
-        raise Exception("@expectedFailureLinux can only be used to decorate a test method")
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        from unittest2 import case
-        self = args[0]
-        platform = sys.platform
-        try:
-            func(*args, **kwargs)
-        except Exception:
-            if "linux" in platform:
-                raise case._ExpectedFailure(sys.exc_info())
-            else:
-                raise
-
-        if "linux" in platform:
-            raise case._UnexpectedSuccess
-    return wrapper
+def expectedFailurei386(bugnumber=None):
+     if callable(bugnumber):
+        @wraps(bugnumber)
+        def expectedFailurei386_easy_wrapper(*args, **kwargs):
+               from unittest2 import case
+               self = args[0]
+               arch = self.getArchitecture()
+               try:
+                   bugnumber(*args, **kwargs)
+               except Exception:
+                   if "i386" in arch:
+                       raise _ExpectedFailure(sys.exc_info(),None)
+                   else:
+                       raise
+               if "i386" in arch:
+                   raise case._UnexpectedSuccess(sys.exc_info(),None)
+        return expectedFailurei386_easy_wrapper
+     else:
+        def expectedFailurei386_impl(func):
+              @wraps(func)
+              def wrapper(*args, **kwargs):
+                       from unittest2 import case
+                       self = args[0]
+                       arch = self.getArchitecture()
+                       try:
+                           func(*args, **kwargs)
+                       except Exception:
+                           if "i386" in arch:
+                               raise _ExpectedFailure(sys.exc_info(),None)
+                           else:
+                               raise
+                       if "i386" in arch:
+                           raise case._UnexpectedSuccess(sys.exc_info(),None)
+              return wrapper
+        return expectedFailurei386_impl
+
+def expectedFailureLinux(bugnumber=None):
+     if callable(bugnumber):
+        @wraps(bugnumber)
+        def expectedFailureLinux_easy_wrapper(*args, **kwargs):
+               from unittest2 import case
+               self = args[0]
+               platform = sys.platform
+               try:
+                   bugnumber(*args, **kwargs)
+               except Exception:
+                   if "linux" in platform:
+                       raise _ExpectedFailure(sys.exc_info(),None)
+                   else:
+                       raise
+               if "linux" in platform:
+                   raise case._UnexpectedSuccess(sys.exc_info(),None)
+        return expectedFailureLinux_easy_wrapper
+     else:
+        def expectedFailureLinux_impl(func):
+              @wraps(func)
+              def wrapper(*args, **kwargs):
+                       from unittest2 import case
+                       self = args[0]
+                       platform = sys.platform
+                       try:
+                           func(*args, **kwargs)
+                       except Exception:
+                           if "linux" in platform:
+                               raise _ExpectedFailure(sys.exc_info(),None)
+                           else:
+                               raise
+                       if "linux" in platform:
+                           raise case._UnexpectedSuccess(sys.exc_info(),None)
+              return wrapper
+        return expectedFailureLinux_impl
 
 def skipOnLinux(func):
     """Decorate the item to skip tests that should be skipped on Linux."""
@@ -832,14 +876,17 @@ class Base(unittest2.TestCase):
             # Once by the Python unittest framework, and a second time by us.
             print >> sbuf, "FAIL"
 
-    def markExpectedFailure(self):
+    def markExpectedFailure(self,err,bugnumber):
         """Callback invoked when an expected failure/error occurred."""
         self.__expected__ = True
         with recording(self, False) as sbuf:
             # False because there's no need to write "expected failure" to the
             # stderr twice.
             # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "expected failure"
+            if bugnumber == None:
+                print >> sbuf, "expected failure"
+            else:
+                print >> sbuf, "expected failure (problem id:" + str(bugnumber) + ")"  
 
     def markSkippedTest(self):
         """Callback invoked when a test is skipped."""
@@ -850,14 +897,17 @@ class Base(unittest2.TestCase):
             # Once by the Python unittest framework, and a second time by us.
             print >> sbuf, "skipped test"
 
-    def markUnexpectedSuccess(self):
+    def markUnexpectedSuccess(self, bugnumber):
         """Callback invoked when an unexpected success occurred."""
         self.__unexpected__ = True
         with recording(self, False) as sbuf:
             # False because there's no need to write "unexpected success" to the
             # stderr twice.
             # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "unexpected success"
+            if bugnumber == None:
+                print >> sbuf, "unexpected success"
+            else:
+                print >> sbuf, "unexpected success (problem id:" + str(bugnumber) + ")"        
 
     def dumpSessionInfo(self):
         """
index 105914b..d6f0a17 100644 (file)
@@ -36,16 +36,23 @@ class _ExpectedFailure(Exception):
     This is an implementation detail.
     """
 
-    def __init__(self, exc_info):
+    def __init__(self, exc_info, bugnumber=None):
         # can't use super because Python 2.4 exceptions are old style
         Exception.__init__(self)
         self.exc_info = exc_info
+        self.bugnumber = bugnumber
 
 class _UnexpectedSuccess(Exception):
     """
     The test was supposed to fail, but it didn't!
     """
 
+    def __init__(self, exc_info, bugnumber=None):
+        # can't use super because Python 2.4 exceptions are old style
+        Exception.__init__(self)
+        self.exc_info = exc_info
+        self.bugnumber = bugnumber
+
 def _id(obj):
     return obj
 
@@ -81,17 +88,27 @@ def skipUnless(condition, reason):
         return skip(reason)
     return _id
 
-
-def expectedFailure(func):
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        try:
-            func(*args, **kwargs)
-        except Exception:
-            raise _ExpectedFailure(sys.exc_info())
-        raise _UnexpectedSuccess
-    return wrapper
-
+def expectedFailure(bugnumber=None):
+     if callable(bugnumber):
+        @wraps(bugnumber)
+        def expectedFailure_easy_wrapper(*args, **kwargs):
+             try:
+                bugnumber(*args, **kwargs)
+             except Exception:
+                raise _ExpectedFailure(sys.exc_info(),None)
+             raise _UnexpectedSuccess(sys.exc_info(),None)
+        return expectedFailure_easy_wrapper
+     else:
+        def expectedFailure_impl(func):
+              @wraps(func)
+              def wrapper(*args, **kwargs):
+                   try:
+                      func(*args, **kwargs)
+                   except Exception:
+                      raise _ExpectedFailure(sys.exc_info(),bugnumber)
+                   raise _UnexpectedSuccess(sys.exc_info(),bugnumber)
+              return wrapper
+        return expectedFailure_impl
 
 class _AssertRaisesContext(object):
     """A context manager used to implement TestCase.assertRaises* methods."""
@@ -343,15 +360,15 @@ class TestCase(unittest.TestCase):
                 except _ExpectedFailure, e:
                     addExpectedFailure = getattr(result, 'addExpectedFailure', None)
                     if addExpectedFailure is not None:
-                        addExpectedFailure(self, e.exc_info)
+                        addExpectedFailure(self, e.exc_info, e.bugnumber)
                     else: 
                         warnings.warn("Use of a TestResult without an addExpectedFailure method is deprecated", 
                                       DeprecationWarning)
                         result.addSuccess(self)
-                except _UnexpectedSuccess:
+                except _UnexpectedSuccess, x:
                     addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
                     if addUnexpectedSuccess is not None:
-                        addUnexpectedSuccess(self)
+                        addUnexpectedSuccess(self, x.bugnumber)
                     else:
                         warnings.warn("Use of a TestResult without an addUnexpectedSuccess method is deprecated", 
                                       DeprecationWarning)
index 7770e64..cacc0ee 100644 (file)
@@ -123,13 +123,13 @@ class TestResult(unittest.TestResult):
         """Called when a test is skipped."""
         self.skipped.append((test, reason))
 
-    def addExpectedFailure(self, test, err):
+    def addExpectedFailure(self, test, err, bugnumber):
         """Called when an expected failure/error occured."""
         self.expectedFailures.append(
             (test, self._exc_info_to_string(err, test)))
 
     @failfast
-    def addUnexpectedSuccess(self, test):
+    def addUnexpectedSuccess(self, test, bugnumber):
         """Called when a test was expected to fail, but succeed."""
         self.unexpectedSuccesses.append(test)
 
index f68e209..755aadc 100644 (file)
@@ -92,12 +92,12 @@ class TextTestResult(result.TestResult):
         super(TextTestResult, self).addSkip(test, reason)
         self.newTestResult(test,"s","skipped %r" % (reason,))
 
-    def addExpectedFailure(self, test, err):
-        super(TextTestResult, self).addExpectedFailure(test, err)
+    def addExpectedFailure(self, test, err, bugnumber):
+        super(TextTestResult, self).addExpectedFailure(test, err, bugnumber)
         self.newTestResult(test,"x","expected failure")
 
-    def addUnexpectedSuccess(self, test):
-        super(TextTestResult, self).addUnexpectedSuccess(test)
+    def addUnexpectedSuccess(self, test, bugnumber):
+        super(TextTestResult, self).addUnexpectedSuccess(test, bugnumber)
         self.newTestResult(test,"u","unexpected success")
 
     def printErrors(self):