Completed
Pull Request — master (#48)
by Angeline
02:22 queued 01:15
created

test_py_aacgmv2.TestConvertCode.teardown()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
# -*- coding: utf-8 -*-
2
from __future__ import division, absolute_import, unicode_literals
3
4
import datetime as dt
5
from io import StringIO
6
import logging
7
import numpy as np
8
import os
9
from sys import version_info
10
import pytest
11
import warnings
12
13
import aacgmv2
14
15 View Code Duplication
class TestFutureDepWarning:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
16
    def setup(self):
17
        # Initialize the routine to be tested
18
        self.test_routine = None
19
        self.test_args = []
20
        self.test_kwargs = {}
21
22
    def teardown(self):
23
        del self.test_routine, self.test_args, self.test_kwargs
24
25
    def test_future_dep_warning(self):
26
        """Test the implementation of FutureWarning for deprecated kwargs"""
27
        if self.test_routine is None:
28
            assert True
29
        else:
30
            with warnings.catch_warnings(record=True) as wout:
31
                # Cause all warnings to always be triggered.
32
                warnings.simplefilter("always")
33
34
                # Trigger a warning.
35
                self.test_routine(*self.test_args, **self.test_kwargs)
36
37
                # Verify some things
38
                assert len(wout) == 1
39
                assert issubclass(wout[-1].category, FutureWarning)
40
                assert "Deprecated keyword" in str(wout[-1].message)
41
42
class TestDepConvertWarning(TestFutureDepWarning):
43
    def setup(self):
44
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
45
        self.test_routine = None
46
        self.test_args = []
47
        self.test_kwargs = {}
48
49
    def teardown(self):
50
        del self.dtime, self.test_routine, self.test_args, self.test_kwargs
51
52
    def test_convert_latlon_warning(self):
53
        """Test future warning for convert_latlon"""
54
55
        self.test_routine = aacgmv2.wrapper.convert_latlon
56
        self.test_args = [60, 0, 300, self.dtime]
57
        self.test_kwargs = {'code': 'TRACE'}
58
        self.test_future_dep_warning()
59
60
    def test_convert_latlon_arr_warning(self):
61
        """Test future warning for convert_latlon_arr"""
62
63
        self.test_routine = aacgmv2.wrapper.convert_latlon_arr
64
        self.test_args = [[60, 60], [0, 0], [300, 300], self.dtime]
65
        self.test_kwargs = {'code': 'TRACE'}
66
        self.test_future_dep_warning()
67
68
    def test_convert_latlon_time_error(self):
69
        """Test single value latlon conversion with a bad datetime"""
70
        self.test_routine = aacgmv2.wrapper.convert_latlon
71
        self.test_args = [60, 0, 300, self.dtime]
72
        self.test_kwargs = {'bad': 'keyword'}
73
        with pytest.raises(TypeError):
74
            self.test_routine(*self.test_args, **self.test_kwargs)
75
76
    def test_convert_latlon_arr_time_error(self):
77
        """Test single value latlon conversion with a bad datetime"""
78
        self.test_routine = aacgmv2.wrapper.convert_latlon_arr
79
        self.test_args = [[60, 60], [0, 0], [300, 300], self.dtime]
80
        self.test_kwargs = {'bad': 'keyword'}
81
        with pytest.raises(TypeError):
82
            self.test_routine(*self.test_args, **self.test_kwargs)
83
84
85
class TestConvertLatLon:
86
    def setup(self):
87
        """Runs before every method to create a clean testing setup"""
88
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
89
        self.ddate = dt.date(2015, 1, 1)
90
        self.in_args = [60, 0]
91
        self.out = None
92
        self.rtol = 1.0e-4
93
94
    def teardown(self):
95
        """Runs after every method to clean up previous testing"""
96
        del self.out, self.in_args, self.rtol, self.dtime, self.ddate
97
98
    @pytest.mark.parametrize('alt,method_code,ref',
99
                             [(300, 'TRACE', [58.2268,81.1613,1.0457]),
100
                              (3000.0, "G2A|BADIDEA", [64.3578,83.2895,1.4694]),
101
                              (7000.0, "G2A|TRACE|BADIDEA",
102
                               [69.3187,85.0845,2.0973])])
103
    def test_convert_latlon(self, alt, method_code, ref):
104
        """Test single value latlon conversion"""
105
        self.in_args.extend([alt, self.dtime, method_code])
106
        self.out = aacgmv2.convert_latlon(*self.in_args)
107
        np.testing.assert_allclose(self.out, ref, rtol=self.rtol)
108
109
    def test_convert_latlon_datetime_date(self):
110
        """Test single latlon conversion with date and datetime input"""
111
        self.in_args.extend([300, self.ddate, 'TRACE'])
112
        self.out = aacgmv2.convert_latlon(*self.in_args)
113
        np.testing.assert_allclose(self.out, [58.2268,81.1613,1.0457],
114
                                   rtol=self.rtol)
115
116
    @pytest.mark.skipif(version_info.major == 2,
117
                        reason='Not raised in Python 2')
118
    def test_convert_latlon_location_failure(self):
119
        """Test single value latlon conversion with a bad location"""
120
        self.out = aacgmv2.convert_latlon(0, 0, 0, self.dtime, self.in_args[-1])
121
        assert np.all(np.isnan(np.array(self.out)))
122
123
    def test_convert_latlon_time_failure(self):
124
        """Test single value latlon conversion with a bad datetime"""
125
        self.in_args.extend([300, None, 'TRACE'])
126
        with pytest.raises(ValueError):
127
            self.out = aacgmv2.convert_latlon(*self.in_args)
128
129
    def test_convert_latlon_maxalt_failure(self):
130
        """test convert_latlon failure for an altitude too high for coeffs"""
131
        self.in_args.extend([2001, self.dtime, ""])
132
        self.out = aacgmv2.convert_latlon(*self.in_args)
133
        assert np.all(np.isnan(np.array(self.out)))
134
135
    def test_convert_latlon_lat_high_failure(self):
136
        """Test error return for co-latitudes above 90 for a single value"""
137
        with pytest.raises(ValueError):
138
            aacgmv2.convert_latlon(91, 0, 300, self.dtime)
139
140
    def test_convert_latlon_lat_low_failure(self):
141
        """Test error return for co-latitudes below -90 for a single value"""
142
        with pytest.raises(ValueError):
143
            aacgmv2.convert_latlon(-91, 0, 300, self.dtime)
144
145
class TestConvertLatLonArr:
146 View Code Duplication
    def setup(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
147
        """Runs before every method to create a clean testing setup"""
148
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
149
        self.ddate = dt.date(2015, 1, 1)
150
        self.lat_in = [60.0, 61.0]
151
        self.lon_in = [0.0, 0.0]
152
        self.alt_in = [300.0, 300.0]
153
        self.method = 'TRACE'
154
        self.out = None
155
        self.ref = [[58.2268, 59.3184], [81.1613, 81.6080], [1.0457, 1.0456]]
156
        self.rtol = 1.0e-4
157
158
    def teardown(self):
159
        """Runs after every method to clean up previous testing"""
160
        del self.lat_in, self.lon_in, self.alt_in, self.dtime, self.ddate
161
        del self.method, self.out, self.ref, self.rtol
162
163
    def test_convert_latlon_arr_single_val(self):
164
        """Test array latlon conversion for a single value"""
165
        self.out = aacgmv2.convert_latlon_arr(self.lat_in[0], self.lon_in[0],
166
                                              self.alt_in[0], self.dtime,
167
                                              self.method)
168
169
        assert len(self.out) == len(self.ref)
170
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
171
172
        for i, oo in enumerate(self.out):
173
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
174
175 View Code Duplication
    def test_convert_latlon_arr_list_single(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
176
        """Test array latlon conversion for list input of single values"""
177
        self.out = aacgmv2.convert_latlon_arr([self.lat_in[0]],
178
                                              [self.lon_in[0]],
179
                                              [self.alt_in[0]], self.dtime,
180
                                              self.method)
181
182
        assert len(self.out) == len(self.ref)
183
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
184
185
        for i, oo in enumerate(self.out):
186
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
187
188
    def test_convert_latlon_arr_list(self):
189
        """Test array latlon conversion for list input"""
190
        self.out = aacgmv2.convert_latlon_arr(self.lat_in, self.lon_in,
191
                                              self.alt_in, self.dtime,
192
                                              self.method)
193
194
        assert len(self.out) == len(self.ref)
195
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.ref[i])
196
                for i, oo in enumerate(self.out)]
197
198
        for i, oo in enumerate(self.out):
199
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
200
201 View Code Duplication
    def test_convert_latlon_arr_arr_single(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
202
        """Test array latlon conversion for array input of shape (1,)"""
203
        self.out = aacgmv2.convert_latlon_arr(np.array([self.lat_in[0]]),
204
                                              np.array([self.lon_in[0]]),
205
                                              np.array([self.alt_in[0]]),
206
                                              self.dtime, self.method)
207
208
        assert len(self.out) == len(self.ref)
209
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
210
211
        for i, oo in enumerate(self.out):
212
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
213
214 View Code Duplication
    def test_convert_latlon_arr_arr(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
215
        """Test array latlon conversion for array input"""
216
        self.out = aacgmv2.convert_latlon_arr(np.array(self.lat_in),
217
                                              np.array(self.lon_in),
218
                                              np.array(self.alt_in),
219
                                              self.dtime, self.method)
220
221
        assert len(self.out) == len(self.ref)
222
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.ref[i])
223
                for i, oo in enumerate(self.out)]
224
225
        for i, oo in enumerate(self.out):
226
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
227
228
    def test_convert_latlon_arr_list_mix(self):
229
        """Test array latlon conversion for mixed types with list"""
230
        self.out = aacgmv2.convert_latlon_arr(self.lat_in, self.lon_in[0],
231
                                              self.alt_in[0], self.dtime,
232
                                              self.method)
233
234
        assert len(self.out) == len(self.ref)
235
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.ref[i])
236
                for i, oo in enumerate(self.out)]
