• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""Tests for absl.flags used as a package."""
15
16import contextlib
17import enum
18import io
19import os
20import shutil
21import sys
22import tempfile
23import unittest
24
25from absl import flags
26from absl.flags import _exceptions
27from absl.flags import _helpers
28from absl.flags.tests import module_bar
29from absl.flags.tests import module_baz
30from absl.flags.tests import module_foo
31from absl.testing import absltest
32
33FLAGS = flags.FLAGS
34
35
36@contextlib.contextmanager
37def _use_gnu_getopt(flag_values, use_gnu_get_opt):
38  old_use_gnu_get_opt = flag_values.is_gnu_getopt()
39  flag_values.set_gnu_getopt(use_gnu_get_opt)
40  yield
41  flag_values.set_gnu_getopt(old_use_gnu_get_opt)
42
43
44class FlagDictToArgsTest(absltest.TestCase):
45
46  def test_flatten_google_flag_map(self):
47    arg_dict = {
48        'week-end': None,
49        'estudia': False,
50        'trabaja': False,
51        'party': True,
52        'monday': 'party',
53        'score': 42,
54        'loadthatstuff': [42, 'hello', 'goodbye'],
55    }
56    self.assertSameElements(
57        ('--week-end', '--noestudia', '--notrabaja', '--party',
58         '--monday=party', '--score=42', '--loadthatstuff=42,hello,goodbye'),
59        flags.flag_dict_to_args(arg_dict))
60
61  def test_flatten_google_flag_map_with_multi_flag(self):
62    arg_dict = {
63        'some_list': ['value1', 'value2'],
64        'some_multi_string': ['value3', 'value4'],
65    }
66    self.assertSameElements(
67        ('--some_list=value1,value2', '--some_multi_string=value3',
68         '--some_multi_string=value4'),
69        flags.flag_dict_to_args(arg_dict, multi_flags={'some_multi_string'}))
70
71
72class Fruit(enum.Enum):
73  APPLE = object()
74  ORANGE = object()
75
76
77class CaseSensitiveFruit(enum.Enum):
78  apple = 1
79  orange = 2
80  APPLE = 3
81
82
83class EmptyEnum(enum.Enum):
84  pass
85
86
87class AliasFlagsTest(absltest.TestCase):
88
89  def setUp(self):
90    super(AliasFlagsTest, self).setUp()
91    self.flags = flags.FlagValues()
92
93  @property
94  def alias(self):
95    return self.flags['alias']
96
97  @property
98  def aliased(self):
99    return self.flags['aliased']
100
101  def define_alias(self, *args, **kwargs):
102    flags.DEFINE_alias(*args, flag_values=self.flags, **kwargs)
103
104  def define_integer(self, *args, **kwargs):
105    flags.DEFINE_integer(*args, flag_values=self.flags, **kwargs)
106
107  def define_multi_integer(self, *args, **kwargs):
108    flags.DEFINE_multi_integer(*args, flag_values=self.flags, **kwargs)
109
110  def define_string(self, *args, **kwargs):
111    flags.DEFINE_string(*args, flag_values=self.flags, **kwargs)
112
113  def assert_alias_mirrors_aliased(self, alias, aliased, ignore_due_to_bug=()):
114    # A few sanity checks to avoid false success
115    self.assertIn('FlagAlias', alias.__class__.__qualname__)
116    self.assertIsNot(alias, aliased)
117    self.assertNotEqual(aliased.name, alias.name)
118
119    alias_state = {}
120    aliased_state = {}
121    attrs = {
122        'allow_hide_cpp',
123        'allow_override',
124        'allow_override_cpp',
125        'allow_overwrite',
126        'allow_using_method_names',
127        'boolean',
128        'default',
129        'default_as_str',
130        'default_unparsed',
131        # TODO(rlevasseur): This should match, but a bug prevents it from being
132        # in sync.
133        # 'using_default_value',
134        'value',
135    }
136    attrs.difference_update(ignore_due_to_bug)
137
138    for attr in attrs:
139      alias_state[attr] = getattr(alias, attr)
140      aliased_state[attr] = getattr(aliased, attr)
141
142    self.assertEqual(aliased_state, alias_state, 'LHS is aliased; RHS is alias')
143
144  def test_serialize_multi(self):
145    self.define_multi_integer('aliased', [0, 1], '')
146    self.define_alias('alias', 'aliased')
147
148    actual = self.alias.serialize()
149    # TODO(rlevasseur): This should check for --alias=0\n--alias=1, but
150    # a bug causes it to serialize incorrectly.
151    self.assertEqual('--alias=[0, 1]', actual)
152
153  def test_allow_overwrite_false(self):
154    self.define_integer('aliased', None, 'help', allow_overwrite=False)
155    self.define_alias('alias', 'aliased')
156
157    with self.assertRaisesRegex(flags.IllegalFlagValueError, 'already defined'):
158      self.flags(['./program', '--alias=1', '--aliased=2'])
159
160    self.assertEqual(1, self.alias.value)
161    self.assertEqual(1, self.aliased.value)
162
163  def test_aliasing_multi_no_default(self):
164
165    def define_flags():
166      self.flags = flags.FlagValues()
167      self.define_multi_integer('aliased', None, 'help')
168      self.define_alias('alias', 'aliased')
169
170    with self.subTest('after defining'):
171      define_flags()
172      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
173      self.assertIsNone(self.alias.value)
174
175    with self.subTest('set alias'):
176      define_flags()
177      self.flags(['./program', '--alias=1', '--alias=2'])
178      self.assertEqual([1, 2], self.alias.value)
179      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
180
181    with self.subTest('set aliased'):
182      define_flags()
183      self.flags(['./program', '--aliased=1', '--aliased=2'])
184      self.assertEqual([1, 2], self.alias.value)
185      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
186
187    with self.subTest('not setting anything'):
188      define_flags()
189      self.flags(['./program'])
190      self.assertEqual(None, self.alias.value)
191      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
192
193  def test_aliasing_multi_with_default(self):
194
195    def define_flags():
196      self.flags = flags.FlagValues()
197      self.define_multi_integer('aliased', [0], 'help')
198      self.define_alias('alias', 'aliased')
199
200    with self.subTest('after defining'):
201      define_flags()
202      self.assertEqual([0], self.alias.default)
203      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
204
205    with self.subTest('set alias'):
206      define_flags()
207      self.flags(['./program', '--alias=1', '--alias=2'])
208      self.assertEqual([1, 2], self.alias.value)
209      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
210
211      self.assertEqual(2, self.alias.present)
212      # TODO(rlevasseur): This should assert 0, but a bug with aliases and
213      # MultiFlag causes the alias to increment aliased's present counter.
214      self.assertEqual(2, self.aliased.present)
215
216    with self.subTest('set aliased'):
217      define_flags()
218      self.flags(['./program', '--aliased=1', '--aliased=2'])
219      self.assertEqual([1, 2], self.alias.value)
220      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
221      self.assertEqual(0, self.alias.present)
222
223      # TODO(rlevasseur): This should assert 0, but a bug with aliases and
224      # MultiFlag causes the alias to increment aliased present counter.
225      self.assertEqual(2, self.aliased.present)
226
227    with self.subTest('not setting anything'):
228      define_flags()
229      self.flags(['./program'])
230      self.assertEqual([0], self.alias.value)
231      self.assert_alias_mirrors_aliased(self.alias, self.aliased)
232      self.assertEqual(0, self.alias.present)
233      self.assertEqual(0, self.aliased.present)
234
235  def test_aliasing_regular(self):
236
237    def define_flags():
238      self.flags = flags.FlagValues()
239      self.define_string('aliased', '', 'help')
240      self.define_alias('alias', 'aliased')
241
242    define_flags()
243    self.assert_alias_mirrors_aliased(self.alias, self.aliased)
244
245    self.flags(['./program', '--alias=1'])
246    self.assertEqual('1', self.alias.value)
247    self.assert_alias_mirrors_aliased(self.alias, self.aliased)
248    self.assertEqual(1, self.alias.present)
249    self.assertEqual('--alias=1', self.alias.serialize())
250    self.assertEqual(1, self.aliased.present)
251
252    define_flags()
253    self.flags(['./program', '--aliased=2'])
254    self.assertEqual('2', self.alias.value)
255    self.assert_alias_mirrors_aliased(self.alias, self.aliased)
256    self.assertEqual(0, self.alias.present)
257    self.assertEqual('--alias=2', self.alias.serialize())
258    self.assertEqual(1, self.aliased.present)
259
260  def test_defining_alias_doesnt_affect_aliased_state_regular(self):
261    self.define_string('aliased', 'default', 'help')
262    self.define_alias('alias', 'aliased')
263
264    self.assertEqual(0, self.aliased.present)
265    self.assertEqual(0, self.alias.present)
266
267  def test_defining_alias_doesnt_affect_aliased_state_multi(self):
268    self.define_multi_integer('aliased', [0], 'help')
269    self.define_alias('alias', 'aliased')
270
271    self.assertEqual([0], self.aliased.value)
272    self.assertEqual([0], self.aliased.default)
273    self.assertEqual(0, self.aliased.present)
274
275    self.assertEqual([0], self.aliased.value)
276    self.assertEqual([0], self.aliased.default)
277    self.assertEqual(0, self.alias.present)
278
279
280class FlagsUnitTest(absltest.TestCase):
281  """Flags Unit Test."""
282
283  maxDiff = None
284
285  def test_flags(self):
286    """Test normal usage with no (expected) errors."""
287    # Define flags
288    number_test_framework_flags = len(FLAGS)
289    repeat_help = 'how many times to repeat (0-5)'
290    flags.DEFINE_integer(
291        'repeat', 4, repeat_help, lower_bound=0, short_name='r')
292    flags.DEFINE_string('name', 'Bob', 'namehelp')
293    flags.DEFINE_boolean('debug', 0, 'debughelp')
294    flags.DEFINE_boolean('q', 1, 'quiet mode')
295    flags.DEFINE_boolean('quack', 0, "superstring of 'q'")
296    flags.DEFINE_boolean('noexec', 1, 'boolean flag with no as prefix')
297    flags.DEFINE_float('float', 3.14, 'using floats')
298    flags.DEFINE_integer('octal', '0o666', 'using octals')
299    flags.DEFINE_integer('decimal', '666', 'using decimals')
300    flags.DEFINE_integer('hexadecimal', '0x666', 'using hexadecimals')
301    flags.DEFINE_integer('x', 3, 'how eXtreme to be')
302    flags.DEFINE_integer('l', 0x7fffffff00000000, 'how long to be')
303    flags.DEFINE_list('args', 'v=1,"vmodule=a=0,b=2"', 'a list of arguments')
304    flags.DEFINE_list('letters', 'a,b,c', 'a list of letters')
305    flags.DEFINE_list('numbers', [1, 2, 3], 'a list of numbers')
306    flags.DEFINE_enum('kwery', None, ['who', 'what', 'Why', 'where', 'when'],
307                      '?')
308    flags.DEFINE_enum(
309        'sense', None, ['Case', 'case', 'CASE'], '?', case_sensitive=True)
310    flags.DEFINE_enum(
311        'cases',
312        None, ['UPPER', 'lower', 'Initial', 'Ot_HeR'],
313        '?',
314        case_sensitive=False)
315    flags.DEFINE_enum(
316        'funny',
317        None, ['Joke', 'ha', 'ha', 'ha', 'ha'],
318        '?',
319        case_sensitive=True)
320    flags.DEFINE_enum(
321        'blah',
322        None, ['bla', 'Blah', 'BLAH', 'blah'],
323        '?',
324        case_sensitive=False)
325    flags.DEFINE_string(
326        'only_once', None, 'test only sets this once', allow_overwrite=False)
327    flags.DEFINE_string(
328        'universe',
329        None,
330        'test tries to set this three times',
331        allow_overwrite=False)
332
333    # Specify number of flags defined above.  The short_name defined
334    # for 'repeat' counts as an extra flag.
335    number_defined_flags = 22 + 1
336    self.assertLen(FLAGS, number_defined_flags + number_test_framework_flags)
337
338    self.assertEqual(FLAGS.repeat, 4)
339    self.assertEqual(FLAGS.name, 'Bob')
340    self.assertEqual(FLAGS.debug, 0)
341    self.assertEqual(FLAGS.q, 1)
342    self.assertEqual(FLAGS.octal, 0o666)
343    self.assertEqual(FLAGS.decimal, 666)
344    self.assertEqual(FLAGS.hexadecimal, 0x666)
345    self.assertEqual(FLAGS.x, 3)
346    self.assertEqual(FLAGS.l, 0x7fffffff00000000)
347    self.assertEqual(FLAGS.args, ['v=1', 'vmodule=a=0,b=2'])
348    self.assertEqual(FLAGS.letters, ['a', 'b', 'c'])
349    self.assertEqual(FLAGS.numbers, [1, 2, 3])
350    self.assertIsNone(FLAGS.kwery)
351    self.assertIsNone(FLAGS.sense)
352    self.assertIsNone(FLAGS.cases)
353    self.assertIsNone(FLAGS.funny)
354    self.assertIsNone(FLAGS.blah)
355
356    flag_values = FLAGS.flag_values_dict()
357    self.assertEqual(flag_values['repeat'], 4)
358    self.assertEqual(flag_values['name'], 'Bob')
359    self.assertEqual(flag_values['debug'], 0)
360    self.assertEqual(flag_values['r'], 4)  # Short for repeat.
361    self.assertEqual(flag_values['q'], 1)
362    self.assertEqual(flag_values['quack'], 0)
363    self.assertEqual(flag_values['x'], 3)
364    self.assertEqual(flag_values['l'], 0x7fffffff00000000)
365    self.assertEqual(flag_values['args'], ['v=1', 'vmodule=a=0,b=2'])
366    self.assertEqual(flag_values['letters'], ['a', 'b', 'c'])
367    self.assertEqual(flag_values['numbers'], [1, 2, 3])
368    self.assertIsNone(flag_values['kwery'])
369    self.assertIsNone(flag_values['sense'])
370    self.assertIsNone(flag_values['cases'])
371    self.assertIsNone(flag_values['funny'])
372    self.assertIsNone(flag_values['blah'])
373
374    # Verify string form of defaults
375    self.assertEqual(FLAGS['repeat'].default_as_str, "'4'")
376    self.assertEqual(FLAGS['name'].default_as_str, "'Bob'")
377    self.assertEqual(FLAGS['debug'].default_as_str, "'false'")
378    self.assertEqual(FLAGS['q'].default_as_str, "'true'")
379    self.assertEqual(FLAGS['quack'].default_as_str, "'false'")
380    self.assertEqual(FLAGS['noexec'].default_as_str, "'true'")
381    self.assertEqual(FLAGS['x'].default_as_str, "'3'")
382    self.assertEqual(FLAGS['l'].default_as_str, "'9223372032559808512'")
383    self.assertEqual(FLAGS['args'].default_as_str, '\'v=1,"vmodule=a=0,b=2"\'')
384    self.assertEqual(FLAGS['letters'].default_as_str, "'a,b,c'")
385    self.assertEqual(FLAGS['numbers'].default_as_str, "'1,2,3'")
386
387    # Verify that the iterator for flags yields all the keys
388    keys = list(FLAGS)
389    keys.sort()
390    reg_flags = list(FLAGS._flags())
391    reg_flags.sort()
392    self.assertEqual(keys, reg_flags)
393
394    # Parse flags
395    # .. empty command line
396    argv = ('./program',)
397    argv = FLAGS(argv)
398    self.assertLen(argv, 1, 'wrong number of arguments pulled')
399    self.assertEqual(argv[0], './program', 'program name not preserved')
400
401    # .. non-empty command line
402    argv = ('./program', '--debug', '--name=Bob', '-q', '--x=8')
403    argv = FLAGS(argv)
404    self.assertLen(argv, 1, 'wrong number of arguments pulled')
405    self.assertEqual(argv[0], './program', 'program name not preserved')
406    self.assertEqual(FLAGS['debug'].present, 1)
407    FLAGS['debug'].present = 0  # Reset
408    self.assertEqual(FLAGS['name'].present, 1)
409    FLAGS['name'].present = 0  # Reset
410    self.assertEqual(FLAGS['q'].present, 1)
411    FLAGS['q'].present = 0  # Reset
412    self.assertEqual(FLAGS['x'].present, 1)
413    FLAGS['x'].present = 0  # Reset
414
415    # Flags list.
416    self.assertLen(FLAGS, number_defined_flags + number_test_framework_flags)
417    self.assertIn('name', FLAGS)
418    self.assertIn('debug', FLAGS)
419    self.assertIn('repeat', FLAGS)
420    self.assertIn('r', FLAGS)
421    self.assertIn('q', FLAGS)
422    self.assertIn('quack', FLAGS)
423    self.assertIn('x', FLAGS)
424    self.assertIn('l', FLAGS)
425    self.assertIn('args', FLAGS)
426    self.assertIn('letters', FLAGS)
427    self.assertIn('numbers', FLAGS)
428
429    # __contains__
430    self.assertIn('name', FLAGS)
431    self.assertNotIn('name2', FLAGS)
432
433    # try deleting a flag
434    del FLAGS.r
435    self.assertLen(FLAGS,
436                   number_defined_flags - 1 + number_test_framework_flags)
437    self.assertNotIn('r', FLAGS)
438
439    # .. command line with extra stuff
440    argv = ('./program', '--debug', '--name=Bob', 'extra')
441    argv = FLAGS(argv)
442    self.assertLen(argv, 2, 'wrong number of arguments pulled')
443    self.assertEqual(argv[0], './program', 'program name not preserved')
444    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
445    self.assertEqual(FLAGS['debug'].present, 1)
446    FLAGS['debug'].present = 0  # Reset
447    self.assertEqual(FLAGS['name'].present, 1)
448    FLAGS['name'].present = 0  # Reset
449
450    # Test reset
451    argv = ('./program', '--debug')
452    argv = FLAGS(argv)
453    self.assertLen(argv, 1, 'wrong number of arguments pulled')
454    self.assertEqual(argv[0], './program', 'program name not preserved')
455    self.assertEqual(FLAGS['debug'].present, 1)
456    self.assertTrue(FLAGS['debug'].value)
457    FLAGS.unparse_flags()
458    self.assertEqual(FLAGS['debug'].present, 0)
459    self.assertFalse(FLAGS['debug'].value)
460
461    # Test that reset restores default value when default value is None.
462    argv = ('./program', '--kwery=who')
463    argv = FLAGS(argv)
464    self.assertLen(argv, 1, 'wrong number of arguments pulled')
465    self.assertEqual(argv[0], './program', 'program name not preserved')
466    self.assertEqual(FLAGS['kwery'].present, 1)
467    self.assertEqual(FLAGS['kwery'].value, 'who')
468    FLAGS.unparse_flags()
469    argv = ('./program', '--kwery=Why')
470    argv = FLAGS(argv)
471    self.assertLen(argv, 1, 'wrong number of arguments pulled')
472    self.assertEqual(argv[0], './program', 'program name not preserved')
473    self.assertEqual(FLAGS['kwery'].present, 1)
474    self.assertEqual(FLAGS['kwery'].value, 'Why')
475    FLAGS.unparse_flags()
476    self.assertEqual(FLAGS['kwery'].present, 0)
477    self.assertIsNone(FLAGS['kwery'].value)
478
479    # Test case sensitive enum.
480    argv = ('./program', '--sense=CASE')
481    argv = FLAGS(argv)
482    self.assertLen(argv, 1, 'wrong number of arguments pulled')
483    self.assertEqual(argv[0], './program', 'program name not preserved')
484    self.assertEqual(FLAGS['sense'].present, 1)
485    self.assertEqual(FLAGS['sense'].value, 'CASE')
486    FLAGS.unparse_flags()
487    argv = ('./program', '--sense=Case')
488    argv = FLAGS(argv)
489    self.assertLen(argv, 1, 'wrong number of arguments pulled')
490    self.assertEqual(argv[0], './program', 'program name not preserved')
491    self.assertEqual(FLAGS['sense'].present, 1)
492    self.assertEqual(FLAGS['sense'].value, 'Case')
493    FLAGS.unparse_flags()
494
495    # Test case insensitive enum.
496    argv = ('./program', '--cases=upper')
497    argv = FLAGS(argv)
498    self.assertLen(argv, 1, 'wrong number of arguments pulled')
499    self.assertEqual(argv[0], './program', 'program name not preserved')
500    self.assertEqual(FLAGS['cases'].present, 1)
501    self.assertEqual(FLAGS['cases'].value, 'UPPER')
502    FLAGS.unparse_flags()
503
504    # Test case sensitive enum with duplicates.
505    argv = ('./program', '--funny=ha')
506    argv = FLAGS(argv)
507    self.assertLen(argv, 1, 'wrong number of arguments pulled')
508    self.assertEqual(argv[0], './program', 'program name not preserved')
509    self.assertEqual(FLAGS['funny'].present, 1)
510    self.assertEqual(FLAGS['funny'].value, 'ha')
511    FLAGS.unparse_flags()
512
513    # Test case insensitive enum with duplicates.
514    argv = ('./program', '--blah=bLah')
515    argv = FLAGS(argv)
516    self.assertLen(argv, 1, 'wrong number of arguments pulled')
517    self.assertEqual(argv[0], './program', 'program name not preserved')
518    self.assertEqual(FLAGS['blah'].present, 1)
519    self.assertEqual(FLAGS['blah'].value, 'Blah')
520    FLAGS.unparse_flags()
521    argv = ('./program', '--blah=BLAH')
522    argv = FLAGS(argv)
523    self.assertLen(argv, 1, 'wrong number of arguments pulled')
524    self.assertEqual(argv[0], './program', 'program name not preserved')
525    self.assertEqual(FLAGS['blah'].present, 1)
526    self.assertEqual(FLAGS['blah'].value, 'Blah')
527    FLAGS.unparse_flags()
528
529    # Test integer argument passing
530    argv = ('./program', '--x', '0x12345')
531    argv = FLAGS(argv)
532    self.assertEqual(FLAGS.x, 0x12345)
533    self.assertEqual(type(FLAGS.x), int)
534
535    argv = ('./program', '--x', '0x1234567890ABCDEF1234567890ABCDEF')
536    argv = FLAGS(argv)
537    self.assertEqual(FLAGS.x, 0x1234567890ABCDEF1234567890ABCDEF)
538    self.assertIsInstance(FLAGS.x, int)
539
540    argv = ('./program', '--x', '0o12345')
541    argv = FLAGS(argv)
542    self.assertEqual(FLAGS.x, 0o12345)
543    self.assertEqual(type(FLAGS.x), int)
544
545    # Treat 0-prefixed parameters as base-10, not base-8
546    argv = ('./program', '--x', '012345')
547    argv = FLAGS(argv)
548    self.assertEqual(FLAGS.x, 12345)
549    self.assertEqual(type(FLAGS.x), int)
550
551    argv = ('./program', '--x', '0123459')
552    argv = FLAGS(argv)
553    self.assertEqual(FLAGS.x, 123459)
554    self.assertEqual(type(FLAGS.x), int)
555
556    argv = ('./program', '--x', '0x123efg')
557    with self.assertRaises(flags.IllegalFlagValueError):
558      argv = FLAGS(argv)
559
560    # Test boolean argument parsing
561    flags.DEFINE_boolean('test0', None, 'test boolean parsing')
562    argv = ('./program', '--notest0')
563    argv = FLAGS(argv)
564    self.assertEqual(FLAGS.test0, 0)
565
566    flags.DEFINE_boolean('test1', None, 'test boolean parsing')
567    argv = ('./program', '--test1')
568    argv = FLAGS(argv)
569    self.assertEqual(FLAGS.test1, 1)
570
571    FLAGS.test0 = None
572    argv = ('./program', '--test0=false')
573    argv = FLAGS(argv)
574    self.assertEqual(FLAGS.test0, 0)
575
576    FLAGS.test1 = None
577    argv = ('./program', '--test1=true')
578    argv = FLAGS(argv)
579    self.assertEqual(FLAGS.test1, 1)
580
581    FLAGS.test0 = None
582    argv = ('./program', '--test0=0')
583    argv = FLAGS(argv)
584    self.assertEqual(FLAGS.test0, 0)
585
586    FLAGS.test1 = None
587    argv = ('./program', '--test1=1')
588    argv = FLAGS(argv)
589    self.assertEqual(FLAGS.test1, 1)
590
591    # Test booleans that already have 'no' as a prefix
592    FLAGS.noexec = None
593    argv = ('./program', '--nonoexec', '--name', 'Bob')
594    argv = FLAGS(argv)
595    self.assertEqual(FLAGS.noexec, 0)
596
597    FLAGS.noexec = None
598    argv = ('./program', '--name', 'Bob', '--noexec')
599    argv = FLAGS(argv)
600    self.assertEqual(FLAGS.noexec, 1)
601
602    # Test unassigned booleans
603    flags.DEFINE_boolean('testnone', None, 'test boolean parsing')
604    argv = ('./program',)
605    argv = FLAGS(argv)
606    self.assertIsNone(FLAGS.testnone)
607
608    # Test get with default
609    flags.DEFINE_boolean('testget1', None, 'test parsing with defaults')
610    flags.DEFINE_boolean('testget2', None, 'test parsing with defaults')
611    flags.DEFINE_boolean('testget3', None, 'test parsing with defaults')
612    flags.DEFINE_integer('testget4', None, 'test parsing with defaults')
613    argv = ('./program', '--testget1', '--notestget2')
614    argv = FLAGS(argv)
615    self.assertEqual(FLAGS.get_flag_value('testget1', 'foo'), 1)
616    self.assertEqual(FLAGS.get_flag_value('testget2', 'foo'), 0)
617    self.assertEqual(FLAGS.get_flag_value('testget3', 'foo'), 'foo')
618    self.assertEqual(FLAGS.get_flag_value('testget4', 'foo'), 'foo')
619
620    # test list code
621    lists = [['hello', 'moo', 'boo', '1'], []]
622
623    flags.DEFINE_list('testcomma_list', '', 'test comma list parsing')
624    flags.DEFINE_spaceseplist('testspace_list', '', 'tests space list parsing')
625    flags.DEFINE_spaceseplist(
626        'testspace_or_comma_list',
627        '',
628        'tests space list parsing with comma compatibility',
629        comma_compat=True)
630
631    for name, sep in (('testcomma_list', ','), ('testspace_list',
632                                                ' '), ('testspace_list', '\n'),
633                      ('testspace_or_comma_list',
634                       ' '), ('testspace_or_comma_list',
635                              '\n'), ('testspace_or_comma_list', ',')):
636      for lst in lists:
637        argv = ('./program', '--%s=%s' % (name, sep.join(lst)))
638        argv = FLAGS(argv)
639        self.assertEqual(getattr(FLAGS, name), lst)
640
641    # Test help text
642    flags_help = str(FLAGS)
643    self.assertNotEqual(
644        flags_help.find('repeat'), -1, 'cannot find flag in help')
645    self.assertNotEqual(
646        flags_help.find(repeat_help), -1, 'cannot find help string in help')
647
648    # Test flag specified twice
649    argv = ('./program', '--repeat=4', '--repeat=2', '--debug', '--nodebug')
650    argv = FLAGS(argv)
651    self.assertEqual(FLAGS.get_flag_value('repeat', None), 2)
652    self.assertEqual(FLAGS.get_flag_value('debug', None), 0)
653
654    # Test MultiFlag with single default value
655    flags.DEFINE_multi_string(
656        's_str',
657        'sing1',
658        'string option that can occur multiple times',
659        short_name='s')
660    self.assertEqual(FLAGS.get_flag_value('s_str', None), ['sing1'])
661
662    # Test MultiFlag with list of default values
663    multi_string_defs = ['def1', 'def2']
664    flags.DEFINE_multi_string(
665        'm_str',
666        multi_string_defs,
667        'string option that can occur multiple times',
668        short_name='m')
669    self.assertEqual(FLAGS.get_flag_value('m_str', None), multi_string_defs)
670
671    # Test flag specified multiple times with a MultiFlag
672    argv = ('./program', '--m_str=str1', '-m', 'str2')
673    argv = FLAGS(argv)
674    self.assertEqual(FLAGS.get_flag_value('m_str', None), ['str1', 'str2'])
675
676    # A flag with allow_overwrite set to False should behave normally when it
677    # is only specified once
678    argv = ('./program', '--only_once=singlevalue')
679    argv = FLAGS(argv)
680    self.assertEqual(FLAGS.get_flag_value('only_once', None), 'singlevalue')
681
682    # A flag with allow_overwrite set to False should complain when it is
683    # specified more than once
684    argv = ('./program', '--universe=ptolemaic', '--universe=copernicean',
685            '--universe=euclidean')
686    self.assertRaisesWithLiteralMatch(
687        flags.IllegalFlagValueError,
688        'flag --universe=copernicean: already defined as ptolemaic', FLAGS,
689        argv)
690
691    # Test single-letter flags; should support both single and double dash
692    argv = ('./program', '-q')
693    argv = FLAGS(argv)
694    self.assertEqual(FLAGS.get_flag_value('q', None), 1)
695
696    argv = ('./program', '--q', '--x', '9', '--noquack')
697    argv = FLAGS(argv)
698    self.assertEqual(FLAGS.get_flag_value('q', None), 1)
699    self.assertEqual(FLAGS.get_flag_value('x', None), 9)
700    self.assertEqual(FLAGS.get_flag_value('quack', None), 0)
701
702    argv = ('./program', '--noq', '--x=10', '--quack')
703    argv = FLAGS(argv)
704    self.assertEqual(FLAGS.get_flag_value('q', None), 0)
705    self.assertEqual(FLAGS.get_flag_value('x', None), 10)
706    self.assertEqual(FLAGS.get_flag_value('quack', None), 1)
707
708    ####################################
709    # Test flag serialization code:
710
711    old_testcomma_list = FLAGS.testcomma_list
712    old_testspace_list = FLAGS.testspace_list
713    old_testspace_or_comma_list = FLAGS.testspace_or_comma_list
714
715    argv = ('./program', FLAGS['test0'].serialize(), FLAGS['test1'].serialize(),
716            FLAGS['s_str'].serialize())
717
718    argv = FLAGS(argv)
719    self.assertEqual(FLAGS['test0'].serialize(), '--notest0')
720    self.assertEqual(FLAGS['test1'].serialize(), '--test1')
721    self.assertEqual(FLAGS['s_str'].serialize(), '--s_str=sing1')
722
723    self.assertEqual(FLAGS['testnone'].serialize(), '')
724
725    testcomma_list1 = ['aa', 'bb']
726    testspace_list1 = ['aa', 'bb', 'cc']
727    testspace_or_comma_list1 = ['aa', 'bb', 'cc', 'dd']
728    FLAGS.testcomma_list = list(testcomma_list1)
729    FLAGS.testspace_list = list(testspace_list1)
730    FLAGS.testspace_or_comma_list = list(testspace_or_comma_list1)
731    argv = ('./program', FLAGS['testcomma_list'].serialize(),
732            FLAGS['testspace_list'].serialize(),
733            FLAGS['testspace_or_comma_list'].serialize())
734    argv = FLAGS(argv)
735    self.assertEqual(FLAGS.testcomma_list, testcomma_list1)
736    self.assertEqual(FLAGS.testspace_list, testspace_list1)
737    self.assertEqual(FLAGS.testspace_or_comma_list, testspace_or_comma_list1)
738
739    testcomma_list1 = ['aa some spaces', 'bb']
740    testspace_list1 = ['aa', 'bb,some,commas,', 'cc']
741    testspace_or_comma_list1 = ['aa', 'bb,some,commas,', 'cc']
742    FLAGS.testcomma_list = list(testcomma_list1)
743    FLAGS.testspace_list = list(testspace_list1)
744    FLAGS.testspace_or_comma_list = list(testspace_or_comma_list1)
745    argv = ('./program', FLAGS['testcomma_list'].serialize(),
746            FLAGS['testspace_list'].serialize(),
747            FLAGS['testspace_or_comma_list'].serialize())
748    argv = FLAGS(argv)
749    self.assertEqual(FLAGS.testcomma_list, testcomma_list1)
750    self.assertEqual(FLAGS.testspace_list, testspace_list1)
751    # We don't expect idempotency when commas are placed in an item value and
752    # comma_compat is enabled.
753    self.assertEqual(FLAGS.testspace_or_comma_list,
754                     ['aa', 'bb', 'some', 'commas', 'cc'])
755
756    FLAGS.testcomma_list = old_testcomma_list
757    FLAGS.testspace_list = old_testspace_list
758    FLAGS.testspace_or_comma_list = old_testspace_or_comma_list
759
760    ####################################
761    # Test flag-update:
762
763    def args_list():
764      # Exclude flags that have different default values based on the
765      # environment.
766      flags_to_exclude = {'log_dir', 'test_srcdir', 'test_tmpdir'}
767      flagnames = set(FLAGS) - flags_to_exclude
768
769      nonbool_flags = []
770      truebool_flags = []
771      falsebool_flags = []
772      for name in flagnames:
773        flag_value = FLAGS.get_flag_value(name, None)
774        if not isinstance(FLAGS[name], flags.BooleanFlag):
775          nonbool_flags.append('--%s %s' % (name, flag_value))
776        elif flag_value:
777          truebool_flags.append('--%s' % name)
778        else:
779          falsebool_flags.append('--no%s' % name)
780      all_flags = nonbool_flags + truebool_flags + falsebool_flags
781      all_flags.sort()
782      return all_flags
783
784    argv = ('./program', '--repeat=3', '--name=giants', '--nodebug')
785
786    FLAGS(argv)
787    self.assertEqual(FLAGS.get_flag_value('repeat', None), 3)
788    self.assertEqual(FLAGS.get_flag_value('name', None), 'giants')
789    self.assertEqual(FLAGS.get_flag_value('debug', None), 0)
790    self.assertListEqual([
791        '--alsologtostderr',
792        "--args ['v=1', 'vmodule=a=0,b=2']",
793        '--blah None',
794        '--cases None',
795        '--decimal 666',
796        '--float 3.14',
797        '--funny None',
798        '--hexadecimal 1638',
799        '--kwery None',
800        '--l 9223372032559808512',
801        "--letters ['a', 'b', 'c']",
802        '--logger_levels {}',
803        "--m ['str1', 'str2']",
804        "--m_str ['str1', 'str2']",
805        '--name giants',
806        '--no?',
807        '--nodebug',
808        '--noexec',
809        '--nohelp',
810        '--nohelpfull',
811        '--nohelpshort',
812        '--nohelpxml',
813        '--nologtostderr',
814        '--noonly_check_args',
815        '--nopdb_post_mortem',
816        '--noq',
817        '--norun_with_pdb',
818        '--norun_with_profiling',
819        '--notest0',
820        '--notestget2',
821        '--notestget3',
822        '--notestnone',
823        '--numbers [1, 2, 3]',
824        '--octal 438',
825        '--only_once singlevalue',
826        '--pdb False',
827        '--profile_file None',
828        '--quack',
829        '--repeat 3',
830        "--s ['sing1']",
831        "--s_str ['sing1']",
832        '--sense None',
833        '--showprefixforinfo',
834        '--stderrthreshold fatal',
835        '--test1',
836        '--test_random_seed 301',
837        '--test_randomize_ordering_seed ',
838        '--testcomma_list []',
839        '--testget1',
840        '--testget4 None',
841        '--testspace_list []',
842        '--testspace_or_comma_list []',
843        '--tmod_baz_x',
844        '--universe ptolemaic',
845        '--use_cprofile_for_profiling',
846        '--v -1',
847        '--verbosity -1',
848        '--x 10',
849        '--xml_output_file ',
850    ], args_list())
851
852    argv = ('./program', '--debug', '--m_str=upd1', '-s', 'upd2')
853    FLAGS(argv)
854    self.assertEqual(FLAGS.get_flag_value('repeat', None), 3)
855    self.assertEqual(FLAGS.get_flag_value('name', None), 'giants')
856    self.assertEqual(FLAGS.get_flag_value('debug', None), 1)
857
858    # items appended to existing non-default value lists for --m/--m_str
859    # new value overwrites default value (not appended to it) for --s/--s_str
860    self.assertListEqual([
861        '--alsologtostderr',
862        "--args ['v=1', 'vmodule=a=0,b=2']",
863        '--blah None',
864        '--cases None',
865        '--debug',
866        '--decimal 666',
867        '--float 3.14',
868        '--funny None',
869        '--hexadecimal 1638',
870        '--kwery None',
871        '--l 9223372032559808512',
872        "--letters ['a', 'b', 'c']",
873        '--logger_levels {}',
874        "--m ['str1', 'str2', 'upd1']",
875        "--m_str ['str1', 'str2', 'upd1']",
876        '--name giants',
877        '--no?',
878        '--noexec',
879        '--nohelp',
880        '--nohelpfull',
881        '--nohelpshort',
882        '--nohelpxml',
883        '--nologtostderr',
884        '--noonly_check_args',
885        '--nopdb_post_mortem',
886        '--noq',
887        '--norun_with_pdb',
888        '--norun_with_profiling',
889        '--notest0',
890        '--notestget2',
891        '--notestget3',
892        '--notestnone',
893        '--numbers [1, 2, 3]',
894        '--octal 438',
895        '--only_once singlevalue',
896        '--pdb False',
897        '--profile_file None',
898        '--quack',
899        '--repeat 3',
900        "--s ['sing1', 'upd2']",
901        "--s_str ['sing1', 'upd2']",
902        '--sense None',
903        '--showprefixforinfo',
904        '--stderrthreshold fatal',
905        '--test1',
906        '--test_random_seed 301',
907        '--test_randomize_ordering_seed ',
908        '--testcomma_list []',
909        '--testget1',
910        '--testget4 None',
911        '--testspace_list []',
912        '--testspace_or_comma_list []',
913        '--tmod_baz_x',
914        '--universe ptolemaic',
915        '--use_cprofile_for_profiling',
916        '--v -1',
917        '--verbosity -1',
918        '--x 10',
919        '--xml_output_file ',
920    ], args_list())
921
922    ####################################
923    # Test all kind of error conditions.
924
925    # Argument not in enum exception
926    argv = ('./program', '--kwery=WHEN')
927    self.assertRaises(flags.IllegalFlagValueError, FLAGS, argv)
928    argv = ('./program', '--kwery=why')
929    self.assertRaises(flags.IllegalFlagValueError, FLAGS, argv)
930
931    # Duplicate flag detection
932    with self.assertRaises(flags.DuplicateFlagError):
933      flags.DEFINE_boolean('run', 0, 'runhelp', short_name='q')
934
935    # Duplicate short flag detection
936    with self.assertRaisesRegex(
937        flags.DuplicateFlagError,
938        r"The flag 'z' is defined twice\. .*First from.*, Second from"):
939      flags.DEFINE_boolean('zoom1', 0, 'runhelp z1', short_name='z')
940      flags.DEFINE_boolean('zoom2', 0, 'runhelp z2', short_name='z')
941      raise AssertionError('duplicate short flag detection failed')
942
943    # Duplicate mixed flag detection
944    with self.assertRaisesRegex(
945        flags.DuplicateFlagError,
946        r"The flag 's' is defined twice\. .*First from.*, Second from"):
947      flags.DEFINE_boolean('short1', 0, 'runhelp s1', short_name='s')
948      flags.DEFINE_boolean('s', 0, 'runhelp s2')
949
950    # Check that duplicate flag detection detects definition sites
951    # correctly.
952    flagnames = ['repeated']
953    original_flags = flags.FlagValues()
954    flags.DEFINE_boolean(
955        flagnames[0],
956        False,
957        'Flag about to be repeated.',
958        flag_values=original_flags)
959    duplicate_flags = module_foo.duplicate_flags(flagnames)
960    with self.assertRaisesRegex(flags.DuplicateFlagError,
961                                'flags_test.*module_foo'):
962      original_flags.append_flag_values(duplicate_flags)
963
964    # Make sure allow_override works
965    try:
966      flags.DEFINE_boolean(
967          'dup1', 0, 'runhelp d11', short_name='u', allow_override=0)
968      flag = FLAGS._flags()['dup1']
969      self.assertEqual(flag.default, 0)
970
971      flags.DEFINE_boolean(
972          'dup1', 1, 'runhelp d12', short_name='u', allow_override=1)
973      flag = FLAGS._flags()['dup1']
974      self.assertEqual(flag.default, 1)
975    except flags.DuplicateFlagError:
976      raise AssertionError('allow_override did not permit a flag duplication')
977
978    # Make sure allow_override works
979    try:
980      flags.DEFINE_boolean(
981          'dup2', 0, 'runhelp d21', short_name='u', allow_override=1)
982      flag = FLAGS._flags()['dup2']
983      self.assertEqual(flag.default, 0)
984
985      flags.DEFINE_boolean(
986          'dup2', 1, 'runhelp d22', short_name='u', allow_override=0)
987      flag = FLAGS._flags()['dup2']
988      self.assertEqual(flag.default, 1)
989    except flags.DuplicateFlagError:
990      raise AssertionError('allow_override did not permit a flag duplication')
991
992    # Make sure that re-importing a module does not cause a DuplicateFlagError
993    # to be raised.
994    try:
995      sys.modules.pop('absl.flags.tests.module_baz')
996      import absl.flags.tests.module_baz
997      del absl
998    except flags.DuplicateFlagError:
999      raise AssertionError('Module reimport caused flag duplication error')
1000
1001    # Make sure that when we override, the help string gets updated correctly
1002    flags.DEFINE_boolean(
1003        'dup3', 0, 'runhelp d31', short_name='u', allow_override=1)
1004    flags.DEFINE_boolean(
1005        'dup3', 1, 'runhelp d32', short_name='u', allow_override=1)
1006    self.assertEqual(str(FLAGS).find('runhelp d31'), -1)
1007    self.assertNotEqual(str(FLAGS).find('runhelp d32'), -1)
1008
1009    # Make sure append_flag_values works
1010    new_flags = flags.FlagValues()
1011    flags.DEFINE_boolean('new1', 0, 'runhelp n1', flag_values=new_flags)
1012    flags.DEFINE_boolean('new2', 0, 'runhelp n2', flag_values=new_flags)
1013    self.assertEqual(len(new_flags._flags()), 2)
1014    old_len = len(FLAGS._flags())
1015    FLAGS.append_flag_values(new_flags)
1016    self.assertEqual(len(FLAGS._flags()) - old_len, 2)
1017    self.assertEqual('new1' in FLAGS._flags(), True)
1018    self.assertEqual('new2' in FLAGS._flags(), True)
1019
1020    # Then test that removing those flags works
1021    FLAGS.remove_flag_values(new_flags)
1022    self.assertEqual(len(FLAGS._flags()), old_len)
1023    self.assertFalse('new1' in FLAGS._flags())
1024    self.assertFalse('new2' in FLAGS._flags())
1025
1026    # Make sure append_flag_values works with flags with shortnames.
1027    new_flags = flags.FlagValues()
1028    flags.DEFINE_boolean('new3', 0, 'runhelp n3', flag_values=new_flags)
1029    flags.DEFINE_boolean(
1030        'new4', 0, 'runhelp n4', flag_values=new_flags, short_name='n4')
1031    self.assertEqual(len(new_flags._flags()), 3)
1032    old_len = len(FLAGS._flags())
1033    FLAGS.append_flag_values(new_flags)
1034    self.assertEqual(len(FLAGS._flags()) - old_len, 3)
1035    self.assertIn('new3', FLAGS._flags())
1036    self.assertIn('new4', FLAGS._flags())
1037    self.assertIn('n4', FLAGS._flags())
1038    self.assertEqual(FLAGS._flags()['n4'], FLAGS._flags()['new4'])
1039
1040    # Then test removing them
1041    FLAGS.remove_flag_values(new_flags)
1042    self.assertEqual(len(FLAGS._flags()), old_len)
1043    self.assertFalse('new3' in FLAGS._flags())
1044    self.assertFalse('new4' in FLAGS._flags())
1045    self.assertFalse('n4' in FLAGS._flags())
1046
1047    # Make sure append_flag_values fails on duplicates
1048    flags.DEFINE_boolean('dup4', 0, 'runhelp d41')
1049    new_flags = flags.FlagValues()
1050    flags.DEFINE_boolean('dup4', 0, 'runhelp d42', flag_values=new_flags)
1051    with self.assertRaises(flags.DuplicateFlagError):
1052      FLAGS.append_flag_values(new_flags)
1053
1054    # Integer out of bounds
1055    with self.assertRaises(flags.IllegalFlagValueError):
1056      argv = ('./program', '--repeat=-4')
1057      FLAGS(argv)
1058
1059    # Non-integer
1060    with self.assertRaises(flags.IllegalFlagValueError):
1061      argv = ('./program', '--repeat=2.5')
1062      FLAGS(argv)
1063
1064    # Missing required argument
1065    with self.assertRaises(flags.Error):
1066      argv = ('./program', '--name')
1067      FLAGS(argv)
1068
1069    # Non-boolean arguments for boolean
1070    with self.assertRaises(flags.IllegalFlagValueError):
1071      argv = ('./program', '--debug=goofup')
1072      FLAGS(argv)
1073
1074    with self.assertRaises(flags.IllegalFlagValueError):
1075      argv = ('./program', '--debug=42')
1076      FLAGS(argv)
1077
1078    # Non-numeric argument for integer flag --repeat
1079    with self.assertRaises(flags.IllegalFlagValueError):
1080      argv = ('./program', '--repeat', 'Bob', 'extra')
1081      FLAGS(argv)
1082
1083    # Aliases of existing flags
1084    with self.assertRaises(flags.UnrecognizedFlagError):
1085      flags.DEFINE_alias('alias_not_a_flag', 'not_a_flag')
1086
1087    # Programmtically modify alias and aliased flag
1088    flags.DEFINE_alias('alias_octal', 'octal')
1089    FLAGS.octal = 0o2222
1090    self.assertEqual(0o2222, FLAGS.octal)
1091    self.assertEqual(0o2222, FLAGS.alias_octal)
1092    FLAGS.alias_octal = 0o4444
1093    self.assertEqual(0o4444, FLAGS.octal)
1094    self.assertEqual(0o4444, FLAGS.alias_octal)
1095
1096    # Setting alias preserves the default of the original
1097    flags.DEFINE_alias('alias_name', 'name')
1098    flags.DEFINE_alias('alias_debug', 'debug')
1099    flags.DEFINE_alias('alias_decimal', 'decimal')
1100    flags.DEFINE_alias('alias_float', 'float')
1101    flags.DEFINE_alias('alias_letters', 'letters')
1102    self.assertEqual(FLAGS['name'].default, FLAGS.alias_name)
1103    self.assertEqual(FLAGS['debug'].default, FLAGS.alias_debug)
1104    self.assertEqual(int(FLAGS['decimal'].default), FLAGS.alias_decimal)
1105    self.assertEqual(float(FLAGS['float'].default), FLAGS.alias_float)
1106    self.assertSameElements(FLAGS['letters'].default, FLAGS.alias_letters)
1107
1108    # Original flags set on command line
1109    argv = ('./program', '--name=Martin', '--debug=True', '--decimal=777',
1110            '--letters=x,y,z')
1111    FLAGS(argv)
1112    self.assertEqual('Martin', FLAGS.name)
1113    self.assertEqual('Martin', FLAGS.alias_name)
1114    self.assertTrue(FLAGS.debug)
1115    self.assertTrue(FLAGS.alias_debug)
1116    self.assertEqual(777, FLAGS.decimal)
1117    self.assertEqual(777, FLAGS.alias_decimal)
1118    self.assertSameElements(['x', 'y', 'z'], FLAGS.letters)
1119    self.assertSameElements(['x', 'y', 'z'], FLAGS.alias_letters)
1120
1121    # Alias flags set on command line
1122    argv = ('./program', '--alias_name=Auston', '--alias_debug=False',
1123            '--alias_decimal=888', '--alias_letters=l,m,n')
1124    FLAGS(argv)
1125    self.assertEqual('Auston', FLAGS.name)
1126    self.assertEqual('Auston', FLAGS.alias_name)
1127    self.assertFalse(FLAGS.debug)
1128    self.assertFalse(FLAGS.alias_debug)
1129    self.assertEqual(888, FLAGS.decimal)
1130    self.assertEqual(888, FLAGS.alias_decimal)
1131    self.assertSameElements(['l', 'm', 'n'], FLAGS.letters)
1132    self.assertSameElements(['l', 'm', 'n'], FLAGS.alias_letters)
1133
1134    # Make sure importing a module does not change flag value parsed
1135    # from commandline.
1136    flags.DEFINE_integer(
1137        'dup5', 1, 'runhelp d51', short_name='u5', allow_override=0)
1138    self.assertEqual(FLAGS.dup5, 1)
1139    self.assertEqual(FLAGS.dup5, 1)
1140    argv = ('./program', '--dup5=3')
1141    FLAGS(argv)
1142    self.assertEqual(FLAGS.dup5, 3)
1143    flags.DEFINE_integer(
1144        'dup5', 2, 'runhelp d52', short_name='u5', allow_override=1)
1145    self.assertEqual(FLAGS.dup5, 3)
1146
1147    # Make sure importing a module does not change user defined flag value.
1148    flags.DEFINE_integer(
1149        'dup6', 1, 'runhelp d61', short_name='u6', allow_override=0)
1150    self.assertEqual(FLAGS.dup6, 1)
1151    FLAGS.dup6 = 3
1152    self.assertEqual(FLAGS.dup6, 3)
1153    flags.DEFINE_integer(
1154        'dup6', 2, 'runhelp d62', short_name='u6', allow_override=1)
1155    self.assertEqual(FLAGS.dup6, 3)
1156
1157    # Make sure importing a module does not change user defined flag value
1158    # even if it is the 'default' value.
1159    flags.DEFINE_integer(
1160        'dup7', 1, 'runhelp d71', short_name='u7', allow_override=0)
1161    self.assertEqual(FLAGS.dup7, 1)
1162    FLAGS.dup7 = 1
1163    self.assertEqual(FLAGS.dup7, 1)
1164    flags.DEFINE_integer(
1165        'dup7', 2, 'runhelp d72', short_name='u7', allow_override=1)
1166    self.assertEqual(FLAGS.dup7, 1)
1167
1168    # Test module_help().
1169    helpstr = FLAGS.module_help(module_baz)
1170
1171    expected_help = '\n' + module_baz.__name__ + ':' + """
1172  --[no]tmod_baz_x: Boolean flag.
1173    (default: 'true')"""
1174
1175    self.assertMultiLineEqual(expected_help, helpstr)
1176
1177    # Test main_module_help().  This must be part of test_flags because
1178    # it depends on dup1/2/3/etc being introduced first.
1179    helpstr = FLAGS.main_module_help()
1180
1181    expected_help = '\n' + sys.argv[0] + ':' + """
1182  --[no]alias_debug: Alias for --debug.
1183    (default: 'false')
1184  --alias_decimal: Alias for --decimal.
1185    (default: '666')
1186    (an integer)
1187  --alias_float: Alias for --float.
1188    (default: '3.14')
1189    (a number)
1190  --alias_letters: Alias for --letters.
1191    (default: 'a,b,c')
1192    (a comma separated list)
1193  --alias_name: Alias for --name.
1194    (default: 'Bob')
1195  --alias_octal: Alias for --octal.
1196    (default: '438')
1197    (an integer)
1198  --args: a list of arguments
1199    (default: 'v=1,"vmodule=a=0,b=2"')
1200    (a comma separated list)
1201  --blah: <bla|Blah|BLAH|blah>: ?
1202  --cases: <UPPER|lower|Initial|Ot_HeR>: ?
1203  --[no]debug: debughelp
1204    (default: 'false')
1205  --decimal: using decimals
1206    (default: '666')
1207    (an integer)
1208  -u,--[no]dup1: runhelp d12
1209    (default: 'true')
1210  -u,--[no]dup2: runhelp d22
1211    (default: 'true')
1212  -u,--[no]dup3: runhelp d32
1213    (default: 'true')
1214  --[no]dup4: runhelp d41
1215    (default: 'false')
1216  -u5,--dup5: runhelp d51
1217    (default: '1')
1218    (an integer)
1219  -u6,--dup6: runhelp d61
1220    (default: '1')
1221    (an integer)
1222  -u7,--dup7: runhelp d71
1223    (default: '1')
1224    (an integer)
1225  --float: using floats
1226    (default: '3.14')
1227    (a number)
1228  --funny: <Joke|ha|ha|ha|ha>: ?
1229  --hexadecimal: using hexadecimals
1230    (default: '1638')
1231    (an integer)
1232  --kwery: <who|what|Why|where|when>: ?
1233  --l: how long to be
1234    (default: '9223372032559808512')
1235    (an integer)
1236  --letters: a list of letters
1237    (default: 'a,b,c')
1238    (a comma separated list)
1239  -m,--m_str: string option that can occur multiple times;
1240    repeat this option to specify a list of values
1241    (default: "['def1', 'def2']")
1242  --name: namehelp
1243    (default: 'Bob')
1244  --[no]noexec: boolean flag with no as prefix
1245    (default: 'true')
1246  --numbers: a list of numbers
1247    (default: '1,2,3')
1248    (a comma separated list)
1249  --octal: using octals
1250    (default: '438')
1251    (an integer)
1252  --only_once: test only sets this once
1253  --[no]q: quiet mode
1254    (default: 'true')
1255  --[no]quack: superstring of 'q'
1256    (default: 'false')
1257  -r,--repeat: how many times to repeat (0-5)
1258    (default: '4')
1259    (a non-negative integer)
1260  -s,--s_str: string option that can occur multiple times;
1261    repeat this option to specify a list of values
1262    (default: "['sing1']")
1263  --sense: <Case|case|CASE>: ?
1264  --[no]test0: test boolean parsing
1265  --[no]test1: test boolean parsing
1266  --testcomma_list: test comma list parsing
1267    (default: '')
1268    (a comma separated list)
1269  --[no]testget1: test parsing with defaults
1270  --[no]testget2: test parsing with defaults
1271  --[no]testget3: test parsing with defaults
1272  --testget4: test parsing with defaults
1273    (an integer)
1274  --[no]testnone: test boolean parsing
1275  --testspace_list: tests space list parsing
1276    (default: '')
1277    (a whitespace separated list)
1278  --testspace_or_comma_list: tests space list parsing with comma compatibility
1279    (default: '')
1280    (a whitespace or comma separated list)
1281  --universe: test tries to set this three times
1282  --x: how eXtreme to be
1283    (default: '3')
1284    (an integer)
1285  -z,--[no]zoom1: runhelp z1
1286    (default: 'false')"""
1287
1288    self.assertMultiLineEqual(expected_help, helpstr)
1289
1290  def test_string_flag_with_wrong_type(self):
1291    fv = flags.FlagValues()
1292    with self.assertRaises(flags.IllegalFlagValueError):
1293      flags.DEFINE_string('name', False, 'help', flag_values=fv)
1294    with self.assertRaises(flags.IllegalFlagValueError):
1295      flags.DEFINE_string('name2', 0, 'help', flag_values=fv)
1296
1297  def test_integer_flag_with_wrong_type(self):
1298    fv = flags.FlagValues()
1299    with self.assertRaises(flags.IllegalFlagValueError):
1300      flags.DEFINE_integer('name', 1e2, 'help', flag_values=fv)
1301    with self.assertRaises(flags.IllegalFlagValueError):
1302      flags.DEFINE_integer('name', [], 'help', flag_values=fv)
1303    with self.assertRaises(flags.IllegalFlagValueError):
1304      flags.DEFINE_integer('name', False, 'help', flag_values=fv)
1305
1306  def test_float_flag_with_wrong_type(self):
1307    fv = flags.FlagValues()
1308    with self.assertRaises(flags.IllegalFlagValueError):
1309      flags.DEFINE_float('name', False, 'help', flag_values=fv)
1310
1311  def test_enum_flag_with_empty_values(self):
1312    fv = flags.FlagValues()
1313    with self.assertRaises(ValueError):
1314      flags.DEFINE_enum('fruit', None, [], 'help', flag_values=fv)
1315
1316  def test_define_enum_class_flag(self):
1317    fv = flags.FlagValues()
1318    flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv)
1319    fv.mark_as_parsed()
1320
1321    self.assertIsNone(fv.fruit)
1322
1323  def test_parse_enum_class_flag(self):
1324    fv = flags.FlagValues()
1325    flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv)
1326
1327    argv = ('./program', '--fruit=orange')
1328    argv = fv(argv)
1329    self.assertEqual(len(argv), 1, 'wrong number of arguments pulled')
1330    self.assertEqual(argv[0], './program', 'program name not preserved')
1331    self.assertEqual(fv['fruit'].present, 1)
1332    self.assertEqual(fv['fruit'].value, Fruit.ORANGE)
1333    fv.unparse_flags()
1334    argv = ('./program', '--fruit=APPLE')
1335    argv = fv(argv)
1336    self.assertEqual(len(argv), 1, 'wrong number of arguments pulled')
1337    self.assertEqual(argv[0], './program', 'program name not preserved')
1338    self.assertEqual(fv['fruit'].present, 1)
1339    self.assertEqual(fv['fruit'].value, Fruit.APPLE)
1340    fv.unparse_flags()
1341
1342  def test_enum_class_flag_help_message(self):
1343    fv = flags.FlagValues()
1344    flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv)
1345
1346    helpstr = fv.main_module_help()
1347    expected_help = '\n%s:\n  --fruit: <apple|orange>: ?' % sys.argv[0]
1348
1349    self.assertEqual(helpstr, expected_help)
1350
1351  def test_enum_class_flag_with_wrong_default_value_type(self):
1352    fv = flags.FlagValues()
1353    with self.assertRaises(_exceptions.IllegalFlagValueError):
1354      flags.DEFINE_enum_class('fruit', 1, Fruit, 'help', flag_values=fv)
1355
1356  def test_enum_class_flag_requires_enum_class(self):
1357    fv = flags.FlagValues()
1358    with self.assertRaises(TypeError):
1359      flags.DEFINE_enum_class(
1360          'fruit', None, ['apple', 'orange'], 'help', flag_values=fv)
1361
1362  def test_enum_class_flag_requires_non_empty_enum_class(self):
1363    fv = flags.FlagValues()
1364    with self.assertRaises(ValueError):
1365      flags.DEFINE_enum_class('empty', None, EmptyEnum, 'help', flag_values=fv)
1366
1367  def test_required_flag(self):
1368    fv = flags.FlagValues()
1369    fl = flags.DEFINE_integer(
1370        name='int_flag',
1371        default=None,
1372        help='help',
1373        required=True,
1374        flag_values=fv)
1375    # Since the flag is required, the FlagHolder should ensure value returned
1376    # is not None.
1377    self.assertTrue(fl._ensure_non_none_value)
1378
1379  def test_illegal_required_flag(self):
1380    fv = flags.FlagValues()
1381    with self.assertRaises(ValueError):
1382      flags.DEFINE_integer(
1383          name='int_flag',
1384          default=3,
1385          help='help',
1386          required=True,
1387          flag_values=fv)
1388
1389
1390class MultiNumericalFlagsTest(absltest.TestCase):
1391
1392  def test_multi_numerical_flags(self):
1393    """Test multi_int and multi_float flags."""
1394    fv = flags.FlagValues()
1395    int_defaults = [77, 88]
1396    flags.DEFINE_multi_integer(
1397        'm_int',
1398        int_defaults,
1399        'integer option that can occur multiple times',
1400        short_name='mi',
1401        flag_values=fv)
1402    self.assertListEqual(fv['m_int'].default, int_defaults)
1403    argv = ('./program', '--m_int=-99', '--mi=101')
1404    fv(argv)
1405    self.assertListEqual(fv.get_flag_value('m_int', None), [-99, 101])
1406
1407    float_defaults = [2.2, 3]
1408    flags.DEFINE_multi_float(
1409        'm_float',
1410        float_defaults,
1411        'float option that can occur multiple times',
1412        short_name='mf',
1413        flag_values=fv)
1414    for (expected, actual) in zip(float_defaults,
1415                                  fv.get_flag_value('m_float', None)):
1416      self.assertAlmostEqual(expected, actual)
1417    argv = ('./program', '--m_float=-17', '--mf=2.78e9')
1418    fv(argv)
1419    expected_floats = [-17.0, 2.78e9]
1420    for (expected, actual) in zip(expected_floats,
1421                                  fv.get_flag_value('m_float', None)):
1422      self.assertAlmostEqual(expected, actual)
1423
1424  def test_multi_numerical_with_tuples(self):
1425    """Verify multi_int/float accept tuples as default values."""
1426    flags.DEFINE_multi_integer(
1427        'm_int_tuple', (77, 88),
1428        'integer option that can occur multiple times',
1429        short_name='mi_tuple')
1430    self.assertListEqual(FLAGS.get_flag_value('m_int_tuple', None), [77, 88])
1431
1432    dict_with_float_keys = {2.2: 'hello', 3: 'happy'}
1433    float_defaults = dict_with_float_keys.keys()
1434    flags.DEFINE_multi_float(
1435        'm_float_tuple',
1436        float_defaults,
1437        'float option that can occur multiple times',
1438        short_name='mf_tuple')
1439    for (expected, actual) in zip(float_defaults,
1440                                  FLAGS.get_flag_value('m_float_tuple', None)):
1441      self.assertAlmostEqual(expected, actual)
1442
1443  def test_single_value_default(self):
1444    """Test multi_int and multi_float flags with a single default value."""
1445    int_default = 77
1446    flags.DEFINE_multi_integer('m_int1', int_default,
1447                               'integer option that can occur multiple times')
1448    self.assertListEqual(FLAGS.get_flag_value('m_int1', None), [int_default])
1449
1450    float_default = 2.2
1451    flags.DEFINE_multi_float('m_float1', float_default,
1452                             'float option that can occur multiple times')
1453    actual = FLAGS.get_flag_value('m_float1', None)
1454    self.assertEqual(1, len(actual))
1455    self.assertAlmostEqual(actual[0], float_default)
1456
1457  def test_bad_multi_numerical_flags(self):
1458    """Test multi_int and multi_float flags with non-parseable values."""
1459
1460    # Test non-parseable defaults.
1461    self.assertRaisesRegex(
1462        flags.IllegalFlagValueError,
1463        r"flag --m_int2=abc: invalid literal for int\(\) with base 10: 'abc'",
1464        flags.DEFINE_multi_integer, 'm_int2', ['abc'], 'desc')
1465
1466    self.assertRaisesRegex(
1467        flags.IllegalFlagValueError, r'flag --m_float2=abc: '
1468        r'(invalid literal for float\(\)|could not convert string to float): '
1469        r"'?abc'?", flags.DEFINE_multi_float, 'm_float2', ['abc'], 'desc')
1470
1471    # Test non-parseable command line values.
1472    fv = flags.FlagValues()
1473    flags.DEFINE_multi_integer(
1474        'm_int2',
1475        '77',
1476        'integer option that can occur multiple times',
1477        flag_values=fv)
1478    argv = ('./program', '--m_int2=def')
1479    self.assertRaisesRegex(
1480        flags.IllegalFlagValueError,
1481        r"flag --m_int2=def: invalid literal for int\(\) with base 10: 'def'",
1482        fv, argv)
1483
1484    flags.DEFINE_multi_float(
1485        'm_float2',
1486        2.2,
1487        'float option that can occur multiple times',
1488        flag_values=fv)
1489    argv = ('./program', '--m_float2=def')
1490    self.assertRaisesRegex(
1491        flags.IllegalFlagValueError, r'flag --m_float2=def: '
1492        r'(invalid literal for float\(\)|could not convert string to float): '
1493        r"'?def'?", fv, argv)
1494
1495
1496class MultiEnumFlagsTest(absltest.TestCase):
1497
1498  def test_multi_enum_flags(self):
1499    """Test multi_enum flags."""
1500    fv = flags.FlagValues()
1501
1502    enum_defaults = ['FOO', 'BAZ']
1503    flags.DEFINE_multi_enum(
1504        'm_enum',
1505        enum_defaults, ['FOO', 'BAR', 'BAZ', 'WHOOSH'],
1506        'Enum option that can occur multiple times',
1507        short_name='me',
1508        flag_values=fv)
1509    self.assertListEqual(fv['m_enum'].default, enum_defaults)
1510    argv = ('./program', '--m_enum=WHOOSH', '--me=FOO')
1511    fv(argv)
1512    self.assertListEqual(fv.get_flag_value('m_enum', None), ['WHOOSH', 'FOO'])
1513
1514  def test_help_text(self):
1515    """Test multi_enum flag's help text."""
1516    fv = flags.FlagValues()
1517
1518    flags.DEFINE_multi_enum(
1519        'm_enum',
1520        None, ['FOO', 'BAR'],
1521        'Enum option that can occur multiple times',
1522        flag_values=fv)
1523    self.assertRegex(
1524        fv['m_enum'].help,
1525        r'<FOO\|BAR>: Enum option that can occur multiple times;\s+'
1526        'repeat this option to specify a list of values')
1527
1528  def test_single_value_default(self):
1529    """Test multi_enum flags with a single default value."""
1530    fv = flags.FlagValues()
1531    enum_default = 'FOO'
1532    flags.DEFINE_multi_enum(
1533        'm_enum1',
1534        enum_default, ['FOO', 'BAR', 'BAZ', 'WHOOSH'],
1535        'enum option that can occur multiple times',
1536        flag_values=fv)
1537    self.assertListEqual(fv['m_enum1'].default, [enum_default])
1538
1539  def test_case_sensitivity(self):
1540    """Test case sensitivity of multi_enum flag."""
1541    fv = flags.FlagValues()
1542    # Test case insensitive enum.
1543    flags.DEFINE_multi_enum(
1544        'm_enum2', ['whoosh'], ['FOO', 'BAR', 'BAZ', 'WHOOSH'],
1545        'Enum option that can occur multiple times',
1546        short_name='me2',
1547        case_sensitive=False,
1548        flag_values=fv)
1549    argv = ('./program', '--m_enum2=bar', '--me2=fOo')
1550    fv(argv)
1551    self.assertListEqual(fv.get_flag_value('m_enum2', None), ['BAR', 'FOO'])
1552
1553    # Test case sensitive enum.
1554    flags.DEFINE_multi_enum(
1555        'm_enum3', ['BAR'], ['FOO', 'BAR', 'BAZ', 'WHOOSH'],
1556        'Enum option that can occur multiple times',
1557        short_name='me3',
1558        case_sensitive=True,
1559        flag_values=fv)
1560    argv = ('./program', '--m_enum3=bar', '--me3=fOo')
1561    self.assertRaisesRegex(
1562        flags.IllegalFlagValueError,
1563        r'flag --m_enum3=invalid: value should be one of <FOO|BAR|BAZ|WHOOSH>',
1564        fv, argv)
1565
1566  def test_bad_multi_enum_flags(self):
1567    """Test multi_enum with invalid values."""
1568
1569    # Test defaults that are not in the permitted list of enums.
1570    self.assertRaisesRegex(
1571        flags.IllegalFlagValueError,
1572        r'flag --m_enum=INVALID: value should be one of <FOO|BAR|BAZ>',
1573        flags.DEFINE_multi_enum, 'm_enum', ['INVALID'], ['FOO', 'BAR', 'BAZ'],
1574        'desc')
1575
1576    self.assertRaisesRegex(
1577        flags.IllegalFlagValueError,
1578        r'flag --m_enum=1234: value should be one of <FOO|BAR|BAZ>',
1579        flags.DEFINE_multi_enum, 'm_enum2', [1234], ['FOO', 'BAR', 'BAZ'],
1580        'desc')
1581
1582    # Test command-line values that are not in the permitted list of enums.
1583    flags.DEFINE_multi_enum('m_enum4', 'FOO', ['FOO', 'BAR', 'BAZ'],
1584                            'enum option that can occur multiple times')
1585    argv = ('./program', '--m_enum4=INVALID')
1586    self.assertRaisesRegex(
1587        flags.IllegalFlagValueError,
1588        r'flag --m_enum4=invalid: value should be one of <FOO|BAR|BAZ>', FLAGS,
1589        argv)
1590
1591
1592class MultiEnumClassFlagsTest(absltest.TestCase):
1593
1594  def test_define_results_in_registered_flag_with_none(self):
1595    fv = flags.FlagValues()
1596    enum_defaults = None
1597    flags.DEFINE_multi_enum_class(
1598        'fruit',
1599        enum_defaults,
1600        Fruit,
1601        'Enum option that can occur multiple times',
1602        flag_values=fv)
1603    fv.mark_as_parsed()
1604
1605    self.assertIsNone(fv.fruit)
1606
1607  def test_help_text(self):
1608    fv = flags.FlagValues()
1609    enum_defaults = None
1610    flags.DEFINE_multi_enum_class(
1611        'fruit',
1612        enum_defaults,
1613        Fruit,
1614        'Enum option that can occur multiple times',
1615        flag_values=fv)
1616
1617    self.assertRegex(
1618        fv['fruit'].help,
1619        r'<apple\|orange>: Enum option that can occur multiple times;\s+'
1620        'repeat this option to specify a list of values')
1621
1622  def test_define_results_in_registered_flag_with_string(self):
1623    fv = flags.FlagValues()
1624    enum_defaults = 'apple'
1625    flags.DEFINE_multi_enum_class(
1626        'fruit',
1627        enum_defaults,
1628        Fruit,
1629        'Enum option that can occur multiple times',
1630        flag_values=fv)
1631    fv.mark_as_parsed()
1632
1633    self.assertListEqual(fv.fruit, [Fruit.APPLE])
1634
1635  def test_define_results_in_registered_flag_with_enum(self):
1636    fv = flags.FlagValues()
1637    enum_defaults = Fruit.APPLE
1638    flags.DEFINE_multi_enum_class(
1639        'fruit',
1640        enum_defaults,
1641        Fruit,
1642        'Enum option that can occur multiple times',
1643        flag_values=fv)
1644    fv.mark_as_parsed()
1645
1646    self.assertListEqual(fv.fruit, [Fruit.APPLE])
1647
1648  def test_define_results_in_registered_flag_with_string_list(self):
1649    fv = flags.FlagValues()
1650    enum_defaults = ['apple', 'APPLE']
1651    flags.DEFINE_multi_enum_class(
1652        'fruit',
1653        enum_defaults,
1654        CaseSensitiveFruit,
1655        'Enum option that can occur multiple times',
1656        flag_values=fv,
1657        case_sensitive=True)
1658    fv.mark_as_parsed()
1659
1660    self.assertListEqual(fv.fruit,
1661                         [CaseSensitiveFruit.apple, CaseSensitiveFruit.APPLE])
1662
1663  def test_define_results_in_registered_flag_with_enum_list(self):
1664    fv = flags.FlagValues()
1665    enum_defaults = [Fruit.APPLE, Fruit.ORANGE]
1666    flags.DEFINE_multi_enum_class(
1667        'fruit',
1668        enum_defaults,
1669        Fruit,
1670        'Enum option that can occur multiple times',
1671        flag_values=fv)
1672    fv.mark_as_parsed()
1673
1674    self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE])
1675
1676  def test_from_command_line_returns_multiple(self):
1677    fv = flags.FlagValues()
1678    enum_defaults = [Fruit.APPLE]
1679    flags.DEFINE_multi_enum_class(
1680        'fruit',
1681        enum_defaults,
1682        Fruit,
1683        'Enum option that can occur multiple times',
1684        flag_values=fv)
1685    argv = ('./program', '--fruit=Apple', '--fruit=orange')
1686    fv(argv)
1687    self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE])
1688
1689  def test_bad_multi_enum_class_flags_from_definition(self):
1690    with self.assertRaisesRegex(
1691        flags.IllegalFlagValueError,
1692        'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'):
1693      flags.DEFINE_multi_enum_class('fruit', ['INVALID'], Fruit, 'desc')
1694
1695  def test_bad_multi_enum_class_flags_from_commandline(self):
1696    fv = flags.FlagValues()
1697    enum_defaults = [Fruit.APPLE]
1698    flags.DEFINE_multi_enum_class(
1699        'fruit', enum_defaults, Fruit, 'desc', flag_values=fv)
1700    argv = ('./program', '--fruit=INVALID')
1701    with self.assertRaisesRegex(
1702        flags.IllegalFlagValueError,
1703        'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'):
1704      fv(argv)
1705
1706
1707class UnicodeFlagsTest(absltest.TestCase):
1708  """Testing proper unicode support for flags."""
1709
1710  def test_unicode_default_and_helpstring(self):
1711    fv = flags.FlagValues()
1712    flags.DEFINE_string(
1713        'unicode_str',
1714        b'\xC3\x80\xC3\xBD'.decode('utf-8'),
1715        b'help:\xC3\xAA'.decode('utf-8'),
1716        flag_values=fv)
1717    argv = ('./program',)
1718    fv(argv)  # should not raise any exceptions
1719
1720    argv = ('./program', '--unicode_str=foo')
1721    fv(argv)  # should not raise any exceptions
1722
1723  def test_unicode_in_list(self):
1724    fv = flags.FlagValues()
1725    flags.DEFINE_list(
1726        'unicode_list',
1727        ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')],
1728        b'help:\xC3\xAB'.decode('utf-8'),
1729        flag_values=fv)
1730    argv = ('./program',)
1731    fv(argv)  # should not raise any exceptions
1732
1733    argv = ('./program', '--unicode_list=hello,there')
1734    fv(argv)  # should not raise any exceptions
1735
1736  def test_xmloutput(self):
1737    fv = flags.FlagValues()
1738    flags.DEFINE_string(
1739        'unicode1',
1740        b'\xC3\x80\xC3\xBD'.decode('utf-8'),
1741        b'help:\xC3\xAC'.decode('utf-8'),
1742        flag_values=fv)
1743    flags.DEFINE_list(
1744        'unicode2',
1745        ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')],
1746        b'help:\xC3\xAD'.decode('utf-8'),
1747        flag_values=fv)
1748    flags.DEFINE_list(
1749        'non_unicode', ['abc', 'def', 'ghi'],
1750        b'help:\xC3\xAD'.decode('utf-8'),
1751        flag_values=fv)
1752
1753    outfile = io.StringIO()
1754    fv.write_help_in_xml_format(outfile)
1755    actual_output = outfile.getvalue()
1756
1757    # The xml output is large, so we just check parts of it.
1758    self.assertIn(
1759        b'<name>unicode1</name>\n'
1760        b'    <meaning>help:\xc3\xac</meaning>\n'
1761        b'    <default>\xc3\x80\xc3\xbd</default>\n'
1762        b'    <current>\xc3\x80\xc3\xbd</current>'.decode('utf-8'),
1763        actual_output)
1764    self.assertIn(
1765        b'<name>unicode2</name>\n'
1766        b'    <meaning>help:\xc3\xad</meaning>\n'
1767        b'    <default>abc,\xc3\x80,\xc3\xbd</default>\n'
1768        b"    <current>['abc', '\xc3\x80', '\xc3\xbd']"
1769        b'</current>'.decode('utf-8'), actual_output)
1770    self.assertIn(
1771        b'<name>non_unicode</name>\n'
1772        b'    <meaning>help:\xc3\xad</meaning>\n'
1773        b'    <default>abc,def,ghi</default>\n'
1774        b"    <current>['abc', 'def', 'ghi']"
1775        b'</current>'.decode('utf-8'), actual_output)
1776
1777
1778class LoadFromFlagFileTest(absltest.TestCase):
1779  """Testing loading flags from a file and parsing them."""
1780
1781  def setUp(self):
1782    self.flag_values = flags.FlagValues()
1783    flags.DEFINE_string(
1784        'unittest_message1',
1785        'Foo!',
1786        'You Add Here.',
1787        flag_values=self.flag_values)
1788    flags.DEFINE_string(
1789        'unittest_message2',
1790        'Bar!',
1791        'Hello, Sailor!',
1792        flag_values=self.flag_values)
1793    flags.DEFINE_boolean(
1794        'unittest_boolflag',
1795        0,
1796        'Some Boolean thing',
1797        flag_values=self.flag_values)
1798    flags.DEFINE_integer(
1799        'unittest_number',
1800        12345,
1801        'Some integer',
1802        lower_bound=0,
1803        flag_values=self.flag_values)
1804    flags.DEFINE_list(
1805        'UnitTestList', '1,2,3', 'Some list', flag_values=self.flag_values)
1806    self.tmp_path = None
1807    self.flag_values.mark_as_parsed()
1808
1809  def tearDown(self):
1810    self._remove_test_files()
1811
1812  def _setup_test_files(self):
1813    """Creates and sets up some dummy flagfile files with bogus flags."""
1814
1815    # Figure out where to create temporary files
1816    self.assertFalse(self.tmp_path)
1817    self.tmp_path = tempfile.mkdtemp()
1818
1819    tmp_flag_file_1 = open(self.tmp_path + '/UnitTestFile1.tst', 'w')
1820    tmp_flag_file_2 = open(self.tmp_path + '/UnitTestFile2.tst', 'w')
1821    tmp_flag_file_3 = open(self.tmp_path + '/UnitTestFile3.tst', 'w')
1822    tmp_flag_file_4 = open(self.tmp_path + '/UnitTestFile4.tst', 'w')
1823
1824    # put some dummy flags in our test files
1825    tmp_flag_file_1.write('#A Fake Comment\n')
1826    tmp_flag_file_1.write('--unittest_message1=tempFile1!\n')
1827    tmp_flag_file_1.write('\n')
1828    tmp_flag_file_1.write('--unittest_number=54321\n')
1829    tmp_flag_file_1.write('--nounittest_boolflag\n')
1830    file_list = [tmp_flag_file_1.name]
1831    # this one includes test file 1
1832    tmp_flag_file_2.write('//A Different Fake Comment\n')
1833    tmp_flag_file_2.write('--flagfile=%s\n' % tmp_flag_file_1.name)
1834    tmp_flag_file_2.write('--unittest_message2=setFromTempFile2\n')
1835    tmp_flag_file_2.write('\t\t\n')
1836    tmp_flag_file_2.write('--unittest_number=6789a\n')
1837    file_list.append(tmp_flag_file_2.name)
1838    # this file points to itself
1839    tmp_flag_file_3.write('--flagfile=%s\n' % tmp_flag_file_3.name)
1840    tmp_flag_file_3.write('--unittest_message1=setFromTempFile3\n')
1841    tmp_flag_file_3.write('#YAFC\n')
1842    tmp_flag_file_3.write('--unittest_boolflag\n')
1843    file_list.append(tmp_flag_file_3.name)
1844    # this file is unreadable
1845    tmp_flag_file_4.write('--flagfile=%s\n' % tmp_flag_file_3.name)
1846    tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n')
1847    tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n')
1848    os.chmod(self.tmp_path + '/UnitTestFile4.tst', 0)
1849    file_list.append(tmp_flag_file_4.name)
1850
1851    tmp_flag_file_1.close()
1852    tmp_flag_file_2.close()
1853    tmp_flag_file_3.close()
1854    tmp_flag_file_4.close()
1855
1856    return file_list  # these are just the file names
1857
1858  def _remove_test_files(self):
1859    """Removes the files we just created."""
1860    if self.tmp_path:
1861      shutil.rmtree(self.tmp_path, ignore_errors=True)
1862      self.tmp_path = None
1863
1864  def _read_flags_from_files(self, argv, force_gnu):
1865    return argv[:1] + self.flag_values.read_flags_from_files(
1866        argv[1:], force_gnu=force_gnu)
1867
1868  #### Flagfile Unit Tests ####
1869  def test_method_flagfiles_1(self):
1870    """Test trivial case with no flagfile based options."""
1871    fake_cmd_line = 'fooScript --unittest_boolflag'
1872    fake_argv = fake_cmd_line.split(' ')
1873    self.flag_values(fake_argv)
1874    self.assertEqual(self.flag_values.unittest_boolflag, 1)
1875    self.assertListEqual(fake_argv,
1876                         self._read_flags_from_files(fake_argv, False))
1877
1878  def test_method_flagfiles_2(self):
1879    """Tests parsing one file + arguments off simulated argv."""
1880    tmp_files = self._setup_test_files()
1881    # specify our temp file on the fake cmd line
1882    fake_cmd_line = 'fooScript --q --flagfile=%s' % tmp_files[0]
1883    fake_argv = fake_cmd_line.split(' ')
1884
1885    # We should see the original cmd line with the file's contents spliced in.
1886    # Flags from the file will appear in the order order they are specified
1887    # in the file, in the same position as the flagfile argument.
1888    expected_results = [
1889        'fooScript', '--q', '--unittest_message1=tempFile1!',
1890        '--unittest_number=54321', '--nounittest_boolflag'
1891    ]
1892    test_results = self._read_flags_from_files(fake_argv, False)
1893    self.assertListEqual(expected_results, test_results)
1894
1895  # end testTwo def
1896
1897  def test_method_flagfiles_3(self):
1898    """Tests parsing nested files + arguments of simulated argv."""
1899    tmp_files = self._setup_test_files()
1900    # specify our temp file on the fake cmd line
1901    fake_cmd_line = ('fooScript --unittest_number=77 --flagfile=%s' %
1902                     tmp_files[1])
1903    fake_argv = fake_cmd_line.split(' ')
1904
1905    expected_results = [
1906        'fooScript', '--unittest_number=77', '--unittest_message1=tempFile1!',
1907        '--unittest_number=54321', '--nounittest_boolflag',
1908        '--unittest_message2=setFromTempFile2', '--unittest_number=6789a'
1909    ]
1910    test_results = self._read_flags_from_files(fake_argv, False)
1911    self.assertListEqual(expected_results, test_results)
1912
1913  # end testThree def
1914
1915  def test_method_flagfiles_3_spaces(self):
1916    """Tests parsing nested files + arguments of simulated argv.
1917
1918    The arguments include a pair that is actually an arg with a value, so it
1919    doesn't stop processing.
1920    """
1921    tmp_files = self._setup_test_files()
1922    # specify our temp file on the fake cmd line
1923    fake_cmd_line = ('fooScript --unittest_number 77 --flagfile=%s' %
1924                     tmp_files[1])
1925    fake_argv = fake_cmd_line.split(' ')
1926
1927    expected_results = [
1928        'fooScript', '--unittest_number', '77',
1929        '--unittest_message1=tempFile1!', '--unittest_number=54321',
1930        '--nounittest_boolflag', '--unittest_message2=setFromTempFile2',
1931        '--unittest_number=6789a'
1932    ]
1933    test_results = self._read_flags_from_files(fake_argv, False)
1934    self.assertListEqual(expected_results, test_results)
1935
1936  def test_method_flagfiles_3_spaces_boolean(self):
1937    """Tests parsing nested files + arguments of simulated argv.
1938
1939    The arguments include a pair that looks like a --x y arg with value, but
1940    since the flag is a boolean it's actually not.
1941    """
1942    tmp_files = self._setup_test_files()
1943    # specify our temp file on the fake cmd line
1944    fake_cmd_line = ('fooScript --unittest_boolflag 77 --flagfile=%s' %
1945                     tmp_files[1])
1946    fake_argv = fake_cmd_line.split(' ')
1947
1948    expected_results = [
1949        'fooScript', '--unittest_boolflag', '77',
1950        '--flagfile=%s' % tmp_files[1]
1951    ]
1952    with _use_gnu_getopt(self.flag_values, False):
1953      test_results = self._read_flags_from_files(fake_argv, False)
1954      self.assertListEqual(expected_results, test_results)
1955
1956  def test_method_flagfiles_4(self):
1957    """Tests parsing self-referential files + arguments of simulated argv.
1958
1959    This test should print a warning to stderr of some sort.
1960    """
1961    tmp_files = self._setup_test_files()
1962    # specify our temp file on the fake cmd line
1963    fake_cmd_line = ('fooScript --flagfile=%s --nounittest_boolflag' %
1964                     tmp_files[2])
1965    fake_argv = fake_cmd_line.split(' ')
1966    expected_results = [
1967        'fooScript', '--unittest_message1=setFromTempFile3',
1968        '--unittest_boolflag', '--nounittest_boolflag'
1969    ]
1970
1971    test_results = self._read_flags_from_files(fake_argv, False)
1972    self.assertListEqual(expected_results, test_results)
1973
1974  def test_method_flagfiles_5(self):
1975    """Test that --flagfile parsing respects the '--' end-of-options marker."""
1976    tmp_files = self._setup_test_files()
1977    # specify our temp file on the fake cmd line
1978    fake_cmd_line = 'fooScript --some_flag -- --flagfile=%s' % tmp_files[0]
1979    fake_argv = fake_cmd_line.split(' ')
1980    expected_results = [
1981        'fooScript', '--some_flag', '--',
1982        '--flagfile=%s' % tmp_files[0]
1983    ]
1984
1985    test_results = self._read_flags_from_files(fake_argv, False)
1986    self.assertListEqual(expected_results, test_results)
1987
1988  def test_method_flagfiles_6(self):
1989    """Test that --flagfile parsing stops at non-options (non-GNU behavior)."""
1990    tmp_files = self._setup_test_files()
1991    # specify our temp file on the fake cmd line
1992    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
1993                     tmp_files[0])
1994    fake_argv = fake_cmd_line.split(' ')
1995    expected_results = [
1996        'fooScript', '--some_flag', 'some_arg',
1997        '--flagfile=%s' % tmp_files[0]
1998    ]
1999
2000    with _use_gnu_getopt(self.flag_values, False):
2001      test_results = self._read_flags_from_files(fake_argv, False)
2002      self.assertListEqual(expected_results, test_results)
2003
2004  def test_method_flagfiles_7(self):
2005    """Test that --flagfile parsing skips over a non-option (GNU behavior)."""
2006    self.flag_values.set_gnu_getopt()
2007    tmp_files = self._setup_test_files()
2008    # specify our temp file on the fake cmd line
2009    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2010                     tmp_files[0])
2011    fake_argv = fake_cmd_line.split(' ')
2012    expected_results = [
2013        'fooScript', '--some_flag', 'some_arg',
2014        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2015        '--nounittest_boolflag'
2016    ]
2017
2018    test_results = self._read_flags_from_files(fake_argv, False)
2019    self.assertListEqual(expected_results, test_results)
2020
2021  def test_method_flagfiles_8(self):
2022    """Test that --flagfile parsing respects force_gnu=True."""
2023    tmp_files = self._setup_test_files()
2024    # specify our temp file on the fake cmd line
2025    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2026                     tmp_files[0])
2027    fake_argv = fake_cmd_line.split(' ')
2028    expected_results = [
2029        'fooScript', '--some_flag', 'some_arg',
2030        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2031        '--nounittest_boolflag'
2032    ]
2033
2034    test_results = self._read_flags_from_files(fake_argv, True)
2035    self.assertListEqual(expected_results, test_results)
2036
2037  def test_method_flagfiles_repeated_non_circular(self):
2038    """Tests that parsing repeated non-circular flagfiles works."""
2039    tmp_files = self._setup_test_files()
2040    # specify our temp files on the fake cmd line
2041    fake_cmd_line = ('fooScript --flagfile=%s --flagfile=%s' %
2042                     (tmp_files[1], tmp_files[0]))
2043    fake_argv = fake_cmd_line.split(' ')
2044    expected_results = [
2045        'fooScript', '--unittest_message1=tempFile1!',
2046        '--unittest_number=54321', '--nounittest_boolflag',
2047        '--unittest_message2=setFromTempFile2', '--unittest_number=6789a',
2048        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2049        '--nounittest_boolflag'
2050    ]
2051
2052    test_results = self._read_flags_from_files(fake_argv, False)
2053    self.assertListEqual(expected_results, test_results)
2054
2055  @unittest.skipIf(
2056      os.name == 'nt',
2057      'There is no good way to create an unreadable file on Windows.')
2058  def test_method_flagfiles_no_permissions(self):
2059    """Test that --flagfile raises except on file that is unreadable."""
2060    tmp_files = self._setup_test_files()
2061    # specify our temp file on the fake cmd line
2062    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2063                     tmp_files[3])
2064    fake_argv = fake_cmd_line.split(' ')
2065    self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files,
2066                      fake_argv, True)
2067
2068  def test_method_flagfiles_not_found(self):
2069    """Test that --flagfile raises except on file that does not exist."""
2070    tmp_files = self._setup_test_files()
2071    # specify our temp file on the fake cmd line
2072    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%sNOTEXIST' %
2073                     tmp_files[3])
2074    fake_argv = fake_cmd_line.split(' ')
2075    self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files,
2076                      fake_argv, True)
2077
2078  def test_flagfiles_user_path_expansion(self):
2079    """Test that user directory referenced paths are correctly expanded.
2080
2081    Test paths like ~/foo. This test depends on whatever account's running
2082    the unit test to have read/write access to their own home directory,
2083    otherwise it'll FAIL.
2084    """
2085    fake_flagfile_item_style_1 = '--flagfile=~/foo.file'
2086    fake_flagfile_item_style_2 = '-flagfile=~/foo.file'
2087
2088    expected_results = os.path.expanduser('~/foo.file')
2089
2090    test_results = self.flag_values._extract_filename(
2091        fake_flagfile_item_style_1)
2092    self.assertEqual(expected_results, test_results)
2093
2094    test_results = self.flag_values._extract_filename(
2095        fake_flagfile_item_style_2)
2096    self.assertEqual(expected_results, test_results)
2097
2098  def test_no_touchy_non_flags(self):
2099    """Test that the flags parser does not mutilate arguments.
2100
2101    The arguments are not supposed to be flags
2102    """
2103    fake_argv = [
2104        'fooScript', '--unittest_boolflag', 'command', '--command_arg1',
2105        '--UnitTestBoom', '--UnitTestB'
2106    ]
2107    with _use_gnu_getopt(self.flag_values, False):
2108      argv = self.flag_values(fake_argv)
2109      self.assertListEqual(argv, fake_argv[:1] + fake_argv[2:])
2110
2111  def test_parse_flags_after_args_if_using_gnugetopt(self):
2112    """Test that flags given after arguments are parsed if using gnu_getopt."""
2113    self.flag_values.set_gnu_getopt()
2114    fake_argv = [
2115        'fooScript', '--unittest_boolflag', 'command', '--unittest_number=54321'
2116    ]
2117    argv = self.flag_values(fake_argv)
2118    self.assertListEqual(argv, ['fooScript', 'command'])
2119
2120  def test_set_default(self):
2121    """Test changing flag defaults."""
2122    # Test that set_default changes both the default and the value,
2123    # and that the value is changed when one is given as an option.
2124    self.flag_values.set_default('unittest_message1', 'New value')
2125    self.assertEqual(self.flag_values.unittest_message1, 'New value')
2126    self.assertEqual(self.flag_values['unittest_message1'].default_as_str,
2127                     "'New value'")
2128    self.flag_values(['dummyscript', '--unittest_message1=Newer value'])
2129    self.assertEqual(self.flag_values.unittest_message1, 'Newer value')
2130
2131    # Test that setting the default to None works correctly.
2132    self.flag_values.set_default('unittest_number', None)
2133    self.assertEqual(self.flag_values.unittest_number, None)
2134    self.assertEqual(self.flag_values['unittest_number'].default_as_str, None)
2135    self.flag_values(['dummyscript', '--unittest_number=56'])
2136    self.assertEqual(self.flag_values.unittest_number, 56)
2137
2138    # Test that setting the default to zero works correctly.
2139    self.flag_values.set_default('unittest_number', 0)
2140    self.assertEqual(self.flag_values['unittest_number'].default, 0)
2141    self.assertEqual(self.flag_values.unittest_number, 56)
2142    self.assertEqual(self.flag_values['unittest_number'].default_as_str, "'0'")
2143    self.flag_values(['dummyscript', '--unittest_number=56'])
2144    self.assertEqual(self.flag_values.unittest_number, 56)
2145
2146    # Test that setting the default to '' works correctly.
2147    self.flag_values.set_default('unittest_message1', '')
2148    self.assertEqual(self.flag_values['unittest_message1'].default, '')
2149    self.assertEqual(self.flag_values.unittest_message1, 'Newer value')
2150    self.assertEqual(self.flag_values['unittest_message1'].default_as_str, "''")
2151    self.flag_values(['dummyscript', '--unittest_message1=fifty-six'])
2152    self.assertEqual(self.flag_values.unittest_message1, 'fifty-six')
2153
2154    # Test that setting the default to false works correctly.
2155    self.flag_values.set_default('unittest_boolflag', False)
2156    self.assertEqual(self.flag_values.unittest_boolflag, False)
2157    self.assertEqual(self.flag_values['unittest_boolflag'].default_as_str,
2158                     "'false'")
2159    self.flag_values(['dummyscript', '--unittest_boolflag=true'])
2160    self.assertEqual(self.flag_values.unittest_boolflag, True)
2161
2162    # Test that setting a list default works correctly.
2163    self.flag_values.set_default('UnitTestList', '4,5,6')
2164    self.assertListEqual(self.flag_values.UnitTestList, ['4', '5', '6'])
2165    self.assertEqual(self.flag_values['UnitTestList'].default_as_str, "'4,5,6'")
2166    self.flag_values(['dummyscript', '--UnitTestList=7,8,9'])
2167    self.assertListEqual(self.flag_values.UnitTestList, ['7', '8', '9'])
2168
2169    # Test that setting invalid defaults raises exceptions
2170    with self.assertRaises(flags.IllegalFlagValueError):
2171      self.flag_values.set_default('unittest_number', 'oops')
2172    with self.assertRaises(flags.IllegalFlagValueError):
2173      self.flag_values.set_default('unittest_number', -1)
2174
2175
2176class FlagsParsingTest(absltest.TestCase):
2177  """Testing different aspects of parsing: '-f' vs '--flag', etc."""
2178
2179  def setUp(self):
2180    self.flag_values = flags.FlagValues()
2181
2182  def test_two_dash_arg_first(self):
2183    flags.DEFINE_string(
2184        'twodash_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2185    flags.DEFINE_string(
2186        'twodash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2187    argv = ('./program', '--', '--twodash_name=Harry')
2188    argv = self.flag_values(argv)
2189    self.assertEqual('Bob', self.flag_values.twodash_name)
2190    self.assertEqual(argv[1], '--twodash_name=Harry')
2191
2192  def test_two_dash_arg_middle(self):
2193    flags.DEFINE_string(
2194        'twodash2_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2195    flags.DEFINE_string(
2196        'twodash2_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2197    argv = ('./program', '--twodash2_blame=Larry', '--',
2198            '--twodash2_name=Harry')
2199    argv = self.flag_values(argv)
2200    self.assertEqual('Bob', self.flag_values.twodash2_name)
2201    self.assertEqual('Larry', self.flag_values.twodash2_blame)
2202    self.assertEqual(argv[1], '--twodash2_name=Harry')
2203
2204  def test_one_dash_arg_first(self):
2205    flags.DEFINE_string(
2206        'onedash_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2207    flags.DEFINE_string(
2208        'onedash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2209    argv = ('./program', '-', '--onedash_name=Harry')
2210    with _use_gnu_getopt(self.flag_values, False):
2211      argv = self.flag_values(argv)
2212      self.assertEqual(len(argv), 3)
2213      self.assertEqual(argv[1], '-')
2214      self.assertEqual(argv[2], '--onedash_name=Harry')
2215
2216  def test_required_flag_not_specified(self):
2217    flags.DEFINE_string(
2218        'str_flag',
2219        default=None,
2220        help='help',
2221        required=True,
2222        flag_values=self.flag_values)
2223    argv = ('./program',)
2224    with _use_gnu_getopt(self.flag_values, False):
2225      with self.assertRaises(flags.IllegalFlagValueError):
2226        self.flag_values(argv)
2227
2228  def test_required_arg_works_with_other_validators(self):
2229    flags.DEFINE_integer(
2230        'int_flag',
2231        default=None,
2232        help='help',
2233        required=True,
2234        lower_bound=4,
2235        flag_values=self.flag_values)
2236    argv = ('./program', '--int_flag=2')
2237    with _use_gnu_getopt(self.flag_values, False):
2238      with self.assertRaises(flags.IllegalFlagValueError):
2239        self.flag_values(argv)
2240
2241  def test_unrecognized_flags(self):
2242    flags.DEFINE_string('name', 'Bob', 'namehelp', flag_values=self.flag_values)
2243    # Unknown flag --nosuchflag
2244    try:
2245      argv = ('./program', '--nosuchflag', '--name=Bob', 'extra')
2246      self.flag_values(argv)
2247      raise AssertionError('Unknown flag exception not raised')
2248    except flags.UnrecognizedFlagError as e:
2249      self.assertEqual(e.flagname, 'nosuchflag')
2250      self.assertEqual(e.flagvalue, '--nosuchflag')
2251
2252    # Unknown flag -w (short option)
2253    try:
2254      argv = ('./program', '-w', '--name=Bob', 'extra')
2255      self.flag_values(argv)
2256      raise AssertionError('Unknown flag exception not raised')
2257    except flags.UnrecognizedFlagError as e:
2258      self.assertEqual(e.flagname, 'w')
2259      self.assertEqual(e.flagvalue, '-w')
2260
2261    # Unknown flag --nosuchflagwithparam=foo
2262    try:
2263      argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 'extra')
2264      self.flag_values(argv)
2265      raise AssertionError('Unknown flag exception not raised')
2266    except flags.UnrecognizedFlagError as e:
2267      self.assertEqual(e.flagname, 'nosuchflagwithparam')
2268      self.assertEqual(e.flagvalue, '--nosuchflagwithparam=foo')
2269
2270    # Allow unknown flag --nosuchflag if specified with undefok
2271    argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchflag',
2272            'extra')
2273    argv = self.flag_values(argv)
2274    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2275    self.assertEqual(argv[0], './program', 'program name not preserved')
2276    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2277
2278    # Allow unknown flag --noboolflag if undefok=boolflag is specified
2279    argv = ('./program', '--noboolflag', '--name=Bob', '--undefok=boolflag',
2280            'extra')
2281    argv = self.flag_values(argv)
2282    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2283    self.assertEqual(argv[0], './program', 'program name not preserved')
2284    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2285
2286    # But not if the flagname is misspelled:
2287    try:
2288      argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchfla',
2289              'extra')
2290      self.flag_values(argv)
2291      raise AssertionError('Unknown flag exception not raised')
2292    except flags.UnrecognizedFlagError as e:
2293      self.assertEqual(e.flagname, 'nosuchflag')
2294
2295    try:
2296      argv = ('./program', '--nosuchflag', '--name=Bob',
2297              '--undefok=nosuchflagg', 'extra')
2298      self.flag_values(argv)
2299      raise AssertionError('Unknown flag exception not raised')
2300    except flags.UnrecognizedFlagError as e:
2301      self.assertEqual(e.flagname, 'nosuchflag')
2302
2303    # Allow unknown short flag -w if specified with undefok
2304    argv = ('./program', '-w', '--name=Bob', '--undefok=w', 'extra')
2305    argv = self.flag_values(argv)
2306    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2307    self.assertEqual(argv[0], './program', 'program name not preserved')
2308    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2309
2310    # Allow unknown flag --nosuchflagwithparam=foo if specified
2311    # with undefok
2312    argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob',
2313            '--undefok=nosuchflagwithparam', 'extra')
2314    argv = self.flag_values(argv)
2315    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2316    self.assertEqual(argv[0], './program', 'program name not preserved')
2317    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2318
2319    # Even if undefok specifies multiple flags
2320    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
2321            '--name=Bob', '--undefok=nosuchflag,w,nosuchflagwithparam', 'extra')
2322    argv = self.flag_values(argv)
2323    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2324    self.assertEqual(argv[0], './program', 'program name not preserved')
2325    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2326
2327    # However, not if undefok doesn't specify the flag
2328    try:
2329      argv = ('./program', '--nosuchflag', '--name=Bob',
2330              '--undefok=another_such', 'extra')
2331      self.flag_values(argv)
2332      raise AssertionError('Unknown flag exception not raised')
2333    except flags.UnrecognizedFlagError as e:
2334      self.assertEqual(e.flagname, 'nosuchflag')
2335
2336    # Make sure --undefok doesn't mask other option errors.
2337    try:
2338      # Provide an option requiring a parameter but not giving it one.
2339      argv = ('./program', '--undefok=name', '--name')
2340      self.flag_values(argv)
2341      raise AssertionError('Missing option parameter exception not raised')
2342    except flags.UnrecognizedFlagError:
2343      raise AssertionError('Wrong kind of error exception raised')
2344    except flags.Error:
2345      pass
2346
2347    # Test --undefok <list>
2348    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
2349            '--name=Bob', '--undefok', 'nosuchflag,w,nosuchflagwithparam',
2350            'extra')
2351    argv = self.flag_values(argv)
2352    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2353    self.assertEqual(argv[0], './program', 'program name not preserved')
2354    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2355
2356    # Test incorrect --undefok with no value.
2357    argv = ('./program', '--name=Bob', '--undefok')
2358    with self.assertRaises(flags.Error):
2359      self.flag_values(argv)
2360
2361
2362class NonGlobalFlagsTest(absltest.TestCase):
2363
2364  def test_nonglobal_flags(self):
2365    """Test use of non-global FlagValues."""
2366    nonglobal_flags = flags.FlagValues()
2367    flags.DEFINE_string('nonglobal_flag', 'Bob', 'flaghelp', nonglobal_flags)
2368    argv = ('./program', '--nonglobal_flag=Mary', 'extra')
2369    argv = nonglobal_flags(argv)
2370    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2371    self.assertEqual(argv[0], './program', 'program name not preserved')
2372    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2373    self.assertEqual(nonglobal_flags['nonglobal_flag'].value, 'Mary')
2374
2375  def test_unrecognized_nonglobal_flags(self):
2376    """Test unrecognized non-global flags."""
2377    nonglobal_flags = flags.FlagValues()
2378    argv = ('./program', '--nosuchflag')
2379    try:
2380      argv = nonglobal_flags(argv)
2381      raise AssertionError('Unknown flag exception not raised')
2382    except flags.UnrecognizedFlagError as e:
2383      self.assertEqual(e.flagname, 'nosuchflag')
2384
2385    argv = ('./program', '--nosuchflag', '--undefok=nosuchflag')
2386
2387    argv = nonglobal_flags(argv)
2388    self.assertEqual(len(argv), 1, 'wrong number of arguments pulled')
2389    self.assertEqual(argv[0], './program', 'program name not preserved')
2390
2391  def test_create_flag_errors(self):
2392    # Since the exception classes are exposed, nothing stops users
2393    # from creating their own instances. This test makes sure that
2394    # people modifying the flags module understand that the external
2395    # mechanisms for creating the exceptions should continue to work.
2396    _ = flags.Error()
2397    _ = flags.Error('message')
2398    _ = flags.DuplicateFlagError()
2399    _ = flags.DuplicateFlagError('message')
2400    _ = flags.IllegalFlagValueError()
2401    _ = flags.IllegalFlagValueError('message')
2402
2403  def test_flag_values_del_attr(self):
2404    """Checks that del self.flag_values.flag_id works."""
2405    default_value = 'default value for test_flag_values_del_attr'
2406    # 1. Declare and delete a flag with no short name.
2407    flag_values = flags.FlagValues()
2408    flags.DEFINE_string(
2409        'delattr_foo', default_value, 'A simple flag.', flag_values=flag_values)
2410
2411    flag_values.mark_as_parsed()
2412    self.assertEqual(flag_values.delattr_foo, default_value)
2413    flag_obj = flag_values['delattr_foo']
2414    # We also check that _FlagIsRegistered works as expected :)
2415    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2416    del flag_values.delattr_foo
2417    self.assertFalse('delattr_foo' in flag_values._flags())
2418    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2419    # If the previous del FLAGS.delattr_foo did not work properly, the
2420    # next definition will trigger a redefinition error.
2421    flags.DEFINE_integer(
2422        'delattr_foo', 3, 'A simple flag.', flag_values=flag_values)
2423    del flag_values.delattr_foo
2424
2425    self.assertFalse('delattr_foo' in flag_values)
2426
2427    # 2. Declare and delete a flag with a short name.
2428    flags.DEFINE_string(
2429        'delattr_bar',
2430        default_value,
2431        'flag with short name',
2432        short_name='x5',
2433        flag_values=flag_values)
2434    flag_obj = flag_values['delattr_bar']
2435    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2436    del flag_values.x5
2437    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2438    del flag_values.delattr_bar
2439    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2440
2441    # 3. Just like 2, but del flag_values.name last
2442    flags.DEFINE_string(
2443        'delattr_bar',
2444        default_value,
2445        'flag with short name',
2446        short_name='x5',
2447        flag_values=flag_values)
2448    flag_obj = flag_values['delattr_bar']
2449    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2450    del flag_values.delattr_bar
2451    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2452    del flag_values.x5
2453    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2454
2455    self.assertFalse('delattr_bar' in flag_values)
2456    self.assertFalse('x5' in flag_values)
2457
2458  def test_list_flag_format(self):
2459    """Tests for correctly-formatted list flags."""
2460    fv = flags.FlagValues()
2461    flags.DEFINE_list('listflag', '', 'A list of arguments', flag_values=fv)
2462
2463    def _check_parsing(listval):
2464      """Parse a particular value for our test flag, --listflag."""
2465      argv = fv(['./program', '--listflag=' + listval, 'plain-arg'])
2466      self.assertEqual(['./program', 'plain-arg'], argv)
2467      return fv.listflag
2468
2469    # Basic success case
2470    self.assertEqual(_check_parsing('foo,bar'), ['foo', 'bar'])
2471    # Success case: newline in argument is quoted.
2472    self.assertEqual(_check_parsing('"foo","bar\nbar"'), ['foo', 'bar\nbar'])
2473    # Failure case: newline in argument is unquoted.
2474    self.assertRaises(flags.IllegalFlagValueError, _check_parsing,
2475                      '"foo",bar\nbar')
2476    # Failure case: unmatched ".
2477    self.assertRaises(flags.IllegalFlagValueError, _check_parsing,
2478                      '"foo,barbar')
2479
2480  def test_flag_definition_via_setitem(self):
2481    with self.assertRaises(flags.IllegalFlagValueError):
2482      flag_values = flags.FlagValues()
2483      flag_values['flag_name'] = 'flag_value'
2484
2485
2486class SetDefaultTest(absltest.TestCase):
2487
2488  def setUp(self):
2489    super().setUp()
2490    self.flag_values = flags.FlagValues()
2491
2492  def test_success(self):
2493    int_holder = flags.DEFINE_integer(
2494        'an_int', 1, 'an int', flag_values=self.flag_values)
2495
2496    flags.set_default(int_holder, 2)
2497    self.flag_values.mark_as_parsed()
2498
2499    self.assertEqual(int_holder.value, 2)
2500
2501  def test_update_after_parse(self):
2502    int_holder = flags.DEFINE_integer(
2503        'an_int', 1, 'an int', flag_values=self.flag_values)
2504
2505    self.flag_values.mark_as_parsed()
2506    flags.set_default(int_holder, 2)
2507
2508    self.assertEqual(int_holder.value, 2)
2509
2510  def test_overridden_by_explicit_assignment(self):
2511    int_holder = flags.DEFINE_integer(
2512        'an_int', 1, 'an int', flag_values=self.flag_values)
2513
2514    self.flag_values.mark_as_parsed()
2515    self.flag_values.an_int = 3
2516    flags.set_default(int_holder, 2)
2517
2518    self.assertEqual(int_holder.value, 3)
2519
2520  def test_restores_back_to_none(self):
2521    int_holder = flags.DEFINE_integer(
2522        'an_int', None, 'an int', flag_values=self.flag_values)
2523
2524    self.flag_values.mark_as_parsed()
2525    flags.set_default(int_holder, 3)
2526    flags.set_default(int_holder, None)
2527
2528    self.assertIsNone(int_holder.value)
2529
2530  def test_failure_on_invalid_type(self):
2531    int_holder = flags.DEFINE_integer(
2532        'an_int', 1, 'an int', flag_values=self.flag_values)
2533
2534    self.flag_values.mark_as_parsed()
2535
2536    with self.assertRaises(flags.IllegalFlagValueError):
2537      flags.set_default(int_holder, 'a')
2538
2539  def test_failure_on_type_protected_none_default(self):
2540    int_holder = flags.DEFINE_integer(
2541        'an_int', 1, 'an int', flag_values=self.flag_values)
2542
2543    self.flag_values.mark_as_parsed()
2544
2545    flags.set_default(int_holder, None)  # NOTE: should be a type failure
2546
2547    with self.assertRaises(flags.IllegalFlagValueError):
2548      _ = int_holder.value  # Will also fail on later access.
2549
2550
2551class KeyFlagsTest(absltest.TestCase):
2552
2553  def setUp(self):
2554    self.flag_values = flags.FlagValues()
2555
2556  def _get_names_of_defined_flags(self, module, flag_values):
2557    """Returns the list of names of flags defined by a module.
2558
2559    Auxiliary for the test_key_flags* methods.
2560
2561    Args:
2562      module: A module object or a string module name.
2563      flag_values: A FlagValues object.
2564
2565    Returns:
2566      A list of strings.
2567    """
2568    return [f.name for f in flag_values.get_flags_for_module(module)]
2569
2570  def _get_names_of_key_flags(self, module, flag_values):
2571    """Returns the list of names of key flags for a module.
2572
2573    Auxiliary for the test_key_flags* methods.
2574
2575    Args:
2576      module: A module object or a string module name.
2577      flag_values: A FlagValues object.
2578
2579    Returns:
2580      A list of strings.
2581    """
2582    return [f.name for f in flag_values.get_key_flags_for_module(module)]
2583
2584  def _assert_lists_have_same_elements(self, list_1, list_2):
2585    # Checks that two lists have the same elements with the same
2586    # multiplicity, in possibly different order.
2587    list_1 = list(list_1)
2588    list_1.sort()
2589    list_2 = list(list_2)
2590    list_2.sort()
2591    self.assertListEqual(list_1, list_2)
2592
2593  def test_key_flags(self):
2594    flag_values = flags.FlagValues()
2595    # Before starting any testing, make sure no flags are already
2596    # defined for module_foo and module_bar.
2597    self.assertListEqual(
2598        self._get_names_of_key_flags(module_foo, flag_values), [])
2599    self.assertListEqual(
2600        self._get_names_of_key_flags(module_bar, flag_values), [])
2601    self.assertListEqual(
2602        self._get_names_of_defined_flags(module_foo, flag_values), [])
2603    self.assertListEqual(
2604        self._get_names_of_defined_flags(module_bar, flag_values), [])
2605
2606    # Defines a few flags in module_foo and module_bar.
2607    module_foo.define_flags(flag_values=flag_values)
2608
2609    try:
2610      # Part 1. Check that all flags defined by module_foo are key for
2611      # that module, and similarly for module_bar.
2612      for module in [module_foo, module_bar]:
2613        self._assert_lists_have_same_elements(
2614            flag_values.get_flags_for_module(module),
2615            flag_values.get_key_flags_for_module(module))
2616        # Also check that each module defined the expected flags.
2617        self._assert_lists_have_same_elements(
2618            self._get_names_of_defined_flags(module, flag_values),
2619            module.names_of_defined_flags())
2620
2621      # Part 2. Check that flags.declare_key_flag works fine.
2622      # Declare that some flags from module_bar are key for
2623      # module_foo.
2624      module_foo.declare_key_flags(flag_values=flag_values)
2625
2626      # Check that module_foo has the expected list of defined flags.
2627      self._assert_lists_have_same_elements(
2628          self._get_names_of_defined_flags(module_foo, flag_values),
2629          module_foo.names_of_defined_flags())
2630
2631      # Check that module_foo has the expected list of key flags.
2632      self._assert_lists_have_same_elements(
2633          self._get_names_of_key_flags(module_foo, flag_values),
2634          module_foo.names_of_declared_key_flags())
2635
2636      # Part 3. Check that flags.adopt_module_key_flags works fine.
2637      # Trigger a call to flags.adopt_module_key_flags(module_bar)
2638      # inside module_foo.  This should declare a few more key
2639      # flags in module_foo.
2640      module_foo.declare_extra_key_flags(flag_values=flag_values)
2641
2642      # Check that module_foo has the expected list of key flags.
2643      self._assert_lists_have_same_elements(
2644          self._get_names_of_key_flags(module_foo, flag_values),
2645          module_foo.names_of_declared_key_flags() +
2646          module_foo.names_of_declared_extra_key_flags())
2647    finally:
2648      module_foo.remove_flags(flag_values=flag_values)
2649
2650  def test_key_flags_with_non_default_flag_values_object(self):
2651    # Check that key flags work even when we use a FlagValues object
2652    # that is not the default flags.self.flag_values object.  Otherwise, this
2653    # test is similar to test_key_flags, but it uses only module_bar.
2654    # The other test module (module_foo) uses only the default values
2655    # for the flag_values keyword arguments.  This way, test_key_flags
2656    # and this method test both the default FlagValues, the explicitly
2657    # specified one, and a mixed usage of the two.
2658
2659    # A brand-new FlagValues object, to use instead of flags.self.flag_values.
2660    fv = flags.FlagValues()
2661
2662    # Before starting any testing, make sure no flags are already
2663    # defined for module_foo and module_bar.
2664    self.assertListEqual(self._get_names_of_key_flags(module_bar, fv), [])
2665    self.assertListEqual(self._get_names_of_defined_flags(module_bar, fv), [])
2666
2667    module_bar.define_flags(flag_values=fv)
2668
2669    # Check that all flags defined by module_bar are key for that
2670    # module, and that module_bar defined the expected flags.
2671    self._assert_lists_have_same_elements(
2672        fv.get_flags_for_module(module_bar),
2673        fv.get_key_flags_for_module(module_bar))
2674    self._assert_lists_have_same_elements(
2675        self._get_names_of_defined_flags(module_bar, fv),
2676        module_bar.names_of_defined_flags())
2677
2678    # Pick two flags from module_bar, declare them as key for the
2679    # current (i.e., main) module (via flags.declare_key_flag), and
2680    # check that we get the expected effect.  The important thing is
2681    # that we always use flags_values=fv (instead of the default
2682    # self.flag_values).
2683    main_module = sys.argv[0]
2684    names_of_flags_defined_by_bar = module_bar.names_of_defined_flags()
2685    flag_name_0 = names_of_flags_defined_by_bar[0]
2686    flag_name_2 = names_of_flags_defined_by_bar[2]
2687
2688    flags.declare_key_flag(flag_name_0, flag_values=fv)
2689    self._assert_lists_have_same_elements(
2690        self._get_names_of_key_flags(main_module, fv), [flag_name_0])
2691
2692    flags.declare_key_flag(flag_name_2, flag_values=fv)
2693    self._assert_lists_have_same_elements(
2694        self._get_names_of_key_flags(main_module, fv),
2695        [flag_name_0, flag_name_2])
2696
2697    # Try with a special (not user-defined) flag too:
2698    flags.declare_key_flag('undefok', flag_values=fv)
2699    self._assert_lists_have_same_elements(
2700        self._get_names_of_key_flags(main_module, fv),
2701        [flag_name_0, flag_name_2, 'undefok'])
2702
2703    flags.adopt_module_key_flags(module_bar, fv)
2704    self._assert_lists_have_same_elements(
2705        self._get_names_of_key_flags(main_module, fv),
2706        names_of_flags_defined_by_bar + ['undefok'])
2707
2708    # Adopt key flags from the flags module itself.
2709    flags.adopt_module_key_flags(flags, flag_values=fv)
2710    self._assert_lists_have_same_elements(
2711        self._get_names_of_key_flags(main_module, fv),
2712        names_of_flags_defined_by_bar + ['flagfile', 'undefok'])
2713
2714  def test_key_flags_with_flagholders(self):
2715    main_module = sys.argv[0]
2716
2717    self.assertListEqual(
2718        self._get_names_of_key_flags(main_module, self.flag_values), [])
2719    self.assertListEqual(
2720        self._get_names_of_defined_flags(main_module, self.flag_values), [])
2721
2722    int_holder = flags.DEFINE_integer(
2723        'main_module_int_fg',
2724        1,
2725        'Integer flag in the main module.',
2726        flag_values=self.flag_values)
2727
2728    flags.declare_key_flag(int_holder, self.flag_values)
2729
2730    self.assertCountEqual(
2731        self.flag_values.get_flags_for_module(main_module),
2732        self.flag_values.get_key_flags_for_module(main_module))
2733
2734    bool_holder = flags.DEFINE_boolean(
2735        'main_module_bool_fg',
2736        False,
2737        'Boolean flag in the main module.',
2738        flag_values=self.flag_values)
2739
2740    flags.declare_key_flag(bool_holder)  # omitted flag_values
2741
2742    self.assertCountEqual(
2743        self.flag_values.get_flags_for_module(main_module),
2744        self.flag_values.get_key_flags_for_module(main_module))
2745
2746    self.assertLen(self.flag_values.get_flags_for_module(main_module), 2)
2747
2748  def test_main_module_help_with_key_flags(self):
2749    # Similar to test_main_module_help, but this time we make sure to
2750    # declare some key flags.
2751
2752    # Safety check that the main module does not declare any flags
2753    # at the beginning of this test.
2754    expected_help = ''
2755    self.assertMultiLineEqual(expected_help,
2756                              self.flag_values.main_module_help())
2757
2758    # Define one flag in this main module and some flags in modules
2759    # a and b.  Also declare one flag from module a and one flag
2760    # from module b as key flags for the main module.
2761    flags.DEFINE_integer(
2762        'main_module_int_fg',
2763        1,
2764        'Integer flag in the main module.',
2765        flag_values=self.flag_values)
2766
2767    try:
2768      main_module_int_fg_help = (
2769          '  --main_module_int_fg: Integer flag in the main module.\n'
2770          "    (default: '1')\n"
2771          '    (an integer)')
2772
2773      expected_help += '\n%s:\n%s' % (sys.argv[0], main_module_int_fg_help)
2774      self.assertMultiLineEqual(expected_help,
2775                                self.flag_values.main_module_help())
2776
2777      # The following call should be a no-op: any flag declared by a
2778      # module is automatically key for that module.
2779      flags.declare_key_flag('main_module_int_fg', flag_values=self.flag_values)
2780      self.assertMultiLineEqual(expected_help,
2781                                self.flag_values.main_module_help())
2782
2783      # The definition of a few flags in an imported module should not
2784      # change the main module help.
2785      module_foo.define_flags(flag_values=self.flag_values)
2786      self.assertMultiLineEqual(expected_help,
2787                                self.flag_values.main_module_help())
2788
2789      flags.declare_key_flag('tmod_foo_bool', flag_values=self.flag_values)
2790      tmod_foo_bool_help = (
2791          '  --[no]tmod_foo_bool: Boolean flag from module foo.\n'
2792          "    (default: 'true')")
2793      expected_help += '\n' + tmod_foo_bool_help
2794      self.assertMultiLineEqual(expected_help,
2795                                self.flag_values.main_module_help())
2796
2797      flags.declare_key_flag('tmod_bar_z', flag_values=self.flag_values)
2798      tmod_bar_z_help = (
2799          '  --[no]tmod_bar_z: Another boolean flag from module bar.\n'
2800          "    (default: 'false')")
2801      # Unfortunately, there is some flag sorting inside
2802      # main_module_help, so we can't keep incrementally extending
2803      # the expected_help string ...
2804      expected_help = ('\n%s:\n%s\n%s\n%s' %
2805                       (sys.argv[0], main_module_int_fg_help, tmod_bar_z_help,
2806                        tmod_foo_bool_help))
2807      self.assertMultiLineEqual(self.flag_values.main_module_help(),
2808                                expected_help)
2809
2810    finally:
2811      # At the end, delete all the flag information we created.
2812      self.flag_values.__delattr__('main_module_int_fg')
2813      module_foo.remove_flags(flag_values=self.flag_values)
2814
2815  def test_adoptmodule_key_flags(self):
2816    # Check that adopt_module_key_flags raises an exception when
2817    # called with a module name (as opposed to a module object).
2818    self.assertRaises(flags.Error, flags.adopt_module_key_flags, 'pyglib.app')
2819
2820  def test_disclaimkey_flags(self):
2821    original_disclaim_module_ids = _helpers.disclaim_module_ids
2822    _helpers.disclaim_module_ids = set(_helpers.disclaim_module_ids)
2823    try:
2824      module_bar.disclaim_key_flags()
2825      module_foo.define_bar_flags(flag_values=self.flag_values)
2826      module_name = self.flag_values.find_module_defining_flag('tmod_bar_x')
2827      self.assertEqual(module_foo.__name__, module_name)
2828    finally:
2829      _helpers.disclaim_module_ids = original_disclaim_module_ids
2830
2831
2832class FindModuleTest(absltest.TestCase):
2833  """Testing methods that find a module that defines a given flag."""
2834
2835  def test_find_module_defining_flag(self):
2836    self.assertEqual(
2837        'default',
2838        FLAGS.find_module_defining_flag('__NON_EXISTENT_FLAG__', 'default'))
2839    self.assertEqual(module_baz.__name__,
2840                     FLAGS.find_module_defining_flag('tmod_baz_x'))
2841
2842  def test_find_module_id_defining_flag(self):
2843    self.assertEqual(
2844        'default',
2845        FLAGS.find_module_id_defining_flag('__NON_EXISTENT_FLAG__', 'default'))
2846    self.assertEqual(
2847        id(module_baz), FLAGS.find_module_id_defining_flag('tmod_baz_x'))
2848
2849  def test_find_module_defining_flag_passing_module_name(self):
2850    my_flags = flags.FlagValues()
2851    module_name = sys.__name__  # Must use an existing module.
2852    flags.DEFINE_boolean(
2853        'flag_name',
2854        True,
2855        'Flag with a different module name.',
2856        flag_values=my_flags,
2857        module_name=module_name)
2858    self.assertEqual(module_name,
2859                     my_flags.find_module_defining_flag('flag_name'))
2860
2861  def test_find_module_id_defining_flag_passing_module_name(self):
2862    my_flags = flags.FlagValues()
2863    module_name = sys.__name__  # Must use an existing module.
2864    flags.DEFINE_boolean(
2865        'flag_name',
2866        True,
2867        'Flag with a different module name.',
2868        flag_values=my_flags,
2869        module_name=module_name)
2870    self.assertEqual(
2871        id(sys), my_flags.find_module_id_defining_flag('flag_name'))
2872
2873
2874class FlagsErrorMessagesTest(absltest.TestCase):
2875  """Testing special cases for integer and float flags error messages."""
2876
2877  def setUp(self):
2878    self.flag_values = flags.FlagValues()
2879
2880  def test_integer_error_text(self):
2881    # Make sure we get proper error text
2882    flags.DEFINE_integer(
2883        'positive',
2884        4,
2885        'non-negative flag',
2886        lower_bound=1,
2887        flag_values=self.flag_values)
2888    flags.DEFINE_integer(
2889        'non_negative',
2890        4,
2891        'positive flag',
2892        lower_bound=0,
2893        flag_values=self.flag_values)
2894    flags.DEFINE_integer(
2895        'negative',
2896        -4,
2897        'negative flag',
2898        upper_bound=-1,
2899        flag_values=self.flag_values)
2900    flags.DEFINE_integer(
2901        'non_positive',
2902        -4,
2903        'non-positive flag',
2904        upper_bound=0,
2905        flag_values=self.flag_values)
2906    flags.DEFINE_integer(
2907        'greater',
2908        19,
2909        'greater-than flag',
2910        lower_bound=4,
2911        flag_values=self.flag_values)
2912    flags.DEFINE_integer(
2913        'smaller',
2914        -19,
2915        'smaller-than flag',
2916        upper_bound=4,
2917        flag_values=self.flag_values)
2918    flags.DEFINE_integer(
2919        'usual',
2920        4,
2921        'usual flag',
2922        lower_bound=0,
2923        upper_bound=10000,
2924        flag_values=self.flag_values)
2925    flags.DEFINE_integer(
2926        'another_usual',
2927        0,
2928        'usual flag',
2929        lower_bound=-1,
2930        upper_bound=1,
2931        flag_values=self.flag_values)
2932
2933    self._check_error_message('positive', -4, 'a positive integer')
2934    self._check_error_message('non_negative', -4, 'a non-negative integer')
2935    self._check_error_message('negative', 0, 'a negative integer')
2936    self._check_error_message('non_positive', 4, 'a non-positive integer')
2937    self._check_error_message('usual', -4, 'an integer in the range [0, 10000]')
2938    self._check_error_message('another_usual', 4,
2939                              'an integer in the range [-1, 1]')
2940    self._check_error_message('greater', -5, 'integer >= 4')
2941    self._check_error_message('smaller', 5, 'integer <= 4')
2942
2943  def test_float_error_text(self):
2944    flags.DEFINE_float(
2945        'positive',
2946        4,
2947        'non-negative flag',
2948        lower_bound=1,
2949        flag_values=self.flag_values)
2950    flags.DEFINE_float(
2951        'non_negative',
2952        4,
2953        'positive flag',
2954        lower_bound=0,
2955        flag_values=self.flag_values)
2956    flags.DEFINE_float(
2957        'negative',
2958        -4,
2959        'negative flag',
2960        upper_bound=-1,
2961        flag_values=self.flag_values)
2962    flags.DEFINE_float(
2963        'non_positive',
2964        -4,
2965        'non-positive flag',
2966        upper_bound=0,
2967        flag_values=self.flag_values)
2968    flags.DEFINE_float(
2969        'greater',
2970        19,
2971        'greater-than flag',
2972        lower_bound=4,
2973        flag_values=self.flag_values)
2974    flags.DEFINE_float(
2975        'smaller',
2976        -19,
2977        'smaller-than flag',
2978        upper_bound=4,
2979        flag_values=self.flag_values)
2980    flags.DEFINE_float(
2981        'usual',
2982        4,
2983        'usual flag',
2984        lower_bound=0,
2985        upper_bound=10000,
2986        flag_values=self.flag_values)
2987    flags.DEFINE_float(
2988        'another_usual',
2989        0,
2990        'usual flag',
2991        lower_bound=-1,
2992        upper_bound=1,
2993        flag_values=self.flag_values)
2994
2995    self._check_error_message('positive', 0.5, 'number >= 1')
2996    self._check_error_message('non_negative', -4.0, 'a non-negative number')
2997    self._check_error_message('negative', 0.5, 'number <= -1')
2998    self._check_error_message('non_positive', 4.0, 'a non-positive number')
2999    self._check_error_message('usual', -4.0, 'a number in the range [0, 10000]')
3000    self._check_error_message('another_usual', 4.0,
3001                              'a number in the range [-1, 1]')
3002    self._check_error_message('smaller', 5.0, 'number <= 4')
3003
3004  def _check_error_message(self, flag_name, flag_value,
3005                           expected_message_suffix):
3006    """Set a flag to a given value and make sure we get expected message."""
3007
3008    try:
3009      self.flag_values.__setattr__(flag_name, flag_value)
3010      raise AssertionError('Bounds exception not raised!')
3011    except flags.IllegalFlagValueError as e:
3012      expected = ('flag --%(name)s=%(value)s: %(value)s is not %(suffix)s' % {
3013          'name': flag_name,
3014          'value': flag_value,
3015          'suffix': expected_message_suffix
3016      })
3017      self.assertEqual(str(e), expected)
3018
3019
3020if __name__ == '__main__':
3021  absltest.main()
3022