~vishvananda/nova/network-refactor

« back to all changes in this revision

Viewing changes to vendor/python-gflags/gflags_helpxml_test.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Copyright (c) 2009, Google Inc.
 
4
# All rights reserved.
 
5
#
 
6
# Redistribution and use in source and binary forms, with or without
 
7
# modification, are permitted provided that the following conditions are
 
8
# met:
 
9
#
 
10
#     * Redistributions of source code must retain the above copyright
 
11
# notice, this list of conditions and the following disclaimer.
 
12
#     * Redistributions in binary form must reproduce the above
 
13
# copyright notice, this list of conditions and the following disclaimer
 
14
# in the documentation and/or other materials provided with the
 
15
# distribution.
 
16
#     * Neither the name of Google Inc. nor the names of its
 
17
# contributors may be used to endorse or promote products derived from
 
18
# this software without specific prior written permission.
 
19
#
 
20
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
21
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
22
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
23
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
24
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
25
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
26
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
27
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
28
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
29
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
30
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
31
 
 
32
"""Unit tests for the XML-format help generated by the gflags.py module."""
 
33
 
 
34
__author__ = 'Alex Salcianu'
 
35
 
 
36
 
 
37
import string
 
38
import StringIO
 
39
import sys
 
40
import unittest
 
41
import xml.dom.minidom
 
42
import xml.sax.saxutils
 
43
 
 
44
# We use the name 'flags' internally in this test, for historical reasons.
 
45
# Don't do this yourself! :-)  Just do 'import gflags; FLAGS=gflags.FLAGS; etc'
 
46
import gflags as flags
 
47
 
 
48
# For historic reasons, we use the name module_bar instead of test_module_bar
 
49
import test_module_bar as module_bar
 
50
 
 
51
def MultiLineEqual(expected_help, help):
 
52
  """Returns True if expected_help == help.  Otherwise returns False
 
53
  and logs the difference in a human-readable way.
 
54
  """
 
55
  if help == expected_help:
 
56
    return True
 
57
 
 
58
  print "Error: FLAGS.MainModuleHelp() didn't return the expected result."
 
59
  print "Got:"
 
60
  print help
 
61
  print "[End of got]"
 
62
 
 
63
  help_lines = help.split('\n')
 
64
  expected_help_lines = expected_help.split('\n')
 
65
 
 
66
  num_help_lines = len(help_lines)
 
67
  num_expected_help_lines = len(expected_help_lines)
 
68
 
 
69
  if num_help_lines != num_expected_help_lines:
 
70
    print "Number of help lines = %d, expected %d" % (
 
71
        num_help_lines, num_expected_help_lines)
 
72
 
 
73
  num_to_match = min(num_help_lines, num_expected_help_lines)
 
74
 
 
75
  for i in range(num_to_match):
 
76
    if help_lines[i] != expected_help_lines[i]:
 
77
      print "One discrepancy: Got:"
 
78
      print help_lines[i]
 
79
      print "Expected:"
 
80
      print expected_help_lines[i]
 
81
      break
 
82
  else:
 
83
    # If we got here, found no discrepancy, print first new line.
 
84
    if num_help_lines > num_expected_help_lines:
 
85
      print "New help line:"
 
86
      print help_lines[num_expected_help_lines]
 
87
    elif num_expected_help_lines > num_help_lines:
 
88
      print "Missing expected help line:"
 
89
      print expected_help_lines[num_help_lines]
 
90
    else:
 
91
      print "Bug in this test -- discrepancy detected but not found."
 
92
 
 
93
  return False
 
94
 
 
95
 
 
96
class _MakeXMLSafeTest(unittest.TestCase):
 
97
 
 
98
  def _Check(self, s, expected_output):
 
99
    self.assertEqual(flags._MakeXMLSafe(s), expected_output)
 
100
 
 
101
  def testMakeXMLSafe(self):
 
102
    self._Check('plain text', 'plain text')
 
103
    self._Check('(x < y) && (a >= b)',
 
104
                '(x &lt; y) &amp;&amp; (a &gt;= b)')
 
105
    # Some characters with ASCII code < 32 are illegal in XML 1.0 and
 
106
    # are removed by us.  However, '\n', '\t', and '\r' are legal.
 
107
    self._Check('\x09\x0btext \x02 with\x0dsome \x08 good & bad chars',
 
108
                '\ttext  with\rsome  good &amp; bad chars')
 
109
 
 
110
 
 
111
def _ListSeparatorsInXMLFormat(separators, indent=''):
 
