test_cmd.TestCommandLine.teardown_method()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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