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