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"""Tests for flags.FlagValues class.""" 16 17import collections 18import copy 19import pickle 20import types 21from unittest import mock 22 23from absl import logging 24from absl.flags import _defines 25from absl.flags import _exceptions 26from absl.flags import _flagvalues 27from absl.flags import _helpers 28from absl.flags import _validators 29from absl.flags.tests import module_foo 30from absl.testing import absltest 31from absl.testing import parameterized 32 33 34class FlagValuesTest(absltest.TestCase): 35 36 def test_bool_flags(self): 37 for arg, expected in (('--nothing', True), 38 ('--nothing=true', True), 39 ('--nothing=false', False), 40 ('--nonothing', False)): 41 fv = _flagvalues.FlagValues() 42 _defines.DEFINE_boolean('nothing', None, '', flag_values=fv) 43 fv(('./program', arg)) 44 self.assertIs(expected, fv.nothing) 45 46 for arg in ('--nonothing=true', '--nonothing=false'): 47 fv = _flagvalues.FlagValues() 48 _defines.DEFINE_boolean('nothing', None, '', flag_values=fv) 49 with self.assertRaises(ValueError): 50 fv(('./program', arg)) 51 52 def test_boolean_flag_parser_gets_string_argument(self): 53 for arg, expected in (('--nothing', 'true'), 54 ('--nothing=true', 'true'), 55 ('--nothing=false', 'false'), 56 ('--nonothing', 'false')): 57 fv = _flagvalues.FlagValues() 58 _defines.DEFINE_boolean('nothing', None, '', flag_values=fv) 59 with mock.patch.object(fv['nothing'].parser, 'parse') as mock_parse: 60 fv(('./program', arg)) 61 mock_parse.assert_called_once_with(expected) 62 63 def test_unregistered_flags_are_cleaned_up(self): 64 fv = _flagvalues.FlagValues() 65 module, module_name = _helpers.get_calling_module_object_and_name() 66 67 # Define first flag. 68 _defines.DEFINE_integer('cores', 4, '', flag_values=fv, short_name='c') 69 old_cores_flag = fv['cores'] 70 fv.register_key_flag_for_module(module_name, old_cores_flag) 71 self.assertEqual(fv.flags_by_module_dict(), 72 {module_name: [old_cores_flag]}) 73 self.assertEqual(fv.flags_by_module_id_dict(), 74 {id(module): [old_cores_flag]}) 75 self.assertEqual(fv.key_flags_by_module_dict(), 76 {module_name: [old_cores_flag]}) 77 78 # Redefine the same flag. 79 _defines.DEFINE_integer( 80 'cores', 4, '', flag_values=fv, short_name='c', allow_override=True) 81 new_cores_flag = fv['cores'] 82 self.assertNotEqual(old_cores_flag, new_cores_flag) 83 self.assertEqual(fv.flags_by_module_dict(), 84 {module_name: [new_cores_flag]}) 85 self.assertEqual(fv.flags_by_module_id_dict(), 86 {id(module): [new_cores_flag]}) 87 # old_cores_flag is removed from key flags, and the new_cores_flag is 88 # not automatically added because it must be registered explicitly. 89 self.assertEqual(fv.key_flags_by_module_dict(), {module_name: []}) 90 91 # Define a new flag but with the same short_name. 92 _defines.DEFINE_integer( 93 'changelist', 94 0, 95 '', 96 flag_values=fv, 97 short_name='c', 98 allow_override=True) 99 old_changelist_flag = fv['changelist'] 100 fv.register_key_flag_for_module(module_name, old_changelist_flag) 101 # The short named flag -c is overridden to be the old_changelist_flag. 102 self.assertEqual(fv['c'], old_changelist_flag) 103 self.assertNotEqual(fv['c'], new_cores_flag) 104 self.assertEqual(fv.flags_by_module_dict(), 105 {module_name: [new_cores_flag, old_changelist_flag]}) 106 self.assertEqual(fv.flags_by_module_id_dict(), 107 {id(module): [new_cores_flag, old_changelist_flag]}) 108 self.assertEqual(fv.key_flags_by_module_dict(), 109 {module_name: [old_changelist_flag]}) 110 111 # Define a flag only with the same long name. 112 _defines.DEFINE_integer( 113 'changelist', 114 0, 115 '', 116 flag_values=fv, 117 short_name='l', 118 allow_override=True) 119 new_changelist_flag = fv['changelist'] 120 self.assertNotEqual(old_changelist_flag, new_changelist_flag) 121 self.assertEqual(fv.flags_by_module_dict(), 122 {module_name: [new_cores_flag, 123 old_changelist_flag, 124 new_changelist_flag]}) 125 self.assertEqual(fv.flags_by_module_id_dict(), 126 {id(module): [new_cores_flag, 127 old_changelist_flag, 128 new_changelist_flag]}) 129 self.assertEqual(fv.key_flags_by_module_dict(), 130 {module_name: [old_changelist_flag]}) 131 132 # Delete the new changelist's long name, it should still be registered 133 # because of its short name. 134 del fv.changelist 135 self.assertNotIn('changelist', fv) 136 self.assertEqual(fv.flags_by_module_dict(), 137 {module_name: [new_cores_flag, 138 old_changelist_flag, 139 new_changelist_flag]}) 140 self.assertEqual(fv.flags_by_module_id_dict(), 141 {id(module): [new_cores_flag, 142 old_changelist_flag, 143 new_changelist_flag]}) 144 self.assertEqual(fv.key_flags_by_module_dict(), 145 {module_name: [old_changelist_flag]}) 146 147 # Delete the new changelist's short name, it should be removed. 148 del fv.l 149 self.assertNotIn('l', fv) 150 self.assertEqual(fv.flags_by_module_dict(), 151 {module_name: [new_cores_flag, 152 old_changelist_flag]}) 153 self.assertEqual(fv.flags_by_module_id_dict(), 154 {id(module): [new_cores_flag, 155 old_changelist_flag]}) 156 self.assertEqual(fv.key_flags_by_module_dict(), 157 {module_name: [old_changelist_flag]}) 158 159 def _test_find_module_or_id_defining_flag(self, test_id): 160 """Tests for find_module_defining_flag and find_module_id_defining_flag. 161 162 Args: 163 test_id: True to test find_module_id_defining_flag, False to test 164 find_module_defining_flag. 165 """ 166 fv = _flagvalues.FlagValues() 167 current_module, current_module_name = ( 168 _helpers.get_calling_module_object_and_name()) 169 alt_module_name = _flagvalues.__name__ 170 171 if test_id: 172 current_module_or_id = id(current_module) 173 alt_module_or_id = id(_flagvalues) 174 testing_fn = fv.find_module_id_defining_flag 175 else: 176 current_module_or_id = current_module_name 177 alt_module_or_id = alt_module_name 178 testing_fn = fv.find_module_defining_flag 179 180 # Define first flag. 181 _defines.DEFINE_integer('cores', 4, '', flag_values=fv, short_name='c') 182 module_or_id_cores = testing_fn('cores') 183 self.assertEqual(module_or_id_cores, current_module_or_id) 184 module_or_id_c = testing_fn('c') 185 self.assertEqual(module_or_id_c, current_module_or_id) 186 187 # Redefine the same flag in another module. 188 _defines.DEFINE_integer( 189 'cores', 190 4, 191 '', 192 flag_values=fv, 193 module_name=alt_module_name, 194 short_name='c', 195 allow_override=True) 196 module_or_id_cores = testing_fn('cores') 197 self.assertEqual(module_or_id_cores, alt_module_or_id) 198 module_or_id_c = testing_fn('c') 199 self.assertEqual(module_or_id_c, alt_module_or_id) 200 201 # Define a new flag but with the same short_name. 202 _defines.DEFINE_integer( 203 'changelist', 204 0, 205 '', 206 flag_values=fv, 207 short_name='c', 208 allow_override=True) 209 module_or_id_cores = testing_fn('cores') 210 self.assertEqual(module_or_id_cores, alt_module_or_id) 211 module_or_id_changelist = testing_fn('changelist') 212 self.assertEqual(module_or_id_changelist, current_module_or_id) 213 module_or_id_c = testing_fn('c') 214 self.assertEqual(module_or_id_c, current_module_or_id) 215 216 # Define a flag in another module only with the same long name. 217 _defines.DEFINE_integer( 218 'changelist', 219 0, 220 '', 221 flag_values=fv, 222 module_name=alt_module_name, 223 short_name='l', 224 allow_override=True) 225 module_or_id_cores = testing_fn('cores') 226 self.assertEqual(module_or_id_cores, alt_module_or_id) 227 module_or_id_changelist = testing_fn('changelist') 228 self.assertEqual(module_or_id_changelist, alt_module_or_id) 229 module_or_id_c = testing_fn('c') 230 self.assertEqual(module_or_id_c, current_module_or_id) 231 module_or_id_l = testing_fn('l') 232 self.assertEqual(module_or_id_l, alt_module_or_id) 233 234 # Delete the changelist flag, its short name should still be registered. 235 del fv.changelist 236 module_or_id_changelist = testing_fn('changelist') 237 self.assertIsNone(module_or_id_changelist) 238 module_or_id_c = testing_fn('c') 239 self.assertEqual(module_or_id_c, current_module_or_id) 240 module_or_id_l = testing_fn('l') 241 self.assertEqual(module_or_id_l, alt_module_or_id) 242 243 def test_find_module_defining_flag(self): 244 self._test_find_module_or_id_defining_flag(test_id=False) 245 246 def test_find_module_id_defining_flag(self): 247 self._test_find_module_or_id_defining_flag(test_id=True) 248 249 def test_set_default(self): 250 fv = _flagvalues.FlagValues() 251 fv.mark_as_parsed() 252 with self.assertRaises(_exceptions.UnrecognizedFlagError): 253 fv.set_default('changelist', 1) 254 _defines.DEFINE_integer('changelist', 0, 'help', flag_values=fv) 255 self.assertEqual(0, fv.changelist) 256 fv.set_default('changelist', 2) 257 self.assertEqual(2, fv.changelist) 258 259 def test_default_gnu_getopt_value(self): 260 self.assertTrue(_flagvalues.FlagValues().is_gnu_getopt()) 261 262 def test_known_only_flags_in_gnustyle(self): 263 264 def run_test(argv, defined_py_flags, expected_argv): 265 fv = _flagvalues.FlagValues() 266 fv.set_gnu_getopt(True) 267 for f in defined_py_flags: 268 if f.startswith('b'): 269 _defines.DEFINE_boolean(f, False, 'help', flag_values=fv) 270 else: 271 _defines.DEFINE_string(f, 'default', 'help', flag_values=fv) 272 output_argv = fv(argv, known_only=True) 273 self.assertEqual(expected_argv, output_argv) 274 275 run_test( 276 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 277 defined_py_flags=[], 278 expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' ')) 279 run_test( 280 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 281 defined_py_flags=['f1'], 282 expected_argv='0 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' ')) 283 run_test( 284 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 285 defined_py_flags=['f2'], 286 expected_argv='0 --f1=v1 cmd --b1 --f3 v3 --nob2'.split(' ')) 287 run_test( 288 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 289 defined_py_flags=['b1'], 290 expected_argv='0 --f1=v1 cmd --f2 v2 --f3 v3 --nob2'.split(' ')) 291 run_test( 292 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 293 defined_py_flags=['f3'], 294 expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --nob2'.split(' ')) 295 run_test( 296 argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '), 297 defined_py_flags=['b2'], 298 expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3'.split(' ')) 299 run_test( 300 argv=('0 --f1=v1 cmd --undefok=f1 --f2 v2 --b1 ' 301 '--f3 v3 --nob2').split(' '), 302 defined_py_flags=['b2'], 303 expected_argv='0 cmd --f2 v2 --b1 --f3 v3'.split(' ')) 304 run_test( 305 argv=('0 --f1=v1 cmd --undefok f1,f2 --f2 v2 --b1 ' 306 '--f3 v3 --nob2').split(' '), 307 defined_py_flags=['b2'], 308 # Note v2 is preserved here, since undefok requires the flag being 309 # specified in the form of --flag=value. 310 expected_argv='0 cmd v2 --b1 --f3 v3'.split(' ')) 311 312 def test_invalid_flag_name(self): 313 with self.assertRaises(_exceptions.Error): 314 _defines.DEFINE_boolean('test ', 0, '') 315 316 with self.assertRaises(_exceptions.Error): 317 _defines.DEFINE_boolean(' test', 0, '') 318 319 with self.assertRaises(_exceptions.Error): 320 _defines.DEFINE_boolean('te st', 0, '') 321 322 with self.assertRaises(_exceptions.Error): 323 _defines.DEFINE_boolean('', 0, '') 324 325 with self.assertRaises(_exceptions.Error): 326 _defines.DEFINE_boolean(1, 0, '') 327 328 def test_len(self): 329 fv = _flagvalues.FlagValues() 330 self.assertEmpty(fv) 331 self.assertFalse(fv) 332 333 _defines.DEFINE_boolean('boolean', False, 'help', flag_values=fv) 334 self.assertLen(fv, 1) 335 self.assertTrue(fv) 336 337 _defines.DEFINE_boolean( 338 'bool', False, 'help', short_name='b', flag_values=fv) 339 self.assertLen(fv, 3) 340 self.assertTrue(fv) 341 342 def test_pickle(self): 343 fv = _flagvalues.FlagValues() 344 with self.assertRaisesRegex(TypeError, "can't pickle FlagValues"): 345 pickle.dumps(fv) 346 347 def test_copy(self): 348 fv = _flagvalues.FlagValues() 349 _defines.DEFINE_integer('answer', 0, 'help', flag_values=fv) 350 fv(['', '--answer=1']) 351 352 with self.assertRaisesRegex(TypeError, 353 'FlagValues does not support shallow copies'): 354 copy.copy(fv) 355 356 fv2 = copy.deepcopy(fv) 357 self.assertEqual(fv2.answer, 1) 358 359 fv2.answer = 42 360 self.assertEqual(fv2.answer, 42) 361 self.assertEqual(fv.answer, 1) 362 363 def test_conflicting_flags(self): 364 fv = _flagvalues.FlagValues() 365 with self.assertRaises(_exceptions.FlagNameConflictsWithMethodError): 366 _defines.DEFINE_boolean('is_gnu_getopt', False, 'help', flag_values=fv) 367 _defines.DEFINE_boolean( 368 'is_gnu_getopt', 369 False, 370 'help', 371 flag_values=fv, 372 allow_using_method_names=True) 373 self.assertFalse(fv['is_gnu_getopt'].value) 374 self.assertIsInstance(fv.is_gnu_getopt, types.MethodType) 375 376 def test_get_flags_for_module(self): 377 fv = _flagvalues.FlagValues() 378 _defines.DEFINE_string('foo', None, 'help', flag_values=fv) 379 module_foo.define_flags(fv) 380 flags = fv.get_flags_for_module('__main__') 381 382 self.assertEqual({'foo'}, {flag.name for flag in flags}) 383 384 flags = fv.get_flags_for_module(module_foo) 385 self.assertEqual({'tmod_foo_bool', 'tmod_foo_int', 'tmod_foo_str'}, 386 {flag.name for flag in flags}) 387 388 def test_get_help(self): 389 fv = _flagvalues.FlagValues() 390 self.assertMultiLineEqual('''\ 391--flagfile: Insert flag definitions from the given file into the command line. 392 (default: '') 393--undefok: comma-separated list of flag names that it is okay to specify on the 394 command line even if the program does not define a flag with that name. 395 IMPORTANT: flags in this list that have arguments MUST use the --flag=value 396 format. 397 (default: '')''', fv.get_help()) 398 399 module_foo.define_flags(fv) 400 self.assertMultiLineEqual(''' 401absl.flags.tests.module_bar: 402 --tmod_bar_t: Sample int flag. 403 (default: '4') 404 (an integer) 405 --tmod_bar_u: Sample int flag. 406 (default: '5') 407 (an integer) 408 --tmod_bar_v: Sample int flag. 409 (default: '6') 410 (an integer) 411 --[no]tmod_bar_x: Boolean flag. 412 (default: 'true') 413 --tmod_bar_y: String flag. 414 (default: 'default') 415 --[no]tmod_bar_z: Another boolean flag from module bar. 416 (default: 'false') 417 418absl.flags.tests.module_foo: 419 --[no]tmod_foo_bool: Boolean flag from module foo. 420 (default: 'true') 421 --tmod_foo_int: Sample int flag. 422 (default: '3') 423 (an integer) 424 --tmod_foo_str: String flag. 425 (default: 'default') 426 427absl.flags: 428 --flagfile: Insert flag definitions from the given file into the command line. 429 (default: '') 430 --undefok: comma-separated list of flag names that it is okay to specify on 431 the command line even if the program does not define a flag with that name. 432 IMPORTANT: flags in this list that have arguments MUST use the --flag=value 433 format. 434 (default: '')''', fv.get_help()) 435 436 self.assertMultiLineEqual(''' 437xxxxabsl.flags.tests.module_bar: 438xxxx --tmod_bar_t: Sample int flag. 439xxxx (default: '4') 440xxxx (an integer) 441xxxx --tmod_bar_u: Sample int flag. 442xxxx (default: '5') 443xxxx (an integer) 444xxxx --tmod_bar_v: Sample int flag. 445xxxx (default: '6') 446xxxx (an integer) 447xxxx --[no]tmod_bar_x: Boolean flag. 448xxxx (default: 'true') 449xxxx --tmod_bar_y: String flag. 450xxxx (default: 'default') 451xxxx --[no]tmod_bar_z: Another boolean flag from module bar. 452xxxx (default: 'false') 453 454xxxxabsl.flags.tests.module_foo: 455xxxx --[no]tmod_foo_bool: Boolean flag from module foo. 456xxxx (default: 'true') 457xxxx --tmod_foo_int: Sample int flag. 458xxxx (default: '3') 459xxxx (an integer) 460xxxx --tmod_foo_str: String flag. 461xxxx (default: 'default') 462 463xxxxabsl.flags: 464xxxx --flagfile: Insert flag definitions from the given file into the command 465xxxx line. 466xxxx (default: '') 467xxxx --undefok: comma-separated list of flag names that it is okay to specify 468xxxx on the command line even if the program does not define a flag with that 469xxxx name. IMPORTANT: flags in this list that have arguments MUST use the 470xxxx --flag=value format. 471xxxx (default: '')''', fv.get_help(prefix='xxxx')) 472 473 self.assertMultiLineEqual(''' 474absl.flags.tests.module_bar: 475 --tmod_bar_t: Sample int flag. 476 (default: '4') 477 (an integer) 478 --tmod_bar_u: Sample int flag. 479 (default: '5') 480 (an integer) 481 --tmod_bar_v: Sample int flag. 482 (default: '6') 483 (an integer) 484 --[no]tmod_bar_x: Boolean flag. 485 (default: 'true') 486 --tmod_bar_y: String flag. 487 (default: 'default') 488 --[no]tmod_bar_z: Another boolean flag from module bar. 489 (default: 'false') 490 491absl.flags.tests.module_foo: 492 --[no]tmod_foo_bool: Boolean flag from module foo. 493 (default: 'true') 494 --tmod_foo_int: Sample int flag. 495 (default: '3') 496 (an integer) 497 --tmod_foo_str: String flag. 498 (default: 'default')''', fv.get_help(include_special_flags=False)) 499 500 def test_str(self): 501 fv = _flagvalues.FlagValues() 502 self.assertEqual(str(fv), fv.get_help()) 503 module_foo.define_flags(fv) 504 self.assertEqual(str(fv), fv.get_help()) 505 506 def test_empty_argv(self): 507 fv = _flagvalues.FlagValues() 508 with self.assertRaises(ValueError): 509 fv([]) 510 511 def test_invalid_argv(self): 512 fv = _flagvalues.FlagValues() 513 with self.assertRaises(TypeError): 514 fv('./program') 515 with self.assertRaises(TypeError): 516 fv(b'./program') 517 with self.assertRaises(TypeError): 518 fv(u'./program') 519 520 def test_flags_dir(self): 521 flag_values = _flagvalues.FlagValues() 522 flag_name1 = 'bool_flag' 523 flag_name2 = 'string_flag' 524 flag_name3 = 'float_flag' 525 description = 'Description' 526 _defines.DEFINE_boolean( 527 flag_name1, None, description, flag_values=flag_values) 528 _defines.DEFINE_string( 529 flag_name2, None, description, flag_values=flag_values) 530 self.assertEqual(sorted([flag_name1, flag_name2]), dir(flag_values)) 531 532 _defines.DEFINE_float( 533 flag_name3, None, description, flag_values=flag_values) 534 self.assertEqual( 535 sorted([flag_name1, flag_name2, flag_name3]), dir(flag_values)) 536 537 def test_flags_into_string_deterministic(self): 538 flag_values = _flagvalues.FlagValues() 539 _defines.DEFINE_string( 540 'fa', 'x', '', flag_values=flag_values, module_name='mb') 541 _defines.DEFINE_string( 542 'fb', 'x', '', flag_values=flag_values, module_name='mb') 543 _defines.DEFINE_string( 544 'fc', 'x', '', flag_values=flag_values, module_name='ma') 545 _defines.DEFINE_string( 546 'fd', 'x', '', flag_values=flag_values, module_name='ma') 547 548 expected = ('--fc=x\n' 549 '--fd=x\n' 550 '--fa=x\n' 551 '--fb=x\n') 552 553 flags_by_module_items = sorted( 554 flag_values.flags_by_module_dict().items(), reverse=True) 555 for _, module_flags in flags_by_module_items: 556 module_flags.sort(reverse=True) 557 558 flag_values.__dict__['__flags_by_module'] = collections.OrderedDict( 559 flags_by_module_items) 560 561 actual = flag_values.flags_into_string() 562 self.assertEqual(expected, actual) 563 564 def test_validate_all_flags(self): 565 fv = _flagvalues.FlagValues() 566 _defines.DEFINE_string('name', None, '', flag_values=fv) 567 _validators.mark_flag_as_required('name', flag_values=fv) 568 with self.assertRaises(_exceptions.IllegalFlagValueError): 569 fv.validate_all_flags() 570 fv.name = 'test' 571 fv.validate_all_flags() 572 573 574class FlagValuesLoggingTest(absltest.TestCase): 575 """Test to make sure logging.* functions won't recurse. 576 577 Logging may and does happen before flags initialization. We need to make 578 sure that any warnings trown by flagvalues do not result in unlimited 579 recursion. 580 """ 581 582 def test_logging_do_not_recurse(self): 583 logging.info('test info') 584 try: 585 raise ValueError('test exception') 586 except ValueError: 587 logging.exception('test message') 588 589 590class FlagSubstrMatchingTests(parameterized.TestCase): 591 """Tests related to flag substring matching.""" 592 593 def _get_test_flag_values(self): 594 """Get a _flagvalues.FlagValues() instance, set up for tests.""" 595 flag_values = _flagvalues.FlagValues() 596 597 _defines.DEFINE_string('strf', '', '', flag_values=flag_values) 598 _defines.DEFINE_boolean('boolf', 0, '', flag_values=flag_values) 599 600 return flag_values 601 602 # Test cases that should always make parsing raise an error. 603 # Tuples of strings with the argv to use. 604 FAIL_TEST_CASES = [ 605 ('./program', '--boo', '0'), 606 ('./program', '--boo=true', '0'), 607 ('./program', '--boo=0'), 608 ('./program', '--noboo'), 609 ('./program', '--st=blah'), 610 ('./program', '--st=de'), 611 ('./program', '--st=blah', '--boo'), 612 ('./program', '--st=blah', 'unused'), 613 ('./program', '--st=--blah'), 614 ('./program', '--st', '--blah'), 615 ] 616 617 @parameterized.parameters(FAIL_TEST_CASES) 618 def test_raise(self, *argv): 619 """Test that raising works.""" 620 fv = self._get_test_flag_values() 621 with self.assertRaises(_exceptions.UnrecognizedFlagError): 622 fv(argv) 623 624 @parameterized.parameters( 625 FAIL_TEST_CASES + [('./program', 'unused', '--st=blah')]) 626 def test_gnu_getopt_raise(self, *argv): 627 """Test that raising works when combined with GNU-style getopt.""" 628 fv = self._get_test_flag_values() 629 fv.set_gnu_getopt() 630 with self.assertRaises(_exceptions.UnrecognizedFlagError): 631 fv(argv) 632 633 634class SettingUnknownFlagTest(absltest.TestCase): 635 636 def setUp(self): 637 super(SettingUnknownFlagTest, self).setUp() 638 self.setter_called = 0 639 640 def set_undef(self, unused_name, unused_val): 641 self.setter_called += 1 642 643 def test_raise_on_undefined(self): 644 new_flags = _flagvalues.FlagValues() 645 with self.assertRaises(_exceptions.UnrecognizedFlagError): 646 new_flags.undefined_flag = 0 647 648 def test_not_raise(self): 649 new_flags = _flagvalues.FlagValues() 650 new_flags._register_unknown_flag_setter(self.set_undef) 651 new_flags.undefined_flag = 0 652 self.assertEqual(self.setter_called, 1) 653 654 def test_not_raise_on_undefined_if_undefok(self): 655 new_flags = _flagvalues.FlagValues() 656 args = ['0', '--foo', '--bar=1', '--undefok=foo,bar'] 657 unparsed = new_flags(args, known_only=True) 658 self.assertEqual(['0'], unparsed) 659 660 def test_re_raise_undefined(self): 661 def setter(unused_name, unused_val): 662 raise NameError() 663 new_flags = _flagvalues.FlagValues() 664 new_flags._register_unknown_flag_setter(setter) 665 with self.assertRaises(_exceptions.UnrecognizedFlagError): 666 new_flags.undefined_flag = 0 667 668 def test_re_raise_invalid(self): 669 def setter(unused_name, unused_val): 670 raise ValueError() 671 new_flags = _flagvalues.FlagValues() 672 new_flags._register_unknown_flag_setter(setter) 673 with self.assertRaises(_exceptions.IllegalFlagValueError): 674 new_flags.undefined_flag = 0 675 676 677class SetAttributesTest(absltest.TestCase): 678 679 def setUp(self): 680 super(SetAttributesTest, self).setUp() 681 self.new_flags = _flagvalues.FlagValues() 682 _defines.DEFINE_boolean( 683 'defined_flag', None, '', flag_values=self.new_flags) 684 _defines.DEFINE_boolean( 685 'another_defined_flag', None, '', flag_values=self.new_flags) 686 self.setter_called = 0 687 688 def set_undef(self, unused_name, unused_val): 689 self.setter_called += 1 690 691 def test_two_defined_flags(self): 692 self.new_flags._set_attributes( 693 defined_flag=False, another_defined_flag=False) 694 self.assertEqual(self.setter_called, 0) 695 696 def test_one_defined_one_undefined_flag(self): 697 with self.assertRaises(_exceptions.UnrecognizedFlagError): 698 self.new_flags._set_attributes(defined_flag=False, undefined_flag=0) 699 700 def test_register_unknown_flag_setter(self): 701 self.new_flags._register_unknown_flag_setter(self.set_undef) 702 self.new_flags._set_attributes(defined_flag=False, undefined_flag=0) 703 self.assertEqual(self.setter_called, 1) 704 705 706class FlagsDashSyntaxTest(absltest.TestCase): 707 708 def setUp(self): 709 super(FlagsDashSyntaxTest, self).setUp() 710 self.fv = _flagvalues.FlagValues() 711 _defines.DEFINE_string( 712 'long_name', 'default', 'help', flag_values=self.fv, short_name='s') 713 714 def test_long_name_one_dash(self): 715 self.fv(['./program', '-long_name=new']) 716 self.assertEqual('new', self.fv.long_name) 717 718 def test_long_name_two_dashes(self): 719 self.fv(['./program', '--long_name=new']) 720 self.assertEqual('new', self.fv.long_name) 721 722 def test_long_name_three_dashes(self): 723 with self.assertRaises(_exceptions.UnrecognizedFlagError): 724 self.fv(['./program', '---long_name=new']) 725 726 def test_short_name_one_dash(self): 727 self.fv(['./program', '-s=new']) 728 self.assertEqual('new', self.fv.s) 729 730 def test_short_name_two_dashes(self): 731 self.fv(['./program', '--s=new']) 732 self.assertEqual('new', self.fv.s) 733 734 def test_short_name_three_dashes(self): 735 with self.assertRaises(_exceptions.UnrecognizedFlagError): 736 self.fv(['./program', '---s=new']) 737 738 739class UnparseFlagsTest(absltest.TestCase): 740 741 def test_using_default_value_none(self): 742 fv = _flagvalues.FlagValues() 743 _defines.DEFINE_string('default_none', None, 'help', flag_values=fv) 744 self.assertTrue(fv['default_none'].using_default_value) 745 fv(['', '--default_none=notNone']) 746 self.assertFalse(fv['default_none'].using_default_value) 747 fv.unparse_flags() 748 self.assertTrue(fv['default_none'].using_default_value) 749 fv(['', '--default_none=alsoNotNone']) 750 self.assertFalse(fv['default_none'].using_default_value) 751 fv.unparse_flags() 752 self.assertTrue(fv['default_none'].using_default_value) 753 754 def test_using_default_value_not_none(self): 755 fv = _flagvalues.FlagValues() 756 _defines.DEFINE_string('default_foo', 'foo', 'help', flag_values=fv) 757 758 fv.mark_as_parsed() 759 self.assertTrue(fv['default_foo'].using_default_value) 760 761 fv(['', '--default_foo=foo']) 762 self.assertFalse(fv['default_foo'].using_default_value) 763 764 fv(['', '--default_foo=notFoo']) 765 self.assertFalse(fv['default_foo'].using_default_value) 766 767 fv.unparse_flags() 768 self.assertTrue(fv['default_foo'].using_default_value) 769 770 fv(['', '--default_foo=alsoNotFoo']) 771 self.assertFalse(fv['default_foo'].using_default_value) 772 773 def test_allow_overwrite_false(self): 774 fv = _flagvalues.FlagValues() 775 _defines.DEFINE_string( 776 'default_none', None, 'help', allow_overwrite=False, flag_values=fv) 777 _defines.DEFINE_string( 778 'default_foo', 'foo', 'help', allow_overwrite=False, flag_values=fv) 779 780 fv.mark_as_parsed() 781 self.assertEqual('foo', fv.default_foo) 782 self.assertIsNone(fv.default_none) 783 784 fv(['', '--default_foo=notFoo', '--default_none=notNone']) 785 self.assertEqual('notFoo', fv.default_foo) 786 self.assertEqual('notNone', fv.default_none) 787 788 fv.unparse_flags() 789 self.assertEqual('foo', fv['default_foo'].value) 790 self.assertIsNone(fv['default_none'].value) 791 792 fv(['', '--default_foo=alsoNotFoo', '--default_none=alsoNotNone']) 793 self.assertEqual('alsoNotFoo', fv.default_foo) 794 self.assertEqual('alsoNotNone', fv.default_none) 795 796 def test_multi_string_default_none(self): 797 fv = _flagvalues.FlagValues() 798 _defines.DEFINE_multi_string('foo', None, 'help', flag_values=fv) 799 fv.mark_as_parsed() 800 self.assertIsNone(fv.foo) 801 fv(['', '--foo=aa']) 802 self.assertEqual(['aa'], fv.foo) 803 fv.unparse_flags() 804 self.assertIsNone(fv['foo'].value) 805 fv(['', '--foo=bb', '--foo=cc']) 806 self.assertEqual(['bb', 'cc'], fv.foo) 807 fv.unparse_flags() 808 self.assertIsNone(fv['foo'].value) 809 810 def test_multi_string_default_string(self): 811 fv = _flagvalues.FlagValues() 812 _defines.DEFINE_multi_string('foo', 'xyz', 'help', flag_values=fv) 813 expected_default = ['xyz'] 814 fv.mark_as_parsed() 815 self.assertEqual(expected_default, fv.foo) 816 fv(['', '--foo=aa']) 817 self.assertEqual(['aa'], fv.foo) 818 fv.unparse_flags() 819 self.assertEqual(expected_default, fv['foo'].value) 820 fv(['', '--foo=bb', '--foo=cc']) 821 self.assertEqual(['bb', 'cc'], fv['foo'].value) 822 fv.unparse_flags() 823 self.assertEqual(expected_default, fv['foo'].value) 824 825 def test_multi_string_default_list(self): 826 fv = _flagvalues.FlagValues() 827 _defines.DEFINE_multi_string( 828 'foo', ['xx', 'yy', 'zz'], 'help', flag_values=fv) 829 expected_default = ['xx', 'yy', 'zz'] 830 fv.mark_as_parsed() 831 self.assertEqual(expected_default, fv.foo) 832 fv(['', '--foo=aa']) 833 self.assertEqual(['aa'], fv.foo) 834 fv.unparse_flags() 835 self.assertEqual(expected_default, fv['foo'].value) 836 fv(['', '--foo=bb', '--foo=cc']) 837 self.assertEqual(['bb', 'cc'], fv.foo) 838 fv.unparse_flags() 839 self.assertEqual(expected_default, fv['foo'].value) 840 841 842class UnparsedFlagAccessTest(absltest.TestCase): 843 844 def test_unparsed_flag_access(self): 845 fv = _flagvalues.FlagValues() 846 _defines.DEFINE_string('name', 'default', 'help', flag_values=fv) 847 with self.assertRaises(_exceptions.UnparsedFlagAccessError): 848 _ = fv.name 849 850 def test_hasattr_raises_in_py3(self): 851 fv = _flagvalues.FlagValues() 852 _defines.DEFINE_string('name', 'default', 'help', flag_values=fv) 853 with self.assertRaises(_exceptions.UnparsedFlagAccessError): 854 _ = hasattr(fv, 'name') 855 856 def test_unparsed_flags_access_raises_after_unparse_flags(self): 857 fv = _flagvalues.FlagValues() 858 _defines.DEFINE_string('a_str', 'default_value', 'help', flag_values=fv) 859 fv.mark_as_parsed() 860 self.assertEqual(fv.a_str, 'default_value') 861 fv.unparse_flags() 862 with self.assertRaises(_exceptions.UnparsedFlagAccessError): 863 _ = fv.a_str 864 865 866class FlagHolderTest(absltest.TestCase): 867 868 def setUp(self): 869 super(FlagHolderTest, self).setUp() 870 self.fv = _flagvalues.FlagValues() 871 self.name_flag = _defines.DEFINE_string( 872 'name', 'default', 'help', flag_values=self.fv) 873 874 def parse_flags(self, *argv): 875 self.fv.unparse_flags() 876 self.fv(['binary_name'] + list(argv)) 877 878 def test_name(self): 879 self.assertEqual('name', self.name_flag.name) 880 881 def test_value_before_flag_parsing(self): 882 with self.assertRaises(_exceptions.UnparsedFlagAccessError): 883 _ = self.name_flag.value 884 885 def test_value_returns_default_value_if_not_explicitly_set(self): 886 self.parse_flags() 887 self.assertEqual('default', self.name_flag.value) 888 889 def test_value_returns_explicitly_set_value(self): 890 self.parse_flags('--name=new_value') 891 self.assertEqual('new_value', self.name_flag.value) 892 893 def test_present_returns_false_before_flag_parsing(self): 894 self.assertFalse(self.name_flag.present) 895 896 def test_present_returns_false_if_not_explicitly_set(self): 897 self.parse_flags() 898 self.assertFalse(self.name_flag.present) 899 900 def test_present_returns_true_if_explicitly_set(self): 901 self.parse_flags('--name=new_value') 902 self.assertTrue(self.name_flag.present) 903 904 def test_allow_override(self): 905 first = _defines.DEFINE_integer( 906 'int_flag', 1, 'help', flag_values=self.fv, allow_override=1) 907 second = _defines.DEFINE_integer( 908 'int_flag', 2, 'help', flag_values=self.fv, allow_override=1) 909 self.parse_flags('--int_flag=3') 910 self.assertEqual(3, first.value) 911 self.assertEqual(3, second.value) 912 self.assertTrue(first.present) 913 self.assertTrue(second.present) 914 915 def test_eq(self): 916 with self.assertRaises(TypeError): 917 self.name_flag == 'value' # pylint: disable=pointless-statement 918 919 def test_eq_reflection(self): 920 with self.assertRaises(TypeError): 921 'value' == self.name_flag # pylint: disable=pointless-statement 922 923 def test_bool(self): 924 with self.assertRaises(TypeError): 925 bool(self.name_flag) 926 927 928if __name__ == '__main__': 929 absltest.main() 930