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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to