112
  """Generates XML encoding of a list of list separators.
 
113
 
 
114
  Args:
 
115
    separators: A list of list separators.  Usually, this should be a
 
116
      string whose characters are the valid list separators, e.g., ','
 
117
      means that both comma (',') and space (' ') are valid list
 
118
      separators.
 
119
    indent: A string that is added at the beginning of each generated
 
120
      XML element.
 
121
 
 
122
  Returns:
 
123
    A string.
 
124
  """
 
125
  result = ''
 
126
  separators = list(separators)
 
127
  separators.sort()
 
128
  for sep_char in separators:
 
129
    result += ('%s<list_separator>%s</list_separator>\n' %
 
130
               (indent, repr(sep_char)))
 
131
  return result
 
132
 
 
133
 
 
134
class WriteFlagHelpInXMLFormatTest(unittest.TestCase):
 
135
  """Test the XML-format help for a single flag at a time.
 
136
 
 
137
  There is one test* method for each kind of DEFINE_* declaration.
 
138
  """
 
139
 
 
140
  def setUp(self):
 
141
    # self.fv is a FlagValues object, just like flags.FLAGS.  Each
 
142
    # test registers one flag with this FlagValues.
 
143
    self.fv = flags.FlagValues()
 
144
 
 
145
  def assertMultiLineEqual(self, expected, actual):
 
146
    self.assert_(MultiLineEqual(expected, actual))
 
147
 
 
148
  def _CheckFlagHelpInXML(self, flag_name, module_name,
 
149
                          expected_output, is_key=False):
 
150
    # StringIO.StringIO is a file object that writes into a memory string.
 
151
    sio = StringIO.StringIO()
 
152
    flag_obj = self.fv[flag_name]
 
153
    flag_obj.WriteInfoInXMLFormat(sio, module_name, is_key=is_key, indent=' ')
 
154
    self.assertMultiLineEqual(sio.getvalue(), expected_output)
 
155
    sio.close()
 
156
 
 
157
  def testFlagHelpInXML_Int(self):
 
158
    flags.DEFINE_integer('index', 17, 'An integer flag', flag_values=self.fv)
 
159
    expected_output_pattern = (
 
160
        ' <flag>\n'
 
161
        '   <file>module.name</file>\n'
 
162
        '   <name>index</name>\n'
 
163
        '   <meaning>An integer flag</meaning>\n'
 
164
        '   <default>17</default>\n'
 
165
        '   <current>%d</current>\n'
 
166
        '   <type>int</type>\n'
 
167
        ' </flag>\n')
 
168
    self._CheckFlagHelpInXML('index', 'module.name',
 
169
                             expected_output_pattern % 17)
 
170
    # Check that the output is correct even when the current value of
 
171
    # a flag is different from the default one.
 
172
    self.fv['index'].value = 20
 
173
    self._CheckFlagHelpInXML('index', 'module.name',
 
174
                             expected_output_pattern % 20)
 
175
 
 
176
  def testFlagHelpInXML_IntWithBounds(self):
 
177
    flags.DEFINE_integer('nb_iters', 17, 'An integer flag',
 
178
                         lower_bound=5, upper_bound=27,
 
179
                         flag_values=self.fv)
 
180
    expected_output = (
 
181
        ' <flag>\n'
 
182
        '   <key>yes</key>\n'
 
183
        '   <file>module.name</file>\n'
 
184
        '   <name>nb_iters</name>\n'
 
185
        '   <meaning>An integer flag</meaning>\n'
 
186
        '   <default>17</default>\n'
 
187
        '   <current>17</current>\n'
 
188
        '   <type>int</type>\n'
 
189
        '   <lower_bound>5</lower_bound>\n'
 
190
        '   <upper_bound>27</upper_bound>\n'
 
191
        ' </flag>\n')
 
192
    self._CheckFlagHelpInXML('nb_iters', 'module.name',
 
193
                             expected_output, is_key=True)
 
194
 
 
195
  def testFlagHelpInXML_String(self):
 
196
    flags.DEFINE_string('file_path', '/path/to/my/dir', 'A test string flag.',
 
197
                        flag_values=self.fv)
 
198
    expected_output = (
 
199
        ' <flag>\n'
 
200
        '   <file>simple_module</file>\n'
 
201
        '   <name>file_path</name>\n'
 
202
        '   <meaning>A test string flag.</meaning>\n'
 
203
        '   <default>/path/to/my/dir</default>\n'
 
204
        '   <current>/path/to/my/dir</current>\n'
 
205
        '   <type>string</type>\n'
 
206
        ' </flag>\n')
 
