|
1 | 1 | from __future__ import (absolute_import, division, print_function,
|
2 | 2 | unicode_literals)
|
3 | 3 |
|
| 4 | +import io |
4 | 5 | import os
|
5 | 6 | import shutil
|
| 7 | +import warnings |
6 | 8 |
|
7 | 9 | from numpy.testing import assert_equal, assert_almost_equal
|
| 10 | +import pytest |
8 | 11 |
|
9 | 12 | from matplotlib.testing.compare import compare_images
|
10 |
| -from matplotlib.testing.decorators import _image_directories |
| 13 | +from matplotlib.testing.decorators import _image_directories, image_comparison |
| 14 | +from matplotlib.testing.exceptions import ImageComparisonFailure |
11 | 15 |
|
12 | 16 |
|
13 | 17 | baseline_dir, result_dir = _image_directories(lambda: 'dummy func')
|
@@ -97,3 +101,118 @@ def test_image_compare_shade_difference():
|
97 | 101 |
|
98 | 102 | # Now test the reverse comparison.
|
99 | 103 | image_comparison_expect_rms(im2, im1, tol=0, expect_rms=1.0)
|
| 104 | + |
| 105 | + |
| 106 | +# |
| 107 | +# The following tests are used by test_nose_image_comparison to ensure that the |
| 108 | +# image_comparison decorator continues to work with nose. They should not be |
| 109 | +# prefixed by test_ so they don't run with pytest. |
| 110 | +# |
| 111 | + |
| 112 | +def nosetest_empty(): |
| 113 | + pass |
| 114 | + |
| 115 | + |
| 116 | +def nosetest_simple_figure(): |
| 117 | + import matplotlib.pyplot as plt |
| 118 | + fig, ax = plt.subplots(figsize=(6.4, 4), dpi=100) |
| 119 | + ax.plot([1, 2, 3], [3, 4, 5]) |
| 120 | + return fig |
| 121 | + |
| 122 | + |
| 123 | +def nosetest_manual_text_removal(): |
| 124 | + from matplotlib.testing.decorators import ImageComparisonTest |
| 125 | + |
| 126 | + fig = nosetest_simple_figure() |
| 127 | + with warnings.catch_warnings(record=True) as w: |
| 128 | + warnings.simplefilter('always') |
| 129 | + # Make sure this removes text like it should. |
| 130 | + ImageComparisonTest.remove_text(fig) |
| 131 | + |
| 132 | + assert len(w) == 1 |
| 133 | + assert 'remove_text function was deprecated in version 2.1.' in str(w[0]) |
| 134 | + |
| 135 | + |
| 136 | +@pytest.mark.parametrize( |
| 137 | + 'func, kwargs, errors, failures, dots', |
| 138 | + [ |
| 139 | + (nosetest_empty, {'baseline_images': []}, [], [], ''), |
| 140 | + (nosetest_empty, {'baseline_images': ['foo']}, |
| 141 | + [(AssertionError, |
| 142 | + 'Test generated 0 images but there are 1 baseline images')], |
| 143 | + [], |
| 144 | + 'E'), |
| 145 | + (nosetest_simple_figure, |
| 146 | + {'baseline_images': ['basn3p02'], 'extensions': ['png'], |
| 147 | + 'remove_text': True}, |
| 148 | + [], |
| 149 | + [(ImageComparisonFailure, 'Image sizes do not match expected size:')], |
| 150 | + 'F'), |
| 151 | + (nosetest_simple_figure, |
| 152 | + {'baseline_images': ['simple']}, |
| 153 | + [], |
| 154 | + [(ImageComparisonFailure, 'images not close')] * 3, |
| 155 | + 'FFF'), |
| 156 | + (nosetest_simple_figure, |
| 157 | + {'baseline_images': ['simple'], 'remove_text': True}, |
| 158 | + [], |
| 159 | + [], |
| 160 | + '...'), |
| 161 | + (nosetest_manual_text_removal, |
| 162 | + {'baseline_images': ['simple']}, |
| 163 | + [], |
| 164 | + [], |
| 165 | + '...'), |
| 166 | + ], |
| 167 | + ids=[ |
| 168 | + 'empty', |
| 169 | + 'extra baselines', |
| 170 | + 'incorrect shape', |
| 171 | + 'failing figure', |
| 172 | + 'passing figure', |
| 173 | + 'manual text removal', |
| 174 | + ]) |
| 175 | +def test_nose_image_comparison(func, kwargs, errors, failures, dots, |
| 176 | + monkeypatch): |
| 177 | + nose = pytest.importorskip('nose') |
| 178 | + monkeypatch.setattr('matplotlib._called_from_pytest', False) |
| 179 | + |
| 180 | + class TestResultVerifier(nose.result.TextTestResult): |
| 181 | + def __init__(self, *args, **kwargs): |
| 182 | + super(TestResultVerifier, self).__init__(*args, **kwargs) |
| 183 | + self.error_count = 0 |
| 184 | + self.failure_count = 0 |
| 185 | + |
| 186 | + def addError(self, test, err): |
| 187 | + super(TestResultVerifier, self).addError(test, err) |
| 188 | + |
| 189 | + if self.error_count < len(errors): |
| 190 | + assert err[0] is errors[self.error_count][0] |
| 191 | + assert errors[self.error_count][1] in str(err[1]) |
| 192 | + else: |
| 193 | + raise err[1] |
| 194 | + self.error_count += 1 |
| 195 | + |
| 196 | + def addFailure(self, test, err): |
| 197 | + super(TestResultVerifier, self).addFailure(test, err) |
| 198 | + |
| 199 | + assert self.failure_count < len(failures), err[1] |
| 200 | + assert err[0] is failures[self.failure_count][0] |
| 201 | + assert failures[self.failure_count][1] in str(err[1]) |
| 202 | + self.failure_count += 1 |
| 203 | + |
| 204 | + func = image_comparison(**kwargs)(func) |
| 205 | + loader = nose.loader.TestLoader() |
| 206 | + suite = loader.loadTestsFromGenerator( |
| 207 | + func, |
| 208 | + 'matplotlib.tests.test_compare_images') |
| 209 | + output = io.StringIO() |
| 210 | + result = TestResultVerifier(stream=output, descriptions=True, verbosity=1) |
| 211 | + with warnings.catch_warnings(): |
| 212 | + # Nose uses deprecated stuff; we don't care about it. |
| 213 | + warnings.simplefilter('ignore', DeprecationWarning) |
| 214 | + suite.run(result=result) |
| 215 | + |
| 216 | + assert output.getvalue() == dots |
| 217 | + assert result.error_count == len(errors) |
| 218 | + assert result.failure_count == len(failures) |
0 commit comments