237
238
        for i, oo in enumerate(self.out):
239
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
240
241
    def test_convert_latlon_arr_arr_mix(self):
242
        """Test array latlon conversion for mixed type with an array"""
243
        self.out = aacgmv2.convert_latlon_arr(np.array(self.lat_in),
244
                                              self.lon_in[0], self.alt_in[0],
245
                                              self.dtime, self.method)
246
247
        assert len(self.out) == len(self.ref)
248
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.ref[i])
249
                for i, oo in enumerate(self.out)]
250
251
        for i, oo in enumerate(self.out):
252
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
253
254
    def test_convert_latlon_arr_mult_failure(self):
255
        """Test array latlon conversion for mix type with multi-dim array"""
256
        with pytest.raises(ValueError):
257
            aacgmv2.convert_latlon_arr(np.full(shape=(3,2), fill_value=50.0),
258
                                       0, 300, self.dtime)
259
260
    @pytest.mark.parametrize('method_code,alt,ref',
261
                             [("BADIDEA", 3000.0, [64.3580,83.2895,1.4694]),
262
                              ("BADIDEA|TRACE", 7000.0,
263
                               [69.3187,85.0845,2.0973])])
264
    def test_convert_latlon_arr_badidea(self, method_code, alt, ref):
265
        """Test array latlon conversion for BADIDEA"""
