|
43 | 43 |
|
44 | 44 | import pytest
|
45 | 45 |
|
46 |
| -SUPPORTED_FORMATS = {'html', 'json'} |
| 46 | +from pytest_mpl.summary.html import generate_summary_basic_html, generate_summary_html |
| 47 | + |
| 48 | +SUPPORTED_FORMATS = {'html', 'json', 'basic-html'} |
47 | 49 |
|
48 | 50 | SHAPE_MISMATCH_ERROR = """Error: Image dimensions did not match.
|
49 | 51 | Expected shape: {expected_shape}
|
50 | 52 | {expected_path}
|
51 | 53 | Actual shape: {actual_shape}
|
52 | 54 | {actual_path}"""
|
53 | 55 |
|
54 |
| -HTML_INTRO = """ |
55 |
| -<!DOCTYPE html> |
56 |
| -<html> |
57 |
| -<head> |
58 |
| -<style> |
59 |
| -table, th, td { |
60 |
| - border: 1px solid black; |
61 |
| -} |
62 |
| -.summary > div { |
63 |
| - padding: 0.5em; |
64 |
| -} |
65 |
| -tr.passed .status, .rms.passed, .hashes.passed { |
66 |
| - color: green; |
67 |
| -} |
68 |
| -tr.failed .status, .rms.failed, .hashes.failed { |
69 |
| - color: red; |
70 |
| -} |
71 |
| -</style> |
72 |
| -</head> |
73 |
| -<body> |
74 |
| -<h2>Image test comparison</h2> |
75 |
| -%summary% |
76 |
| -<table> |
77 |
| - <tr> |
78 |
| - <th>Test Name</th> |
79 |
| - <th>Baseline image</th> |
80 |
| - <th>Diff</th> |
81 |
| - <th>New image</th> |
82 |
| - </tr> |
83 |
| -""" |
84 |
| - |
85 | 56 |
|
86 | 57 | def _download_file(baseline, filename):
|
87 | 58 | # Note that baseline can be a comma-separated list of URLs that we can
|
@@ -162,7 +133,7 @@ def pytest_addoption(parser):
|
162 | 133 | group.addoption('--mpl-generate-summary', action='store',
|
163 | 134 | help="Generate a summary report of any failed tests"
|
164 | 135 | ", in --mpl-results-path. The type of the report should be "
|
165 |
| - "specified. Supported types are `html` and `json`. " |
| 136 | + "specified. Supported types are `html`, `json` and `basic-html`. " |
166 | 137 | "Multiple types can be specified separated by commas.")
|
167 | 138 |
|
168 | 139 | results_path_help = "directory for test results, relative to location where py.test is run"
|
@@ -712,105 +683,6 @@ def item_function_wrapper(*args, **kwargs):
|
712 | 683 | else:
|
713 | 684 | item.obj = item_function_wrapper
|
714 | 685 |
|
715 |
| - def generate_stats(self): |
716 |
| - """ |
717 |
| - Generate a dictionary of summary statistics. |
718 |
| - """ |
719 |
| - stats = {'passed': 0, 'failed': 0, 'passed_baseline': 0, 'failed_baseline': 0, 'skipped': 0} |
720 |
| - for test in self._test_results.values(): |
721 |
| - if test['status'] == 'passed': |
722 |
| - stats['passed'] += 1 |
723 |
| - if test['rms'] is not None: |
724 |
| - stats['failed_baseline'] += 1 |
725 |
| - elif test['status'] == 'failed': |
726 |
| - stats['failed'] += 1 |
727 |
| - if test['rms'] is None: |
728 |
| - stats['passed_baseline'] += 1 |
729 |
| - elif test['status'] == 'skipped': |
730 |
| - stats['skipped'] += 1 |
731 |
| - else: |
732 |
| - raise ValueError(f"Unknown test status '{test['status']}'.") |
733 |
| - self._test_stats = stats |
734 |
| - |
735 |
| - def generate_summary_html(self): |
736 |
| - """ |
737 |
| - Generate a simple HTML table of the failed test results |
738 |
| - """ |
739 |
| - html_file = self.results_dir / 'fig_comparison.html' |
740 |
| - with open(html_file, 'w') as f: |
741 |
| - |
742 |
| - passed = f"{self._test_stats['passed']} passed" |
743 |
| - if self._test_stats['failed_baseline'] > 0: |
744 |
| - passed += (" hash comparison, although " |
745 |
| - f"{self._test_stats['failed_baseline']} " |
746 |
| - "of those have a different baseline image") |
747 |
| - |
748 |
| - failed = f"{self._test_stats['failed']} failed" |
749 |
| - if self._test_stats['passed_baseline'] > 0: |
750 |
| - failed += (" hash comparison, although " |
751 |
| - f"{self._test_stats['passed_baseline']} " |
752 |
| - "of those have a matching baseline image") |
753 |
| - |
754 |
| - f.write(HTML_INTRO.replace('%summary%', f'<p>{passed}.</p><p>{failed}.</p>')) |
755 |
| - |
756 |
| - for test_name in sorted(self._test_results.keys()): |
757 |
| - summary = self._test_results[test_name] |
758 |
| - |
759 |
| - if not self.results_always and summary['result_image'] is None: |
760 |
| - continue # Don't show test if no result image |
761 |
| - |
762 |
| - if summary['rms'] is None and summary['tolerance'] is not None: |
763 |
| - rms = (f'<div class="rms passed">\n' |
764 |
| - f' <strong>RMS:</strong> ' |
765 |
| - f' < <span class="tolerance">{summary["tolerance"]}</span>\n' |
766 |
| - f'</div>') |
767 |
| - elif summary['rms'] is not None: |
768 |
| - rms = (f'<div class="rms failed">\n' |
769 |
| - f' <strong>RMS:</strong> ' |
770 |
| - f' <span class="rms">{summary["rms"]}</span>\n' |
771 |
| - f'</div>') |
772 |
| - else: |
773 |
| - rms = '' |
774 |
| - |
775 |
| - hashes = '' |
776 |
| - if summary['baseline_hash'] is not None: |
777 |
| - hashes += (f' <div class="baseline">Baseline: ' |
778 |
| - f'{summary["baseline_hash"]}</div>\n') |
779 |
| - if summary['result_hash'] is not None: |
780 |
| - hashes += (f' <div class="result">Result: ' |
781 |
| - f'{summary["result_hash"]}</div>\n') |
782 |
| - if len(hashes) > 0: |
783 |
| - if summary["baseline_hash"] == summary["result_hash"]: |
784 |
| - hash_result = 'passed' |
785 |
| - else: |
786 |
| - hash_result = 'failed' |
787 |
| - hashes = f'<div class="hashes {hash_result}">\n{hashes}</div>' |
788 |
| - |
789 |
| - images = {} |
790 |
| - for image_type in ['baseline_image', 'diff_image', 'result_image']: |
791 |
| - if summary[image_type] is not None: |
792 |
| - images[image_type] = f'<img src="{summary[image_type]}" />' |
793 |
| - else: |
794 |
| - images[image_type] = '' |
795 |
| - |
796 |
| - f.write(f'<tr class="{summary["status"]}">\n' |
797 |
| - ' <td>\n' |
798 |
| - ' <div class="summary">\n' |
799 |
| - f' <div class="test-name">{test_name}</div>\n' |
800 |
| - f' <div class="status">{summary["status"]}</div>\n' |
801 |
| - f' {rms}{hashes}\n' |
802 |
| - ' </td>\n' |
803 |
| - f' <td>{images["baseline_image"]}</td>\n' |
804 |
| - f' <td>{images["diff_image"]}</td>\n' |
805 |
| - f' <td>{images["result_image"]}</td>\n' |
806 |
| - '</tr>\n\n') |
807 |
| - |
808 |
| - f.write('</table>\n') |
809 |
| - f.write('</body>\n') |
810 |
| - f.write('</html>') |
811 |
| - |
812 |
| - return html_file |
813 |
| - |
814 | 686 | def generate_summary_json(self):
|
815 | 687 | json_file = self.results_dir / 'results.json'
|
816 | 688 | with open(json_file, 'w') as f:
|
@@ -843,13 +715,14 @@ def pytest_unconfigure(self, config):
|
843 | 715 | if self._test_results[test_name][image_type] == '%EXISTS%':
|
844 | 716 | self._test_results[test_name][image_type] = str(directory / filename)
|
845 | 717 |
|
846 |
| - self.generate_stats() |
847 |
| - |
848 | 718 | if 'json' in self.generate_summary:
|
849 | 719 | summary = self.generate_summary_json()
|
850 | 720 | print(f"A JSON report can be found at: {summary}")
|
851 | 721 | if 'html' in self.generate_summary:
|
852 |
| - summary = self.generate_summary_html() |
| 722 | + summary = generate_summary_html(self._test_results, self.results_dir) |
| 723 | + print(f"A summary of the failed tests can be found at: {summary}") |
| 724 | + if 'basic-html' in self.generate_summary: |
| 725 | + summary = generate_summary_basic_html(self._test_results, self.results_dir) |
853 | 726 | print(f"A summary of the failed tests can be found at: {summary}")
|
854 | 727 |
|
855 | 728 |
|
|
0 commit comments