forked from python-openxml/python-docx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_image.py
More file actions
332 lines (274 loc) · 12.2 KB
/
test_image.py
File metadata and controls
332 lines (274 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# encoding: utf-8
"""
Test suite for docx.image package
"""
from __future__ import absolute_import, print_function, unicode_literals
import pytest
from docx.compat import BytesIO
from docx.image.bmp import Bmp
from docx.image.exceptions import UnrecognizedImageError
from docx.image.gif import Gif
from docx.image.image import BaseImageHeader, Image, _ImageHeaderFactory
from docx.image.jpeg import Exif, Jfif
from docx.image.png import Png
from docx.image.tiff import Tiff
from docx.opc.constants import CONTENT_TYPE as CT
from docx.shared import Emu, Length
from ..unitutil.file import test_file
from ..unitutil.mock import (
function_mock, class_mock, initializer_mock, instance_mock, method_mock,
property_mock
)
class DescribeImage(object):
def it_can_construct_from_an_image_blob(self, from_blob_fixture):
blob_, BytesIO_, _from_stream_, stream_, image_ = from_blob_fixture
image = Image.from_blob(blob_)
BytesIO_.assert_called_once_with(blob_)
_from_stream_.assert_called_once_with(stream_, blob_)
assert image is image_
def it_can_construct_from_an_image_path(self, from_path_fixture):
image_path, _from_stream_, stream_, blob, filename, image_ = (
from_path_fixture
)
image = Image.from_file(image_path)
_from_stream_.assert_called_once_with(stream_, blob, filename)
assert image is image_
def it_can_construct_from_an_image_file_like(self, from_filelike_fixture):
image_stream, _from_stream_, blob, image_ = from_filelike_fixture
image = Image.from_file(image_stream)
_from_stream_.assert_called_once_with(image_stream, blob, None)
assert image is image_
def it_can_construct_from_an_image_stream(self, from_stream_fixture):
# fixture ----------------------
stream_, blob_, filename_in = from_stream_fixture[:3]
_ImageHeaderFactory_, image_header_ = from_stream_fixture[3:5]
Image__init_, filename_out = from_stream_fixture[5:]
# exercise ---------------------
image = Image._from_stream(stream_, blob_, filename_in)
# verify -----------------------
_ImageHeaderFactory_.assert_called_once_with(stream_)
Image__init_.assert_called_once_with(
blob_, filename_out, image_header_
)
assert isinstance(image, Image)
def it_provides_access_to_the_image_blob(self):
blob = b'foobar'
image = Image(blob, None, None)
assert image.blob == blob
def it_knows_the_image_content_type(self, content_type_fixture):
image_header_, content_type = content_type_fixture
image = Image(None, None, image_header_)
assert image.content_type == content_type
def it_knows_the_image_px_dimensions(self, dimensions_fixture):
image_header_, px_width, px_height = dimensions_fixture
image = Image(None, None, image_header_)
assert image.px_width == px_width
assert image.px_height == px_height
def it_knows_the_horz_and_vert_dpi_of_the_image(self, dpi_fixture):
image_header_, horz_dpi, vert_dpi = dpi_fixture
image = Image(None, None, image_header_)
assert image.horz_dpi == horz_dpi
assert image.vert_dpi == vert_dpi
def it_knows_the_image_native_size(self, size_fixture):
image, width, height = size_fixture
assert (image.width, image.height) == (width, height)
assert isinstance(image.width, Length)
assert isinstance(image.height, Length)
def it_can_scale_its_dimensions(self, scale_fixture):
image, width, height, expected_value = scale_fixture
scaled_width, scaled_height = image.scaled_dimensions(width, height)
assert (scaled_width, scaled_height) == expected_value
assert isinstance(scaled_width, Length)
assert isinstance(scaled_height, Length)
def it_knows_the_image_filename(self):
filename = 'foobar.png'
image = Image(None, filename, None)
assert image.filename == filename
def it_knows_the_image_filename_extension(self):
image = Image(None, 'foobar.png', None)
assert image.ext == 'png'
def it_knows_the_sha1_of_its_image(self):
blob = b'fO0Bar'
image = Image(blob, None, None)
assert image.sha1 == '4921e7002ddfba690a937d54bda226a7b8bdeb68'
def it_correctly_characterizes_known_images(self, known_image_fixture):
image_path, characteristics = known_image_fixture
ext, content_type, px_width, px_height, horz_dpi, vert_dpi = (
characteristics
)
with open(test_file(image_path), 'rb') as stream:
image = Image.from_file(stream)
assert image.content_type == content_type
assert image.ext == ext
assert image.px_width == px_width
assert image.px_height == px_height
assert image.horz_dpi == horz_dpi
assert image.vert_dpi == vert_dpi
# fixtures -------------------------------------------------------
@pytest.fixture
def content_type_fixture(self, image_header_):
content_type = 'image/foobar'
image_header_.content_type = content_type
return image_header_, content_type
@pytest.fixture
def dimensions_fixture(self, image_header_):
px_width, px_height = 111, 222
image_header_.px_width = px_width
image_header_.px_height = px_height
return image_header_, px_width, px_height
@pytest.fixture
def dpi_fixture(self, image_header_):
horz_dpi, vert_dpi = 333, 444
image_header_.horz_dpi = horz_dpi
image_header_.vert_dpi = vert_dpi
return image_header_, horz_dpi, vert_dpi
@pytest.fixture
def from_blob_fixture(
self, blob_, BytesIO_, _from_stream_, stream_, image_):
return blob_, BytesIO_, _from_stream_, stream_, image_
@pytest.fixture
def from_filelike_fixture(self, _from_stream_, image_):
image_path = test_file('python-icon.png')
with open(image_path, 'rb') as f:
blob = f.read()
image_stream = BytesIO(blob)
return image_stream, _from_stream_, blob, image_
@pytest.fixture
def from_path_fixture(self, _from_stream_, BytesIO_, stream_, image_):
filename = 'python-icon.png'
image_path = test_file(filename)
with open(image_path, 'rb') as f:
blob = f.read()
return image_path, _from_stream_, stream_, blob, filename, image_
@pytest.fixture(params=['foobar.png', None])
def from_stream_fixture(
self, request, stream_, blob_, _ImageHeaderFactory_,
image_header_, Image__init_):
filename_in = request.param
filename_out = 'image.png' if filename_in is None else filename_in
return (
stream_, blob_, filename_in, _ImageHeaderFactory_, image_header_,
Image__init_, filename_out
)
@pytest.fixture(params=[0, 1, 2, 3, 4, 5, 6, 7, 8])
def known_image_fixture(self, request):
cases = (
('python.bmp', ('bmp', CT.BMP, 211, 71, 96, 96)),
('sonic.gif', ('gif', CT.GIF, 290, 360, 72, 72)),
('python-icon.jpeg', ('jpg', CT.JPEG, 204, 204, 72, 72)),
('300-dpi.jpg', ('jpg', CT.JPEG, 1504, 1936, 300, 300)),
('monty-truth.png', ('png', CT.PNG, 150, 214, 72, 72)),
('150-dpi.png', ('png', CT.PNG, 901, 1350, 150, 150)),
('300-dpi.png', ('png', CT.PNG, 860, 579, 300, 300)),
('72-dpi.tiff', ('tiff', CT.TIFF, 48, 48, 72, 72)),
('300-dpi.TIF', ('tiff', CT.TIFF, 2464, 3248, 300, 300)),
# ('CVS_LOGO.WMF', ('wmf', CT.X_WMF, 149, 59, 72, 72)),
)
image_filename, characteristics = cases[request.param]
return image_filename, characteristics
@pytest.fixture(params=[
(None, None, 1000, 2000),
(100, None, 100, 200),
(None, 500, 250, 500),
(1500, 1500, 1500, 1500),
])
def scale_fixture(self, request, width_prop_, height_prop_):
width, height, scaled_width, scaled_height = request.param
width_prop_.return_value = Emu(1000)
height_prop_.return_value = Emu(2000)
image = Image(None, None, None)
return image, width, height, (scaled_width, scaled_height)
@pytest.fixture
def size_fixture(self, image_header_):
image_header_.px_width, image_header_.px_height = 150, 75
image_header_.horz_dpi, image_header_.vert_dpi = 72, 200
image = Image(None, None, image_header_)
return image, 1905000, 342900
# fixture components ---------------------------------------------
@pytest.fixture
def blob_(self, request):
return instance_mock(request, bytes)
@pytest.fixture
def BytesIO_(self, request, stream_):
return class_mock(
request, 'docx.image.image.BytesIO', return_value=stream_
)
@pytest.fixture
def filename_(self, request):
return instance_mock(request, str)
@pytest.fixture
def _from_stream_(self, request, image_):
return method_mock(
request, Image, '_from_stream', return_value=image_
)
@pytest.fixture
def height_prop_(self, request):
return property_mock(request, Image, 'height')
@pytest.fixture
def image_(self, request):
return instance_mock(request, Image)
@pytest.fixture
def _ImageHeaderFactory_(self, request, image_header_):
return function_mock(
request, 'docx.image.image._ImageHeaderFactory',
return_value=image_header_
)
@pytest.fixture
def image_header_(self, request):
return instance_mock(request, BaseImageHeader, default_ext='png')
@pytest.fixture
def Image__init_(self, request):
return initializer_mock(request, Image)
@pytest.fixture
def stream_(self, request):
return instance_mock(request, BytesIO)
@pytest.fixture
def width_prop_(self, request):
return property_mock(request, Image, 'width')
class Describe_ImageHeaderFactory(object):
def it_constructs_the_right_class_for_a_given_image_stream(
self, call_fixture):
stream, expected_class = call_fixture
image_header = _ImageHeaderFactory(stream)
assert isinstance(image_header, expected_class)
def it_raises_on_unrecognized_image_stream(self):
stream = BytesIO(b'foobar 666 not an image stream')
with pytest.raises(UnrecognizedImageError):
_ImageHeaderFactory(stream)
# fixtures -------------------------------------------------------
@pytest.fixture(params=[
('python-icon.png', Png),
('python-icon.jpeg', Jfif),
('exif-420-dpi.jpg', Exif),
('sonic.gif', Gif),
('72-dpi.tiff', Tiff),
('little-endian.tif', Tiff),
('python.bmp', Bmp),
])
def call_fixture(self, request):
image_filename, expected_class = request.param
image_path = test_file(image_filename)
with open(image_path, 'rb') as f:
blob = f.read()
image_stream = BytesIO(blob)
image_stream.seek(666)
return image_stream, expected_class
class DescribeBaseImageHeader(object):
def it_defines_content_type_as_an_abstract_property(self):
base_image_header = BaseImageHeader(None, None, None, None)
with pytest.raises(NotImplementedError):
base_image_header.content_type
def it_defines_default_ext_as_an_abstract_property(self):
base_image_header = BaseImageHeader(None, None, None, None)
with pytest.raises(NotImplementedError):
base_image_header.default_ext
def it_knows_the_image_dimensions(self):
px_width, px_height = 42, 24
image_header = BaseImageHeader(px_width, px_height, None, None)
assert image_header.px_width == px_width
assert image_header.px_height == px_height
def it_knows_the_horz_and_vert_dpi_of_the_image(self):
horz_dpi, vert_dpi = 42, 24
image_header = BaseImageHeader(None, None, horz_dpi, vert_dpi)
assert image_header.horz_dpi == horz_dpi
assert image_header.vert_dpi == vert_dpi