266
        self.out = aacgmv2.convert_latlon_arr(self.lat_in[0], self.lon_in[0],
267
                                              [alt], self.dtime, method_code)
268
269
        assert len(self.out) == len(ref)
270
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
271
272
        for i, oo in enumerate(self.out):
273
            np.testing.assert_allclose(oo, [ref[i]], rtol=self.rtol)
274
275
    @pytest.mark.skipif(version_info.major == 2,
276
                        reason='Not raised in Python 2')
277
    def test_convert_latlon_arr_location_failure(self):
278
        """Test array latlon conversion with a bad location"""
279
280
        with warnings.catch_warnings():
281
            # Causes all warnings to be surpressed
282
            warnings.simplefilter("ignore")
283
284
            # Trigger a warning
285
            self.out = aacgmv2.convert_latlon_arr([0], [0], [0], self.dtime, "")
286
287
            # Test the output
288
            assert len(self.out) == len(self.ref)
289
            assert np.any(~np.isfinite(np.array(self.out)))
290
291
    def test_convert_latlon_arr_mult_arr_unequal_failure(self):
292
        """Test array latlon conversion for unequal sized arrays"""
293
        with pytest.raises(ValueError):
294
            aacgmv2.convert_latlon_arr(np.array([[60, 61, 62], [63, 64, 65]]),
295
                                       np.array([0, 1]), 300, self.dtime)
296
297
    def test_convert_latlon_arr_time_failure(self):
298
        """Test array latlon conversion with a bad time"""
299
        with pytest.raises(ValueError):
300
            aacgmv2.convert_latlon_arr(self.lat_in, self.lon_in, self.alt_in,
301
                                       None, self.method)
302
303
    def test_convert_latlon_arr_datetime_date(self):
304
        """Test array latlon conversion with date and datetime input"""
305
        self.out = aacgmv2.convert_latlon_arr(self.lat_in, self.lon_in,
306
                                              self.alt_in, self.ddate,
307
                                              self.method)
308
309
        assert len(self.out) == len(self.ref)
310
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.ref[i])
311
                for i, oo in enumerate(self.out)]
312
313
        for i, oo in enumerate(self.out):
314
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
315
316
    def test_convert_latlon_arr_maxalt_failure(self):
317
        """test convert_latlon_arr failure for altitudes too high for coeffs"""
318
        self.method = ""
319
        self.out = aacgmv2.convert_latlon_arr(self.lat_in[0], self.lon_in[0],
320
                                              [2001], self.dtime, self.method)
321
        assert np.all(np.isnan(np.array(self.out)))
322
323
    def test_convert_latlon_arr_lat_failure(self):
324
        """Test error return for co-latitudes above 90 for an array"""
325
        with pytest.raises(ValueError):
326
            aacgmv2.convert_latlon_arr([91, 60, -91], 0, 300, self.dtime)
327
328
class TestGetAACGMCoord:
329
    def setup(self):
330
        """Runs before every method to create a clean testing setup"""
331
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
332
        self.ddate = dt.date(2015, 1, 1)
333
        self.in_args = [60, 0]
334
        self.out = None
335
        self.rtol = 1.0e-4
336
337
    def teardown(self):
338
        """Runs after every method to clean up previous testing"""
339
        del self.out, self.in_args, self.rtol, self.dtime, self.ddate
340
341
    @pytest.mark.parametrize('alt,method_code,ref',
342
                             [(300, 'TRACE', [58.2268,81.1613,0.1888]),
343
                              (3000.0, "G2A|BADIDEA", [64.3578,83.2895,0.3307]),
344
                              (7000.0, "G2A|TRACE|BADIDEA",
345
                               [69.3187,85.0845,0.4503])])
346
    def test_get_aacgm_coord(self, alt, method_code, ref):
347
        """Test single value AACGMV2 calculation, defaults to TRACE"""
348
        self.in_args.extend([alt, self.dtime, method_code])
349
        self.out = aacgmv2.get_aacgm_coord(*self.in_args)
350
        np.testing.assert_allclose(self.out, ref, rtol=self.rtol)
351
352
    def test_get_aacgm_coord_datetime_date(self):
353
        """Test single AACGMV2 calculation with date and datetime input"""
354
        self.in_args.extend([300.0, self.ddate, 'TRACE'])
355
        self.out = aacgmv2.get_aacgm_coord(*self.in_args)
356
        np.testing.assert_allclose(self.out, [58.2268,81.1613,0.1888],
357
                                   rtol=self.rtol)