207
    self._CheckFlagHelpInXML('file_path', 'simple_module',
 
208
                             expected_output)
 
209
 
 
210
  def testFlagHelpInXML_StringWithXMLIllegalChars(self):
 
211
    flags.DEFINE_string('file_path', '/path/to/\x08my/dir',
 
212
                        'A test string flag.', flag_values=self.fv)
 
213
    # '\x08' is not a legal character in XML 1.0 documents.  Our
 
214
    # current code purges such characters from the generated XML.
 
215
    expected_output = (
 
216
        ' <flag>\n'
 
217
        '   <file>simple_module</file>\n'
 
218
        '   <name>file_path</name>\n'
 
219
        '   <meaning>A test string flag.</meaning>\n'
 
220
        '   <default>/path/to/my/dir</default>\n'
 
221
        '   <current>/path/to/my/dir</current>\n'
 
222
        '   <type>string</type>\n'
 
223
        ' </flag>\n')
 
224
    self._CheckFlagHelpInXML('file_path', 'simple_module',
 
225
                             expected_output)
 
226
 
 
227
  def testFlagHelpInXML_Boolean(self):
 
228
    flags.DEFINE_boolean('use_hack', False, 'Use performance hack',
 
229
                         flag_values=self.fv)
 
230
    expected_output = (
 
231
        ' <flag>\n'
 
232
        '   <key>yes</key>\n'
 
233
        '   <file>a_module</file>\n'
 
234
        '   <name>use_hack</name>\n'
 
235
        '   <meaning>Use performance hack</meaning>\n'
 
236
        '   <default>false</default>\n'
 
237
        '   <current>false</current>\n'
 
238
        '   <type>bool</type>\n'
 
239
        ' </flag>\n')
 
240
    self._CheckFlagHelpInXML('use_hack', 'a_module',
 
241
                             expected_output, is_key=True)
 
242
 
 
243
  def testFlagHelpInXML_Enum(self):
 
244
    flags.DEFINE_enum('cc_version', 'stable', ['stable', 'experimental'],
 
245
                      'Compiler version to use.', flag_values=self.fv)
 
246
    expected_output = (
 
247
        ' <flag>\n'
 
248
        '   <file>tool</file>\n'
 
249
        '   <name>cc_version</name>\n'
 
250
        '   <meaning>&lt;stable|experimental&gt;: '
 
251
        'Compiler version to use.</meaning>\n'
 
252
        '   <default>stable</default>\n'
 
253
        '   <current>stable</current>\n'
 
254
        '   <type>string enum</type>\n'
 
255
        '   <enum_value>stable</enum_value>\n'
 
256
        '   <enum_value>experimental</enum_value>\n'
 
257
        ' </flag>\n')
 
258
    self._CheckFlagHelpInXML('cc_version', 'tool', expected_output)
 
259
 
 
260
  def testFlagHelpInXML_CommaSeparatedList(self):
 
261
    flags.DEFINE_list('files', 'a.cc,a.h,archive/old.zip',
 
262
                      'Files to process.', flag_values=self.fv)
 
263
    expected_output = (
 
264
        ' <flag>\n'
 
265
        '   <file>tool</file>\n'
 
266
        '   <name>files</name>\n'
 
267
        '   <meaning>Files to process.</meaning>\n'
 
268
        '   <default>a.cc,a.h,archive/old.zip</default>\n'
 
269
        '   <current>[\'a.cc\', \'a.h\', \'archive/old.zip\']</current>\n'
 
270
        '   <type>comma separated list of strings</type>\n'
 
271
        '   <list_separator>\',\'</list_separator>\n'
 
272
        ' </flag>\n')
 
273
    self._CheckFlagHelpInXML('files', 'tool', expected_output)
 
274
 
 
275
  def testFlagHelpInXML_SpaceSeparatedList(self):
 
276
    flags.DEFINE_spaceseplist('dirs', 'src libs bin',
 
277
                              'Directories to search.', flag_values=self.fv)
 
278
    expected_output = (
 
279
        ' <flag>\n'
 
280
        '   <file>tool</file>\n'
 
281
        '   <name>dirs</name>\n'
 
282
        '   <meaning>Directories to search.</meaning>\n'
 
283
        '   <default>src libs bin</default>\n'
 
284
        '   <current>[\'src\', \'libs\', \'bin\']</current>\n'
 
285
        '   <type>whitespace separated list of strings</type>\n'
 
286
        'LIST_SEPARATORS'
 
287
        ' </flag>\n').replace('LIST_SEPARATORS',
 
288
                              _ListSeparatorsInXMLFormat(string.whitespace,
 
289
                                                         indent='   '))
 
