<rdar://problem/12362092>
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)
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@175942 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/dotest.py b/test/dotest.py
index 8ed13da..e5e2fdf 100755
--- a/test/dotest.py
+++ b/test/dotest.py
@@ -1459,14 +1459,14 @@
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 @@
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)))
diff --git a/test/lang/objc/foundation/TestObjCMethods2.py b/test/lang/objc/foundation/TestObjCMethods2.py
index 4ed2c9b..37e3f1e 100644
--- a/test/lang/objc/foundation/TestObjCMethods2.py
+++ b/test/lang/objc/foundation/TestObjCMethods2.py
@@ -133,8 +133,7 @@
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 @@
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")
diff --git a/test/lldbtest.py b/test/lldbtest.py
index d45e6d4..fa18b86 100644
--- a/test/lldbtest.py
+++ b/test/lldbtest.py
@@ -368,27 +368,41 @@
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 @@
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
+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
- 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 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 @@
# 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 @@
# 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):
"""
diff --git a/test/unittest2/case.py b/test/unittest2/case.py
index 105914b..d6f0a17 100644
--- a/test/unittest2/case.py
+++ b/test/unittest2/case.py
@@ -36,16 +36,23 @@
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 @@
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 @@
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)
diff --git a/test/unittest2/result.py b/test/unittest2/result.py
index 7770e64..cacc0ee 100644
--- a/test/unittest2/result.py
+++ b/test/unittest2/result.py
@@ -123,13 +123,13 @@
"""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)
diff --git a/test/unittest2/runner.py b/test/unittest2/runner.py
index f68e209..755aadc 100644
--- a/test/unittest2/runner.py
+++ b/test/unittest2/runner.py
@@ -92,12 +92,12 @@
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):