bbli created this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
[LLDB] Hi, this is a patch for the proposed GSoC project "Add support for
batch-testing to the LLDB testsuite". The project aimed to add continuation
functionality when multiple assertions are called one after another, similar to
how GoogleTest's EXPECT_* macros work. Test results from running "ninja
check-lldb" were the same before and after the patch, and I have included a
test case for the new functionality.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D81697
Files:
lldb/packages/Python/lldbsuite/test/lldbtest.py
lldb/test/API/test_batch/TestBatch.py
lldb/third_party/Python/module/unittest2/unittest2/case.py
lldb/third_party/Python/module/unittest2/unittest2/result.py
Index: lldb/third_party/Python/module/unittest2/unittest2/result.py
===================================================================
--- lldb/third_party/Python/module/unittest2/unittest2/result.py
+++ lldb/third_party/Python/module/unittest2/unittest2/result.py
@@ -58,6 +58,7 @@
self._original_stdout = sys.stdout
self._original_stderr = sys.stderr
self._mirrorOutput = False
+ self.batchSuccess = True
def startTest(self, test):
"Called when the given test is about to be run"
Index: lldb/third_party/Python/module/unittest2/unittest2/case.py
===================================================================
--- lldb/third_party/Python/module/unittest2/unittest2/case.py
+++ lldb/third_party/Python/module/unittest2/unittest2/case.py
@@ -234,6 +234,10 @@
"""
self._testMethodName = methodName
self._resultForDoCleanups = None
+
+ self._batch = False
+ self._result = None
+
try:
testMethod = getattr(self, methodName)
except AttributeError:
@@ -410,6 +414,8 @@
SB objects and prevent them from being deleted in time.
"""
try:
+ self._result = result
+ self._result.batchSuccess = True # Just in case
testMethod()
except self.failureException:
result.addFailure(self, sys.exc_info())
@@ -437,7 +443,8 @@
except Exception:
result.addError(self, sys.exc_info())
else:
- return True
+ return self._result.batchSuccess
+ self._result = None
return False
def doCleanups(self):
Index: lldb/test/API/test_batch/TestBatch.py
===================================================================
--- /dev/null
+++ lldb/test/API/test_batch/TestBatch.py
@@ -0,0 +1,31 @@
+from lldbsuite.test.lldbtest import *
+
+class TestBatch(TestBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ NO_DEBUG_INFO_TESTCASE = True
+ x = 0
+
+ def test_batch(self):
+ self.enter_batch()
+
+ self.assertTrue(False)
+ self.assertTrue(False)
+
+ self.assertTrue(True)
+
+ self.exit_batch()
+
+ def test_context_manager(self):
+ with self.batchTest():
+ self.x += 1
+ self.assertFalse(True)
+ self.assertFalse(True)
+ self.assertEqual(self.x, 1)
+
+ def test_early_exit(self):
+ with self.batchTest():
+ self.assertFalse(True)
+ self.assertFalse(False)
+ raise IndexError
+ self.assertTrue(False)
Index: lldb/packages/Python/lldbsuite/test/lldbtest.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -50,6 +50,7 @@
import time
import traceback
import distutils.spawn
+import contextlib
# Third-party modules
import unittest2
@@ -1850,6 +1851,285 @@
# Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
timeWaitNextLaunch = 1.0
+ def enter_batch(self):
+ self._batch = True
+
+ def exit_batch(self):
+ self._batch = False
+
+ @contextlib.contextmanager
+ def batchTest(self):
+ try:
+ self.enter_batch()
+ yield
+ finally:
+ self.exit_batch()
+
+ # Assertion Overides
+ def assertTrue(self, expr, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertTrue(expr, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertTrue(expr, msg)
+
+ def assertFalse(self, expr, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertFalse( expr, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertFalse( expr, msg)
+ def assertRaises(self,excClass, callableObj=None, *args, **kwargs):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertRaises(excClass, callableObj, *args, **kwargs)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertRaises(excClass, callableObj, *args, **kwargs)
+ def assertEqual(self, first, second, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertEqual( first, second, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertEqual( first, second, msg)
+ def assertNotEqual(self, first, second, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertNotEqual( first, second, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertNotEqual( first, second, msg)
+ def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertAlmostEqual( first, second, places, msg, delta)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertAlmostEqual( first, second, places, msg, delta)
+ def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertNotAlmostEqual( first, second, places, msg, delta)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertNotAlmostEqual( first, second, places, msg, delta)
+ # assertSequenceEqual is called internally by the following methods, so overriding it may obscure traceback during failures
+ def assertListEqual(self, list1, list2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertListEqual( list1, list2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertListEqual( list1, list2, msg)
+ def assertTupleEqual(self, tuple1, tuple2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertTupleEqual( tuple1, tuple2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertTupleEqual( tuple1, tuple2, msg)
+ def assertSetEqual(self, set1, set2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ super(TestBase,self).assertSetEqual( set1, set2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ super(TestBase,self).assertSetEqual( set1, set2, msg)
+ def assertIn(self, member, container, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ super(TestBase,self).assertIn( member, container, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ super(TestBase,self).assertIn( member, container, msg)
+ def assertNotIn(self, member, container, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ super(TestBase,self).assertNotIn( member, container, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ super(TestBase,self).assertNotIn( member, container, msg)
+ def assertIs(self, expr1, expr2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ super(TestBase,self).assertIs( expr1, expr2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ super(TestBase,self).assertIs( expr1, expr2, msg)
+ def assertIsNot(self, expr1, expr2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ super(TestBase,self).assertIsNot( expr1, expr2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ super(TestBase,self).assertIsNot( expr1, expr2, msg)
+ def assertDictEqual(self, d1, d2, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertDictEqual( d1, d2, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertDictEqual( d1, d2, msg)
+ def assertDictContainsSubset(self, expected, actual, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertDictContainsSubset( expected, actual, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertDictContainsSubset( expected, actual, msg)
+ def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertItemsEqual( expected_seq, actual_seq, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertItemsEqual( expected_seq, actual_seq, msg)
+ def assertMultiLineEqual(self, first, second, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertMultiLineEqual( first, second, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertMultiLineEqual( first, second, msg)
+ def assertLess(self, a, b, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertLess( a, b, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertLess( a, b, msg)
+ def assertLessEqual(self, a, b, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertLessEqual( a, b, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertLessEqual( a, b, msg)
+ def assertGreater(self, a, b, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertGreater( a, b, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertGreater( a, b, msg)
+ def assertGreaterEqual(self, a, b, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertGreaterEqual( a, b, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertGreaterEqual( a, b, msg)
+ def assertIsNone(self, obj, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertIsNone( obj, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertIsNone( obj, msg)
+ def assertIsNotNone(self, obj, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertIsNotNone( obj, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertIsNotNone( obj, msg)
+ def assertIsInstance(self, obj, cls, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertIsInstance( obj, cls, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertIsInstance( obj, cls, msg)
+ def assertNotIsInstance(self, obj, cls, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertNotIsInstance( obj, cls, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertNotIsInstance( obj, cls, msg)
+ def assertRaisesRegexp(self, expected_exception, expected_regexp, callable_obj=None, *args, **kwargs):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertRaisesRegexp( expected_exception, expected_regexp, callable_obj, *args, **kwargs)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertRaisesRegexp( expected_exception, expected_regexp, callable_obj, *args, **kwargs)
+ def assertRegexpMatches(self, text, expected_regexp, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertRegexpMatches( text, expected_regexp, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertRegexpMatches( text, expected_regexp, msg)
+ def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
+ if self._result is not None and self._batch:
+ try:
+ return super(TestBase,self).assertNotRegexpMatches( text, unexpected_regexp, msg)
+ except self.failureException:
+ self._result.addFailure(self, sys.exc_info())
+ self._batchSuccess = False
+ else:
+ return super(TestBase,self).assertNotRegexpMatches( text, unexpected_regexp, msg)
+
def generateSource(self, source):
template = source + '.template'
temp = os.path.join(self.getSourceDir(), template)
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits