xref: /aosp_15_r20/external/pigweed/pw_cli/py/envparse_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2020 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Tests for pw_cli.envparse."""
15
16import math
17import unittest
18
19from pw_cli import envparse
20
21# pylint: disable=no-member
22
23
24class ErrorError(Exception):
25    pass
26
27
28def error(value: str):
29    raise ErrorError('error!')
30
31
32class TestEnvironmentParser(unittest.TestCase):
33    """Tests for envparse.EnvironmentParser."""
34
35    def setUp(self):
36        self.raw_env = {
37            'PATH': '/bin:/usr/bin:/usr/local/bin',
38            'FOO': '2020',
39            'ReVeRsE': 'pigweed',
40        }
41
42        self.parser = envparse.EnvironmentParser(error_on_unrecognized=True)
43        self.parser.add_var('PATH')
44        self.parser.add_var('FOO', type=int)
45        self.parser.add_var('BAR', type=bool)
46        self.parser.add_var('BAZ', type=float, default=math.pi)
47        self.parser.add_var('ReVeRsE', type=lambda s: s[::-1])
48        self.parser.add_var('INT', type=int)
49        self.parser.add_var('ERROR', type=error)
50
51    def test_string_value(self):
52        env = self.parser.parse_env(env=self.raw_env)
53        self.assertEqual(env.PATH, self.raw_env['PATH'])
54
55    def test_int_value(self):
56        env = self.parser.parse_env(env=self.raw_env)
57        self.assertEqual(env.FOO, 2020)
58
59    def test_custom_value(self):
60        env = self.parser.parse_env(env=self.raw_env)
61        self.assertEqual(env.ReVeRsE, 'deewgip')
62
63    def test_empty_value(self):
64        env = self.parser.parse_env(env=self.raw_env)
65        self.assertEqual(env.BAR, None)
66
67    def test_default_value(self):
68        env = self.parser.parse_env(env=self.raw_env)
69        self.assertEqual(env.BAZ, math.pi)
70
71    def test_unknown_key(self):
72        env = self.parser.parse_env(env=self.raw_env)
73        with self.assertRaises(AttributeError):
74            env.BBBBB  # pylint: disable=pointless-statement
75
76    def test_bad_value(self):
77        raw_env = {**self.raw_env, 'INT': 'not an int'}
78        with self.assertRaises(envparse.EnvironmentValueError) as ctx:
79            self.parser.parse_env(env=raw_env)
80
81        self.assertEqual(ctx.exception.variable, 'INT')
82        self.assertIsInstance(ctx.exception.__cause__, ValueError)
83
84    def test_custom_exception(self):
85        raw_env = {**self.raw_env, 'ERROR': 'error'}
86        with self.assertRaises(envparse.EnvironmentValueError) as ctx:
87            self.parser.parse_env(env=raw_env)
88
89        self.assertEqual(ctx.exception.variable, 'ERROR')
90        self.assertIsInstance(ctx.exception.__cause__, ErrorError)
91
92
93class TestEnvironmentParserWithPrefix(unittest.TestCase):
94    """Tests for envparse.EnvironmentParser using a prefix."""
95
96    def setUp(self):
97        self.raw_env = {
98            'PW_FOO': '001',
99            'PW_BAR': '010',
100            'PW_BAZ': '100',
101            'IGNORED': '011',
102        }
103
104    def test_parse_unrecognized_variable(self):
105        parser = envparse.EnvironmentParser(
106            prefix='PW_', error_on_unrecognized=True
107        )
108        parser.add_var('PW_FOO')
109        parser.add_var('PW_BAR')
110
111        with self.assertRaises(ValueError):
112            parser.parse_env(env=self.raw_env)
113
114    def test_parse_unrecognized_but_allowed_suffix(self):
115        parser = envparse.EnvironmentParser(
116            prefix='PW_', error_on_unrecognized=True
117        )
118        parser.add_allowed_suffix('_ALLOWED_SUFFIX')
119
120        env = parser.parse_env(env={'PW_FOO_ALLOWED_SUFFIX': '001'})
121        self.assertEqual(env.PW_FOO_ALLOWED_SUFFIX, '001')
122
123    def test_parse_allowed_suffix_but_not_suffix(self):
124        parser = envparse.EnvironmentParser(
125            prefix='PW_', error_on_unrecognized=True
126        )
127        parser.add_allowed_suffix('_ALLOWED_SUFFIX')
128
129        with self.assertRaises(ValueError):
130            parser.parse_env(env={'PW_FOO_ALLOWED_SUFFIX_FOO': '001'})
131
132    def test_parse_ignore_unrecognized(self):
133        parser = envparse.EnvironmentParser(
134            prefix='PW_', error_on_unrecognized=False
135        )
136        parser.add_var('PW_FOO')
137        parser.add_var('PW_BAR')
138
139        env = parser.parse_env(env=self.raw_env)
140        self.assertEqual(env.PW_FOO, self.raw_env['PW_FOO'])
141        self.assertEqual(env.PW_BAR, self.raw_env['PW_BAR'])
142
143    def test_add_var_without_prefix(self):
144        parser = envparse.EnvironmentParser(
145            prefix='PW_', error_on_unrecognized=True
146        )
147        with self.assertRaises(ValueError):
148            parser.add_var('FOO')
149
150
151class TestStrictBool(unittest.TestCase):
152    """Tests for envparse.strict_bool."""
153
154    def setUp(self):
155        self.good_bools = ['true', '1', 'TRUE', 'tRuE']
156        self.bad_bools = [
157            '',
158            'false',
159            '0',
160            'foo',
161            '2',
162            '999',
163            'ok',
164            'yes',
165            'no',
166        ]
167
168    def test_good_bools(self):
169        self.assertTrue(
170            all(envparse.strict_bool(val) for val in self.good_bools)
171        )
172
173    def test_bad_bools(self):
174        self.assertFalse(
175            any(envparse.strict_bool(val) for val in self.bad_bools)
176        )
177
178
179if __name__ == '__main__':
180    unittest.main()
181