1import os
2import unittest
3from decimal import Decimal, InvalidOperation
4import json
5
6try:
7    # python 3.4+ should use builtin unittest.mock not mock package
8    from unittest.mock import patch
9    from unittest import mock
10except ImportError:
11    from mock import patch
12    import mock
13
14import sys
15
16from envs import env
17
18class EnvTestCase(unittest.TestCase):
19    def setUp(self):
20        # Integer
21        os.environ.setdefault('VALID_INTEGER', '1')
22        os.environ.setdefault('INVALID_INTEGER', '["seven"]')
23        # String
24        os.environ.setdefault('VALID_STRING', 'seven')
25        # Boolean
26        os.environ.setdefault('VALID_BOOLEAN', 'True')
27        os.environ.setdefault('VALID_BOOLEAN_FALSE', 'false')
28        os.environ.setdefault('INVALID_BOOLEAN', 'seven')
29        # List
30        os.environ.setdefault('VALID_LIST', "['1','2','3']")
31        os.environ.setdefault('INVALID_LIST', "1")
32        # Tuple
33        os.environ.setdefault('VALID_TUPLE', "('True','FALSE')")
34        os.environ.setdefault('INVALID_TUPLE', '1')
35        # Dict
36        os.environ.setdefault('VALID_DICT', "{'first_name':'Suge'}")
37        os.environ.setdefault('INVALID_DICT', 'Aaron Rogers')
38        # Float
39        os.environ.setdefault('VALID_FLOAT', "5.0")
40        os.environ.setdefault('INVALID_FLOAT', '[5.0]')
41        # Decimal
42        os.environ.setdefault('VALID_DECIMAL', "2.39")
43        os.environ.setdefault('INVALID_DECIMAL', "FOOBAR")
44
45    def test_integer_valid(self):
46        self.assertEqual(1, env('VALID_INTEGER', var_type='integer'))
47
48    def test_integer_invalid(self):
49        with self.assertRaises(TypeError) as vm:
50            env('INVALID_INTEGER', var_type='integer')
51
52    def test_wrong_var_type(self):
53        with self.assertRaises(ValueError) as vm:
54            env('INVALID_INTEGER', var_type='set')
55
56    def test_string_valid(self):
57        self.assertEqual('seven', env('VALID_STRING'))
58
59    def test_boolean_valid(self):
60        self.assertEqual(True, env('VALID_BOOLEAN', var_type='boolean'))
61
62    def test_boolean_valid_false(self):
63        self.assertEqual(False, env('VALID_BOOLEAN_FALSE', var_type='boolean'))
64
65    def test_boolean_invalid(self):
66        with self.assertRaises(ValueError) as vm:
67            env('INVALID_BOOLEAN', var_type='boolean')
68
69    def test_list_valid(self):
70        self.assertEqual(['1', '2', '3'], env('VALID_LIST', var_type='list'))
71
72    def test_list_invalid(self):
73        with self.assertRaises(TypeError) as vm:
74            env('INVALID_LIST', var_type='list')
75
76    def test_tuple_valid(self):
77        self.assertEqual(('True', 'FALSE'), env('VALID_TUPLE', var_type='tuple'))
78
79    def test_tuple_invalid(self):
80        with self.assertRaises(TypeError) as vm:
81            env('INVALID_TUPLE', var_type='tuple')
82
83    def test_dict_valid(self):
84        self.assertEqual({'first_name': 'Suge'}, env('VALID_DICT', var_type='dict'))
85
86    def test_dict_invalid(self):
87        with self.assertRaises(SyntaxError) as vm:
88            env('INVALID_DICT', var_type='dict')
89
90    def test_float_valid(self):
91        self.assertEqual(5.0, env('VALID_FLOAT', var_type='float'))
92
93    def test_float_invalid(self):
94        with self.assertRaises(TypeError) as vm:
95            env('INVALID_FLOAT', var_type='float')
96
97    def test_decimal_valid(self):
98        self.assertEqual(Decimal('2.39'), env('VALID_DECIMAL', var_type='decimal'))
99
100    def test_decimal_invalid(self):
101        with self.assertRaises(ArithmeticError) as vm:
102            env('INVALID_DECIMAL', var_type='decimal')
103
104    def test_defaults(self):
105        self.assertEqual(env('HELLO', 5, var_type='integer'), 5)
106        self.assertEqual(env('HELLO', 5.0, var_type='float'), 5.0)
107        self.assertEqual(env('HELLO', [], var_type='list'), [])
108        self.assertEqual(env('HELLO', {}, var_type='dict'), {})
109        self.assertEqual(env('HELLO', (), var_type='tuple'), ())
110        self.assertEqual(env('HELLO', 'world'), 'world')
111        self.assertEqual(env('HELLO', False, var_type='boolean'), False)
112        self.assertEqual(env('HELLO', 'False', var_type='boolean'), False)
113        self.assertEqual(env('HELLO', 'true', var_type='boolean'), True)
114        self.assertEqual(env('HELLO', Decimal('3.14'), var_type='decimal'), Decimal('3.14'))
115
116'''
117Each CLI Test must be run outside of test suites in isolation
118since Click CLI Runner alters the global context
119'''
120def setup_CliRunner(test_func):
121    '''
122    Decorator to initialize environment for CliRunner.
123    '''
124    def wrapper():
125        from click.testing import CliRunner
126        try:
127            from cli import envs as cli_envs
128        except ImportError:
129            from .cli import envs as cli_envs
130
131        try:
132            from cli import envs
133        except ImportError:
134            from .cli import envs
135
136        test_func()
137
138    return wrapper
139
140@mock.patch.object(sys, 'argv', ["list-envs"])
141@setup_CliRunner
142def test_list_envs():
143    os.environ.setdefault('DEBUG', 'True')
144
145    runner = CliRunner()
146    result = runner.invoke(envs, ['list-envs', '--settings-file', 'envs.test_settings', '--keep-result', 'True'], catch_exceptions=False)
147
148    output_expected = [{"default": None, "value": None, "var_type": "string", "key": "DATABASE_URL"},{"default": False, "value": "True", "var_type": "boolean", "key": "DEBUG"},{"default": [], "value": None, "var_type": "list", "key": "MIDDLEWARE"},{}]
149
150    with open('.envs_result', 'r') as f:
151        output_actual = json.load(f)
152
153    exit_code_expected = 0
154    exit_code_actual = result.exit_code
155
156
157    assert exit_code_actual == exit_code_expected
158    assert output_actual == output_expected
159
160
161
162
163
164if __name__ == '__main__':
165    unittest.main()
166
167