Passed
Pull Request — develop (#32)
by Angeline
01:35 queued 18s
created

test_dep_aacgmv2   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 320
Duplicated Lines 23.13 %

Importance

Changes 0
Metric Value
wmc 56
eloc 228
dl 74
loc 320
rs 5.5199
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A TestDepAACGMV2.test_convert_arr_single() 12 12 2
A TestDepAACGMV2Warning.test_igrf_dipole_axis_warning() 0 6 1
A TestDepAACGMV2.test_convert_location_failure() 0 10 2
A TestDepAACGMV2.test_convert_mult_array_mix() 17 17 2
A TestDepAACGMV2Warning.test_gc2gd_lat_warning() 0 6 1
A TestDepAACGMV2Warning.test_convert_warning() 0 6 1
A TestDepAACGMV2.test_convert_arr_mix() 12 12 2
A TestDepAACGMV2.test_gc2gd_lat_list() 0 8 2
A TestDepAACGMV2.teardown() 0 3 1
A TestDepAACGMV2.test_warning_below_ground_convert() 0 13 3
A TestDepAACGMV2.test_convert_list_mix() 0 12 2
A TestFutureDepWarning.setup() 0 5 1
A TestDepAACGMV2.test_convert_unequal_arra() 18 18 2
A TestDepAACGMV2.test_gc2gd_lat_arr() 0 8 2
A TestDepAACGMV2.test_convert_lat_failure() 0 6 3
A TestDepAACGMV2.test_convert_time_failure() 0 6 3
A TestFutureDepWarning.teardown() 0 2 1
A TestFutureDepWarning.test_future_dep_warning() 0 16 3
A TestDepAACGMV2Warning.setup() 0 5 1
A TestDepAACGMV2.test_subsol() 0 12 2
A TestDepAACGMV2.test_convert_list() 0 22 3
A TestDepAACGMV2.test_gc2gd_lat() 0 7 2
A TestDepAACGMV2.test_convert_maxalt_failure() 0 7 3
A TestDepAACGMV2.test_convert_arr() 15 15 2
A TestDepAACGMV2Warning.teardown() 0 2 1
A TestDepAACGMV2Warning.test_subsol_warning() 0 8 1
A TestDepAACGMV2.test_convert_single_val() 0 11 2
A TestDepAACGMV2.test_convert_datetime_date() 0 8 2
A TestDepAACGMV2.test_igrf_dipole_axis() 0 8 2
A TestDepAACGMV2.setup() 0 6 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 test_dep_aacgmv2 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
from __future__ import division, absolute_import, unicode_literals
3
4
import datetime as dt
5
import numpy as np
6
import pytest
7
import aacgmv2
8
import warnings
9
10
class TestFutureDepWarning:
11
    def setup(self):
12
        # Initialize the routine to be tested
13
        self.test_routine = None
14
        self.test_args = []
15
        self.test_kwargs = {}
16
17
    def teardown(self):
18
        del self.test_routine, self.test_args, self.test_kwargs
19
20
    def test_future_dep_warning(self):
21
        """Test the implementation of FutureWarning for deprecated routines"""
22
        if self.test_routine is None:
23
            assert True
24
        else:
25
            with warnings.catch_warnings(record=True) as w:
26
                # Cause all warnings to always be triggered.
27
                warnings.simplefilter("always")
28
29
                # Trigger a warning.
30
                self.test_routine(*self.test_args, **self.test_kwargs)
31
32
                # Verify some things
33
                assert len(w) == 1
34
                assert issubclass(w[-1].category, FutureWarning)
35
                assert "Deprecated routine" in str(w[-1].message)
36
37
38
class TestDepAACGMV2Warning(TestFutureDepWarning):
39
    def setup(self):
40
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
41
        self.test_routine = None
42
        self.test_args = []
43
        self.test_kwargs = {}
44
45
    def teardown(self):
46
        del self.dtime, self.test_routine, self.test_args, self.test_kwargs
47
48
    def test_convert_warning(self):
49
        """Test future deprecation warning for convert"""
50
51
        self.test_routine = aacgmv2.deprecated.convert
52
        self.test_args = [60, 0, 300, self.dtime]
53
        self.test_future_dep_warning()
54
55
    def test_subsol_warning(self):
56
        """Test future deprecation warning for subsol"""
57
58
        self.test_routine = aacgmv2.deprecated.subsol
59
        self.test_args = [self.dtime.year, int(self.dtime.strftime("%j")),
60
                          self.dtime.second + self.dtime.minute * 60 +
61
                          self.dtime.hour * 3600]
62
        self.test_future_dep_warning()
63
64
    def test_gc2gd_lat_warning(self):
65
        """Test future deprecation warning for gc2gd_lat"""
66
67
        self.test_routine = aacgmv2.deprecated.gc2gd_lat
68
        self.test_args = [60.0]
69
        self.test_future_dep_warning()
70
71
    def test_igrf_dipole_axis_warning(self):
72
        """Test future deprecation warning for igrf_dipole_axis"""
73
74
        self.test_routine = aacgmv2.deprecated.igrf_dipole_axis
75
        self.test_args = [self.dtime]
76
        self.test_future_dep_warning()
77
        
78
class TestDepAACGMV2:
79
    def setup(self):
80
        """Runs before every method to create a clean testing setup"""
81
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
82
        self.ddate = dt.date(2015, 1, 1)
83
        self.lat = None
84
        self.lon = None
85
86
    def teardown(self):
87
        """Runs after every method to clean up previous testing"""
88
        del self.dtime, self.ddate, self.lat, self.lon
89
90
    def test_convert_single_val(self):
91
        """Test conversion for a single value"""
92
        with warnings.catch_warnings():
93
            warnings.simplefilter("ignore")
94
            self.lat, self.lon = aacgmv2.convert(60, 0, 300, self.dtime)
95
96
        assert isinstance(self.lat, np.ndarray)
97
        assert isinstance(self.lon, np.ndarray)
98
        assert self.lat.shape == self.lon.shape and self.lat.shape == (1,)
99
        np.testing.assert_allclose(self.lat, [58.2258], rtol=1e-4)
100
        np.testing.assert_allclose(self.lon, [81.1685], rtol=1e-4)
101
102
    def test_convert_list(self):
103
        """Test conversion for list input"""
104
        with warnings.catch_warnings():
105
            warnings.simplefilter("ignore")
106
            self.lat, self.lon = aacgmv2.convert([60], [0], [300], self.dtime)
107
108
        assert isinstance(self.lat, np.ndarray)
109
        assert isinstance(self.lon, np.ndarray)
110
        assert self.lat.shape == self.lon.shape and self.lat.shape == (1,)
111
        np.testing.assert_allclose(self.lat, [58.2258], rtol=1e-4)
112
        np.testing.assert_allclose(self.lon, [81.1685], rtol=1e-4)
113
114
        with warnings.catch_warnings():
115
            warnings.simplefilter("ignore")
116
            self.lat, self.lon = aacgmv2.convert([60, 61], [0, 0], [300, 300],
117
                                                 self.dtime)
118
119
        assert isinstance(self.lat, np.ndarray)
120
        assert isinstance(self.lon, np.ndarray)
121
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2,)
122
        np.testing.assert_allclose(self.lat, [58.2258, 59.3186], rtol=1e-4)
