Passed
Push — master ( 9e03c4...3276cc )
by Jaisen
02:00
created

elodie.tests.media.photo_test   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 405
Duplicated Lines 32.1 %

Importance

Changes 0
Metric Value
eloc 255
dl 130
loc 405
rs 9.1199
c 0
b 0
f 0
wmc 41

30 Functions

Rating   Name   Duplication   Size   Complexity  
A test_get_date_taken() 0 6 1
A test_empty_album() 0 3 1
A test_set_location_minus() 25 25 1
A test_get_camera_make() 0 5 1
A test_is_valid() 0 4 1
A test_is_valid_fallback_using_pillow() 0 4 1
A test_get_coordinate_longitude() 0 5 1
A _test_photo_type_set() 0 29 4
A test_get_coordinate_default() 0 5 1
A test_get_coordinates_without_exif() 0 7 1
A test_get_metadata_of_invalid_photo() 0 5 1
A test_has_album() 0 5 1
A test_get_coordinate_latitude() 0 5 1
A test_get_camera_make_not_set() 0 5 1
A test_set_title_non_ascii() 20 20 1
A test_various_types() 0 16 3
A test_get_camera_model_not_set() 0 5 1
A test_get_date_taken_without_exif() 0 8 1
A test_get_coordinates_with_zero_coordinate() 0 7 1
A test_set_location() 25 25 1
A test_get_coordinate_longitude_plus() 0 5 1
A test_photo_extensions() 0 17 1
A test_set_date_taken_with_missing_datetimeoriginal() 0 22 1
A test_is_not_valid() 0 4 1
A test_get_camera_model() 0 5 1
A test_get_coordinate_latitude_minus() 0 5 1
A test_set_date_taken() 20 20 1
A _test_photo_type_get() 0 25 5
A test_set_album() 21 21 1
A test_set_title() 19 19 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like elodie.tests.media.photo_test often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8
2
# Project imports
3
from __future__ import unicode_literals
4
import os
5
import sys
6
7
from datetime import datetime
8
import shutil
9
import tempfile
10
import time
11
12
from nose.plugins.skip import SkipTest
13
14
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))))
15
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
16
17
import helper
18
from elodie.media.media import Media
19
from elodie.media.photo import Photo
20
21
os.environ['TZ'] = 'GMT'
22
23
def test_photo_extensions():
24
    photo = Photo()
25
    extensions = photo.extensions
26
27
    assert 'arw' in extensions
28
    assert 'cr2' in extensions
29
    assert 'dng' in extensions
30
    assert 'gif' in extensions
31
    assert 'heic' in extensions
32
    assert 'jpg' in extensions
33
    assert 'jpeg' in extensions
34
    assert 'nef' in extensions
35
    assert 'rw2' in extensions
36
37
    valid_extensions = Photo.get_valid_extensions()
38
39
    assert extensions == valid_extensions, valid_extensions
40
41
def test_empty_album():
42
    photo = Photo(helper.get_file('plain.jpg'))
43
    assert photo.get_album() is None
44
45
def test_has_album():
46
    photo = Photo(helper.get_file('with-album.jpg'))
47
    album = photo.get_album()
48
49
    assert album == 'Test Album', album
50
51
def test_is_valid():
52
    photo = Photo(helper.get_file('plain.jpg'))
53
54
    assert photo.is_valid()
55
56
def test_is_not_valid():
57
    photo = Photo(helper.get_file('text.txt'))
58
59
    assert not photo.is_valid()
60
61
def test_get_metadata_of_invalid_photo():
62
    photo = Photo(helper.get_file('invalid.jpg'))
63
    metadata = photo.get_metadata()
64
65
    assert metadata is None
66
67
def test_get_coordinate_default():
68
    photo = Photo(helper.get_file('with-location.jpg'))
69
    coordinate = photo.get_coordinate()
70
71
    assert helper.isclose(coordinate,37.3667027222), coordinate
72
73
def test_get_coordinate_latitude():
74
    photo = Photo(helper.get_file('with-location.jpg'))
75
    coordinate = photo.get_coordinate('latitude')
76
77
    assert helper.isclose(coordinate,37.3667027222), coordinate
78
79
def test_get_coordinate_latitude_minus():
80
    photo = Photo(helper.get_file('with-location-inv.jpg'))