290
    self._CheckFlagHelpInXML('dirs', 'tool', expected_output)
 
291
 
 
292
  def testFlagHelpInXML_MultiString(self):
 
293
    flags.DEFINE_multistring('to_delete', ['a.cc', 'b.h'],
 
294
                             'Files to delete', flag_values=self.fv)
 
295
    expected_output = (
 
296
        ' <flag>\n'
 
297
        '   <file>tool</file>\n'
 
298
        '   <name>to_delete</name>\n'
 
299
        '   <meaning>Files to delete;\n    '
 
300
        'repeat this option to specify a list of values</meaning>\n'
 
301
        '   <default>[\'a.cc\', \'b.h\']</default>\n'
 
302
        '   <current>[\'a.cc\', \'b.h\']</current>\n'
 
303
        '   <type>multi string</type>\n'
 
304
        ' </flag>\n')
 
305
    self._CheckFlagHelpInXML('to_delete', 'tool', expected_output)
 
306
 
 
307
  def testFlagHelpInXML_MultiInt(self):
 
308
    flags.DEFINE_multi_int('cols', [5, 7, 23],
 
309
                           'Columns to select', flag_values=self.fv)
 
310
    expected_output = (
 
311
        ' <flag>\n'
 
312
        '   <file>tool</file>\n'
 
313
        '   <name>cols</name>\n'
 
314
        '   <meaning>Columns to select;\n    '
 
315
        'repeat this option to specify a list of values</meaning>\n'
 
316
        '   <default>[5, 7, 23]</default>\n'
 
317
        '   <current>[5, 7, 23]</current>\n'
 
318
        '   <type>multi int</type>\n'
 
319
        ' </flag>\n')
 
320
    self._CheckFlagHelpInXML('cols', 'tool', expected_output)
 
321
 
 
322
 
 
323
# The next EXPECTED_HELP_XML_* constants are parts of a template for
 
324
# the expected XML output from WriteHelpInXMLFormatTest below.  When
 
325
# we assemble these parts into a single big string, we'll take into
 
326
# account the ordering between the name of the main module and the
 
327
# name of module_bar.  Next, we'll fill in the docstring for this
 
328
# module (%(usage_doc)s), the name of the main module
 
329
# (%(main_module_name)s) and the name of the module module_bar
 
330
# (%(module_bar_name)s).  See WriteHelpInXMLFormatTest below.
 
331
#
 
332
# NOTE: given the current implementation of _GetMainModule(), we
 
333
# already know the ordering between the main module and module_bar.
 
334
# However, there is no guarantee that _GetMainModule will never be
 
335
# changed in the future (especially since it's far from perfect).
 
336
EXPECTED_HELP_XML_START = """\
 
337
<?xml version="1.0"?>
 
338
<AllFlags>
 
339
  <program>gflags_helpxml_test.py</program>
 
340
  <usage>%(usage_doc)s</usage>
 
341
"""
 
