• 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_short_name(self):
1595    fv = flags.FlagValues()
1596    flags.DEFINE_multi_enum_class(
1597        'fruit',
1598        None,
1599        Fruit,
1600        'Enum option that can occur multiple times',
1601        flag_values=fv,
1602        short_name='me')
1603    self.assertEqual(fv['fruit'].short_name, 'me')
1604
1605  def test_define_results_in_registered_flag_with_none(self):
1606    fv = flags.FlagValues()
1607    enum_defaults = None
1608    flags.DEFINE_multi_enum_class(
1609        'fruit',
1610        enum_defaults,
1611        Fruit,
1612        'Enum option that can occur multiple times',
1613        flag_values=fv)
1614    fv.mark_as_parsed()
1615
1616    self.assertIsNone(fv.fruit)
1617
1618  def test_help_text(self):
1619    fv = flags.FlagValues()
1620    enum_defaults = None
1621    flags.DEFINE_multi_enum_class(
1622        'fruit',
1623        enum_defaults,
1624        Fruit,
1625        'Enum option that can occur multiple times',
1626        flag_values=fv)
1627
1628    self.assertRegex(
1629        fv['fruit'].help,
1630        r'<apple\|orange>: Enum option that can occur multiple times;\s+'
1631        'repeat this option to specify a list of values')
1632
1633  def test_define_results_in_registered_flag_with_string(self):
1634    fv = flags.FlagValues()
1635    enum_defaults = 'apple'
1636    flags.DEFINE_multi_enum_class(
1637        'fruit',
1638        enum_defaults,
1639        Fruit,
1640        'Enum option that can occur multiple times',
1641        flag_values=fv)
1642    fv.mark_as_parsed()
1643
1644    self.assertListEqual(fv.fruit, [Fruit.APPLE])
1645
1646  def test_define_results_in_registered_flag_with_enum(self):
1647    fv = flags.FlagValues()
1648    enum_defaults = Fruit.APPLE
1649    flags.DEFINE_multi_enum_class(
1650        'fruit',
1651        enum_defaults,
1652        Fruit,
1653        'Enum option that can occur multiple times',
1654        flag_values=fv)
1655    fv.mark_as_parsed()
1656
1657    self.assertListEqual(fv.fruit, [Fruit.APPLE])
1658
1659  def test_define_results_in_registered_flag_with_string_list(self):
1660    fv = flags.FlagValues()
1661    enum_defaults = ['apple', 'APPLE']
1662    flags.DEFINE_multi_enum_class(
1663        'fruit',
1664        enum_defaults,
1665        CaseSensitiveFruit,
1666        'Enum option that can occur multiple times',
1667        flag_values=fv,
1668        case_sensitive=True)
1669    fv.mark_as_parsed()
1670
1671    self.assertListEqual(fv.fruit,
1672                         [CaseSensitiveFruit.apple, CaseSensitiveFruit.APPLE])
1673
1674  def test_define_results_in_registered_flag_with_enum_list(self):
1675    fv = flags.FlagValues()
1676    enum_defaults = [Fruit.APPLE, Fruit.ORANGE]
1677    flags.DEFINE_multi_enum_class(
1678        'fruit',
1679        enum_defaults,
1680        Fruit,
1681        'Enum option that can occur multiple times',
1682        flag_values=fv)
1683    fv.mark_as_parsed()
1684
1685    self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE])
1686
1687  def test_from_command_line_returns_multiple(self):
1688    fv = flags.FlagValues()
1689    enum_defaults = [Fruit.APPLE]
1690    flags.DEFINE_multi_enum_class(
1691        'fruit',
1692        enum_defaults,
1693        Fruit,
1694        'Enum option that can occur multiple times',
1695        flag_values=fv)
1696    argv = ('./program', '--fruit=Apple', '--fruit=orange')
1697    fv(argv)
1698    self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE])
1699
1700  def test_bad_multi_enum_class_flags_from_definition(self):
1701    with self.assertRaisesRegex(
1702        flags.IllegalFlagValueError,
1703        'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'):
1704      flags.DEFINE_multi_enum_class('fruit', ['INVALID'], Fruit, 'desc')
1705
1706  def test_bad_multi_enum_class_flags_from_commandline(self):
1707    fv = flags.FlagValues()
1708    enum_defaults = [Fruit.APPLE]
1709    flags.DEFINE_multi_enum_class(
1710        'fruit', enum_defaults, Fruit, 'desc', flag_values=fv)
1711    argv = ('./program', '--fruit=INVALID')
1712    with self.assertRaisesRegex(
1713        flags.IllegalFlagValueError,
1714        'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'):
1715      fv(argv)
1716
1717
1718class UnicodeFlagsTest(absltest.TestCase):
1719  """Testing proper unicode support for flags."""
1720
1721  def test_unicode_default_and_helpstring(self):
1722    fv = flags.FlagValues()
1723    flags.DEFINE_string(
1724        'unicode_str',
1725        b'\xC3\x80\xC3\xBD'.decode('utf-8'),
1726        b'help:\xC3\xAA'.decode('utf-8'),
1727        flag_values=fv)
1728    argv = ('./program',)
1729    fv(argv)  # should not raise any exceptions
1730
1731    argv = ('./program', '--unicode_str=foo')
1732    fv(argv)  # should not raise any exceptions
1733
1734  def test_unicode_in_list(self):
1735    fv = flags.FlagValues()
1736    flags.DEFINE_list(
1737        'unicode_list',
1738        ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')],
1739        b'help:\xC3\xAB'.decode('utf-8'),
1740        flag_values=fv)
1741    argv = ('./program',)
1742    fv(argv)  # should not raise any exceptions
1743
1744    argv = ('./program', '--unicode_list=hello,there')
1745    fv(argv)  # should not raise any exceptions
1746
1747  def test_xmloutput(self):
1748    fv = flags.FlagValues()
1749    flags.DEFINE_string(
1750        'unicode1',
1751        b'\xC3\x80\xC3\xBD'.decode('utf-8'),
1752        b'help:\xC3\xAC'.decode('utf-8'),
1753        flag_values=fv)
1754    flags.DEFINE_list(
1755        'unicode2',
1756        ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')],
1757        b'help:\xC3\xAD'.decode('utf-8'),
1758        flag_values=fv)
1759    flags.DEFINE_list(
1760        'non_unicode', ['abc', 'def', 'ghi'],
1761        b'help:\xC3\xAD'.decode('utf-8'),
1762        flag_values=fv)
1763
1764    outfile = io.StringIO()
1765    fv.write_help_in_xml_format(outfile)
1766    actual_output = outfile.getvalue()
1767
1768    # The xml output is large, so we just check parts of it.
1769    self.assertIn(
1770        b'<name>unicode1</name>\n'
1771        b'    <meaning>help:\xc3\xac</meaning>\n'
1772        b'    <default>\xc3\x80\xc3\xbd</default>\n'
1773        b'    <current>\xc3\x80\xc3\xbd</current>'.decode('utf-8'),
1774        actual_output)
1775    self.assertIn(
1776        b'<name>unicode2</name>\n'
1777        b'    <meaning>help:\xc3\xad</meaning>\n'
1778        b'    <default>abc,\xc3\x80,\xc3\xbd</default>\n'
1779        b"    <current>['abc', '\xc3\x80', '\xc3\xbd']"
1780        b'</current>'.decode('utf-8'), actual_output)
1781    self.assertIn(
1782        b'<name>non_unicode</name>\n'
1783        b'    <meaning>help:\xc3\xad</meaning>\n'
1784        b'    <default>abc,def,ghi</default>\n'
1785        b"    <current>['abc', 'def', 'ghi']"
1786        b'</current>'.decode('utf-8'), actual_output)
1787
1788
1789class LoadFromFlagFileTest(absltest.TestCase):
1790  """Testing loading flags from a file and parsing them."""
1791
1792  def setUp(self):
1793    self.flag_values = flags.FlagValues()
1794    flags.DEFINE_string(
1795        'unittest_message1',
1796        'Foo!',
1797        'You Add Here.',
1798        flag_values=self.flag_values)
1799    flags.DEFINE_string(
1800        'unittest_message2',
1801        'Bar!',
1802        'Hello, Sailor!',
1803        flag_values=self.flag_values)
1804    flags.DEFINE_boolean(
1805        'unittest_boolflag',
1806        0,
1807        'Some Boolean thing',
1808        flag_values=self.flag_values)
1809    flags.DEFINE_integer(
1810        'unittest_number',
1811        12345,
1812        'Some integer',
1813        lower_bound=0,
1814        flag_values=self.flag_values)
1815    flags.DEFINE_list(
1816        'UnitTestList', '1,2,3', 'Some list', flag_values=self.flag_values)
1817    self.tmp_path = None
1818    self.flag_values.mark_as_parsed()
1819
1820  def tearDown(self):
1821    self._remove_test_files()
1822
1823  def _setup_test_files(self):
1824    """Creates and sets up some dummy flagfile files with bogus flags."""
1825
1826    # Figure out where to create temporary files
1827    self.assertFalse(self.tmp_path)
1828    self.tmp_path = tempfile.mkdtemp()
1829
1830    tmp_flag_file_1 = open(self.tmp_path + '/UnitTestFile1.tst', 'w')
1831    tmp_flag_file_2 = open(self.tmp_path + '/UnitTestFile2.tst', 'w')
1832    tmp_flag_file_3 = open(self.tmp_path + '/UnitTestFile3.tst', 'w')
1833    tmp_flag_file_4 = open(self.tmp_path + '/UnitTestFile4.tst', 'w')
1834
1835    # put some dummy flags in our test files
1836    tmp_flag_file_1.write('#A Fake Comment\n')
1837    tmp_flag_file_1.write('--unittest_message1=tempFile1!\n')
1838    tmp_flag_file_1.write('\n')
1839    tmp_flag_file_1.write('--unittest_number=54321\n')
1840    tmp_flag_file_1.write('--nounittest_boolflag\n')
1841    file_list = [tmp_flag_file_1.name]
1842    # this one includes test file 1
1843    tmp_flag_file_2.write('//A Different Fake Comment\n')
1844    tmp_flag_file_2.write('--flagfile=%s\n' % tmp_flag_file_1.name)
1845    tmp_flag_file_2.write('--unittest_message2=setFromTempFile2\n')
1846    tmp_flag_file_2.write('\t\t\n')
1847    tmp_flag_file_2.write('--unittest_number=6789a\n')
1848    file_list.append(tmp_flag_file_2.name)
1849    # this file points to itself
1850    tmp_flag_file_3.write('--flagfile=%s\n' % tmp_flag_file_3.name)
1851    tmp_flag_file_3.write('--unittest_message1=setFromTempFile3\n')
1852    tmp_flag_file_3.write('#YAFC\n')
1853    tmp_flag_file_3.write('--unittest_boolflag\n')
1854    file_list.append(tmp_flag_file_3.name)
1855    # this file is unreadable
1856    tmp_flag_file_4.write('--flagfile=%s\n' % tmp_flag_file_3.name)
1857    tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n')
1858    tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n')
1859    os.chmod(self.tmp_path + '/UnitTestFile4.tst', 0)
1860    file_list.append(tmp_flag_file_4.name)
1861
1862    tmp_flag_file_1.close()
1863    tmp_flag_file_2.close()
1864    tmp_flag_file_3.close()
1865    tmp_flag_file_4.close()
1866
1867    return file_list  # these are just the file names
1868
1869  def _remove_test_files(self):
1870    """Removes the files we just created."""
1871    if self.tmp_path:
1872      shutil.rmtree(self.tmp_path, ignore_errors=True)
1873      self.tmp_path = None
1874
1875  def _read_flags_from_files(self, argv, force_gnu):
1876    return argv[:1] + self.flag_values.read_flags_from_files(
1877        argv[1:], force_gnu=force_gnu)
1878
1879  #### Flagfile Unit Tests ####
1880  def test_method_flagfiles_1(self):
1881    """Test trivial case with no flagfile based options."""
1882    fake_cmd_line = 'fooScript --unittest_boolflag'
1883    fake_argv = fake_cmd_line.split(' ')
1884    self.flag_values(fake_argv)
1885    self.assertEqual(self.flag_values.unittest_boolflag, 1)
1886    self.assertListEqual(fake_argv,
1887                         self._read_flags_from_files(fake_argv, False))
1888
1889  def test_method_flagfiles_2(self):
1890    """Tests parsing one file + arguments off simulated argv."""
1891    tmp_files = self._setup_test_files()
1892    # specify our temp file on the fake cmd line
1893    fake_cmd_line = 'fooScript --q --flagfile=%s' % tmp_files[0]
1894    fake_argv = fake_cmd_line.split(' ')
1895
1896    # We should see the original cmd line with the file's contents spliced in.
1897    # Flags from the file will appear in the order order they are specified
1898    # in the file, in the same position as the flagfile argument.
1899    expected_results = [
1900        'fooScript', '--q', '--unittest_message1=tempFile1!',
1901        '--unittest_number=54321', '--nounittest_boolflag'
1902    ]
1903    test_results = self._read_flags_from_files(fake_argv, False)
1904    self.assertListEqual(expected_results, test_results)
1905
1906  # end testTwo def
1907
1908  def test_method_flagfiles_3(self):
1909    """Tests parsing nested files + arguments of simulated argv."""
1910    tmp_files = self._setup_test_files()
1911    # specify our temp file on the fake cmd line
1912    fake_cmd_line = ('fooScript --unittest_number=77 --flagfile=%s' %
1913                     tmp_files[1])
1914    fake_argv = fake_cmd_line.split(' ')
1915
1916    expected_results = [
1917        'fooScript', '--unittest_number=77', '--unittest_message1=tempFile1!',
1918        '--unittest_number=54321', '--nounittest_boolflag',
1919        '--unittest_message2=setFromTempFile2', '--unittest_number=6789a'
1920    ]
1921    test_results = self._read_flags_from_files(fake_argv, False)
1922    self.assertListEqual(expected_results, test_results)
1923
1924  # end testThree def
1925
1926  def test_method_flagfiles_3_spaces(self):
1927    """Tests parsing nested files + arguments of simulated argv.
1928
1929    The arguments include a pair that is actually an arg with a value, so it
1930    doesn't stop processing.
1931    """
1932    tmp_files = self._setup_test_files()
1933    # specify our temp file on the fake cmd line
1934    fake_cmd_line = ('fooScript --unittest_number 77 --flagfile=%s' %
1935                     tmp_files[1])
1936    fake_argv = fake_cmd_line.split(' ')
1937
1938    expected_results = [
1939        'fooScript', '--unittest_number', '77',
1940        '--unittest_message1=tempFile1!', '--unittest_number=54321',
1941        '--nounittest_boolflag', '--unittest_message2=setFromTempFile2',
1942        '--unittest_number=6789a'
1943    ]
1944    test_results = self._read_flags_from_files(fake_argv, False)
1945    self.assertListEqual(expected_results, test_results)
1946
1947  def test_method_flagfiles_3_spaces_boolean(self):
1948    """Tests parsing nested files + arguments of simulated argv.
1949
1950    The arguments include a pair that looks like a --x y arg with value, but
1951    since the flag is a boolean it's actually not.
1952    """
1953    tmp_files = self._setup_test_files()
1954    # specify our temp file on the fake cmd line
1955    fake_cmd_line = ('fooScript --unittest_boolflag 77 --flagfile=%s' %
1956                     tmp_files[1])
1957    fake_argv = fake_cmd_line.split(' ')
1958
1959    expected_results = [
1960        'fooScript', '--unittest_boolflag', '77',
1961        '--flagfile=%s' % tmp_files[1]
1962    ]
1963    with _use_gnu_getopt(self.flag_values, False):
1964      test_results = self._read_flags_from_files(fake_argv, False)
1965      self.assertListEqual(expected_results, test_results)
1966
1967  def test_method_flagfiles_4(self):
1968    """Tests parsing self-referential files + arguments of simulated argv.
1969
1970    This test should print a warning to stderr of some sort.
1971    """
1972    tmp_files = self._setup_test_files()
1973    # specify our temp file on the fake cmd line
1974    fake_cmd_line = ('fooScript --flagfile=%s --nounittest_boolflag' %
1975                     tmp_files[2])
1976    fake_argv = fake_cmd_line.split(' ')
1977    expected_results = [
1978        'fooScript', '--unittest_message1=setFromTempFile3',
1979        '--unittest_boolflag', '--nounittest_boolflag'
1980    ]
1981
1982    test_results = self._read_flags_from_files(fake_argv, False)
1983    self.assertListEqual(expected_results, test_results)
1984
1985  def test_method_flagfiles_5(self):
1986    """Test that --flagfile parsing respects the '--' end-of-options marker."""
1987    tmp_files = self._setup_test_files()
1988    # specify our temp file on the fake cmd line
1989    fake_cmd_line = 'fooScript --some_flag -- --flagfile=%s' % tmp_files[0]
1990    fake_argv = fake_cmd_line.split(' ')
1991    expected_results = [
1992        'fooScript', '--some_flag', '--',
1993        '--flagfile=%s' % tmp_files[0]
1994    ]
1995
1996    test_results = self._read_flags_from_files(fake_argv, False)
1997    self.assertListEqual(expected_results, test_results)
1998
1999  def test_method_flagfiles_6(self):
2000    """Test that --flagfile parsing stops at non-options (non-GNU behavior)."""
2001    tmp_files = self._setup_test_files()
2002    # specify our temp file on the fake cmd line
2003    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2004                     tmp_files[0])
2005    fake_argv = fake_cmd_line.split(' ')
2006    expected_results = [
2007        'fooScript', '--some_flag', 'some_arg',
2008        '--flagfile=%s' % tmp_files[0]
2009    ]
2010
2011    with _use_gnu_getopt(self.flag_values, False):
2012      test_results = self._read_flags_from_files(fake_argv, False)
2013      self.assertListEqual(expected_results, test_results)
2014
2015  def test_method_flagfiles_7(self):
2016    """Test that --flagfile parsing skips over a non-option (GNU behavior)."""
2017    self.flag_values.set_gnu_getopt()
2018    tmp_files = self._setup_test_files()
2019    # specify our temp file on the fake cmd line
2020    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2021                     tmp_files[0])
2022    fake_argv = fake_cmd_line.split(' ')
2023    expected_results = [
2024        'fooScript', '--some_flag', 'some_arg',
2025        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2026        '--nounittest_boolflag'
2027    ]
2028
2029    test_results = self._read_flags_from_files(fake_argv, False)
2030    self.assertListEqual(expected_results, test_results)
2031
2032  def test_method_flagfiles_8(self):
2033    """Test that --flagfile parsing respects force_gnu=True."""
2034    tmp_files = self._setup_test_files()
2035    # specify our temp file on the fake cmd line
2036    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2037                     tmp_files[0])
2038    fake_argv = fake_cmd_line.split(' ')
2039    expected_results = [
2040        'fooScript', '--some_flag', 'some_arg',
2041        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2042        '--nounittest_boolflag'
2043    ]
2044
2045    test_results = self._read_flags_from_files(fake_argv, True)
2046    self.assertListEqual(expected_results, test_results)
2047
2048  def test_method_flagfiles_repeated_non_circular(self):
2049    """Tests that parsing repeated non-circular flagfiles works."""
2050    tmp_files = self._setup_test_files()
2051    # specify our temp files on the fake cmd line
2052    fake_cmd_line = ('fooScript --flagfile=%s --flagfile=%s' %
2053                     (tmp_files[1], tmp_files[0]))
2054    fake_argv = fake_cmd_line.split(' ')
2055    expected_results = [
2056        'fooScript', '--unittest_message1=tempFile1!',
2057        '--unittest_number=54321', '--nounittest_boolflag',
2058        '--unittest_message2=setFromTempFile2', '--unittest_number=6789a',
2059        '--unittest_message1=tempFile1!', '--unittest_number=54321',
2060        '--nounittest_boolflag'
2061    ]
2062
2063    test_results = self._read_flags_from_files(fake_argv, False)
2064    self.assertListEqual(expected_results, test_results)
2065
2066  @unittest.skipIf(
2067      os.name == 'nt',
2068      'There is no good way to create an unreadable file on Windows.')
2069  def test_method_flagfiles_no_permissions(self):
2070    """Test that --flagfile raises except on file that is unreadable."""
2071    tmp_files = self._setup_test_files()
2072    # specify our temp file on the fake cmd line
2073    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' %
2074                     tmp_files[3])
2075    fake_argv = fake_cmd_line.split(' ')
2076    self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files,
2077                      fake_argv, True)
2078
2079  def test_method_flagfiles_not_found(self):
2080    """Test that --flagfile raises except on file that does not exist."""
2081    tmp_files = self._setup_test_files()
2082    # specify our temp file on the fake cmd line
2083    fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%sNOTEXIST' %
2084                     tmp_files[3])
2085    fake_argv = fake_cmd_line.split(' ')
2086    self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files,
2087                      fake_argv, True)
2088
2089  def test_flagfiles_user_path_expansion(self):
2090    """Test that user directory referenced paths are correctly expanded.
2091
2092    Test paths like ~/foo. This test depends on whatever account's running
2093    the unit test to have read/write access to their own home directory,
2094    otherwise it'll FAIL.
2095    """
2096    fake_flagfile_item_style_1 = '--flagfile=~/foo.file'
2097    fake_flagfile_item_style_2 = '-flagfile=~/foo.file'
2098
2099    expected_results = os.path.expanduser('~/foo.file')
2100
2101    test_results = self.flag_values._extract_filename(
2102        fake_flagfile_item_style_1)
2103    self.assertEqual(expected_results, test_results)
2104
2105    test_results = self.flag_values._extract_filename(
2106        fake_flagfile_item_style_2)
2107    self.assertEqual(expected_results, test_results)
2108
2109  def test_no_touchy_non_flags(self):
2110    """Test that the flags parser does not mutilate arguments.
2111
2112    The arguments are not supposed to be flags
2113    """
2114    fake_argv = [
2115        'fooScript', '--unittest_boolflag', 'command', '--command_arg1',
2116        '--UnitTestBoom', '--UnitTestB'
2117    ]
2118    with _use_gnu_getopt(self.flag_values, False):
2119      argv = self.flag_values(fake_argv)
2120      self.assertListEqual(argv, fake_argv[:1] + fake_argv[2:])
2121
2122  def test_parse_flags_after_args_if_using_gnugetopt(self):
2123    """Test that flags given after arguments are parsed if using gnu_getopt."""
2124    self.flag_values.set_gnu_getopt()
2125    fake_argv = [
2126        'fooScript', '--unittest_boolflag', 'command', '--unittest_number=54321'
2127    ]
2128    argv = self.flag_values(fake_argv)
2129    self.assertListEqual(argv, ['fooScript', 'command'])
2130
2131  def test_set_default(self):
2132    """Test changing flag defaults."""
2133    # Test that set_default changes both the default and the value,
2134    # and that the value is changed when one is given as an option.
2135    self.flag_values.set_default('unittest_message1', 'New value')
2136    self.assertEqual(self.flag_values.unittest_message1, 'New value')
2137    self.assertEqual(self.flag_values['unittest_message1'].default_as_str,
2138                     "'New value'")
2139    self.flag_values(['dummyscript', '--unittest_message1=Newer value'])
2140    self.assertEqual(self.flag_values.unittest_message1, 'Newer value')
2141
2142    # Test that setting the default to None works correctly.
2143    self.flag_values.set_default('unittest_number', None)
2144    self.assertEqual(self.flag_values.unittest_number, None)
2145    self.assertEqual(self.flag_values['unittest_number'].default_as_str, None)
2146    self.flag_values(['dummyscript', '--unittest_number=56'])
2147    self.assertEqual(self.flag_values.unittest_number, 56)
2148
2149    # Test that setting the default to zero works correctly.
2150    self.flag_values.set_default('unittest_number', 0)
2151    self.assertEqual(self.flag_values['unittest_number'].default, 0)
2152    self.assertEqual(self.flag_values.unittest_number, 56)
2153    self.assertEqual(self.flag_values['unittest_number'].default_as_str, "'0'")
2154    self.flag_values(['dummyscript', '--unittest_number=56'])
2155    self.assertEqual(self.flag_values.unittest_number, 56)
2156
2157    # Test that setting the default to '' works correctly.
2158    self.flag_values.set_default('unittest_message1', '')
2159    self.assertEqual(self.flag_values['unittest_message1'].default, '')
2160    self.assertEqual(self.flag_values.unittest_message1, 'Newer value')
2161    self.assertEqual(self.flag_values['unittest_message1'].default_as_str, "''")
2162    self.flag_values(['dummyscript', '--unittest_message1=fifty-six'])
2163    self.assertEqual(self.flag_values.unittest_message1, 'fifty-six')
2164
2165    # Test that setting the default to false works correctly.
2166    self.flag_values.set_default('unittest_boolflag', False)
2167    self.assertEqual(self.flag_values.unittest_boolflag, False)
2168    self.assertEqual(self.flag_values['unittest_boolflag'].default_as_str,
2169                     "'false'")
2170    self.flag_values(['dummyscript', '--unittest_boolflag=true'])
2171    self.assertEqual(self.flag_values.unittest_boolflag, True)
2172
2173    # Test that setting a list default works correctly.
2174    self.flag_values.set_default('UnitTestList', '4,5,6')
2175    self.assertListEqual(self.flag_values.UnitTestList, ['4', '5', '6'])
2176    self.assertEqual(self.flag_values['UnitTestList'].default_as_str, "'4,5,6'")
2177    self.flag_values(['dummyscript', '--UnitTestList=7,8,9'])
2178    self.assertListEqual(self.flag_values.UnitTestList, ['7', '8', '9'])
2179
2180    # Test that setting invalid defaults raises exceptions
2181    with self.assertRaises(flags.IllegalFlagValueError):
2182      self.flag_values.set_default('unittest_number', 'oops')
2183    with self.assertRaises(flags.IllegalFlagValueError):
2184      self.flag_values.set_default('unittest_number', -1)
2185
2186
2187class FlagsParsingTest(absltest.TestCase):
2188  """Testing different aspects of parsing: '-f' vs '--flag', etc."""
2189
2190  def setUp(self):
2191    self.flag_values = flags.FlagValues()
2192
2193  def test_two_dash_arg_first(self):
2194    flags.DEFINE_string(
2195        'twodash_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2196    flags.DEFINE_string(
2197        'twodash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2198    argv = ('./program', '--', '--twodash_name=Harry')
2199    argv = self.flag_values(argv)
2200    self.assertEqual('Bob', self.flag_values.twodash_name)
2201    self.assertEqual(argv[1], '--twodash_name=Harry')
2202
2203  def test_two_dash_arg_middle(self):
2204    flags.DEFINE_string(
2205        'twodash2_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2206    flags.DEFINE_string(
2207        'twodash2_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2208    argv = ('./program', '--twodash2_blame=Larry', '--',
2209            '--twodash2_name=Harry')
2210    argv = self.flag_values(argv)
2211    self.assertEqual('Bob', self.flag_values.twodash2_name)
2212    self.assertEqual('Larry', self.flag_values.twodash2_blame)
2213    self.assertEqual(argv[1], '--twodash2_name=Harry')
2214
2215  def test_one_dash_arg_first(self):
2216    flags.DEFINE_string(
2217        'onedash_name', 'Bob', 'namehelp', flag_values=self.flag_values)
2218    flags.DEFINE_string(
2219        'onedash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values)
2220    argv = ('./program', '-', '--onedash_name=Harry')
2221    with _use_gnu_getopt(self.flag_values, False):
2222      argv = self.flag_values(argv)
2223      self.assertEqual(len(argv), 3)
2224      self.assertEqual(argv[1], '-')
2225      self.assertEqual(argv[2], '--onedash_name=Harry')
2226
2227  def test_required_flag_not_specified(self):
2228    flags.DEFINE_string(
2229        'str_flag',
2230        default=None,
2231        help='help',
2232        required=True,
2233        flag_values=self.flag_values)
2234    argv = ('./program',)
2235    with _use_gnu_getopt(self.flag_values, False):
2236      with self.assertRaises(flags.IllegalFlagValueError):
2237        self.flag_values(argv)
2238
2239  def test_required_arg_works_with_other_validators(self):
2240    flags.DEFINE_integer(
2241        'int_flag',
2242        default=None,
2243        help='help',
2244        required=True,
2245        lower_bound=4,
2246        flag_values=self.flag_values)
2247    argv = ('./program', '--int_flag=2')
2248    with _use_gnu_getopt(self.flag_values, False):
2249      with self.assertRaises(flags.IllegalFlagValueError):
2250        self.flag_values(argv)
2251
2252  def test_unrecognized_flags(self):
2253    flags.DEFINE_string('name', 'Bob', 'namehelp', flag_values=self.flag_values)
2254    # Unknown flag --nosuchflag
2255    try:
2256      argv = ('./program', '--nosuchflag', '--name=Bob', 'extra')
2257      self.flag_values(argv)
2258      raise AssertionError('Unknown flag exception not raised')
2259    except flags.UnrecognizedFlagError as e:
2260      self.assertEqual(e.flagname, 'nosuchflag')
2261      self.assertEqual(e.flagvalue, '--nosuchflag')
2262
2263    # Unknown flag -w (short option)
2264    try:
2265      argv = ('./program', '-w', '--name=Bob', 'extra')
2266      self.flag_values(argv)
2267      raise AssertionError('Unknown flag exception not raised')
2268    except flags.UnrecognizedFlagError as e:
2269      self.assertEqual(e.flagname, 'w')
2270      self.assertEqual(e.flagvalue, '-w')
2271
2272    # Unknown flag --nosuchflagwithparam=foo
2273    try:
2274      argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 'extra')
2275      self.flag_values(argv)
2276      raise AssertionError('Unknown flag exception not raised')
2277    except flags.UnrecognizedFlagError as e:
2278      self.assertEqual(e.flagname, 'nosuchflagwithparam')
2279      self.assertEqual(e.flagvalue, '--nosuchflagwithparam=foo')
2280
2281    # Allow unknown flag --nosuchflag if specified with undefok
2282    argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchflag',
2283            'extra')
2284    argv = self.flag_values(argv)
2285    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2286    self.assertEqual(argv[0], './program', 'program name not preserved')
2287    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2288
2289    # Allow unknown flag --noboolflag if undefok=boolflag is specified
2290    argv = ('./program', '--noboolflag', '--name=Bob', '--undefok=boolflag',
2291            'extra')
2292    argv = self.flag_values(argv)
2293    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2294    self.assertEqual(argv[0], './program', 'program name not preserved')
2295    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2296
2297    # But not if the flagname is misspelled:
2298    try:
2299      argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchfla',
2300              'extra')
2301      self.flag_values(argv)
2302      raise AssertionError('Unknown flag exception not raised')
2303    except flags.UnrecognizedFlagError as e:
2304      self.assertEqual(e.flagname, 'nosuchflag')
2305
2306    try:
2307      argv = ('./program', '--nosuchflag', '--name=Bob',
2308              '--undefok=nosuchflagg', 'extra')
2309      self.flag_values(argv)
2310      raise AssertionError('Unknown flag exception not raised')
2311    except flags.UnrecognizedFlagError as e:
2312      self.assertEqual(e.flagname, 'nosuchflag')
2313
2314    # Allow unknown short flag -w if specified with undefok
2315    argv = ('./program', '-w', '--name=Bob', '--undefok=w', 'extra')
2316    argv = self.flag_values(argv)
2317    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2318    self.assertEqual(argv[0], './program', 'program name not preserved')
2319    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2320
2321    # Allow unknown flag --nosuchflagwithparam=foo if specified
2322    # with undefok
2323    argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob',
2324            '--undefok=nosuchflagwithparam', 'extra')
2325    argv = self.flag_values(argv)
2326    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2327    self.assertEqual(argv[0], './program', 'program name not preserved')
2328    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2329
2330    # Even if undefok specifies multiple flags
2331    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
2332            '--name=Bob', '--undefok=nosuchflag,w,nosuchflagwithparam', 'extra')
2333    argv = self.flag_values(argv)
2334    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2335    self.assertEqual(argv[0], './program', 'program name not preserved')
2336    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2337
2338    # However, not if undefok doesn't specify the flag
2339    try:
2340      argv = ('./program', '--nosuchflag', '--name=Bob',
2341              '--undefok=another_such', 'extra')
2342      self.flag_values(argv)
2343      raise AssertionError('Unknown flag exception not raised')
2344    except flags.UnrecognizedFlagError as e:
2345      self.assertEqual(e.flagname, 'nosuchflag')
2346
2347    # Make sure --undefok doesn't mask other option errors.
2348    try:
2349      # Provide an option requiring a parameter but not giving it one.
2350      argv = ('./program', '--undefok=name', '--name')
2351      self.flag_values(argv)
2352      raise AssertionError('Missing option parameter exception not raised')
2353    except flags.UnrecognizedFlagError:
2354      raise AssertionError('Wrong kind of error exception raised')
2355    except flags.Error:
2356      pass
2357
2358    # Test --undefok <list>
2359    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
2360            '--name=Bob', '--undefok', 'nosuchflag,w,nosuchflagwithparam',
2361            'extra')
2362    argv = self.flag_values(argv)
2363    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2364    self.assertEqual(argv[0], './program', 'program name not preserved')
2365    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2366
2367    # Test incorrect --undefok with no value.
2368    argv = ('./program', '--name=Bob', '--undefok')
2369    with self.assertRaises(flags.Error):
2370      self.flag_values(argv)
2371
2372
2373class NonGlobalFlagsTest(absltest.TestCase):
2374
2375  def test_nonglobal_flags(self):
2376    """Test use of non-global FlagValues."""
2377    nonglobal_flags = flags.FlagValues()
2378    flags.DEFINE_string('nonglobal_flag', 'Bob', 'flaghelp', nonglobal_flags)
2379    argv = ('./program', '--nonglobal_flag=Mary', 'extra')
2380    argv = nonglobal_flags(argv)
2381    self.assertEqual(len(argv), 2, 'wrong number of arguments pulled')
2382    self.assertEqual(argv[0], './program', 'program name not preserved')
2383    self.assertEqual(argv[1], 'extra', 'extra argument not preserved')
2384    self.assertEqual(nonglobal_flags['nonglobal_flag'].value, 'Mary')
2385
2386  def test_unrecognized_nonglobal_flags(self):
2387    """Test unrecognized non-global flags."""
2388    nonglobal_flags = flags.FlagValues()
2389    argv = ('./program', '--nosuchflag')
2390    try:
2391      argv = nonglobal_flags(argv)
2392      raise AssertionError('Unknown flag exception not raised')
2393    except flags.UnrecognizedFlagError as e:
2394      self.assertEqual(e.flagname, 'nosuchflag')
2395
2396    argv = ('./program', '--nosuchflag', '--undefok=nosuchflag')
2397
2398    argv = nonglobal_flags(argv)
2399    self.assertEqual(len(argv), 1, 'wrong number of arguments pulled')
2400    self.assertEqual(argv[0], './program', 'program name not preserved')
2401
2402  def test_create_flag_errors(self):
2403    # Since the exception classes are exposed, nothing stops users
2404    # from creating their own instances. This test makes sure that
2405    # people modifying the flags module understand that the external
2406    # mechanisms for creating the exceptions should continue to work.
2407    _ = flags.Error()
2408    _ = flags.Error('message')
2409    _ = flags.DuplicateFlagError()
2410    _ = flags.DuplicateFlagError('message')
2411    _ = flags.IllegalFlagValueError()
2412    _ = flags.IllegalFlagValueError('message')
2413
2414  def test_flag_values_del_attr(self):
2415    """Checks that del self.flag_values.flag_id works."""
2416    default_value = 'default value for test_flag_values_del_attr'
2417    # 1. Declare and delete a flag with no short name.
2418    flag_values = flags.FlagValues()
2419    flags.DEFINE_string(
2420        'delattr_foo', default_value, 'A simple flag.', flag_values=flag_values)
2421
2422    flag_values.mark_as_parsed()
2423    self.assertEqual(flag_values.delattr_foo, default_value)
2424    flag_obj = flag_values['delattr_foo']
2425    # We also check that _FlagIsRegistered works as expected :)
2426    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2427    del flag_values.delattr_foo
2428    self.assertFalse('delattr_foo' in flag_values._flags())
2429    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2430    # If the previous del FLAGS.delattr_foo did not work properly, the
2431    # next definition will trigger a redefinition error.
2432    flags.DEFINE_integer(
2433        'delattr_foo', 3, 'A simple flag.', flag_values=flag_values)
2434    del flag_values.delattr_foo
2435
2436    self.assertFalse('delattr_foo' in flag_values)
2437
2438    # 2. Declare and delete a flag with a short name.
2439    flags.DEFINE_string(
2440        'delattr_bar',
2441        default_value,
2442        'flag with short name',
2443        short_name='x5',
2444        flag_values=flag_values)
2445    flag_obj = flag_values['delattr_bar']
2446    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2447    del flag_values.x5
2448    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2449    del flag_values.delattr_bar
2450    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2451
2452    # 3. Just like 2, but del flag_values.name last
2453    flags.DEFINE_string(
2454        'delattr_bar',
2455        default_value,
2456        'flag with short name',
2457        short_name='x5',
2458        flag_values=flag_values)
2459    flag_obj = flag_values['delattr_bar']
2460    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2461    del flag_values.delattr_bar
2462    self.assertTrue(flag_values._flag_is_registered(flag_obj))
2463    del flag_values.x5
2464    self.assertFalse(flag_values._flag_is_registered(flag_obj))
2465
2466    self.assertFalse('delattr_bar' in flag_values)
2467    self.assertFalse('x5' in flag_values)
2468
2469  def test_list_flag_format(self):
2470    """Tests for correctly-formatted list flags."""
2471    fv = flags.FlagValues()
2472    flags.DEFINE_list('listflag', '', 'A list of arguments', flag_values=fv)
2473
2474    def _check_parsing(listval):
2475      """Parse a particular value for our test flag, --listflag."""
2476      argv = fv(['./program', '--listflag=' + listval, 'plain-arg'])
2477      self.assertEqual(['./program', 'plain-arg'], argv)
2478      return fv.listflag
2479
2480    # Basic success case
2481    self.assertEqual(_check_parsing('foo,bar'), ['foo', 'bar'])
2482    # Success case: newline in argument is quoted.
2483    self.assertEqual(_check_parsing('"foo","bar\nbar"'), ['foo', 'bar\nbar'])
2484    # Failure case: newline in argument is unquoted.
2485    self.assertRaises(flags.IllegalFlagValueError, _check_parsing,
2486                      '"foo",bar\nbar')
2487    # Failure case: unmatched ".
2488    self.assertRaises(flags.IllegalFlagValueError, _check_parsing,
2489                      '"foo,barbar')
2490
2491  def test_flag_definition_via_setitem(self):
2492    with self.assertRaises(flags.IllegalFlagValueError):
2493      flag_values = flags.FlagValues()
2494      flag_values['flag_name'] = 'flag_value'
2495
2496
2497class SetDefaultTest(absltest.TestCase):
2498
2499  def setUp(self):
2500    super().setUp()
2501    self.flag_values = flags.FlagValues()
2502
2503  def test_success(self):
2504    int_holder = flags.DEFINE_integer(
2505        'an_int', 1, 'an int', flag_values=self.flag_values)
2506
2507    flags.set_default(int_holder, 2)
2508    self.flag_values.mark_as_parsed()
2509
2510    self.assertEqual(int_holder.value, 2)
2511
2512  def test_update_after_parse(self):
2513    int_holder = flags.DEFINE_integer(
2514        'an_int', 1, 'an int', flag_values=self.flag_values)
2515
2516    self.flag_values.mark_as_parsed()
2517    flags.set_default(int_holder, 2)
2518
2519    self.assertEqual(int_holder.value, 2)
2520
2521  def test_overridden_by_explicit_assignment(self):
2522    int_holder = flags.DEFINE_integer(
2523        'an_int', 1, 'an int', flag_values=self.flag_values)
2524
2525    self.flag_values.mark_as_parsed()
2526    self.flag_values.an_int = 3
2527    flags.set_default(int_holder, 2)
2528
2529    self.assertEqual(int_holder.value, 3)
2530
2531  def test_restores_back_to_none(self):
2532    int_holder = flags.DEFINE_integer(
2533        'an_int', None, 'an int', flag_values=self.flag_values)
2534
2535    self.flag_values.mark_as_parsed()
2536    flags.set_default(int_holder, 3)
2537    flags.set_default(int_holder, None)
2538
2539    self.assertIsNone(int_holder.value)
2540
2541  def test_failure_on_invalid_type(self):
2542    int_holder = flags.DEFINE_integer(
2543        'an_int', 1, 'an int', flag_values=self.flag_values)
2544
2545    self.flag_values.mark_as_parsed()
2546
2547    with self.assertRaises(flags.IllegalFlagValueError):
2548      flags.set_default(int_holder, 'a')
2549
2550  def test_failure_on_type_protected_none_default(self):
2551    int_holder = flags.DEFINE_integer(
2552        'an_int', 1, 'an int', flag_values=self.flag_values)
2553
2554    self.flag_values.mark_as_parsed()
2555
2556    flags.set_default(int_holder, None)  # NOTE: should be a type failure
2557
2558    with self.assertRaises(flags.IllegalFlagValueError):
2559      _ = int_holder.value  # Will also fail on later access.
2560
2561
2562class KeyFlagsTest(absltest.TestCase):
2563
2564  def setUp(self):
2565    self.flag_values = flags.FlagValues()
2566
2567  def _get_names_of_defined_flags(self, module, flag_values):
2568    """Returns the list of names of flags defined by a module.
2569
2570    Auxiliary for the test_key_flags* methods.
2571
2572    Args:
2573      module: A module object or a string module name.
2574      flag_values: A FlagValues object.
2575
2576    Returns:
2577      A list of strings.
2578    """
2579    return [f.name for f in flag_values.get_flags_for_module(module)]
2580
2581  def _get_names_of_key_flags(self, module, flag_values):
2582    """Returns the list of names of key flags for a module.
2583
2584    Auxiliary for the test_key_flags* methods.
2585
2586    Args:
2587      module: A module object or a string module name.
2588      flag_values: A FlagValues object.
2589
2590    Returns:
2591      A list of strings.
2592    """
2593    return [f.name for f in flag_values.get_key_flags_for_module(module)]
2594
2595  def _assert_lists_have_same_elements(self, list_1, list_2):
2596    # Checks that two lists have the same elements with the same
2597    # multiplicity, in possibly different order.
2598    list_1 = list(list_1)
2599    list_1.sort()
2600    list_2 = list(list_2)
2601    list_2.sort()
2602    self.assertListEqual(list_1, list_2)
2603
2604  def test_key_flags(self):
2605    flag_values = flags.FlagValues()
2606    # Before starting any testing, make sure no flags are already
2607    # defined for module_foo and module_bar.
2608    self.assertListEqual(
2609        self._get_names_of_key_flags(module_foo, flag_values), [])
2610    self.assertListEqual(
2611        self._get_names_of_key_flags(module_bar, flag_values), [])
2612    self.assertListEqual(
2613        self._get_names_of_defined_flags(module_foo, flag_values), [])
2614    self.assertListEqual(
2615        self._get_names_of_defined_flags(module_bar, flag_values), [])
2616
2617    # Defines a few flags in module_foo and module_bar.
2618    module_foo.define_flags(flag_values=flag_values)
2619
2620    try:
2621      # Part 1. Check that all flags defined by module_foo are key for
2622      # that module, and similarly for module_bar.
2623      for module in [module_foo, module_bar]:
2624        self._assert_lists_have_same_elements(
2625            flag_values.get_flags_for_module(module),
2626            flag_values.get_key_flags_for_module(module))
2627        # Also check that each module defined the expected flags.
2628        self._assert_lists_have_same_elements(
2629            self._get_names_of_defined_flags(module, flag_values),
2630            module.names_of_defined_flags())
2631
2632      # Part 2. Check that flags.declare_key_flag works fine.
2633      # Declare that some flags from module_bar are key for
2634      # module_foo.
2635      module_foo.declare_key_flags(flag_values=flag_values)
2636
2637      # Check that module_foo has the expected list of defined flags.
2638      self._assert_lists_have_same_elements(
2639          self._get_names_of_defined_flags(module_foo, flag_values),
2640          module_foo.names_of_defined_flags())
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
2647      # Part 3. Check that flags.adopt_module_key_flags works fine.
2648      # Trigger a call to flags.adopt_module_key_flags(module_bar)
2649      # inside module_foo.  This should declare a few more key
2650      # flags in module_foo.
2651      module_foo.declare_extra_key_flags(flag_values=flag_values)
2652
2653      # Check that module_foo has the expected list of key flags.
2654      self._assert_lists_have_same_elements(
2655          self._get_names_of_key_flags(module_foo, flag_values),
2656          module_foo.names_of_declared_key_flags() +
2657          module_foo.names_of_declared_extra_key_flags())
2658    finally:
2659      module_foo.remove_flags(flag_values=flag_values)
2660
2661  def test_key_flags_with_non_default_flag_values_object(self):
2662    # Check that key flags work even when we use a FlagValues object
2663    # that is not the default flags.self.flag_values object.  Otherwise, this
2664    # test is similar to test_key_flags, but it uses only module_bar.
2665    # The other test module (module_foo) uses only the default values
2666    # for the flag_values keyword arguments.  This way, test_key_flags
2667    # and this method test both the default FlagValues, the explicitly
2668    # specified one, and a mixed usage of the two.
2669
2670    # A brand-new FlagValues object, to use instead of flags.self.flag_values.
2671    fv = flags.FlagValues()
2672
2673    # Before starting any testing, make sure no flags are already
2674    # defined for module_foo and module_bar.
2675    self.assertListEqual(self._get_names_of_key_flags(module_bar, fv), [])
2676    self.assertListEqual(self._get_names_of_defined_flags(module_bar, fv), [])
2677
2678    module_bar.define_flags(flag_values=fv)
2679
2680    # Check that all flags defined by module_bar are key for that
2681    # module, and that module_bar defined the expected flags.
2682    self._assert_lists_have_same_elements(
2683        fv.get_flags_for_module(module_bar),
2684        fv.get_key_flags_for_module(module_bar))
2685    self._assert_lists_have_same_elements(
2686        self._get_names_of_defined_flags(module_bar, fv),
2687        module_bar.names_of_defined_flags())
2688
2689    # Pick two flags from module_bar, declare them as key for the
2690    # current (i.e., main) module (via flags.declare_key_flag), and
2691    # check that we get the expected effect.  The important thing is
2692    # that we always use flags_values=fv (instead of the default
2693    # self.flag_values).
2694    main_module = sys.argv[0]
2695    names_of_flags_defined_by_bar = module_bar.names_of_defined_flags()
2696    flag_name_0 = names_of_flags_defined_by_bar[0]
2697    flag_name_2 = names_of_flags_defined_by_bar[2]
2698
2699    flags.declare_key_flag(flag_name_0, flag_values=fv)
2700    self._assert_lists_have_same_elements(
2701        self._get_names_of_key_flags(main_module, fv), [flag_name_0])
2702
2703    flags.declare_key_flag(flag_name_2, flag_values=fv)
2704    self._assert_lists_have_same_elements(
2705        self._get_names_of_key_flags(main_module, fv),
2706        [flag_name_0, flag_name_2])
2707
2708    # Try with a special (not user-defined) flag too:
2709    flags.declare_key_flag('undefok', flag_values=fv)
2710    self._assert_lists_have_same_elements(
2711        self._get_names_of_key_flags(main_module, fv),
2712        [flag_name_0, flag_name_2, 'undefok'])
2713
2714    flags.adopt_module_key_flags(module_bar, fv)
2715    self._assert_lists_have_same_elements(
2716        self._get_names_of_key_flags(main_module, fv),
2717        names_of_flags_defined_by_bar + ['undefok'])
2718
2719    # Adopt key flags from the flags module itself.
2720    flags.adopt_module_key_flags(flags, flag_values=fv)
2721    self._assert_lists_have_same_elements(
2722        self._get_names_of_key_flags(main_module, fv),
2723        names_of_flags_defined_by_bar + ['flagfile', 'undefok'])
2724
2725  def test_key_flags_with_flagholders(self):
2726    main_module = sys.argv[0]
2727
2728    self.assertListEqual(
2729        self._get_names_of_key_flags(main_module, self.flag_values), [])
2730    self.assertListEqual(
2731        self._get_names_of_defined_flags(main_module, self.flag_values), [])
2732
2733    int_holder = flags.DEFINE_integer(
2734        'main_module_int_fg',
2735        1,
2736        'Integer flag in the main module.',
2737        flag_values=self.flag_values)
2738
2739    flags.declare_key_flag(int_holder, self.flag_values)
2740
2741    self.assertCountEqual(
2742        self.flag_values.get_flags_for_module(main_module),
2743        self.flag_values.get_key_flags_for_module(main_module))
2744
2745    bool_holder = flags.DEFINE_boolean(
2746        'main_module_bool_fg',
2747        False,
2748        'Boolean flag in the main module.',
2749        flag_values=self.flag_values)
2750
2751    flags.declare_key_flag(bool_holder)  # omitted flag_values
2752
2753    self.assertCountEqual(
2754        self.flag_values.get_flags_for_module(main_module),
2755        self.flag_values.get_key_flags_for_module(main_module))
2756
2757    self.assertLen(self.flag_values.get_flags_for_module(main_module), 2)
2758
2759  def test_main_module_help_with_key_flags(self):
2760    # Similar to test_main_module_help, but this time we make sure to
2761    # declare some key flags.
2762
2763    # Safety check that the main module does not declare any flags
2764    # at the beginning of this test.
2765    expected_help = ''
2766    self.assertMultiLineEqual(expected_help,
2767                              self.flag_values.main_module_help())
2768
2769    # Define one flag in this main module and some flags in modules
2770    # a and b.  Also declare one flag from module a and one flag
2771    # from module b as key flags for the main module.
2772    flags.DEFINE_integer(
2773        'main_module_int_fg',
2774        1,
2775        'Integer flag in the main module.',
2776        flag_values=self.flag_values)
2777
2778    try:
2779      main_module_int_fg_help = (
2780          '  --main_module_int_fg: Integer flag in the main module.\n'
2781          "    (default: '1')\n"
2782          '    (an integer)')
2783
2784      expected_help += '\n%s:\n%s' % (sys.argv[0], main_module_int_fg_help)
2785      self.assertMultiLineEqual(expected_help,
2786                                self.flag_values.main_module_help())
2787
2788      # The following call should be a no-op: any flag declared by a
2789      # module is automatically key for that module.
2790      flags.declare_key_flag('main_module_int_fg', flag_values=self.flag_values)
2791      self.assertMultiLineEqual(expected_help,
2792                                self.flag_values.main_module_help())
2793
2794      # The definition of a few flags in an imported module should not
2795      # change the main module help.
2796      module_foo.define_flags(flag_values=self.flag_values)
2797      self.assertMultiLineEqual(expected_help,
2798                                self.flag_values.main_module_help())
2799
2800      flags.declare_key_flag('tmod_foo_bool', flag_values=self.flag_values)
2801      tmod_foo_bool_help = (
2802          '  --[no]tmod_foo_bool: Boolean flag from module foo.\n'
2803          "    (default: 'true')")
2804      expected_help += '\n' + tmod_foo_bool_help
2805      self.assertMultiLineEqual(expected_help,
2806                                self.flag_values.main_module_help())
2807
2808      flags.declare_key_flag('tmod_bar_z', flag_values=self.flag_values)
2809      tmod_bar_z_help = (
2810          '  --[no]tmod_bar_z: Another boolean flag from module bar.\n'
2811          "    (default: 'false')")
2812      # Unfortunately, there is some flag sorting inside
2813      # main_module_help, so we can't keep incrementally extending
2814      # the expected_help string ...
2815      expected_help = ('\n%s:\n%s\n%s\n%s' %
2816                       (sys.argv[0], main_module_int_fg_help, tmod_bar_z_help,
2817                        tmod_foo_bool_help))
2818      self.assertMultiLineEqual(self.flag_values.main_module_help(),
2819                                expected_help)
2820
2821    finally:
2822      # At the end, delete all the flag information we created.
2823      self.flag_values.__delattr__('main_module_int_fg')
2824      module_foo.remove_flags(flag_values=self.flag_values)
2825
2826  def test_adoptmodule_key_flags(self):
2827    # Check that adopt_module_key_flags raises an exception when
2828    # called with a module name (as opposed to a module object).
2829    self.assertRaises(flags.Error, flags.adopt_module_key_flags, 'pyglib.app')
2830
2831  def test_disclaimkey_flags(self):
2832    original_disclaim_module_ids = _helpers.disclaim_module_ids
2833    _helpers.disclaim_module_ids = set(_helpers.disclaim_module_ids)
2834    try:
2835      module_bar.disclaim_key_flags()
2836      module_foo.define_bar_flags(flag_values=self.flag_values)
2837      module_name = self.flag_values.find_module_defining_flag('tmod_bar_x')
2838      self.assertEqual(module_foo.__name__, module_name)
2839    finally:
2840      _helpers.disclaim_module_ids = original_disclaim_module_ids
2841
2842
2843class FindModuleTest(absltest.TestCase):
2844  """Testing methods that find a module that defines a given flag."""
2845
2846  def test_find_module_defining_flag(self):
2847    self.assertEqual(
2848        'default',
2849        FLAGS.find_module_defining_flag('__NON_EXISTENT_FLAG__', 'default'))
2850    self.assertEqual(module_baz.__name__,
2851                     FLAGS.find_module_defining_flag('tmod_baz_x'))
2852
2853  def test_find_module_id_defining_flag(self):
2854    self.assertEqual(
2855        'default',
2856        FLAGS.find_module_id_defining_flag('__NON_EXISTENT_FLAG__', 'default'))
2857    self.assertEqual(
2858        id(module_baz), FLAGS.find_module_id_defining_flag('tmod_baz_x'))
2859
2860  def test_find_module_defining_flag_passing_module_name(self):
2861    my_flags = flags.FlagValues()
2862    module_name = sys.__name__  # Must use an existing module.
2863    flags.DEFINE_boolean(
2864        'flag_name',
2865        True,
2866        'Flag with a different module name.',
2867        flag_values=my_flags,
2868        module_name=module_name)
2869    self.assertEqual(module_name,
2870                     my_flags.find_module_defining_flag('flag_name'))
2871
2872  def test_find_module_id_defining_flag_passing_module_name(self):
2873    my_flags = flags.FlagValues()
2874    module_name = sys.__name__  # Must use an existing module.
2875    flags.DEFINE_boolean(
2876        'flag_name',
2877        True,
2878        'Flag with a different module name.',
2879        flag_values=my_flags,
2880        module_name=module_name)
2881    self.assertEqual(
2882        id(sys), my_flags.find_module_id_defining_flag('flag_name'))
2883
2884
2885class FlagsErrorMessagesTest(absltest.TestCase):
2886  """Testing special cases for integer and float flags error messages."""
2887
2888  def setUp(self):
2889    self.flag_values = flags.FlagValues()
2890
2891  def test_integer_error_text(self):
2892    # Make sure we get proper error text
2893    flags.DEFINE_integer(
2894        'positive',
2895        4,
2896        'non-negative flag',
2897        lower_bound=1,
2898        flag_values=self.flag_values)
2899    flags.DEFINE_integer(
2900        'non_negative',
2901        4,
2902        'positive flag',
2903        lower_bound=0,
2904        flag_values=self.flag_values)
2905    flags.DEFINE_integer(
2906        'negative',
2907        -4,
2908        'negative flag',
2909        upper_bound=-1,
2910        flag_values=self.flag_values)
2911    flags.DEFINE_integer(
2912        'non_positive',
2913        -4,
2914        'non-positive flag',
2915        upper_bound=0,
2916        flag_values=self.flag_values)
2917    flags.DEFINE_integer(
2918        'greater',
2919        19,
2920        'greater-than flag',
2921        lower_bound=4,
2922        flag_values=self.flag_values)
2923    flags.DEFINE_integer(
2924        'smaller',
2925        -19,
2926        'smaller-than flag',
2927        upper_bound=4,
2928        flag_values=self.flag_values)
2929    flags.DEFINE_integer(
2930        'usual',
2931        4,
2932        'usual flag',
2933        lower_bound=0,
2934        upper_bound=10000,
2935        flag_values=self.flag_values)
2936    flags.DEFINE_integer(
2937        'another_usual',
2938        0,
2939        'usual flag',
2940        lower_bound=-1,
2941        upper_bound=1,
2942        flag_values=self.flag_values)
2943
2944    self._check_error_message('positive', -4, 'a positive integer')
2945    self._check_error_message('non_negative', -4, 'a non-negative integer')
2946    self._check_error_message('negative', 0, 'a negative integer')
2947    self._check_error_message('non_positive', 4, 'a non-positive integer')
2948    self._check_error_message('usual', -4, 'an integer in the range [0, 10000]')
2949    self._check_error_message('another_usual', 4,
2950                              'an integer in the range [-1, 1]')
2951    self._check_error_message('greater', -5, 'integer >= 4')
2952    self._check_error_message('smaller', 5, 'integer <= 4')
2953
2954  def test_float_error_text(self):
2955    flags.DEFINE_float(
2956        'positive',
2957        4,
2958        'non-negative flag',
2959        lower_bound=1,
2960        flag_values=self.flag_values)
2961    flags.DEFINE_float(
2962        'non_negative',
2963        4,
2964        'positive flag',
2965        lower_bound=0,
2966        flag_values=self.flag_values)
2967    flags.DEFINE_float(
2968        'negative',
2969        -4,
2970        'negative flag',
2971        upper_bound=-1,
2972        flag_values=self.flag_values)
2973    flags.DEFINE_float(
2974        'non_positive',
2975        -4,
2976        'non-positive flag',
2977        upper_bound=0,
2978        flag_values=self.flag_values)
2979    flags.DEFINE_float(
2980        'greater',
2981        19,
2982        'greater-than flag',
2983        lower_bound=4,
2984        flag_values=self.flag_values)
2985    flags.DEFINE_float(
2986        'smaller',
2987        -19,
2988        'smaller-than flag',
2989        upper_bound=4,
2990        flag_values=self.flag_values)
2991    flags.DEFINE_float(
2992        'usual',
2993        4,
2994        'usual flag',
2995        lower_bound=0,
2996        upper_bound=10000,
2997        flag_values=self.flag_values)
2998    flags.DEFINE_float(
2999        'another_usual',
3000        0,
3001        'usual flag',
3002        lower_bound=-1,
3003        upper_bound=1,
3004        flag_values=self.flag_values)
3005
3006    self._check_error_message('positive', 0.5, 'number >= 1')
3007    self._check_error_message('non_negative', -4.0, 'a non-negative number')
3008    self._check_error_message('negative', 0.5, 'number <= -1')
3009    self._check_error_message('non_positive', 4.0, 'a non-positive number')
3010    self._check_error_message('usual', -4.0, 'a number in the range [0, 10000]')
3011    self._check_error_message('another_usual', 4.0,
3012                              'a number in the range [-1, 1]')
3013    self._check_error_message('smaller', 5.0, 'number <= 4')
3014
3015  def _check_error_message(self, flag_name, flag_value,
3016                           expected_message_suffix):
3017    """Set a flag to a given value and make sure we get expected message."""
3018
3019    try:
3020      self.flag_values.__setattr__(flag_name, flag_value)
3021      raise AssertionError('Bounds exception not raised!')
3022    except flags.IllegalFlagValueError as e:
3023      expected = ('flag --%(name)s=%(value)s: %(value)s is not %(suffix)s' % {
3024          'name': flag_name,
3025          'value': flag_value,
3026          'suffix': expected_message_suffix
3027      })
3028      self.assertEqual(str(e), expected)
3029
3030
3031if __name__ == '__main__':
3032  absltest.main()
3033