358
359
    @pytest.mark.skipif(version_info.major == 2,
360
                        reason='Not raised in Python 2')
361
    def test_get_aacgm_coord_location_failure(self):
362
        """Test single value AACGMV2 calculation with a bad location"""
363
        self.in_args.extend([0.0, self.dtime, 'TRACE'])
364
        self.in_args[0] = 0.0
365
366
        self.out = aacgmv2.get_aacgm_coord(*self.in_args)
367
        np.all(np.isnan(np.array(self.out)))
368
369
    def test_get_aacgm_coord_maxalt_failure(self):
370
        """test get_aacgm_coord failure for an altitude too high for coeffs"""
371
        self.in_args.extend([2001, self.dtime, ""])
372
        self.out = aacgmv2.get_aacgm_coord(*self.in_args)
373
        assert np.all(np.isnan(np.array(self.out)))
374
    
375
    @pytest.mark.parametrize('in_index,value',
376
                             [(3, None), (0, 91.0), (0, -91.0)])
377
    def test_get_aacgm_coord_raise_value_error(self, in_index, value):
378
        """Test different ways to raise a ValueError"""
379
        self.in_args.extend([300.0, self.dtime])
380
        self.in_args[in_index] = value
381
        with pytest.raises(ValueError):
382
            self.out = aacgmv2.get_aacgm_coord(*self.in_args)
383
384
385
class TestGetAACGMCoordArr:
386 View Code Duplication
    def setup(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
387
        """Runs before every method to create a clean testing setup"""
388
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
389
        self.ddate = dt.date(2015, 1, 1)
390
        self.lat_in = [60.0, 61.0]
391
        self.lon_in = [0.0, 0.0]
392
        self.alt_in = [300.0, 300.0]
393
        self.method = 'TRACE'
394
        self.out = None
395
        self.ref = [[58.22676,59.31847], [81.16135,81.60797], [0.18880,0.21857]]
396
        self.rtol = 1.0e-4
397
398
    def teardown(self):
399
        """Runs after every method to clean up previous testing"""
400
        del self.out, self.ref, self.lat_in, self.dtime, self.ddate
401
        del self.lon_in, self.alt_in, self.method, self.rtol
402
403
    def test_get_aacgm_coord_arr_single_val(self):
404
        """Test array AACGMV2 calculation for a single value"""
405
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in[0], self.lon_in[0],
406
                                               self.alt_in[0], self.dtime,
407
                                               self.method)
408
409
        assert len(self.out) == len(self.ref)
410
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
411
412
        for i, oo in enumerate(self.out):
413
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
414
415 View Code Duplication
    def test_get_aacgm_coord_arr_list_single(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
416
        """Test array AACGMV2 calculation for list input of single values"""
417
        self.out = aacgmv2.get_aacgm_coord_arr([self.lat_in[0]],
418
                                               [self.lon_in[0]],
419
                                               [self.alt_in[0]], self.dtime,
420
                                               self.method)
421
422
        assert len(self.out) == len(self.ref)
423
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
424
425
        for i, oo in enumerate(self.out):
426
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
427
428
    def test_get_aacgm_coord_arr_list(self):
429
        """Test array AACGMV2 calculation for list input"""
430
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in,self.lon_in,
431
                                               self.alt_in, self.dtime,
432
                                               self.method)
433
434
        assert len(self.out) == len(self.ref)
435
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
436
                for oo in self.out]
437
438
        for i, oo in enumerate(self.out):
439
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
440
441 View Code Duplication
    def test_get_aacgm_coord_arr_arr_single(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
442
        """Test array AACGMV2 calculation for array with a single value"""
443
        self.out = aacgmv2.get_aacgm_coord_arr(np.array([self.lat_in[0]]),
444
                                               np.array([self.lon_in[0]]),
445
                                               np.array([self.alt_in[0]]),
446
                                               self.dtime, self.method)
447
448
449
        assert len(self.out) == len(self.ref)
450
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
451
452
        for i, oo in enumerate(self.out):
453
            np.testing.assert_allclose(oo, [self.ref[i][0]], rtol=self.rtol)
454
455 View Code Duplication
    def test_get_aacgm_coord_arr_arr(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
456
        """Test array AACGMV2 calculation for an array"""
457
        self.out = aacgmv2.get_aacgm_coord_arr(np.array(self.lat_in),
458
                                               np.array(self.lon_in),
459
                                               np.array(self.alt_in),
460
                                               self.dtime, self.method)
461
462
        assert len(self.out) == len(self.ref)
463
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
464
                for oo in self.out]
465
466
        for i, oo in enumerate(self.out):
467
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
468
469
    def test_get_aacgm_coord_arr_list_mix(self):
470
        """Test array AACGMV2 calculation for a list and floats"""
471
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in[0],
472
                                               self.alt_in[0], self.dtime,
473
                                               self.method)
474
475
        assert len(self.out) == len(self.ref)
476
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
477
                for oo in self.out]
478
479
        for i, oo in enumerate(self.out):
480
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)  
481
482
    def test_get_aacgm_coord_arr_arr_mix(self):
483
        """Test array AACGMV2 calculation for an array and floats"""
484
        self.out = aacgmv2.get_aacgm_coord_arr(np.array(self.lat_in),
485
                                               self.lon_in[0], self.alt_in[0],
486
                                               self.dtime, self.method)
