Passed
Pull Request — develop (#57)
by Angeline
01:13
created

TestFutureDepWarning.test_future_dep_warning()   A

Complexity

Conditions 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 16
Ratio 100 %

Importance

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