Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/unit/test_clidocs.py
2637 views
1
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
import json
14
15
from botocore.model import ShapeResolver, StructureShape, StringShape, \
16
ListShape, MapShape, Shape, DenormalizedStructureBuilder
17
18
from awscli.testutils import mock, unittest, FileCreator
19
from awscli.clidocs import OperationDocumentEventHandler, \
20
CLIDocumentEventHandler, TopicListerDocumentEventHandler, \
21
TopicDocumentEventHandler, GlobalOptionsDocumenter, \
22
ServiceDocumentEventHandler
23
from awscli.bcdoc.restdoc import ReSTDocument
24
from awscli.help import ServiceHelpCommand, TopicListerCommand, \
25
TopicHelpCommand, HelpCommand
26
from awscli.arguments import CustomArgument
27
28
29
class TestRecursiveShapes(unittest.TestCase):
30
def setUp(self):
31
self.arg_table = {}
32
self.help_command = mock.Mock()
33
self.help_command.event_class = 'custom'
34
self.help_command.arg_table = self.arg_table
35
self.operation_model = mock.Mock()
36
self.operation_model.service_model.operation_names = []
37
self.help_command.obj = self.operation_model
38
self.operation_handler = OperationDocumentEventHandler(
39
self.help_command)
40
41
def assert_rendered_docs_contain(self, expected):
42
writes = [args[0][0] for args in
43
self.help_command.doc.write.call_args_list]
44
writes = '\n'.join(writes)
45
self.assertIn(expected, writes)
46
47
def assert_proper_indentation(self):
48
indent = self.help_command.doc.style.indent.call_count
49
dedent = self.help_command.doc.style.dedent.call_count
50
message = 'Imbalanced indentation: indent (%s) != dedent (%s)'
51
self.assertEqual(indent, dedent, message % (indent, dedent))
52
53
def test_handle_recursive_input(self):
54
shape_map = {
55
'RecursiveStruct': {
56
'type': 'structure',
57
'members': {
58
'A': {'shape': 'NonRecursive'},
59
'B': {'shape': 'RecursiveStruct'},
60
}
61
},
62
'NonRecursive': {'type': 'string'}
63
}
64
shape = StructureShape('RecursiveStruct', shape_map['RecursiveStruct'],
65
ShapeResolver(shape_map))
66
67
self.arg_table['arg-name'] = mock.Mock(argument_model=shape)
68
self.operation_handler.doc_option_example(
69
'arg-name', self.help_command, 'process-cli-arg.foo.bar')
70
self.assert_rendered_docs_contain('{ ... recursive ... }')
71
72
def test_handle_recursive_output(self):
73
shape_map = {
74
'RecursiveStruct': {
75
'type': 'structure',
76
'members': {
77
'A': {'shape': 'NonRecursive'},
78
'B': {'shape': 'RecursiveStruct'},
79
}
80
},
81
'NonRecursive': {'type': 'string'}
82
}
83
shape = StructureShape('RecursiveStruct', shape_map['RecursiveStruct'],
84
ShapeResolver(shape_map))
85
86
operation_model = mock.Mock()
87
operation_model.output_shape = shape
88
self.help_command.obj = operation_model
89
self.operation_handler.doc_output(self.help_command, 'event-name')
90
self.assert_rendered_docs_contain('( ... recursive ... )')
91
92
def test_handle_empty_nested_struct(self):
93
shape_map = {
94
'InputStruct': {
95
'type': 'structure',
96
'members': {
97
'A': {'shape': 'Empty'},
98
}
99
},
100
'Empty': {'type': 'structure', 'members': {}}
101
}
102
shape = StructureShape('InputStruct', shape_map['InputStruct'],
103
ShapeResolver(shape_map))
104
105
self.arg_table['arg-name'] = mock.Mock(argument_model=shape)
106
self.operation_handler.doc_option_example(
107
'arg-name', self.help_command, 'process-cli-arg.foo.bar')
108
self.assert_proper_indentation()
109
110
def test_handle_no_output_shape(self):
111
operation_model = mock.Mock()
112
operation_model.output_shape = None
113
self.help_command.obj = operation_model
114
self.operation_handler.doc_output(self.help_command, 'event-name')
115
self.assert_rendered_docs_contain('None')
116
117
def test_handle_memberless_output_shape(self):
118
shape_map = {
119
'NoMembers': {
120
'type': 'structure',
121
'members': {}
122
}
123
}
124
shape = StructureShape('NoMembers', shape_map['NoMembers'],
125
ShapeResolver(shape_map))
126
127
operation_model = mock.Mock()
128
operation_model.output_shape = shape
129
self.help_command.obj = operation_model
130
self.operation_handler.doc_output(self.help_command, 'event-name')
131
self.assert_rendered_docs_contain('None')
132
133
134
class TestCLIDocumentEventHandler(unittest.TestCase):
135
def setUp(self):
136
self.session = mock.Mock()
137
self.obj = None
138
self.command_table = {}
139
self.arg_table = {}
140
self.name = 'my-command'
141
self.event_class = 'aws'
142
143
def create_help_command(self):
144
help_command = mock.Mock()
145
help_command.doc = ReSTDocument()
146
help_command.event_class = 'custom'
147
help_command.arg_table = {}
148
operation_model = mock.Mock()
149
operation_model.documentation = 'description'
150
operation_model.service_model.operation_names = []
151
help_command.obj = operation_model
152
return help_command
153
154
def create_tagged_union_shape(self):
155
shape_model = {
156
'type': 'structure',
157
'union': True,
158
'members': {}
159
}
160
tagged_union = StructureShape('tagged_union', shape_model)
161
return tagged_union
162
163
def get_help_docs_for_argument(self, shape):
164
arg_table = {'arg-name': mock.Mock(argument_model=shape)}
165
help_command = mock.Mock()
166
help_command.doc = ReSTDocument()
167
help_command.event_class = 'custom'
168
help_command.arg_table = arg_table
169
operation_model = mock.Mock()
170
operation_model.service_model.operation_names = []
171
help_command.obj = operation_model
172
operation_handler = OperationDocumentEventHandler(help_command)
173
operation_handler.doc_option('arg-name', help_command)
174
return help_command.doc.getvalue().decode('utf-8')
175
176
def test_breadcrumbs_man(self):
177
# Create an arbitrary help command class. This was chosen
178
# because it is fairly easy to instantiate.
179
help_cmd = ServiceHelpCommand(
180
self.session, self.obj, self.command_table, self.arg_table,
181
self.name, self.event_class
182
)
183
184
doc_handler = CLIDocumentEventHandler(help_cmd)
185
doc_handler.doc_breadcrumbs(help_cmd)
186
# These should not show up in the man page
187
self.assertEqual(help_cmd.doc.getvalue().decode('utf-8'), '')
188
189
def test_breadcrumbs_html(self):
190
help_cmd = ServiceHelpCommand(
191
self.session, self.obj, self.command_table, self.arg_table,
192
self.name, self.event_class
193
)
194
help_cmd.doc.target = 'html'
195
doc_handler = CLIDocumentEventHandler(help_cmd)
196
doc_handler.doc_breadcrumbs(help_cmd)
197
self.assertEqual(
198
help_cmd.doc.getvalue().decode('utf-8'),
199
'[ :ref:`aws <cli:aws>` ]\n\n'
200
)
201
202
def test_breadcrumbs_service_command_html(self):
203
help_cmd = ServiceHelpCommand(
204
self.session, self.obj, self.command_table, self.arg_table,
205
self.name, 'ec2'
206
)
207
help_cmd.doc.target = 'html'
208
doc_handler = CLIDocumentEventHandler(help_cmd)
209
doc_handler.doc_breadcrumbs(help_cmd)
210
self.assertEqual(
211
help_cmd.doc.getvalue().decode('utf-8'),
212
'[ :ref:`aws <cli:aws>` ]\n\n'
213
)
214
215
def test_breadcrumbs_operation_command_html(self):
216
help_cmd = ServiceHelpCommand(
217
self.session, self.obj, self.command_table, self.arg_table,
218
self.name, 'ec2.run-instances'
219
)
220
help_cmd.doc.target = 'html'
221
doc_handler = CLIDocumentEventHandler(help_cmd)
222
doc_handler.doc_breadcrumbs(help_cmd)
223
self.assertEqual(
224
help_cmd.doc.getvalue().decode('utf-8'),
225
'[ :ref:`aws <cli:aws>` . :ref:`ec2 <cli:aws ec2>` ]\n\n'
226
)
227
228
def test_breadcrumbs_wait_command_html(self):
229
help_cmd = ServiceHelpCommand(
230
self.session, self.obj, self.command_table, self.arg_table,
231
self.name, 's3api.wait.object-exists'
232
)
233
help_cmd.doc.target = 'html'
234
doc_handler = CLIDocumentEventHandler(help_cmd)
235
doc_handler.doc_breadcrumbs(help_cmd)
236
self.assertEqual(
237
help_cmd.doc.getvalue().decode('utf-8'),
238
('[ :ref:`aws <cli:aws>` . :ref:`s3api <cli:aws s3api>`'
239
' . :ref:`wait <cli:aws s3api wait>` ]\n\n')
240
)
241
242
def test_documents_json_header_shape(self):
243
shape = {
244
'type': 'string',
245
'jsonvalue': True,
246
'location': 'header',
247
'locationName': 'X-Amz-Header-Name'
248
}
249
shape = StringShape('JSONValueArg', shape)
250
rendered = self.get_help_docs_for_argument(shape)
251
self.assertIn('(JSON)', rendered)
252
253
def test_documents_enum_values(self):
254
shape = {
255
'type': 'string',
256
'enum': ['FOO', 'BAZ']
257
}
258
shape = StringShape('EnumArg', shape)
259
rendered = self.get_help_docs_for_argument(shape)
260
self.assertIn('Possible values', rendered)
261
self.assertIn('FOO', rendered)
262
self.assertIn('BAZ', rendered)
263
264
def test_documents_recursive_input(self):
265
shape_map = {
266
'RecursiveStruct': {
267
'type': 'structure',
268
'members': {
269
'A': {'shape': 'NonRecursive'},
270
'B': {'shape': 'RecursiveStruct'},
271
}
272
},
273
'NonRecursive': {'type': 'string'}
274
}
275
shape = StructureShape('RecursiveStruct',
276
shape_map['RecursiveStruct'],
277
ShapeResolver(shape_map))
278
rendered = self.get_help_docs_for_argument(shape)
279
self.assertIn('( ... recursive ... )', rendered)
280
281
def test_documents_nested_structure(self):
282
shape_map = {
283
'UpperStructure': {
284
'type': 'structure',
285
'members': {
286
'A': {'shape': 'NestedStruct'},
287
'B': {'shape': 'NestedStruct'},
288
}
289
},
290
'NestedStruct': {
291
'type': 'structure',
292
'members': {
293
'Nested_A': {'shape': 'Line'},
294
'Nested_B': {'shape': 'Line'},
295
}
296
},
297
'Line': {'type': 'string'}
298
}
299
shape = StructureShape('UpperStructure',
300
shape_map['UpperStructure'],
301
ShapeResolver(shape_map))
302
rendered = self.get_help_docs_for_argument(shape)
303
self.assertEqual(rendered.count('A -> (structure)'), 1)
304
self.assertEqual(rendered.count('B -> (structure)'), 1)
305
self.assertEqual(rendered.count('Nested_A -> (string)'), 2)
306
self.assertEqual(rendered.count('Nested_B -> (string)'), 2)
307
308
def test_documents_nested_list(self):
309
shape_map = {
310
'UpperList': {
311
'type': 'list',
312
'member': {'shape': 'NestedStruct'},
313
},
314
'NestedStruct': {
315
'type': 'structure',
316
'members': {
317
'Nested_A': {'shape': 'Line'},
318
'Nested_B': {'shape': 'Line'},
319
}
320
},
321
'Line': {'type': 'string'}
322
}
323
shape = ListShape('UpperList', shape_map['UpperList'],
324
ShapeResolver(shape_map))
325
rendered = self.get_help_docs_for_argument(shape)
326
self.assertEqual(rendered.count('(structure)'), 1)
327
self.assertEqual(rendered.count('Nested_A -> (string)'), 1)
328
self.assertEqual(rendered.count('Nested_B -> (string)'), 1)
329
330
def test_documents_nested_map(self):
331
shape_map = {
332
'UpperMap': {
333
'type': 'map',
334
'key': {'shape': 'NestedStruct'},
335
'value': {'shape': 'NestedStruct'},
336
},
337
'NestedStruct': {
338
'type': 'structure',
339
'members': {
340
'Nested_A': {'shape': 'Line'},
341
'Nested_B': {'shape': 'Line'},
342
}
343
},
344
'Line': {'type': 'string'}
345
}
346
shape = MapShape('UpperMap', shape_map['UpperMap'],
347
ShapeResolver(shape_map))
348
rendered = self.get_help_docs_for_argument(shape)
349
self.assertEqual(rendered.count('key -> (structure)'), 1)
350
self.assertEqual(rendered.count('value -> (structure)'), 1)
351
self.assertEqual(rendered.count('Nested_A -> (string)'), 2)
352
self.assertEqual(rendered.count('Nested_B -> (string)'), 2)
353
354
def test_description_only_for_crosslink_manpage(self):
355
help_command = self.create_help_command()
356
operation_handler = OperationDocumentEventHandler(help_command)
357
operation_handler.doc_description(help_command=help_command)
358
rendered = help_command.doc.getvalue().decode('utf-8')
359
# The links are generated in the "man" mode.
360
self.assertIn('See also: AWS API Documentation', rendered)
361
362
def test_includes_webapi_crosslink_in_html(self):
363
help_command = self.create_help_command()
364
# Configure this for 'html' generation:
365
help_command.obj.service_model.metadata = {'uid': 'service-1-2-3'}
366
help_command.obj.name = 'myoperation'
367
help_command.doc.target = 'html'
368
369
operation_handler = OperationDocumentEventHandler(help_command)
370
operation_handler.doc_description(help_command=help_command)
371
rendered = help_command.doc.getvalue().decode('utf-8')
372
# Should expect an external link because we're generating html.
373
self.assertIn(
374
'See also: `AWS API Documentation '
375
'<https://docs.aws.amazon.com/goto/'
376
'WebAPI/service-1-2-3/myoperation>`_', rendered)
377
378
def test_includes_streaming_blob_options(self):
379
help_command = self.create_help_command()
380
blob_shape = Shape('blob_shape', {'type': 'blob'})
381
blob_shape.serialization = {'streaming': True}
382
blob_arg = CustomArgument('blob_arg', argument_model=blob_shape)
383
help_command.arg_table = {'blob_arg': blob_arg}
384
operation_handler = OperationDocumentEventHandler(help_command)
385
operation_handler.doc_option(arg_name='blob_arg',
386
help_command=help_command)
387
rendered = help_command.doc.getvalue().decode('utf-8')
388
self.assertIn('streaming blob', rendered)
389
390
def test_streaming_blob_comes_after_docstring(self):
391
help_command = self.create_help_command()
392
blob_shape = Shape('blob_shape', {'type': 'blob'})
393
blob_shape.serialization = {'streaming': True}
394
blob_arg = CustomArgument(name='blob_arg',
395
argument_model=blob_shape,
396
help_text='FooBar')
397
help_command.arg_table = {'blob_arg': blob_arg}
398
operation_handler = OperationDocumentEventHandler(help_command)
399
operation_handler.doc_option(arg_name='blob_arg',
400
help_command=help_command)
401
rendered = help_command.doc.getvalue().decode('utf-8')
402
self.assertRegex(rendered, r'FooBar[\s\S]*streaming blob')
403
404
def test_includes_tagged_union_options(self):
405
help_command = self.create_help_command()
406
tagged_union = self.create_tagged_union_shape()
407
arg = CustomArgument(name='tagged_union',
408
argument_model=tagged_union)
409
help_command.arg_table = {'tagged_union': arg}
410
operation_handler = OperationDocumentEventHandler(help_command)
411
operation_handler.doc_option(arg_name='tagged_union',
412
help_command=help_command)
413
rendered = help_command.doc.getvalue().decode('utf-8')
414
self.assertIn('(tagged union structure)', rendered)
415
416
def test_tagged_union_comes_after_docstring_options(self):
417
help_command = self.create_help_command()
418
tagged_union = self.create_tagged_union_shape()
419
arg = CustomArgument(name='tagged_union',
420
argument_model=tagged_union,
421
help_text='FooBar')
422
help_command.arg_table = {'tagged_union': arg}
423
operation_handler = OperationDocumentEventHandler(help_command)
424
operation_handler.doc_option(arg_name='tagged_union',
425
help_command=help_command)
426
rendered = help_command.doc.getvalue().decode('utf-8')
427
self.assertRegex(rendered, r'FooBar[\s\S]*Tagged Union')
428
429
def test_tagged_union_comes_after_docstring_output(self):
430
help_command = self.create_help_command()
431
tagged_union = self.create_tagged_union_shape()
432
tagged_union.documentation = "FooBar"
433
shape = DenormalizedStructureBuilder().with_members({
434
'foo': {
435
'type': 'structure',
436
'union': True,
437
'documentation': 'FooBar',
438
'members': {}
439
}
440
}).build_model()
441
help_command.obj.output_shape = shape
442
operation_handler = OperationDocumentEventHandler(help_command)
443
operation_handler.doc_output(help_command=help_command,
444
event_name='foobar')
445
rendered = help_command.doc.getvalue().decode('utf-8')
446
self.assertRegex(rendered, r'FooBar[\s\S]*Tagged Union')
447
448
def test_meta_description_operation_command_html(self):
449
help_cmd = ServiceHelpCommand(
450
self.session, self.obj, self.command_table, self.arg_table,
451
self.name, 'ec2.run-instances'
452
)
453
help_cmd.doc.target = 'html'
454
doc_handler = OperationDocumentEventHandler(help_cmd)
455
doc_handler.doc_meta_description(help_cmd)
456
457
meta_description = help_cmd.doc.getvalue().decode('utf-8')
458
self.assertIn(".. meta::\n :description: ", meta_description)
459
self.assertIn('to run the ec2 run-instances command', meta_description)
460
461
def test_meta_description_service_html(self):
462
help_cmd = ServiceHelpCommand(
463
self.session, self.obj, self.command_table, self.arg_table,
464
self.name, 'ec2'
465
)
466
help_cmd.doc.target = 'html'
467
doc_handler = ServiceDocumentEventHandler(help_cmd)
468
doc_handler.doc_meta_description(help_cmd)
469
470
meta_description = help_cmd.doc.getvalue().decode('utf-8')
471
self.assertIn(".. meta::\n :description: Learn about the AWS CLI ", meta_description)
472
self.assertIn(' ec2 commands', meta_description)
473
474
475
class TestTopicDocumentEventHandlerBase(unittest.TestCase):
476
def setUp(self):
477
self.session = mock.Mock()
478
self.file_creator = FileCreator()
479
480
self.tags_dict = {}
481
482
# Make a temporary json index to base information on
483
self.json_index = self.file_creator.create_file('index.json', '')
484
with open(self.json_index, 'w') as f:
485
json.dump(self.tags_dict, f, indent=4, sort_keys=True)
486
487
self.index_patch = mock.patch('awscli.topictags.TopicTagDB.index_file',
488
self.json_index)
489
self.dir_patch = mock.patch('awscli.topictags.TopicTagDB.topic_dir',
490
self.file_creator.rootdir)
491
self.index_patch.start()
492
self.dir_patch.start()
493
494
def tearDown(self):
495
self.dir_patch.stop()
496
self.index_patch.stop()
497
self.file_creator.remove_all()
498
499
500
class TestTopicListerDocumentEventHandler(TestTopicDocumentEventHandlerBase):
501
def setUp(self):
502
super(TestTopicListerDocumentEventHandler, self).setUp()
503
self.descriptions = [
504
'This describes the first topic',
505
'This describes the second topic',
506
'This describes the third topic'
507
]
508
self.tags_dict = {
509
'topic-name-1': {
510
'title': ['The first topic title'],
511
'description': [self.descriptions[0]],
512
'category': ['General']
513
},
514
'topic-name-2': {
515
'title': ['The second topic title'],
516
'description': [self.descriptions[1]],
517
'category': ['S3']
518
},
519
'topic-name-3': {
520
'title': ['The third topic title'],
521
'description': [self.descriptions[2]],
522
'category': ['General']
523
}
524
525
}
526
527
with open(self.json_index, 'w') as f:
528
json.dump(self.tags_dict, f, indent=4, sort_keys=True)
529
530
self.cmd = TopicListerCommand(self.session)
531
self.doc_handler = TopicListerDocumentEventHandler(self.cmd)
532
533
def test_breadcrumbs(self):
534
self.doc_handler.doc_breadcrumbs(self.cmd)
535
self.assertEqual(self.cmd.doc.getvalue().decode('utf-8'), '')
536
self.cmd.doc.target = 'html'
537
self.doc_handler.doc_breadcrumbs(self.cmd)
538
self.assertEqual(
539
'[ :ref:`aws <cli:aws>` ]',
540
self.cmd.doc.getvalue().decode('utf-8')
541
)
542
543
def test_title(self):
544
self.doc_handler.doc_title(self.cmd)
545
title_contents = self.cmd.doc.getvalue().decode('utf-8')
546
self.assertIn('.. _cli:aws help %s:' % self.cmd.name, title_contents)
547
self.assertIn('AWS CLI Topic Guide', title_contents)
548
549
def test_description(self):
550
self.doc_handler.doc_description(self.cmd)
551
self.assertIn(
552
'This is the AWS CLI Topic Guide',
553
self.cmd.doc.getvalue().decode('utf-8')
554
)
555
556
def test_subitems_start(self):
557
ref_output = [
558
'-------\nGeneral\n-------',
559
('* topic-name-1: %s\n'
560
'* topic-name-3: %s\n' %
561
(self.descriptions[0], self.descriptions[2])),
562
'--\nS3\n--',
563
'* topic-name-2: %s\n' % self.descriptions[1]
564
]
565
566
self.doc_handler.doc_subitems_start(self.cmd)
567
contents = self.cmd.doc.getvalue().decode('utf-8')
568
569
for line in ref_output:
570
self.assertIn(line, contents)
571
# Make sure the toctree is not in the man page
572
self.assertNotIn('.. toctree::', contents)
573
574
def test_subitems_start_html(self):
575
self.cmd.doc.target = 'html'
576
ref_output = [
577
'-------\nGeneral\n-------',
578
('* :ref:`topic-name-1 <cli:aws help topic-name-1>`: %s\n'
579
'* :ref:`topic-name-3 <cli:aws help topic-name-3>`: %s\n' %
580
(self.descriptions[0], self.descriptions[2])),
581
'--\nS3\n--',
582
('* :ref:`topic-name-2 <cli:aws help topic-name-2>`: %s\n' %
583
self.descriptions[1])
584
]
585
586
self.doc_handler.doc_subitems_start(self.cmd)
587
contents = self.cmd.doc.getvalue().decode('utf-8')
588
589
for line in ref_output:
590
self.assertIn(line, contents)
591
# Make sure the hidden toctree is in the html
592
self.assertIn('.. toctree::', contents)
593
self.assertIn(':hidden:', contents)
594
595
596
class TestTopicDocumentEventHandler(TestTopicDocumentEventHandlerBase):
597
def setUp(self):
598
super(TestTopicDocumentEventHandler, self).setUp()
599
self.name = 'topic-name-1'
600
self.title = 'The first topic title'
601
self.description = 'This is about the first topic'
602
self.category = 'General'
603
self.related_command = 'foo'
604
self.related_topic = 'topic-name-2'
605
self.topic_body = 'Hello World!'
606
607
self.tags_dict = {
608
self.name: {
609
'title': [self.title],
610
'description': [self.description],
611
'category': [self.category],
612
'related topic': [self.related_topic],
613
'related command': [self.related_command]
614
}
615
}
616
with open(self.json_index, 'w') as f:
617
json.dump(self.tags_dict, f, indent=4, sort_keys=True)
618
619
self.cmd = TopicHelpCommand(self.session, self.name)
620
self.doc_handler = TopicDocumentEventHandler(self.cmd)
621
622
def test_breadcrumbs(self):
623
self.doc_handler.doc_breadcrumbs(self.cmd)
624
self.assertEqual(self.cmd.doc.getvalue().decode('utf-8'), '')
625
self.cmd.doc.target = 'html'
626
self.doc_handler.doc_breadcrumbs(self.cmd)
627
self.assertEqual(
628
'[ :ref:`aws <cli:aws>` . :ref:`topics <cli:aws help topics>` ]',
629
self.cmd.doc.getvalue().decode('utf-8')
630
)
631
632
def test_title(self):
633
self.doc_handler.doc_title(self.cmd)
634
title_contents = self.cmd.doc.getvalue().decode('utf-8')
635
self.assertIn('.. _cli:aws help %s:' % self.name, title_contents)
636
self.assertIn(self.title, title_contents)
637
638
def test_description(self):
639
lines = [
640
':title: ' + self.title,
641
':description: ' + self.description,
642
':category:' + self.category,
643
':related command: ' + self.related_command,
644
':related topic: ' + self.related_topic,
645
self.topic_body
646
]
647
body = '\n'.join(lines)
648
self.file_creator.create_file(self.name + '.rst', body)
649
self.doc_handler.doc_description(self.cmd)
650
contents = self.cmd.doc.getvalue().decode('utf-8')
651
self.assertIn(self.topic_body, contents)
652
self.assertNotIn(':title ' + self.title, contents)
653
654
def test_description_no_tags(self):
655
lines = [
656
self.topic_body
657
]
658
body = '\n'.join(lines)
659
self.file_creator.create_file(self.name + '.rst', body)
660
self.doc_handler.doc_description(self.cmd)
661
contents = self.cmd.doc.getvalue().decode('utf-8')
662
self.assertIn(self.topic_body, contents)
663
664
def test_description_tags_in_body(self):
665
lines = [
666
':title: ' + self.title,
667
':description: ' + self.description,
668
':related command: ' + self.related_command
669
]
670
body_lines = [
671
':related_topic: ' + self.related_topic,
672
self.topic_body,
673
':foo: bar'
674
]
675
body = '\n'.join(lines + body_lines)
676
ref_body = '\n'.join(body_lines)
677
self.file_creator.create_file(self.name + '.rst', body)
678
self.doc_handler.doc_description(self.cmd)
679
contents = self.cmd.doc.getvalue().decode('utf-8')
680
self.assertIn(ref_body, contents)
681
682
def test_excludes_global_options(self):
683
self.doc_handler.doc_global_option(self.cmd)
684
global_options = self.cmd.doc.getvalue().decode('utf-8')
685
self.assertNotIn('Global Options', global_options)
686
687
688
class TestGlobalOptionsDocumenter(unittest.TestCase):
689
def create_help_command(self):
690
types = ['blob', 'integer', 'boolean', 'string']
691
arg_table = {}
692
for t in types:
693
name = f'{t}_type'
694
help_text = f'This arg type is {t}'
695
choices = ['A', 'B', 'C'] if t == 'string' else []
696
arg_table[name] = CustomArgument(name=name,
697
cli_type_name=t,
698
help_text=help_text,
699
choices=choices)
700
help_command = mock.Mock(spec=HelpCommand)
701
help_command.arg_table = arg_table
702
help_command.doc = ReSTDocument()
703
return help_command
704
705
def create_documenter(self):
706
return GlobalOptionsDocumenter(self.create_help_command())
707
708
def test_doc_global_options(self):
709
documenter = self.create_documenter()
710
options = documenter.doc_global_options()
711
self.assertIn('``--string_type`` (string)', options)
712
self.assertIn('``--integer_type`` (integer)', options)
713
self.assertIn('``--boolean_type`` (boolean)', options)
714
self.assertIn('``--blob_type`` (blob)', options)
715
self.assertIn('* A', options)
716
self.assertIn('* B', options)
717
self.assertIn('* C', options)
718
719
def test_doc_global_synopsis(self):
720
documenter = self.create_documenter()
721
synopsis = documenter.doc_global_synopsis()
722
self.assertIn('[--string_type <value>]', synopsis)
723
self.assertIn('[--integer_type <value>]', synopsis)
724
self.assertIn('[--boolean_type]', synopsis)
725
self.assertIn('[--blob_type <value>]', synopsis)
726
727