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