81
    coordinate = photo.get_coordinate('latitude')
82
83
    assert helper.isclose(coordinate,-37.3667027222), coordinate
84
85
def test_get_coordinate_longitude():
86
    photo = Photo(helper.get_file('with-location.jpg'))
87
    coordinate = photo.get_coordinate('longitude')
88
89
    assert helper.isclose(coordinate,-122.033383611), coordinate
90
91
def test_get_coordinate_longitude_plus():
92
    photo = Photo(helper.get_file('with-location-inv.jpg'))
93
    coordinate = photo.get_coordinate('longitude')
94
95
    assert helper.isclose(coordinate,122.033383611), coordinate
96
97
def test_get_coordinates_without_exif():
98
    photo = Photo(helper.get_file('no-exif.jpg'))
99
    latitude = photo.get_coordinate('latitude')
100
    longitude = photo.get_coordinate('longitude')
101
102
    assert latitude is None, latitude
103
    assert longitude is None, longitude
104
105
def test_get_coordinates_with_zero_coordinate():
106
    photo = Photo(helper.get_file('with-location-zero-coordinate.jpg'))
107
    latitude = photo.get_coordinate('latitude')
108
    longitude = photo.get_coordinate('longitude')
109
110
    assert helper.isclose(latitude,51.55325), latitude
111
    assert helper.isclose(longitude,-0.00417777777778), longitude
112
113
def test_get_date_taken():
114
    photo = Photo(helper.get_file('plain.jpg'))
115
    date_taken = photo.get_date_taken()
116
117
    #assert date_taken == (2015, 12, 5, 0, 59, 26, 5, 339, 0), date_taken
118
    assert date_taken == helper.time_convert((2015, 12, 5, 0, 59, 26, 5, 339, 0)), date_taken
119
120
def test_get_date_taken_without_exif():
121
    source = helper.get_file('no-exif.jpg')
122
    photo = Photo(source)
123
    date_taken = photo.get_date_taken()
124
125
    date_taken_from_file = time.gmtime(min(os.path.getmtime(source), os.path.getctime(source)))
126
127
    assert date_taken == date_taken_from_file, date_taken
128
129
def test_get_camera_make():
130
    photo = Photo(helper.get_file('with-location.jpg'))
131
    make = photo.get_camera_make()
132
133
    assert make == 'Canon', make
134
135
def test_get_camera_make_not_set():
136
    photo = Photo(helper.get_file('no-exif.jpg'))
137
    make = photo.get_camera_make()
138
139
    assert make is None, make
140
141
def test_get_camera_model():
142
    photo = Photo(helper.get_file('with-location.jpg'))
143
    model = photo.get_camera_model()
144
145
    assert model == 'Canon EOS REBEL T2i', model
146
147
def test_get_camera_model_not_set():
148
    photo = Photo(helper.get_file('no-exif.jpg'))
149
    model = photo.get_camera_model()
150
151
    assert model is None, model
152
153
def test_is_valid():
154
    photo = Photo(helper.get_file('with-location.jpg'))
155
156
    assert photo.is_valid()
157
158
def test_is_not_valid():
159
    photo = Photo(helper.get_file('text.txt'))
160
161
    assert not photo.is_valid()
162
163
def test_is_valid_fallback_using_pillow():
164
    photo = Photo(helper.get_file('imghdr-error.jpg'))
165
166
    assert photo.is_valid()
167
168
169 View Code Duplication
def test_set_album():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
170
    temporary_folder, folder = helper.create_working_folder()
171
172
    origin = '%s/photo.jpg' % folder
173
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
174
175
    photo = Photo(origin)
176
    metadata = photo.get_metadata()
177
178
    assert metadata['album'] is None, metadata['album']
179
180
    status = photo.set_album('Test Album')
181
182
    assert status == True, status
183
184
    photo_new = Photo(origin)
185
    metadata_new = photo_new.get_metadata()
186
187
    shutil.rmtree(folder)
188
189
    assert metadata_new['album'] == 'Test Album', metadata_new['album']
190
191
def test_set_date_taken_with_missing_datetimeoriginal():
192
    # When datetimeoriginal (or other key) is missing we have to add it gh-74
193
    # https://github.com/jmathai/elodie/issues/74
194
    temporary_folder, folder = helper.create_working_folder()