123
        np.testing.assert_allclose(self.lon, [81.1685, 81.6140], rtol=1e-4)
124
125 View Code Duplication
    def test_convert_arr_single(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
126
        """Test conversion for array input with one element"""
127
        with warnings.catch_warnings():
128
            warnings.simplefilter("ignore")
129
            self.lat, self.lon = aacgmv2.convert(np.array([60]), np.array([0]),
130
                                                 np.array([300]), self.dtime)
131
132
        assert isinstance(self.lat, np.ndarray)
133
        assert isinstance(self.lon, np.ndarray)
134
        assert self.lat.shape == self.lon.shape and self.lat.shape == (1,)
135
        np.testing.assert_allclose(self.lat, [58.2258], rtol=1e-4)
136
        np.testing.assert_allclose(self.lon, [81.1685], rtol=1e-4)
137
138 View Code Duplication
    def test_convert_arr(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
139
        """Test conversion for array input"""
140
        
141
        with warnings.catch_warnings():
142
            warnings.simplefilter("ignore")
143
            self.lat, self.lon = aacgmv2.convert(np.array([60, 61]),
144
                                                 np.array([0, 0]),
145
                                                 np.array([300, 300]),
146
                                                 self.dtime)
147
148
        assert isinstance(self.lat, np.ndarray)
149
        assert isinstance(self.lon, np.ndarray)
150
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2,)
151
        np.testing.assert_allclose(self.lat, [58.2258, 59.3186], rtol=1e-4)
152
        np.testing.assert_allclose(self.lon, [81.1685, 81.6140], rtol=1e-4)
153
154
    def test_convert_list_mix(self):
155
        """Test conversion for a list and floats"""
156
        
157
        with warnings.catch_warnings():
158
            warnings.simplefilter("ignore")
159
            self.lat, self.lon = aacgmv2.convert([60, 61], 0, 300, self.dtime)
160
161
        assert isinstance(self.lat, np.ndarray)
162
        assert isinstance(self.lon, np.ndarray)
163
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2,)
164
        np.testing.assert_allclose(self.lat, [58.2258, 59.3186], rtol=1e-4)
