1515from .sort import TestOrder
1616
1717
18+
1819class ResultsReporter :
1920 def __init__ (self ):
2021 self .results = Results ()
@@ -37,7 +38,6 @@ def pytest_collection_modifyitems(self, session, config, items):
3738 for mark in item .iter_markers (name = 'task' ):
3839 self .tests [name ] = Test (name = name , task_id = mark .kwargs ['taskno' ])
3940
40-
4141 def _sort_by_lineno (item ):
4242 test_id = Hierarchy (item .nodeid )
4343 source = Path (item .fspath )
@@ -50,28 +50,60 @@ def pytest_runtest_logreport(self, report):
5050 Process a test setup / call / teardown report.
5151 """
5252
53- name = report .head_line if report .head_line else "." .join (report .nodeid .split ("::" )[1 :])
53+ name = "." .join (report .nodeid .split ("::" )[1 :])
54+ if report .head_line :
55+ name = report .head_line .split (" (" )[0 ]
5456
5557
58+ #Add variation name to test output.
5659 if name not in self .tests :
5760 self .tests [name ] = Test (name )
5861
59-
6062 state = self .tests [name ]
6163
6264 # ignore successful setup and teardown stages
6365 if report .passed and report .when != "call" :
6466 return
6567
66- # Update tests that have already failed with capstdout and return.
68+ #Update tests that have already failed with capstdout and return.
6769 if not state .is_passing ():
68- if report .capstdout .rstrip ('FFFFFFFF ' ).rstrip ('uuuuu' ):
69- state .output = report .capstdout .rstrip ('FFFFFFFF ' ).rstrip ('uuuuu' )
70+
71+ #Check if a report is a concept exercise subtest parent.
72+ if report .capstdout :
73+
74+ #split up the captured stdout by subtest result.
75+ captures = [item for item in report .capstdout .split ('\n u' )]
76+ if captures [0 ].startswith ('u' ):
77+ captures [0 ] = captures [0 ][1 :]
78+
79+ parsed_captures = []
80+
81+ # Insert spacers for subtests and stdout entries in correct position.
82+ for item in captures :
83+ empties = len (item ) - len (item .lstrip ('u' ))
84+ if empties > 0 :
85+ for number in range (1 , empties + 1 ):
86+ parsed_captures .append (' ' )
87+ parsed_captures .append (item .lstrip ('u' ))
88+ else : parsed_captures .append (item )
89+
90+ # Generate variation numbers for each subtest output section.
91+ variants = (f'[variation #{ number } ]: { item } ' for
92+ item , number in zip (parsed_captures , range (1 , len (parsed_captures )+ 1 )))
93+
94+ # Go through the variations and match them to self.tests.
95+ # Insert matched variation output into test output field.
96+ for item in variants :
97+ for name in self .tests :
98+ if item .split (":" )[0 ] in name and report .nodeid .split ("::" )[2 ] in name :
99+ self .tests [name ].output = item .split ("]: " )[1 ]
100+ else :
101+ state .output = report .capstdout
70102 return
71103
72- # Record captured relevant stdout content for passed tests.
73- if report .capstdout :
74- state .output = report .capstdout
104+ else :
105+ if report .capstdout :
106+ state .output = report .capstdout
75107
76108 # Handle details of test failure
77109 if report .failed :
@@ -108,7 +140,6 @@ def pytest_runtest_logreport(self, report):
108140 )
109141 self .tests [parent_test_name ].test_code = state .test_code
110142
111-
112143 def pytest_sessionfinish (self , session , exitstatus ):
113144 """
114145 Processes the results into a report.
@@ -209,6 +240,7 @@ def run(slug: Slug, indir: Directory, outdir: Directory, args: List[str]) -> Non
209240
210241 # dump the report
211242 out_file .write_text (reporter .results .as_json ())
243+
212244 # remove cache directories
213245 for cache_dir in ['.pytest_cache' , '__pycache__' ]:
214246 dirpath = indir / cache_dir
0 commit comments