Completed
Push — develop ( 74ca54...4e7c62 )
by Angeline
14s queued 12s
created

test_cmd.TestCommandLine.setup()   A

Complexity

Conditions 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 16
rs 9.9
c 0
b 0
f 0
cc 2
nop 1
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={}, pipe_out=False):
41
        """Execute the command and load data from self.outfile
42
43
        Parameters
44
        ----------
45
        command : list or str
46
            List or string containing command to execute using subprocess
47
        command_kwargs : dict
48
            Dict containing optional kwargs for subprocess.Popen command
49
            (default={})
50
        pipe_out : bool
51
            Return pipe output instead of output from a data file if True
52
            (default=False)
53
54
        Returns
55
        -------
56
        data : np.array, NoneType, or subprocess.Popen attribute
57
            Numpy array of data from output file, None if no file was created,
58
            or the requested output from the pipe command.
59
60
        """
61
        pipe = subprocess.Popen(command, **command_kwargs)
62
        out = pipe.communicate()
63
        pipe.wait()
64
65
        if pipe_out:
66
            data = out
67
        elif os.path.isfile(self.outfile):
68
            data = np.loadtxt(self.outfile)
69
        else:
70
            data = None
71
72
        return data
73
74
    @pytest.mark.parametrize("date_str", [("2015"), ("201501"), ('20150101'),
75
                                          ('20150101000000')])
76
    def test_convert_w_datetime(self, date_str):
77
        """Test command line with different date and time specification."""
78
        # Build and execute the apexpy command line call
79
        cmd = ['python', '-m', 'apexpy', 'geo', 'apex', date_str, '--height',
80
               '300', '-i', self.infile, '-o', self.outfile]
81
        data = self.execute_command_line(cmd)
82
83
        # Test the outfile existance and values
84
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
85
        np.testing.assert_allclose(data, [[57.47145462, 93.62657928],
86
                                          [58.52458191, 94.03150177],
87
                                          [59.57331467, 94.46398163]],
88
                                   rtol=1e-4)
89
        return
90
91
    def test_convert_single_line(self):
92
        """Test command line with a single line of output."""
93
        # Build and execute the apexpy command line call
94
        cmd = ['python', '-m', 'apexpy', 'geo', 'apex', '20150101000000',
95
               '--height', '300', '-i', self.singlefile, '-o', self.outfile]
96
        data = self.execute_command_line(cmd)
97
98
        # Test the outfile existance and values
99
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
100
        np.testing.assert_allclose(data, [57.47145462, 93.62657928], rtol=1e-4)
101
        return
102
103
    @pytest.mark.parametrize("height, out_list",
104
                             [("300", [57.47145462, 93.62657928]),
105
                              ("100 --refh=300", [56.01779556, 93.35305023])])
106
    def test_convert_stdin_stdout_w_height_flags(self, height, out_list):
107
        """Test use of pipe input to command-line call with height flags."""
108
        # Build and execute the apexpy command line call
109
        cmd = ''.join(['echo 60 15 | python -m apexpy geo apex 2015 --height ',
110
                       '{:s}'.format(height)])
111
        cmd_kwargs = {'shell': True, 'stdout': subprocess.PIPE}
112
        stdout, _ = self.execute_command_line(cmd, cmd_kwargs, True)
113
114
        assert stdout is not None, 'error executing: {:s}'.format(' '.join(cmd))
115
        np.testing.assert_allclose(np.array(stdout.split(b' '), dtype=float),
116
                                   out_list, rtol=1e-4)
117
        return
118
119
    def test_convert_mlt(self):
120
        """Test magnetic local time conversion."""
121
        # Build and execute the apexpy command line call
122
        cmd = ['python', '-m', 'apexpy', 'geo', 'mlt', '20150101000000',
123
               '--height', '300', '-i', self.singlefile, '-o', self.outfile]
124
        data = self.execute_command_line(cmd)
125
126
        # Test the outfile existance and values
127
        assert data is not None, 'error executing: {:s}'.format(' '.join(cmd))
128
        np.testing.assert_allclose(data, [57.469547, 1.06324], rtol=1e-4)
129
        return
130
131
    @pytest.mark.parametrize("date_str", [("201501010"), ("2015010100000")])
132
    def test_invalid_date(self, date_str):
133
        """Test raises ValueError with an invalid input date."""
134
        # Build and execute the command
135
        cmd = 'echo 60 15 | python -m apexpy geo apex {:s}'.format(date_str)
136
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
137
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
138
139
        # Evaluate the error output
140
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
141
        assert b'ValueError' in stderr, 'invalid date error not raised'
142
        return
143
144
    def test_mlt_nodatetime(self):
145
        """Test raises ValueError when time not provided for MLT calc."""
146
        # Build and execute the command
147
        cmd = 'echo 60 15 | python -m apexpy geo mlt 20150101'
148
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
149
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
150
151
        # Evaluate the error output
152
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
153
        assert b'ValueError' in stderr, 'invalid time error not raised'
154
        return
155
156
    @pytest.mark.parametrize("coords", [("foobar apex"), ("geo foobar")])
157
    def test_invalid_coord(self, coords):
158
        """Test raises error when bad coordinate input provided."""
159
        # Build and execute the command
160
        cmd = 'echo 60 15 | python -m apexpy {:s} 2015'.format(coords)
161
        cmd_kwargs = {'shell': True, 'stderr': subprocess.PIPE}
162
        _, stderr = self.execute_command_line(cmd, cmd_kwargs, True)
163
164
        # Evaluate the error output
165
        assert stderr is not None, 'error executing: {:s}'.format(' '.join(cmd))
166
        assert b'invalid choice' in stderr, 'invalid coord error not raised'
167
        return
168