@@ -118,6 +118,76 @@ 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 (test_doc .path , "test.test_example.TestClass.test_with_doc" )
189+ self .assertEqual (test_doc .result , "error" )
190+
121191 def test_parse_multiple_error_messages (self ):
122192 """Test parsing multiple error messages."""
123193 stdout = """
@@ -644,6 +714,102 @@ def test_one(self):
644714 method = self ._parse_method (code )
645715 self .assertFalse (_is_super_call_only (method ))
646716
717+ def test_async_await_super_call (self ):
718+ """Test async method that awaits super().same_name()."""
719+ code = """
720+ class Foo:
721+ async def test_one(self):
722+ return await super().test_one()
723+ """
724+ method = self ._parse_method (code )
725+ self .assertTrue (_is_super_call_only (method ))
726+
727+ def test_async_await_mismatched_super_call (self ):
728+ """Test async method that awaits super().different_name()."""
729+ code = """
730+ class Foo:
731+ async def test_one(self):
732+ return await super().test_two()
733+ """
734+ method = self ._parse_method (code )
735+ self .assertFalse (_is_super_call_only (method ))
736+
737+ def test_async_without_await (self ):
738+ """Test async method that calls super() without await (sync super call in async method)."""
739+ code = """
740+ class Foo:
741+ async def test_one(self):
742+ return super().test_one()
743+ """
744+ method = self ._parse_method (code )
745+ self .assertTrue (_is_super_call_only (method ))
746+
747+
748+ class TestAsyncInheritedOverride (unittest .TestCase ):
749+ """Tests for async inherited method override generation."""
750+
751+ def test_inherited_async_method_generates_async_override (self ):
752+ """Test that inherited async methods get async def + await override."""
753+ code = """import unittest
754+
755+ class BaseTest:
756+ async def test_async_one(self):
757+ pass
758+
759+ class TestChild(BaseTest, unittest.TestCase):
760+ pass
761+ """
762+ failing = {("TestChild" , "test_async_one" )}
763+ result = apply_test_changes (code , failing , set ())
764+
765+ self .assertIn ("async def test_async_one(self):" , result )
766+ self .assertIn ("return await super().test_async_one()" , result )
767+ self .assertIn ("@unittest.expectedFailure" , result )
768+
769+ def test_inherited_sync_method_generates_sync_override (self ):
770+ """Test that inherited sync methods get sync def override."""
771+ code = """import unittest
772+
773+ class BaseTest:
774+ def test_sync_one(self):
775+ pass
776+
777+ class TestChild(BaseTest, unittest.TestCase):
778+ pass
779+ """
780+ failing = {("TestChild" , "test_sync_one" )}
781+ result = apply_test_changes (code , failing , set ())
782+
783+ self .assertIn ("def test_sync_one(self):" , result )
784+ self .assertIn ("return super().test_sync_one()" , result )
785+ self .assertNotIn ("async def test_sync_one" , result )
786+ self .assertNotIn ("await" , result )
787+
788+ def test_remove_async_super_call_override (self ):
789+ """Test removing async super call override on unexpected success."""
790+ code = f"""import unittest
791+
792+ class BaseTest:
793+ async def test_async_one(self):
794+ pass
795+
796+ class TestChild(BaseTest, unittest.TestCase):
797+ # { COMMENT }
798+ @unittest.expectedFailure
799+ async def test_async_one(self):
800+ return await super().test_async_one()
801+ """
802+ successes = {("TestChild" , "test_async_one" )}
803+ result = apply_test_changes (code , set (), successes )
804+
805+ # The override in TestChild should be removed; base class method remains
806+ self .assertNotIn ("return await super().test_async_one()" , result )
807+ self .assertNotIn ("@unittest.expectedFailure" , result )
808+ self .assertIn ("class TestChild" , result )
809+ # Base class method should still be present
810+ self .assertIn ("class BaseTest" , result )
811+ self .assertIn ("async def test_async_one(self):" , result )
812+
647813
648814if __name__ == "__main__" :
649815 unittest .main ()
0 commit comments