1# Copyright 2017 The Abseil Authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://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, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Additional tests for Flag classes. 16 17Most of the Flag classes are covered in the flags_test.py. 18""" 19 20import copy 21import enum 22import pickle 23 24from absl.flags import _argument_parser 25from absl.flags import _exceptions 26from absl.flags import _flag 27from absl.testing import absltest 28from absl.testing import parameterized 29 30 31class FlagTest(absltest.TestCase): 32 33 def setUp(self): 34 super().setUp() 35 self.flag = _flag.Flag( 36 _argument_parser.ArgumentParser(), 37 _argument_parser.ArgumentSerializer(), 38 'fruit', 'apple', 'help') 39 40 def test_default_unparsed(self): 41 flag = _flag.Flag( 42 _argument_parser.ArgumentParser(), 43 _argument_parser.ArgumentSerializer(), 44 'fruit', 'apple', 'help') 45 self.assertEqual('apple', flag.default_unparsed) 46 47 flag = _flag.Flag( 48 _argument_parser.IntegerParser(), 49 _argument_parser.ArgumentSerializer(), 50 'number', '1', 'help') 51 self.assertEqual('1', flag.default_unparsed) 52 53 flag = _flag.Flag( 54 _argument_parser.IntegerParser(), 55 _argument_parser.ArgumentSerializer(), 56 'number', 1, 'help') 57 self.assertEqual(1, flag.default_unparsed) 58 59 def test_no_truthiness(self): 60 with self.assertRaises(TypeError): 61 if self.flag: 62 self.fail('Flag instances must raise rather than be truthy.') 63 64 def test_set_default_overrides_current_value(self): 65 self.assertEqual('apple', self.flag.value) 66 self.flag._set_default('orange') 67 self.assertEqual('orange', self.flag.value) 68 69 def test_set_default_overrides_current_value_when_not_using_default(self): 70 self.flag.using_default_value = False 71 self.assertEqual('apple', self.flag.value) 72 self.flag._set_default('orange') 73 self.assertEqual('apple', self.flag.value) 74 75 def test_pickle(self): 76 with self.assertRaisesRegex(TypeError, "can't pickle Flag objects"): 77 pickle.dumps(self.flag) 78 79 def test_copy(self): 80 self.flag.value = 'orange' 81 82 with self.assertRaisesRegex(TypeError, 83 'Flag does not support shallow copies'): 84 copy.copy(self.flag) 85 86 flag2 = copy.deepcopy(self.flag) 87 self.assertEqual(flag2.value, 'orange') 88 89 flag2.value = 'mango' 90 self.assertEqual(flag2.value, 'mango') 91 self.assertEqual(self.flag.value, 'orange') 92 93 94class BooleanFlagTest(parameterized.TestCase): 95 96 @parameterized.parameters(('', '(no help available)'), 97 ('Is my test brilliant?', 'Is my test brilliant?')) 98 def test_help_text(self, helptext_input, helptext_output): 99 f = _flag.BooleanFlag('a_bool', False, helptext_input) 100 self.assertEqual(helptext_output, f.help) 101 102 103class EnumFlagTest(parameterized.TestCase): 104 105 @parameterized.parameters( 106 ('', '<apple|orange>: (no help available)'), 107 ('Type of fruit.', '<apple|orange>: Type of fruit.')) 108 def test_help_text(self, helptext_input, helptext_output): 109 f = _flag.EnumFlag('fruit', 'apple', helptext_input, ['apple', 'orange']) 110 self.assertEqual(helptext_output, f.help) 111 112 def test_empty_values(self): 113 with self.assertRaises(ValueError): 114 _flag.EnumFlag('fruit', None, 'help', []) 115 116 117class Fruit(enum.Enum): 118 APPLE = 1 119 ORANGE = 2 120 121 122class EmptyEnum(enum.Enum): 123 pass 124 125 126class EnumClassFlagTest(parameterized.TestCase): 127 128 @parameterized.parameters( 129 ('', '<apple|orange>: (no help available)'), 130 ('Type of fruit.', '<apple|orange>: Type of fruit.')) 131 def test_help_text_case_insensitive(self, helptext_input, helptext_output): 132 f = _flag.EnumClassFlag('fruit', None, helptext_input, Fruit) 133 self.assertEqual(helptext_output, f.help) 134 135 @parameterized.parameters( 136 ('', '<APPLE|ORANGE>: (no help available)'), 137 ('Type of fruit.', '<APPLE|ORANGE>: Type of fruit.')) 138 def test_help_text_case_sensitive(self, helptext_input, helptext_output): 139 f = _flag.EnumClassFlag( 140 'fruit', None, helptext_input, Fruit, case_sensitive=True) 141 self.assertEqual(helptext_output, f.help) 142 143 def test_requires_enum(self): 144 with self.assertRaises(TypeError): 145 _flag.EnumClassFlag('fruit', None, 'help', ['apple', 'orange']) 146 147 def test_requires_non_empty_enum_class(self): 148 with self.assertRaises(ValueError): 149 _flag.EnumClassFlag('empty', None, 'help', EmptyEnum) 150 151 def test_accepts_literal_default(self): 152 f = _flag.EnumClassFlag('fruit', Fruit.APPLE, 'A sample enum flag.', Fruit) 153 self.assertEqual(Fruit.APPLE, f.value) 154 155 def test_accepts_string_default(self): 156 f = _flag.EnumClassFlag('fruit', 'ORANGE', 'A sample enum flag.', Fruit) 157 self.assertEqual(Fruit.ORANGE, f.value) 158 159 def test_case_sensitive_rejects_default_with_wrong_case(self): 160 with self.assertRaises(_exceptions.IllegalFlagValueError): 161 _flag.EnumClassFlag( 162 'fruit', 'oranGe', 'A sample enum flag.', Fruit, case_sensitive=True) 163 164 def test_case_insensitive_accepts_string_default(self): 165 f = _flag.EnumClassFlag( 166 'fruit', 'oranGe', 'A sample enum flag.', Fruit, case_sensitive=False) 167 self.assertEqual(Fruit.ORANGE, f.value) 168 169 def test_default_value_does_not_exist(self): 170 with self.assertRaises(_exceptions.IllegalFlagValueError): 171 _flag.EnumClassFlag('fruit', 'BANANA', 'help', Fruit) 172 173 174class MultiEnumClassFlagTest(parameterized.TestCase): 175 176 @parameterized.named_parameters( 177 ('NoHelpSupplied', '', '<apple|orange>: (no help available);\n ' + 178 'repeat this option to specify a list of values', False), 179 ('WithHelpSupplied', 'Type of fruit.', 180 '<APPLE|ORANGE>: Type of fruit.;\n ' + 181 'repeat this option to specify a list of values', True)) 182 def test_help_text(self, helptext_input, helptext_output, case_sensitive): 183 f = _flag.MultiEnumClassFlag( 184 'fruit', None, helptext_input, Fruit, case_sensitive=case_sensitive) 185 self.assertEqual(helptext_output, f.help) 186 187 def test_requires_enum(self): 188 with self.assertRaises(TypeError): 189 _flag.MultiEnumClassFlag('fruit', None, 'help', ['apple', 'orange']) 190 191 def test_requires_non_empty_enum_class(self): 192 with self.assertRaises(ValueError): 193 _flag.MultiEnumClassFlag('empty', None, 'help', EmptyEnum) 194 195 def test_rejects_wrong_case_when_case_sensitive(self): 196 with self.assertRaisesRegex(_exceptions.IllegalFlagValueError, 197 '<APPLE|ORANGE>'): 198 _flag.MultiEnumClassFlag( 199 'fruit', ['APPLE', 'Orange'], 200 'A sample enum flag.', 201 Fruit, 202 case_sensitive=True) 203 204 def test_accepts_case_insensitive(self): 205 f = _flag.MultiEnumClassFlag('fruit', ['apple', 'APPLE'], 206 'A sample enum flag.', Fruit) 207 self.assertListEqual([Fruit.APPLE, Fruit.APPLE], f.value) 208 209 def test_accepts_literal_default(self): 210 f = _flag.MultiEnumClassFlag('fruit', Fruit.APPLE, 'A sample enum flag.', 211 Fruit) 212 self.assertListEqual([Fruit.APPLE], f.value) 213 214 def test_accepts_list_of_literal_default(self): 215 f = _flag.MultiEnumClassFlag('fruit', [Fruit.APPLE, Fruit.ORANGE], 216 'A sample enum flag.', Fruit) 217 self.assertListEqual([Fruit.APPLE, Fruit.ORANGE], f.value) 218 219 def test_accepts_string_default(self): 220 f = _flag.MultiEnumClassFlag('fruit', 'ORANGE', 'A sample enum flag.', 221 Fruit) 222 self.assertListEqual([Fruit.ORANGE], f.value) 223 224 def test_accepts_list_of_string_default(self): 225 f = _flag.MultiEnumClassFlag('fruit', ['ORANGE', 'APPLE'], 226 'A sample enum flag.', Fruit) 227 self.assertListEqual([Fruit.ORANGE, Fruit.APPLE], f.value) 228 229 def test_default_value_does_not_exist(self): 230 with self.assertRaisesRegex(_exceptions.IllegalFlagValueError, 231 '<apple|banana>'): 232 _flag.MultiEnumClassFlag('fruit', 'BANANA', 'help', Fruit) 233 234 235if __name__ == '__main__': 236 absltest.main() 237