487
488
        assert len(self.out) == len(self.ref)
489
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
490
                for oo in self.out]
491
492
        for i, oo in enumerate(self.out):
493
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
494
495
    def test_get_aacgm_coord_arr_mult_failure(self):
496
        """Test aacgm_coord_arr failure with multi-dim array input"""
497
498
        with pytest.raises(ValueError):
499
            (self.mlat_out, self.mlon_out,
500
             self.mlt_out) = aacgmv2.get_aacgm_coord_arr(
501
                 np.array([[60, 61, 62], [63, 64, 65]]), 0, 300, self.dtime)
502
503
    def test_get_aacgm_coord_arr_badidea(self):
504
        """Test array AACGMV2 calculation for BADIDEA"""
505
        self.method = "|".join([self.method, "BADIDEA"])
506
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in[0], self.lon_in[0],
507
                                               [3000.0], self.dtime,
508
                                               self.method)
509
510
        assert len(self.out) == len(self.ref)
511
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
512
513
        self.ref = [64.3481, 83.2885, 0.3306]
514
        for i, oo in enumerate(self.out):
515
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
516
517
    @pytest.mark.skipif(version_info.major == 2,
518
                        reason='Not raised in Python 2')
519
    def test_get_aacgm_coord_arr_location_failure(self):
520
        """Test array AACGMV2 calculation with a bad location"""
521
        self.out = aacgmv2.get_aacgm_coord_arr([0], [0], [0], self.dtime,
522
                                               self.method)
523
524
        
525
        assert len(self.out) == len(self.ref)
526
        assert [isinstance(oo, np.ndarray) and len(oo) == 1 for oo in self.out]
527
        assert np.any([np.isnan(oo) for oo in self.out])
528
529
    def test_get_aacgm_coord_arr_time_failure(self):
530
        """Test array AACGMV2 calculation with a bad time"""
531
        with pytest.raises(ValueError):
532
            aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in, self.alt_in,
533
                                        None, self.method)
534
535
    def test_get_aacgm_coord_arr_mlat_failure(self):
536
        """Test error return for co-latitudes above 90 for an array"""
537
538
        self.lat_in = [91, 60, -91]
539
        with pytest.raises(ValueError):
540
            self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in[0],
541
                                                   self.alt_in[0], self.dtime,
542
                                                   self.method)
543
544 View Code Duplication
    def test_get_aacgm_coord_arr_datetime_date(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
545
        """Test array AACGMV2 calculation with date and datetime input"""
546
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in,
547
                                               self.alt_in, self.ddate,
548
                                               self.method)
549
        self.ref = aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in,
550
                                               self.alt_in, self.dtime,
551
                                               self.method)
552
553
        assert len(self.out) == len(self.ref)
554
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
555
                for oo in self.out]
556
557
        for i, oo in enumerate(self.out):
558
            np.testing.assert_allclose(oo, self.ref[i], rtol=self.rtol)
559
560
    def test_get_aacgm_coord_arr_maxalt_failure(self):
561
        """test aacgm_coord_arr failure for an altitude too high for coeff"""
562
        self.method = ""
563
        self.alt_in = [2001 for ll in self.lat_in]
564
        self.out = aacgmv2.get_aacgm_coord_arr(self.lat_in, self.lon_in,
565
                                               self.alt_in, self.dtime,
566
                                               self.method)
567
568
        assert len(self.out) == len(self.ref)
569
        assert [isinstance(oo, np.ndarray) and len(oo) == len(self.lat_in)
570
                for oo in self.out]
571
        assert np.all(np.isnan(np.array(self.out)))
572
573
574
class TestConvertCode:
575
    def setup(self):
576
        self.c_method_code = None
577
578
    def teardown(self):
579
        del self.c_method_code
580
581
    @pytest.mark.parametrize('method_code',
582
                             [('G2A'), ('A2G'), ('TRACE'), ('ALLOWTRACE'),
583
                              ('BADIDEA'), ('GEOCENTRIC'), ('g2a')])
584
    def test_convert_str_to_bit(self, method_code):
585
        """Test conversion from string code to bit"""
586
        if hasattr(aacgmv2._aacgmv2, method_code.upper()):
587
            self.c_method_code = getattr(aacgmv2._aacgmv2, method_code.upper())
588
        else:
589
            raise ValueError('cannot find method in C code: {:}'.format(
590
                method_code))
591
592
        assert aacgmv2.convert_str_to_bit(method_code) == self.c_method_code
593
594
595
    def test_convert_str_to_bit_spaces(self):
596
        """Test conversion from string code to bit for a code with spaces"""
597
        if(aacgmv2.convert_str_to_bit("G2A | trace") !=
598
           aacgmv2._aacgmv2.G2A + aacgmv2._aacgmv2.TRACE):
599
            raise AssertionError()
600
601
    def test_convert_str_to_bit_invalid(self):
602
        """Test conversion from string code to bit for an invalid code"""
603
        if aacgmv2.convert_str_to_bit("ggoogg|") != aacgmv2._aacgmv2.G2A:
604
            raise AssertionError()
605
606
    @pytest.mark.parametrize('bool_dict,method_code',
607
                             [({}, 'G2A'), ({'a2g': True}, 'A2G'),
608
                              ({'trace': True}, 'TRACE'),
609
                              ({'allowtrace': True}, 'ALLOWTRACE'),
610
                              ({'badidea': True}, 'BADIDEA'),
611
                              ({'geocentric': True}, 'GEOCENTRIC')])