195
196
    origin = '%s/photo.jpg' % folder
197
    shutil.copyfile(helper.get_file('no-exif.jpg'), origin)
198
199
    photo = Photo(origin)
200
    status = photo.set_date_taken(datetime(2013, 9, 30, 7, 6, 5))
201
202
    assert status == True, status
203
204
    photo_new = Photo(origin)
205
    metadata = photo_new.get_metadata()
206
207
    date_taken = metadata['date_taken']
208
209
    shutil.rmtree(folder)
210
211
    #assert date_taken == (2013, 9, 30, 7, 6, 5, 0, 273, 0), metadata['date_taken']
212
    assert date_taken == helper.time_convert((2013, 9, 30, 7, 6, 5, 0, 273, 0)), metadata['date_taken']
213
214 View Code Duplication
def test_set_date_taken():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
215
    temporary_folder, folder = helper.create_working_folder()
216
217
    origin = '%s/photo.jpg' % folder
218
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
219
220
    photo = Photo(origin)
221
    status = photo.set_date_taken(datetime(2013, 9, 30, 7, 6, 5))
222
223
    assert status == True, status
224
225
    photo_new = Photo(origin)
226
    metadata = photo_new.get_metadata()
227
228
    date_taken = metadata['date_taken']
229
230
    shutil.rmtree(folder)
231
232
    #assert date_taken == (2013, 9, 30, 7, 6, 5, 0, 273, 0), metadata['date_taken']
233
    assert date_taken == helper.time_convert((2013, 9, 30, 7, 6, 5, 0, 273, 0)), metadata['date_taken']
234
235 View Code Duplication
def test_set_location():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
236
    temporary_folder, folder = helper.create_working_folder()
237
238
    origin = '%s/photo.jpg' % folder
239
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
240
241
    photo = Photo(origin)
242
    origin_metadata = photo.get_metadata()
243
244
    # Verify that original photo has different location info that what we
245
    #   will be setting and checking
246
    assert not helper.isclose(origin_metadata['latitude'], 11.1111111111), origin_metadata['latitude']
247
    assert not helper.isclose(origin_metadata['longitude'], 99.9999999999), origin_metadata['longitude']
248
249
    status = photo.set_location(11.1111111111, 99.9999999999)
250
251
    assert status == True, status
252
253
    photo_new = Photo(origin)
254
    metadata = photo_new.get_metadata()
255
256
    shutil.rmtree(folder)
257
258
    assert helper.isclose(metadata['latitude'], 11.1111111111), metadata['latitude']
259
    assert helper.isclose(metadata['longitude'], 99.9999999999), metadata['longitude']
260
261 View Code Duplication
def test_set_location_minus():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
262
    temporary_folder, folder = helper.create_working_folder()
263
264
    origin = '%s/photo.jpg' % folder
265
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
266
267
    photo = Photo(origin)
268
    origin_metadata = photo.get_metadata()
269
270
    # Verify that original photo has different location info that what we
271
    #   will be setting and checking
272
    assert not helper.isclose(origin_metadata['latitude'], 11.1111111111), origin_metadata['latitude']
273
    assert not helper.isclose(origin_metadata['longitude'], 99.9999999999), origin_metadata['longitude']
274
275
    status = photo.set_location(-11.1111111111, -99.9999999999)
276
277
    assert status == True, status
278
279
    photo_new = Photo(origin)
280
    metadata = photo_new.get_metadata()
281
282
    shutil.rmtree(folder)
283
284
    assert helper.isclose(metadata['latitude'], -11.1111111111), metadata['latitude']
285
    assert helper.isclose(metadata['longitude'], -99.9999999999), metadata['longitude']
286
287 View Code Duplication
def test_set_title():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
288
    temporary_folder, folder = helper.create_working_folder()
289
290
    origin = '%s/photo.jpg' % folder
291
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
292
293
    photo = Photo(origin)
294
    origin_metadata = photo.get_metadata()
295
296
    status = photo.set_title('my photo title')
297
298
    assert status == True, status
299
300
    photo_new = Photo(origin)
301
    metadata = photo_new.get_metadata()
302
303
    shutil.rmtree(folder)
304
305
    assert metadata['title'] == 'my photo title', metadata['title']
