@@ -118,6 +118,78 @@ def test_parse_error_message(self):
118118 self .assertEqual (len (result .tests ), 1 )
119119 self .assertEqual (result .tests [0 ].error_message , "AssertionError: 1 != 2" )
120120
121+ def test_parse_directory_test_multiple_submodules (self ):
122+ """Test parsing directory test output with multiple submodules.
123+
124+ When running a directory test (e.g., test_asyncio), the output contains
125+ multiple submodules separated by '------' lines. Failures in submodules
126+ after the first one must still be detected.
127+ """
128+ stdout = """\
129+ Run 3 tests sequentially
130+ 0:00:00 [ 1/3] test_asyncio.test_buffered_proto
131+ test_ok (test.test_asyncio.test_buffered_proto.TestProto.test_ok) ... ok
132+
133+ ----------------------------------------------------------------------
134+ Ran 1 tests in 0.1s
135+
136+ OK
137+
138+ 0:00:01 [ 2/3] test_asyncio.test_events
139+ test_create (test.test_asyncio.test_events.TestEvents.test_create) ... FAIL
140+
141+ ----------------------------------------------------------------------
142+ Ran 1 tests in 0.2s
143+
144+ FAILED (failures=1)
145+
146+ 0:00:02 [ 3/3] test_asyncio.test_tasks
147+ test_gather (test.test_asyncio.test_tasks.TestTasks.test_gather) ... ERROR
148+
149+ ----------------------------------------------------------------------
150+ Ran 1 tests in 0.3s
151+
152+ FAILED (errors=1)
153+
154+ == Tests result: FAILURE ==
155+ """
156+ result = parse_results (self ._make_result (stdout ))
157+ self .assertEqual (len (result .tests ), 2 )
158+ names = {t .name for t in result .tests }
159+ self .assertIn ("test_create" , names )
160+ self .assertIn ("test_gather" , names )
161+ # Verify results
162+ test_create = next (t for t in result .tests if t .name == "test_create" )
163+ test_gather = next (t for t in result .tests if t .name == "test_gather" )
164+ self .assertEqual (test_create .result , "fail" )
165+ self .assertEqual (test_gather .result , "error" )
166+ self .assertEqual (result .tests_result , "FAILURE" )
167+
168+ def test_parse_multiline_test_with_docstring (self ):
169+ """Test parsing tests where docstring appears on a separate line.
170+
171+ Some tests have docstrings that cause the output to span two lines:
172+ test_name (path)
173+ docstring ... ERROR
174+ """
175+ stdout = """\
176+ Run 3 tests sequentially
177+ test_ok (test.test_example.TestClass.test_ok) ... ok
178+ test_with_doc (test.test_example.TestClass.test_with_doc)
179+ Test that something works ... ERROR
180+ test_normal_fail (test.test_example.TestClass.test_normal_fail) ... FAIL
181+ """
182+ result = parse_results (self ._make_result (stdout ))
183+ self .assertEqual (len (result .tests ), 2 )
184+ names = {t .name for t in result .tests }
185+ self .assertIn ("test_with_doc" , names )
186+ self .assertIn ("test_normal_fail" , names )
187+ test_doc = next (t for t in result .tests if t .name == "test_with_doc" )
188+ self .assertEqual (
189+ test_doc .path , "test.test_example.TestClass.test_with_doc"
190+ )
191+ self .assertEqual (test_doc .result , "error" )
192+
121193 def test_parse_multiple_error_messages (self ):
122194 """Test parsing multiple error messages."""
123195 stdout = """
@@ -644,6 +716,102 @@ def test_one(self):
644716 method = self ._parse_method (code )
645717 self .assertFalse (_is_super_call_only (method ))
646718
719+ def test_async_await_super_call (self ):
720+ """Test async method that awaits super().same_name()."""
721+ code = """
722+ class Foo:
723+ async def test_one(self):
724+ return await super().test_one()
725+ """
726+ method = self ._parse_method (code )
727+ self .assertTrue (_is_super_call_only (method ))
728+
729+ def test_async_await_mismatched_super_call (self ):
730+ """Test async method that awaits super().different_name()."""
731+ code = """
732+ class Foo:
733+ async def test_one(self):
734+ return await super().test_two()
735+ """
736+ method = self ._parse_method (code )
737+ self .assertFalse (_is_super_call_only (method ))
738+
739+ def test_async_without_await (self ):
740+ """Test async method that calls super() without await (sync super call in async method)."""
741+ code = """
742+ class Foo:
743+ async def test_one(self):
744+ return super().test_one()
745+ """
746+ method = self ._parse_method (code )
747+ self .assertTrue (_is_super_call_only (method ))
748+
749+
750+ class TestAsyncInheritedOverride (unittest .TestCase ):
751+ """Tests for async inherited method override generation."""
752+
753+ def test_inherited_async_method_generates_async_override (self ):
754+ """Test that inherited async methods get async def + await override."""
755+ code = """import unittest
756+
757+ class BaseTest:
758+ async def test_async_one(self):
759+ pass
760+
761+ class TestChild(BaseTest, unittest.TestCase):
762+ pass
763+ """
764+ failing = {("TestChild" , "test_async_one" )}
765+ result = apply_test_changes (code , failing , set ())
766+
767+ self .assertIn ("async def test_async_one(self):" , result )
768+ self .assertIn ("return await super().test_async_one()" , result )
769+ self .assertIn ("@unittest.expectedFailure" , result )
770+
771+ def test_inherited_sync_method_generates_sync_override (self ):
772+ """Test that inherited sync methods get sync def override."""
773+ code = """import unittest
774+
775+ class BaseTest:
776+ def test_sync_one(self):
777+ pass
778+
779+ class TestChild(BaseTest, unittest.TestCase):
780+ pass
781+ """
782+ failing = {("TestChild" , "test_sync_one" )}
783+ result = apply_test_changes (code , failing , set ())
784+
785+ self .assertIn ("def test_sync_one(self):" , result )
786+ self .assertIn ("return super().test_sync_one()" , result )
787+ self .assertNotIn ("async def test_sync_one" , result )
788+ self .assertNotIn ("await" , result )
789+
790+ def test_remove_async_super_call_override (self ):
791+ """Test removing async super call override on unexpected success."""
792+ code = f"""import unittest
793+
794+ class BaseTest:
795+ async def test_async_one(self):
796+ pass
797+
798+ class TestChild(BaseTest, unittest.TestCase):
799+ # { COMMENT }
800+ @unittest.expectedFailure
801+ async def test_async_one(self):
802+ return await super().test_async_one()
803+ """
804+ successes = {("TestChild" , "test_async_one" )}
805+ result = apply_test_changes (code , set (), successes )
806+
807+ # The override in TestChild should be removed; base class method remains
808+ self .assertNotIn ("return await super().test_async_one()" , result )
809+ self .assertNotIn ("@unittest.expectedFailure" , result )
810+ self .assertIn ("class TestChild" , result )
811+ # Base class method should still be present
812+ self .assertIn ("class BaseTest" , result )
813+ self .assertIn ("async def test_async_one(self):" , result )
814+
647815
648816if __name__ == "__main__" :
649817 unittest .main ()
0 commit comments