612
    def test_convert_bool_to_bit(self, bool_dict, method_code):
613
        """Test conversion from Boolean code to bit"""
614
        if hasattr(aacgmv2._aacgmv2, method_code.upper()):
615
            self.c_method_code = getattr(aacgmv2._aacgmv2, method_code.upper())
616
        else:
617
            raise ValueError('cannot find method in C code: {:}'.format(
618
                method_code))
619
620
        assert aacgmv2.convert_bool_to_bit(**bool_dict) == self.c_method_code
621
622
623
class TestMLTConvert:
624
    def setup(self):
625
        """Runs before every method to create a clean testing setup"""
626
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
627
        self.dtime2 = dt.datetime(2015, 1, 1, 10, 0, 0)
628
        self.ddate = dt.date(2015, 1, 1)
629
        self.mlon_out = None
630
        self.mlt_out = None
631
        self.mlt_diff = None
632
        self.mlon_list = [270.0, 80.0, -95.0]
633
        self.mlt_list = [12.0, 25.0, -1.0]
634
        self.mlon_comp = [-101.670617955439, 93.329382044561, 63.329382044561]
635
        self.mlt_comp = [12.7780412 ,  0.11137453, 12.44470786]
636
        self.diff_comp = np.ones(shape=(3,)) * -10.52411552
637
638
    def teardown(self):
639
        """Runs after every method to clean up previous testing"""
640
        del self.mlon_out, self.mlt_out, self.mlt_list, self.mlon_list
641
        del self.mlon_comp, self.mlt_comp, self.mlt_diff, self.diff_comp
642
643
    def test_date_input(self):
644
        """Test to see that the date input works"""
645
        self.mlt_out = aacgmv2.convert_mlt(self.mlon_list, self.ddate,
646
                                           m2a=False)
647
        np.testing.assert_allclose(self.mlt_out, self.mlt_comp, rtol=1.0e-4)
648
649
    def test_datetime_exception(self):
650
        """Test to see that a value error is raised with bad time input"""
651
        with pytest.raises(ValueError):
652
            self.mlt_out = aacgmv2.wrapper.convert_mlt(self.mlon_list, 1997)
653
654
    def test_inv_convert_mlt_single(self):
655
        """Test MLT inversion for a single value"""
656
        for i,mlt in enumerate(self.mlt_list):
657
            self.mlon_out = aacgmv2.convert_mlt(mlt, self.dtime, m2a=True)
658
            np.testing.assert_almost_equal(self.mlon_out, self.mlon_comp[i],
659
                                           decimal=4)
660
661
    def test_inv_convert_mlt_list(self):
662
        """Test MLT inversion for a list"""
663
        self.mlon_out = aacgmv2.convert_mlt(self.mlt_list, self.dtime, m2a=True)
664
        np.testing.assert_allclose(self.mlon_out, self.mlon_comp, rtol=1.0e-4)
665
666
    def test_inv_convert_mlt_arr(self):
667
        """Test MLT inversion for an array"""
668
        self.mlon_out = aacgmv2.convert_mlt(np.array(self.mlt_list), self.dtime,
669
                                            m2a=True)
670
671
        np.testing.assert_allclose(self.mlon_out, self.mlon_comp, rtol=1.0e-4)
672
673
    def test_inv_convert_mlt_wrapping(self):
674
        """Test MLT wrapping"""
675
        self.mlon_out = aacgmv2.convert_mlt(np.array([1, 25, -1, 23]),
676
                                            self.dtime, m2a=True)
677
678
        np.testing.assert_almost_equal(self.mlon_out[0], self.mlon_out[1],
679
                                       decimal=6)
680
        np.testing.assert_almost_equal(self.mlon_out[2], self.mlon_out[3],
681
                                       decimal=6)
682
683
    def test_mlt_convert_mlon_wrapping(self):
684
        """Test mlon wrapping"""
685
        self.mlt_out = aacgmv2.convert_mlt(np.array([270, -90, 1, 361]),
686
                                           self.dtime, m2a=False)
687
688
        np.testing.assert_almost_equal(self.mlt_out[0], self.mlt_out[1],
689
                                       decimal=6)
690
        np.testing.assert_almost_equal(self.mlt_out[2], self.mlt_out[3],
691
                                       decimal=6)
692
693
    def test_mlt_convert_single(self):
694
        """Test MLT calculation for a single value"""
695
        for i,mlon in enumerate(self.mlon_list):
696
            self.mlt_out = aacgmv2.convert_mlt(mlon, self.dtime, m2a=False)
697
            np.testing.assert_almost_equal(self.mlt_out, self.mlt_comp[i],
698
                                           decimal=4)
699
700
    def test_mlt_convert_list(self):
701
        """Test MLT calculation for a list"""
702
        self.mlt_out = aacgmv2.convert_mlt(self.mlon_list, self.dtime,
703
                                           m2a=False)
704
        np.testing.assert_allclose(self.mlt_out, self.mlt_comp, rtol=1.0e-4)
705
706
    def test_mlt_convert_arr(self):
707
        """Test MLT calculation for an array"""