165
        np.testing.assert_allclose(self.lon, [81.1685, 81.6140], rtol=1e-4)
166
167 View Code Duplication
    def test_convert_arr_mix(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
168
        """Test conversion for an array and floats"""
169
        with warnings.catch_warnings():
170
            warnings.simplefilter("ignore")
171
            self.lat, self.lon = aacgmv2.convert(np.array([60, 61]), 0, 300,
172
                                                 self.dtime)
173
174
        assert isinstance(self.lat, np.ndarray)
175
        assert isinstance(self.lon, np.ndarray)
176
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2,)
177
        np.testing.assert_allclose(self.lat, [58.2258, 59.3186], rtol=1e-4)
178
        np.testing.assert_allclose(self.lon, [81.1685, 81.6140], rtol=1e-4)
179
180 View Code Duplication
    def test_convert_mult_array_mix(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
181
        """Test conversion for a multi-dim array and floats"""
182
        with warnings.catch_warnings():
183
            warnings.simplefilter("ignore")
184
            self.lat, self.lon = aacgmv2.convert(np.array([[60, 61, 62],
185
                                                           [63, 64, 65]]), 0,
186
                                                 300, self.dtime)
187
188
        assert isinstance(self.lat, np.ndarray)
189
        assert isinstance(self.lon, np.ndarray)
190
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2, 3)
191
        np.testing.assert_allclose(self.lat, [[58.2258, 59.3186, 60.4040],
192
                                         [61.4820, 62.5528, 63.6164]],
193
                                   rtol=1e-4)
194
        np.testing.assert_allclose(self.lon, [[81.1685, 81.6140, 82.0872],
195
                                         [82.5909, 83.1286, 83.7039]],
196
                                   rtol=1e-4)