342
 
 
343
EXPECTED_HELP_XML_FOR_FLAGS_FROM_MAIN_MODULE = """\
 
344
  <flag>
 
345
    <key>yes</key>
 
346
    <file>%(main_module_name)s</file>
 
347
    <name>cc_version</name>
 
348
    <meaning>&lt;stable|experimental&gt;: Compiler version to use.</meaning>
 
349
    <default>stable</default>
 
350
    <current>stable</current>
 
351
    <type>string enum</type>
 
352
    <enum_value>stable</enum_value>
 
353
    <enum_value>experimental</enum_value>
 
354
  </flag>
 
355
  <flag>
 
356
    <key>yes</key>
 
357
    <file>%(main_module_name)s</file>
 
358
    <name>cols</name>
 
359
    <meaning>Columns to select;
 
360
    repeat this option to specify a list of values</meaning>
 
361
    <default>[5, 7, 23]</default>
 
362
    <current>[5, 7, 23]</current>
 
363
    <type>multi int</type>
 
364
  </flag>
 
365
  <flag>
 
366
    <key>yes</key>
 
367
    <file>%(main_module_name)s</file>
 
368
    <name>dirs</name>
 
369
    <meaning>Directories to create.</meaning>
 
370
    <default>src libs bins</default>
 
371
    <current>['src', 'libs', 'bins']</current>
 
372
    <type>whitespace separated list of strings</type>
 
373
%(whitespace_separators)s  </flag>
 
374
  <flag>
 
375
    <key>yes</key>
 
376
    <file>%(main_module_name)s</file>
 
377
    <name>file_path</name>
 
378
    <meaning>A test string flag.</meaning>
 
379
    <default>/path/to/my/dir</default>
 
380
    <current>/path/to/my/dir</current>
 
381
    <type>string</type>
 
382
  </flag>
 
383
  <flag>
 
384
    <key>yes</key>
 
385
    <file>%(main_module_name)s</file>
 
386
    <name>files</name>
 
387
    <meaning>Files to process.</meaning>
 
388
    <default>a.cc,a.h,archive/old.zip</default>
 
389
    <current>['a.cc', 'a.h', 'archive/old.zip']</current>
 
390
    <type>comma separated list of strings</type>
 
391
    <list_separator>\',\'</list_separator>
 
392
  </flag>
 
393
  <flag>
 
394
    <key>yes</key>
 
395
    <file>%(main_module_name)s</file>
 
396
    <name>index</name>
 
397
    <meaning>An integer flag</meaning>
 
398
    <default>17</default>
 
399
    <current>17</current>
 
400
    <type>int</type>
 
401
  </flag>
 
402
  <flag>
 
403
    <key>yes</key>
 
404
    <file>%(main_module_name)s</file>
 
405
    <name>nb_iters</name>
 
406
    <meaning>An integer flag</meaning>
 
407
    <default>17</default>
 
408
    <current>17</current>
 
409
    <type>int</type>
 
410
    <lower_bound>5</lower_bound>
 
411
    <upper_bound>27</upper_bound>
 
412
  </flag>
 
413
  <flag>
 
414
    <key>yes</key>
 
415
    <file>%(main_module_name)s</file>
 
416
    <name>to_delete</name>
 
417
    <meaning>Files to delete;
 
418
    repeat this option to specify a list of values</meaning>
 
419
    <default>['a.cc', 'b.h']</default>
 
420
    <current>['a.cc', 'b.h']</current>
 
421
    <type>multi string</type>
 
422
  </flag>
 
423
  <flag>
 
424
    <key>yes</key>
 
425
    <file>%(main_module_name)s</file>
 
426
    <name>use_hack</name>
 
427
    <meaning>Use performance hack</meaning>
 
428
    <default>false</default>
 
429
    <current>false</current>
 
430
    <type>bool</type>
 
431
  </flag>
 
432
"""
 
433
 
 
434
EXPECTED_HELP_XML_FOR_FLAGS_FROM_MODULE_BAR = """\
 
435
  <flag>
 
436
    <file>%(module_bar_name)s</file>
 
437
    <name>tmod_bar_t</name>
 
438
    <meaning>Sample int flag.</meaning>
 
439
    <default>4</default>
 
440
    <current>4</current>
 
441
    <type>int</type>
 
442
  </flag>
 
443
  <flag>
 
444
    <key>yes</key>
 
445
    <file>%(module_bar_name)s</file>
 
446
    <name>tmod_bar_u</name>
 
447
    <meaning>Sample int flag.</meaning>
 
448
    <default>5</default>
 
449
    <current>5</current>
 
450
    <type>int</type>
 
451
  </flag>
 
452
  <flag>
 
453
    <file>%(module_bar_name)s</file>
 
454
    <name>tmod_bar_v</name>
 
455
    <meaning>Sample int flag.</meaning>
 
456
    <default>6</default>
 
457
    <current>6</current>
 
458
    <type>int</type>
 
459
  </flag>
 
460
  <flag>
 
461
    <file>%(module_bar_name)s</file>
 
462
    <name>tmod_bar_x</name>
 
463
    <meaning>Boolean flag.</meaning>
 
464
    <default>true</default>
 
465
    <current>true</current>
 
466
    <type>bool</type>
 
467
  </flag>
 
468
  <flag>
 
469
    <file>%(module_bar_name)s</file>
 
470
    <name>tmod_bar_y</name>
 
471
    <meaning>String flag.</meaning>
 
472
    <default>default</default>
 
473
    <current>default</current>
 
474
    <type>string</type>
 
475
  </flag>
 
476
  <flag>
 
477
    <key>yes</key>
 
478
    <file>%(module_bar_name)s</file>
 
479
    <name>tmod_bar_z</name>
 
480
    <meaning>Another boolean flag from module bar.</meaning>
 
481
    <default>false</default>
 
482
    <current>false</current>
 
483
    <type>bool</type>
 
484
  </flag>
 
485
"""
 