306
307 View Code Duplication
def test_set_title_non_ascii():
0 ignored issues
show
Duplication introduced by Jaisen Mathai
This code seems to be duplicated in your project.
Loading history...
308
    temporary_folder, folder = helper.create_working_folder()
309
310
    origin = '%s/photo.jpg' % folder
311
    shutil.copyfile(helper.get_file('plain.jpg'), origin)
312
313
    photo = Photo(origin)
314
    origin_metadata = photo.get_metadata()
315
316
    unicode_title = u'形声字 / 形聲字'
317
318
    status = photo.set_title(unicode_title)
319
    assert status == True, status
320
321
    photo_new = Photo(origin)
322
    metadata = photo_new.get_metadata()
323
324
    shutil.rmtree(folder)
325
326
    assert metadata['title'] == unicode_title, metadata['title']
327
328
# This is a test generator that will test reading and writing to
329
# various RAW formats. Each sample file has a different date which
330
# is the only information which needs to be added to run the tests
331
# for that file type.
332
# https://nose.readthedocs.io/en/latest/writing_tests.html#test-generators
333
def test_various_types():
334
    types = Photo.extensions
335
    #extensions = ('arw', 'cr2', 'dng', 'gif', 'jpeg', 'jpg', 'nef', 'rw2')
336
    dates = {
337
        'arw': (2007, 4, 8, 17, 41, 18, 6, 98, 0),
338
        'cr2': (2005, 10, 29, 16, 14, 44, 5, 302, 0),
339
        'dng': (2009, 10, 20, 9, 10, 46, 1, 293, 0),
340
        'heic': (2019, 5, 26, 10, 33, 20, 6, 146, 0),
341
        'nef': (2008, 10, 24, 9, 12, 56, 4, 298, 0),
342
        'rw2': (2014, 11, 19, 23, 7, 44, 2, 323, 0)
343
    }
344
345
    for type in types:
346
        if type in dates:
347
            yield (_test_photo_type_get, type, dates[type])
348
            yield (_test_photo_type_set, type, dates[type])
349
350
def _test_photo_type_get(type, date):
351
    temporary_folder, folder = helper.create_working_folder()
352
353
    photo_name = 'photo.{}'.format(type)
354
    photo_file = helper.get_file(photo_name)
355
    origin = '{}/{}'.format(folder, photo_name)
356
357
    if not photo_file:
358
        photo_file = helper.download_file(photo_name, folder)
359
        if not photo_file or not os.path.isfile(photo_file):
360
            raise SkipTest('{} file not downlaoded'.format(type))
361
362
        # downloading for each test is costly so we save it in the working directory
363
        file_path_save_as = helper.get_file_path(photo_name)
364
        if os.path.isfile(photo_file):
365
            shutil.copyfile(photo_file, file_path_save_as)
366
367
    shutil.copyfile(photo_file, origin)
368
369
    photo = Photo(origin)
370
    metadata = photo.get_metadata()
371
372
    shutil.rmtree(folder)
373
374
    assert metadata['date_taken'] == helper.time_convert(date), '{} date {}'.format(type, metadata['date_taken'])
375
376
def _test_photo_type_set(type, date):
377
    temporary_folder, folder = helper.create_working_folder()
378
379
    photo_name = 'photo.{}'.format(type)
380
    photo_file = helper.get_file(photo_name)
381
    origin = '{}/{}'.format(folder, photo_name)
382
383
    if not photo_file:
384
        photo_file = helper.download_file(photo_name, folder)
385
        if not photo_file or not os.path.isfile(photo_file):
386
            raise SkipTest('{} file not downlaoded'.format(type))
387
388
    shutil.copyfile(photo_file, origin)
389
390
    photo = Photo(origin)
391
    origin_metadata = photo.get_metadata()
392
393
    status = photo.set_location(11.1111111111, 99.9999999999)
394
395
    assert status == True, status
396
397
    photo_new = Photo(origin)
398
    metadata = photo_new.get_metadata()
399
400
    shutil.rmtree(folder)
401
402
    assert metadata['date_taken'] == helper.time_convert(date), '{} date {}'.format(type, metadata['date_taken'])
403
    assert helper.isclose(metadata['latitude'], 11.1111111111), '{} lat {}'.format(type, metadata['latitude'])
404
    assert helper.isclose(metadata['longitude'], 99.9999999999), '{} lon {}'.format(type, metadata['latitude'])
405