Passed
Pull Request — develop (#90)
by Angeline
01:38
created

TestCommandLine.test_invalid_coord()   A

Complexity

Conditions 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 12
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
# -*- coding: utf-8 -*-
2
"""Unit tests for command line execution."""
3
4
import numpy as np
5
import os
6
import pytest
7
import subprocess
8
9
10
class TestCommandLine():
11
    def setup(self):
12
        """Runs before every test method to create a clean environment."""
13
        # Define the desired working paths
14
        self.startdir = os.path.abspath(os.path.curdir)
15
        split_dirs = os.path.split(os.path.dirname(os.path.abspath(__file__)))
16
        self.workdir = split_dirs[0]
17
18
        # Change directory, if needed
19
        if self.startdir != self.workdir:
20
            os.chdir(self.workdir)
21
22
        # Define the test filenames
23
        self.outfile = os.path.join(split_dirs[1], 'output.txt')
24
        self.infile = os.path.join(split_dirs[1], 'test_convert.txt')
25
        self.singlefile = os.path.join(split_dirs[1],
26
                                       'test_convert_single_line.txt')
27
28
    def teardown(self):
29
        """Runs after every method to clean up previous testing."""
30
        # Remove testing output
31
        if os.path.isfile(self.outfile):
32
            os.remove(self.outfile)
33
34
        # Return to starting directory
35
        if self.startdir != os.path.abspath(os.path.curdir):
36
            os.chdir(self.startdir)
37
38
        del self.outfile, self.infile, self.singlefile
39
40
    def execute_command_line(self, command, command_kwargs=None,
41
                             pipe_out=False):
42
        """Execute the command and load data from self.outfile
43
44
        Parameters
45
        ----------
46
        command : list or str
47
            List or string containing command to execute using subprocess
48
        command_kwargs : dict or NoneType
49
            Dict containing optional kwargs for subprocess.Popen command or
50
            None if using defaults. (default=None)
51
        pipe_out : bool
52
            Return pipe output instead of output from a data file if True
53
            (default=False)
54
55
        Returns
56
        -------
57
        data : np.array, NoneType, or subprocess.Popen attribute
58
            Numpy array of data from output file, None if no file was created,
59
            or the requested output from the pipe command.
60
61
        """
62
        if command_kwargs is None:
63
            command_kwargs = {}
64
65
        pipe = subprocess.Popen(command, **command_kwargs)
66
        out = pipe.communicate()
67
        pipe.wait()
68
69
        if pipe_out:
70
            data = out
71
        elif os.path.isfile(self.outfile):
72
            data = np.loadtxt(self.outfile)
73
        else:
74
            data = None
75
76
        return data
77
78
    @pytest.mark.parametrize("date_str", [("2015"), ("201501"), ('20150101'),
79
                                          ('20150101000000')])
80
    def test_convert_w_datetime(self, date_str):
81
        """Test command line with different date and time specification."""
82
        # Build and execute the apexpy command line call
83
        cmd = ['python', '-m', 'apexpy', 'geo', 'apex', date_str, '--height',
84
               '300', '-i', self.infile, '-o', self.outfile]
85
        data = self.execute_command_line(cmd)
86
87
        # Test the outfile existance and values
88
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
89
        np.testing.assert_allclose(data, [[57.47145462, 93.62657928],
90
                                          [58.52458191, 94.03150177],
91
                                          [59.57331467, 94.46398163]],
92
                                   rtol=1e-4)
93
        return
94
95
    def test_convert_single_line(self):
96
        """Test command line with a single line of output."""
97
        # Build and execute the apexpy command line call
98
        cmd = ['python', '-m', 'apexpy', 'geo', 'apex', '20150101000000',
99
               '--height', '300', '-i', self.singlefile, '-o', self.outfile]
100
        data = self.execute_command_line(cmd)
101
102
        # Test the outfile existance and values
103
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
104
        np.testing.assert_allclose(data, [57.47145462, 93.62657928], rtol=1e-4)
105
        return
106
107
    @pytest.mark.parametrize("height, out_list",
108
                             [("300", [57.47145462, 93.62657928]),
109
                              ("100 --refh=300", [56.01779556, 93.35305023])])
110
    def test_convert_stdin_stdout_w_height_flags(self, height, out_list):
111
        """Test use of pipe input to command-line call with height flags."""
112
        # Build and execute the apexpy command line call
113
        cmd = ''.join(['echo 60 15 | python -m apexpy geo apex 2015 --height ',
114
                       '{:s}'.format(height)])
115
        cmd_kwargs = {'shell': True, 'stdout': subprocess.PIPE}
116
        stdout, _ = self.execute_command_line(cmd, cmd_kwargs, True)
117
118
        assert stdout is not None, 'error executing: {:s}'.format(' '.join(cmd))
119
        np.testing.assert_allclose(np.array(stdout.split(b' '), dtype=float),
120
                                   out_list, rtol=1e-4)
121
        return
122
123
    def test_convert_mlt(self):
124
        """Test magnetic local time conversion."""
125
        # Build and execute the apexpy command line call
126
        cmd = ['python', '-m', 'apexpy', 'geo', 'mlt', '20150101000000',
127
               '--height', '300', '-i', self.singlefile, '-o', self.outfile]
128
        data = self.execute_command_line(cmd)
129
130
        # Test the outfile existance and values
131
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
132
        np.testing.assert_allclose(data, [57.469547, 1.06324], rtol=1e-4)
133
        return
134
135
    @pytest.mark.parametrize("date_str", [("201501010"), ("2015010100000")])
136
    def test_invalid_date(self, date_str):
137
        """Test raises ValueError with an invalid input date."""
138
        # Build and execute the command
139
        cmd = 'echo 60 15 | python -m apexpy geo apex {:s}'.format(date_str)
140
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
141
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
142
143
        # Evaluate the error output
144
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
145
        assert b'ValueError' in stderr, 'invalid date error not raised'
146
        return
147
148
    def test_mlt_nodatetime(self):
149
        """Test raises ValueError when time not provided for MLT calc."""
150
        # Build and execute the command
151
        cmd = 'echo 60 15 | python -m apexpy geo mlt 20150101'
152
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
153
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
154
155
        # Evaluate the error output
156
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
157
        assert b'ValueError' in stderr, 'invalid time error not raised'
158
        return
159
160
    @pytest.mark.parametrize("coords", [("foobar apex"), ("geo foobar")])
161
    def test_invalid_coord(self, coords):
162
        """Test raises error when bad coordinate input provided."""
163
        # Build and execute the command
164
        cmd = 'echo 60 15 | python -m apexpy {:s} 2015'.format(coords)
165
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
166
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
167
168
        # Evaluate the error output
169
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
170
        assert b'invalid choice' in stderr, 'invalid coord error not raised'
171
        return
172