486
 
 
487
EXPECTED_HELP_XML_END = """\
 
488
</AllFlags>
 
489
"""
 
490
 
 
491
 
 
492
class WriteHelpInXMLFormatTest(unittest.TestCase):
 
493
  """Big test of FlagValues.WriteHelpInXMLFormat, with several flags."""
 
494
 
 
495
  def assertMultiLineEqual(self, expected, actual):
 
496
    self.assert_(MultiLineEqual(expected, actual))
 
497
 
 
498
  def testWriteHelpInXMLFormat(self):
 
499
    fv = flags.FlagValues()
 
500
    # Since these flags are defined by the top module, they are all key.
 
501
    flags.DEFINE_integer('index', 17, 'An integer flag', flag_values=fv)
 
502
    flags.DEFINE_integer('nb_iters', 17, 'An integer flag',
 
503
                         lower_bound=5, upper_bound=27, flag_values=fv)
 
504
    flags.DEFINE_string('file_path', '/path/to/my/dir', 'A test string flag.',
 
505
                        flag_values=fv)
 
506
    flags.DEFINE_boolean('use_hack', False, 'Use performance hack',
 
507
                         flag_values=fv)
 
508
    flags.DEFINE_enum('cc_version', 'stable', ['stable', 'experimental'],
 
509
                      'Compiler version to use.', flag_values=fv)
 
510
    flags.DEFINE_list('files', 'a.cc,a.h,archive/old.zip',
 
511
                      'Files to process.', flag_values=fv)
 
512
    flags.DEFINE_spaceseplist('dirs', 'src libs bins',
 
513
                              'Directories to create.', flag_values=fv)
 
514
    flags.DEFINE_multistring('to_delete', ['a.cc', 'b.h'],
 
515
                             'Files to delete', flag_values=fv)
 
516
    flags.DEFINE_multi_int('cols', [5, 7, 23],
 
517
                           'Columns to select', flag_values=fv)
 
518
    # Define a few flags in a different module.
 
519
    module_bar.DefineFlags(flag_values=fv)
 
520
    # And declare only a few of them to be key.  This way, we have
 
521
    # different kinds of flags, defined in different modules, and not
 
522
    # all of them are key flags.
 
523
    flags.DECLARE_key_flag('tmod_bar_z', flag_values=fv)
 
524
    flags.DECLARE_key_flag('tmod_bar_u', flag_values=fv)
 
525
 
 
526
    # Generate flag help in XML format in the StringIO sio.
 
527
    sio = StringIO.StringIO()
 
528
    fv.WriteHelpInXMLFormat(sio)
 
529
 
 
530
    # Check that we got the expected result.
 
531
    expected_output_template = EXPECTED_HELP_XML_START
 
532
    main_module_name = flags._GetMainModule()
 
533
    module_bar_name = module_bar.__name__
 
534
 
 
535
    if main_module_name < module_bar_name:
 
536
      expected_output_template += EXPECTED_HELP_XML_FOR_FLAGS_FROM_MAIN_MODULE
 
537
      expected_output_template += EXPECTED_HELP_XML_FOR_FLAGS_FROM_MODULE_BAR
 
538
    else:
 
539
      expected_output_template += EXPECTED_HELP_XML_FOR_FLAGS_FROM_MODULE_BAR
 
540
      expected_output_template += EXPECTED_HELP_XML_FOR_FLAGS_FROM_MAIN_MODULE
 
541
 
 
542
    expected_output_template += EXPECTED_HELP_XML_END
 
543
 
 
544
    # XML representation of the whitespace list separators.
 
545
    whitespace_separators = _ListSeparatorsInXMLFormat(string.whitespace,
 
546
                                                       indent='    ')
 
547
    expected_output = (
 
548
        expected_output_template %
 
549
        {'usage_doc': sys.modules['__main__'].__doc__,
 
550
         'main_module_name': main_module_name,
 
551
         'module_bar_name': module_bar_name,
 
552
         'whitespace_separators': whitespace_separators})
 
553
 
 
554
    actual_output = sio.getvalue()
 
555
    self.assertMultiLineEqual(actual_output, expected_output)
 
556
 
 
557
    # Also check that our result is valid XML.  minidom.parseString
 
558
    # throws an xml.parsers.expat.ExpatError in case of an error.
 
559
    xml.dom.minidom.parseString(actual_output)
 
560
 
 
561
 
 
562
if __name__ == '__main__':
 
563
  unittest.main()