708
        self.mlt_out = aacgmv2.convert_mlt(np.array(self.mlon_list),
709
                                           self.dtime, m2a=False)
710
        np.testing.assert_allclose(self.mlt_out, self.mlt_comp, rtol=1.0e-4)
711
712
    def test_mlt_convert_list_w_times(self):
713
        """Test MLT calculation for data and time arrays"""
714
        self.dtime = [self.dtime for dd in self.mlon_list]
715
        self.mlt_out = aacgmv2.convert_mlt(self.mlon_list, self.dtime,
716
                                           m2a=False)
717
        np.testing.assert_allclose(self.mlt_out, self.mlt_comp, rtol=1.0e-4)
718
719
    def test_mlt_convert_change(self):
720
        """Test that MLT changes with UT"""
721
        self.mlt_out = aacgmv2.convert_mlt(self.mlon_list, self.dtime)
722
        self.mlt_diff = np.array(self.mlt_out) \
723
            - np.array(aacgmv2.convert_mlt(self.mlon_list, self.dtime2))
724
725
        np.testing.assert_allclose(self.mlt_diff, self.diff_comp, rtol=1.0e-4)
726
727
    def test_mlt_convert_multidim_failure(self):
728
        """Test MLT calculation failure for multi-dimensional arrays"""
729
        self.mlon_list = np.full(shape=(3,2), fill_value=50.0)
730
        with pytest.raises(ValueError):
731
            aacgmv2.convert_mlt(self.mlon_list, self.dtime, m2a=False)
732
733
    def test_mlt_convert_mismatch_failure(self):
734
        """Test MLT calculation failure for mismatched array input"""
735
        with pytest.raises(ValueError):
736
            aacgmv2.convert_mlt(self.mlon_list, [self.dtime, self.dtime2],
737
                                m2a=False)
738
739
class TestCoeffPath:
740
741
    def setup(self):
742
        """Runs before every method to create a clean testing setup"""
743
        os.environ['IGRF_COEFFS'] = "default_igrf"
744
        os.environ['AACGM_v2_DAT_PREFIX'] = "default_coeff"
745
        self.default_igrf = os.environ['IGRF_COEFFS']
746
        self.default_coeff = os.environ['AACGM_v2_DAT_PREFIX']
747
748
    def teardown(self):
749
        """Runs after every method to clean up previous testing"""
750
        del self.default_igrf, self.default_coeff
751
752
    def test_set_coeff_path_default(self):
753
        """Test the coefficient path setting using default values"""
754
        aacgmv2.wrapper.set_coeff_path()
755
756
        if os.environ['IGRF_COEFFS'] != self.default_igrf:
757
            raise AssertionError()
758
        if os.environ['AACGM_v2_DAT_PREFIX'] != self.default_coeff:
759
            raise AssertionError()
760
761
    @classmethod
762
    def test_set_coeff_path_string(self):
763
        """Test the coefficient path setting using two user specified values"""
764
        aacgmv2.wrapper.set_coeff_path("hi", "bye")
765
766
        if os.environ['IGRF_COEFFS'] != "hi":
767
            raise AssertionError()
768
        if os.environ['AACGM_v2_DAT_PREFIX'] != "bye":
769
            raise AssertionError()
770
771
    @classmethod
772
    def test_set_coeff_path_true(self):
773
        """Test the coefficient path setting using the module values"""
774
        aacgmv2.wrapper.set_coeff_path(True, True)
775
776
        if os.environ['IGRF_COEFFS'] != aacgmv2.IGRF_COEFFS:
777
            raise AssertionError()
778
        if os.environ['AACGM_v2_DAT_PREFIX'] != aacgmv2.AACGM_v2_DAT_PREFIX:
779
            raise AssertionError()
780
781
    def test_set_only_aacgm_coeff_path(self):
782
        """Test the coefficient path setting using a mix of input"""
783
        aacgmv2.wrapper.set_coeff_path(coeff_prefix="hi")
784
785
        if os.environ['IGRF_COEFFS'] != self.default_igrf:
786
            raise AssertionError()
787
        if os.environ['AACGM_v2_DAT_PREFIX'] != "hi":
788
            raise AssertionError()
789
790
    def test_set_only_igrf_coeff_path(self):
791
        """Test the coefficient path setting using a mix of input"""
792
        aacgmv2.wrapper.set_coeff_path(igrf_file="hi")
793
794
        if os.environ['IGRF_COEFFS'] != "hi":
795
            raise AssertionError()
796
        if os.environ['AACGM_v2_DAT_PREFIX'] != self.default_coeff:
797
            raise AssertionError()
798
799
    @classmethod
800
    def test_set_both_mixed(self):
801
        """Test the coefficient path setting using a mix of input"""
802
        aacgmv2.wrapper.set_coeff_path(igrf_file=True, coeff_prefix="hi")
803
804
        if os.environ['IGRF_COEFFS'] != aacgmv2.IGRF_COEFFS:
805
            raise AssertionError()
806
        if os.environ['AACGM_v2_DAT_PREFIX'] != "hi":
807
            raise AssertionError()
808
809
class TestHeightReturns:
810
    def setup(self):
811
        """Runs before every method to create a clean testing setup"""
812
        self.code = aacgmv2._aacgmv2.A2G
813
        self.bad_code = aacgmv2._aacgmv2.BADIDEA
814
        self.trace_code = aacgmv2._aacgmv2.TRACE