197
198 View Code Duplication
    def test_convert_unequal_arra(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
199
        """Test conversion for unequal sized arrays"""
200
        with warnings.catch_warnings():
201
            warnings.simplefilter("ignore")
202
            self.lat, self.lon = aacgmv2.convert(np.array([[60, 61, 62],
203
                                                           [63, 64, 65]]),
204
                                                 np.array([0]), np.array([300]),
205
                                                 self.dtime)
206
207
        assert isinstance(self.lat, np.ndarray)
208
        assert isinstance(self.lon, np.ndarray)
209
        assert self.lat.shape == self.lon.shape and self.lat.shape == (2, 3)
210
        np.testing.assert_allclose(self.lat, [[58.2258, 59.3186, 60.4040],
211
                                              [61.4820, 62.5528, 63.6164]],
212
                                   rtol=1e-4)
213
        np.testing.assert_allclose(self.lon, [[81.1685, 81.6140, 82.0872],
214
                                              [82.5909, 83.1286, 83.7039]],
215
                                   rtol=1e-4)
216
217
    def test_convert_location_failure(self):
218
        """Test conversion with a bad location"""
219
        with warnings.catch_warnings():
220
            warnings.simplefilter("ignore")
221
            self.lat, self.lon = aacgmv2.convert([0], [0], [0], self.dtime)
222
223
        assert isinstance(self.lat, np.ndarray)
224
        assert isinstance(self.lon, np.ndarray)
225
        assert self.lat.shape == self.lon.shape and self.lat.shape == (1,)
226
        assert np.all([np.isnan(self.lat), np.isnan(self.lon)])
227
228
    def test_convert_time_failure(self):
229
        """Test conversion with a bad time"""
230
        with pytest.raises(AssertionError):
231
            with warnings.catch_warnings():
232
                warnings.simplefilter("ignore")
233
                self.lat, self.lon = aacgmv2.convert([60], [0], [300], None)
234
235
    def test_convert_datetime_date(self):
236
        """Test conversion with date and datetime input"""
237
        with warnings.catch_warnings():
238
            warnings.simplefilter("ignore")
239
            self.lat, self.lon = aacgmv2.convert([60], [0], [300], self.ddate)
240
241
        np.testing.assert_allclose(self.lat, [58.2258], rtol=1e-4)
242
        np.testing.assert_allclose(self.lon, [81.1685], rtol=1e-4)
243
244
    def test_warning_below_ground_convert(self):
245
        """ Test that a warning is issued if altitude is below zero"""
246
        import logbook
247
        lwarn = u"conversion not intended for altitudes < 0 km"
248
249
        with logbook.TestHandler() as handler:
250
            with warnings.catch_warnings():
251
                warnings.simplefilter("ignore")
252
                self.lat, self.lon = aacgmv2.convert([60], [0], [-1],
253
                                                     self.dtime)
254
                assert handler.has_warning(lwarn)
255
256
        handler.close()
257
258
    def test_convert_maxalt_failure(self):
259
        """For an array, test failure for an altitude too high for
260
        coefficients"""
261
        with pytest.raises(ValueError):
262
            with warnings.catch_warnings():
263
                warnings.simplefilter("ignore")
264
                aacgmv2.convert([60], [0], [2001], self.dtime)
265
266
    def test_convert_lat_failure(self):
267
        """Test error return for co-latitudes above 90 for an array"""
268
        with pytest.raises(AssertionError):
269
            with warnings.catch_warnings():
270
                warnings.simplefilter("ignore")
271
                aacgmv2.convert([91, 60, -91], 0, 300, self.dtime)
272
273
    def test_subsol(self):
274
        """Test the subsolar calculation"""
275
        doy = int(self.dtime.strftime("%j"))
276
        ut = self.dtime.hour * 3600.0 + self.dtime.minute * 60.0 + \
277
             self.dtime.second
278
        with warnings.catch_warnings():
279
            warnings.simplefilter("ignore")
280
            self.lon, self.lat = aacgmv2.deprecated.subsol(self.dtime.year,
281
                                                           doy, ut)
282
283
        np.testing.assert_almost_equal(self.lon, -179.2004, decimal=4)
284
        np.testing.assert_almost_equal(self.lat, -23.0431, decimal=4)
285
286
    def test_gc2gd_lat(self):
287
        """Test the geocentric to geodetic conversion"""
288
        with warnings.catch_warnings():
289
            warnings.simplefilter("ignore")
290
            self.lat = aacgmv2.deprecated.gc2gd_lat(45.0)
291
292
        np.testing.assert_almost_equal(self.lat, 45.1924, decimal=4)
293
294
    def test_gc2gd_lat_list(self):
295
        """Test the geocentric to geodetic conversion"""
296
        self.lat = [45.0, -45.0]
297
        with warnings.catch_warnings():
298
            warnings.simplefilter("ignore")
299
            self.lat = aacgmv2.deprecated.gc2gd_lat(self.lat)
300
301
        np.testing.assert_allclose(self.lat, [45.1924, -45.1924], rtol=1.0e-4)
302
303
    def test_gc2gd_lat_arr(self):
304
        """Test the geocentric to geodetic conversion"""
305
        self.lat = np.array([45.0, -45.0])
306
        with warnings.catch_warnings():
307
            warnings.simplefilter("ignore")
308
            self.lat = aacgmv2.deprecated.gc2gd_lat(self.lat)
309
310
        np.testing.assert_allclose(self.lat, [45.1924, -45.1924], rtol=1.0e-4)
311
312
    def test_igrf_dipole_axis(self):
313
        """Test the IGRF dipole axis calculation"""
314
        with warnings.catch_warnings():
315
            warnings.simplefilter("ignore")
316
            m = aacgmv2.deprecated.igrf_dipole_axis(self.dtime)
317
318
        np.testing.assert_allclose(m, [0.050253, -0.160608, 0.985738],
319
                                   rtol=1.0e-4)
320