11
11
import warnings
12
12
from base64 import b64decode
13
13
from base64 import b64encode
14
+ from collections import defaultdict
14
15
from collections import OrderedDict
15
16
from functools import lru_cache
16
17
from html import escape
@@ -148,6 +149,7 @@ def __init__(self, logfile, config):
148
149
self .rerun = 0 if has_rerun else None
149
150
self .self_contained = config .getoption ("self_contained_html" )
150
151
self .config = config
152
+ self .reports = defaultdict (list )
151
153
152
154
class TestResult :
153
155
def __init__ (self , outcome , report , logfile , config ):
@@ -279,7 +281,12 @@ def append_extra_html(self, extra, extra_index, test_index):
279
281
def append_log_html (self , report , additional_html ):
280
282
log = html .div (class_ = "log" )
281
283
if report .longrepr :
282
- for line in report .longreprtext .splitlines ():
284
+ # longreprtext is only filled out on failure by pytest
285
+ # otherwise will be None.
286
+ # Use full_text if longreprtext is None-ish
287
+ # we added full_text elsewhere in this file.
288
+ text = report .longreprtext or report .full_text
289
+ for line in text .splitlines ():
283
290
separator = line .startswith ("_ " * 10 )
284
291
if separator :
285
292
log .append (line [:80 ])
@@ -620,15 +627,66 @@ def _save_report(self, report_content):
620
627
with open (style_path , "w" , encoding = "utf-8" ) as f :
621
628
f .write (self .style_css )
622
629
630
+ def _post_process_reports (self ):
631
+ for test_name , test_reports in self .reports .items ():
632
+ outcome = "passed"
633
+ wasxfail = False
634
+ failure_when = None
635
+ full_text = ""
636
+ extras = []
637
+ duration = 0.0
638
+
639
+ # in theory the last one should have all logs so we just go
640
+ # through them all to figure out the outcome, xfail, duration,
641
+ # extras, and when it swapped from pass
642
+ for test_report in test_reports :
643
+ full_text += test_report .longreprtext
644
+ extras .extend (getattr (test_report , "extra" , []))
645
+ duration += getattr (test_report , "duration" , 0.0 )
646
+
647
+ if (
648
+ test_report .outcome not in ("passed" , "rerun" )
649
+ and outcome == "passed"
650
+ ):
651
+ outcome = test_report .outcome
652
+ failure_when = test_report .when
653
+
654
+ if hasattr (test_report , "wasxfail" ):
655
+ wasxfail = True
656
+
657
+ if test_report .outcome == "rerun" :
658
+ self .append_other (test_report )
659
+
660
+ # the following test_report.<X> = settings come at the end of us
661
+ # looping through all test_reports that make up a single
662
+ # case.
663
+
664
+ # outcome on the right comes from the outcome of the various
665
+ # test_reports that make up this test case
666
+ # we are just carrying it over to the final report.
667
+ test_report .outcome = outcome
668
+ test_report .when = "call"
669
+ test_report .nodeid = test_name
670
+ test_report .longrepr = full_text
671
+ test_report .extra = extras
672
+ test_report .duration = duration
673
+
674
+ if wasxfail :
675
+ test_report .wasxfail = True
676
+
677
+ if test_report .outcome == "passed" :
678
+ self .append_passed (test_report )
679
+ elif test_report .outcome == "skipped" :
680
+ self .append_skipped (test_report )
681
+ elif test_report .outcome == "failed" :
682
+ test_report .when = failure_when
683
+ self .append_failed (test_report )
684
+
685
+ # we don't append other here since the only case supported
686
+ # for append_other is rerun, which is handled in the loop above
687
+
623
688
def pytest_runtest_logreport (self , report ):
624
- if report .passed :
625
- self .append_passed (report )
626
- elif report .failed :
627
- self .append_failed (report )
628
- elif report .skipped :
629
- self .append_skipped (report )
630
- else :
631
- self .append_other (report )
689
+ self .reports [report .nodeid ].append (report )
632
690
633
691
def pytest_collectreport (self , report ):
634
692
if report .failed :
@@ -638,6 +696,7 @@ def pytest_sessionstart(self, session):
638
696
self .suite_start_time = time .time ()
639
697
640
698
def pytest_sessionfinish (self , session ):
699
+ self ._post_process_reports ()
641
700
report_content = self ._generate_report (session )
642
701
self ._save_report (report_content )
643
702
0 commit comments