815
        
816
    def teardown(self):
817
        """Runs after every method to clean up previous testing"""
818
        del self.code, self.bad_code
819
820
    def test_low_height_good(self):
821
        """ Test to see that a very low height is still accepted"""
822
823
        assert aacgmv2.wrapper.test_height(-1, self.code)
824
825
    def test_high_coeff_bad(self):
826
        """ Test to see that a high altitude for coefficent use fails"""
827
828
        assert not aacgmv2.wrapper.test_height(aacgmv2.high_alt_coeff+10.0,
829
                                               self.code)
830
831
    def test_high_coeff_good(self):
832
        """ Test a high altitude for coefficent use with badidea """
833
834
        assert aacgmv2.wrapper.test_height(aacgmv2.high_alt_coeff+10.0,
835
                                           self.bad_code)
836
837
    def test_low_coeff_good(self):
838
        """ Test that a normal height succeeds"""
839
        assert aacgmv2.wrapper.test_height(aacgmv2.high_alt_coeff*0.5,
840
                                           self.code)
841
842
    def test_high_trace_bad(self):
843
        """ Test that a high trace height fails"""
844
        assert not aacgmv2.wrapper.test_height(aacgmv2.high_alt_trace+10.0,
845
                                               self.code)
846
847
    def test_low_trace_good(self):
848
        """ Test that a high coefficient height succeeds with trace"""
849
        assert aacgmv2.wrapper.test_height(aacgmv2.high_alt_coeff+10.0,
850
                                           self.trace_code)
851
852
    def test_high_trace_good(self):
853
        """ Test that a high trace height succeeds with badidea"""
854
        assert aacgmv2.wrapper.test_height(aacgmv2.high_alt_trace+10.0,
855
                                           self.bad_code)
856
857
858
class TestPyLogging:
859
    def setup(self):
860
        """Runs before every method to create a clean testing setup"""
861
862
        self.lwarn = u""
863
        self.lout = u""
864
        self.log_capture = StringIO()
865
        aacgmv2.logger.addHandler(logging.StreamHandler(self.log_capture))
866
        aacgmv2.logger.setLevel(logging.INFO)
867
868
    def teardown(self):
869
        """Runs after every method to clean up previous testing"""
870
        self.log_capture.close()
871
        del self.lwarn, self.lout, self.log_capture
872
873
874
    def test_warning_below_ground(self):
875
        """ Test that a warning is issued if height < 0 for height test """
876
        self.lwarn = u"conversion not intended for altitudes < 0 km"
877
878
        aacgmv2.wrapper.test_height(-1, 0)
879
        self.lout = self.log_capture.getvalue()
880
        if self.lout.find(self.lwarn) < 0:
881
            raise AssertionError()
882
883
    def test_warning_magnetosphere(self):
884
        """ Test that a warning is issued if altitude is very high"""
885
        self.lwarn = u"coordinates are not intended for the magnetosphere"
886
887
        aacgmv2.wrapper.test_height(70000, aacgmv2._aacgmv2.TRACE)
888
        self.lout = self.log_capture.getvalue()
889
        if self.lout.find(self.lwarn) < 0:
890
            raise AssertionError()
891
892
    def test_warning_high_coeff(self):
893
        """ Test that a warning is issued if altitude is very high"""
894
        self.lwarn = u"must either use field-line tracing (trace=True"
895
896
        aacgmv2.wrapper.test_height(3000, 0)
897
        self.lout = self.log_capture.getvalue()
898
        if self.lout.find(self.lwarn) < 0:
899
            raise AssertionError()
900
901
    def test_warning_single_loc_in_arr(self):
902
        """ Test that user is warned they should be using simpler routine"""
903
        self.lwarn = u"for a single location, consider using"
904
905
        aacgmv2.convert_latlon_arr(60, 0, 300, dt.datetime(2015,1,1,0,0,0))
906
        self.lout = self.log_capture.getvalue()
907
        if self.lout.find(self.lwarn) < 0:
908
            raise AssertionError()
909
910
class TestTimeReturns:
911
    def setup(self):
912
        """Runs before every method to create a clean testing setup"""
913
        self.dtime = dt.datetime(2015, 1, 1, 0, 0, 0)
914
        self.dtime2 = dt.datetime(2015, 1, 1, 10, 10, 10)
915
        self.ddate = dt.date(2015, 1, 1)
916
        
917
    def teardown(self):
918
        """Runs after every method to clean up previous testing"""
919
        del self.dtime, self.ddate, self.dtime2
920
921
    def test_good_time(self):
922
        """ Test to see that a good datetime is accepted"""
923
924
        assert self.dtime == aacgmv2.wrapper.test_time(self.dtime)
925
926
    def test_good_time_with_nonzero_time(self):
927
        """ Test to see that a good datetime with h/m/s is accepted"""
928
929
        assert self.dtime2 == aacgmv2.wrapper.test_time(self.dtime2)
930
931
    def test_good_date(self):
932
        """ Test to see that a good date has a good datetime output"""
933
934
        assert self.dtime == aacgmv2.wrapper.test_time(self.dtime)
935
936
    def test_bad_time(self):
937
        """ Test to see that a warning is raised with a bad time input"""
938
        with pytest.raises(ValueError):
939
            aacgmv2.wrapper.test_time(2015)
940