~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_help.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-06 18:59:24 UTC
  • mto: This revision was merged to the branch mainline in revision 4522.
  • Revision ID: john@arbash-meinel.com-20090706185924-qlhn1j607117lgdj
Start implementing an Annotator.add_special_text functionality.

The Python implementation supports it. Basically, it is meant to allow things
like WT and PreviewTree to insert the 'current' content into the graph, so that
we can get local modifications into the annotations.
There is also some work here to get support for texts that are already cached
in the annotator. So that we avoid extracting them, and can shortcut the
history.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Unit tests for the bzrlib.help module."""
 
18
 
 
19
from cStringIO import StringIO
 
20
 
 
21
from bzrlib import (
 
22
    builtins,
 
23
    commands,
 
24
    errors,
 
25
    help,
 
26
    help_topics,
 
27
    plugin,
 
28
    tests,
 
29
    )
 
30
 
 
31
 
 
32
class TestHelp(tests.TestCase):
 
33
 
 
34
    def setUp(self):
 
35
        tests.TestCase.setUp(self)
 
36
        commands.install_bzr_command_hooks()
 
37
 
 
38
 
 
39
class TestCommandHelp(tests.TestCase):
 
40
    """Tests for help on commands."""
 
41
 
 
42
    def test_command_help_includes_see_also(self):
 
43
        class cmd_WithSeeAlso(commands.Command):
 
44
            """A sample command."""
 
45
            _see_also = ['foo', 'bar']
 
46
        cmd = cmd_WithSeeAlso()
 
47
        helptext = cmd.get_help_text()
 
48
        self.assertEndsWith(
 
49
            helptext,
 
50
            '  -v, --verbose  Display more information.\n'
 
51
            '  -q, --quiet    Only display errors and warnings.\n'
 
52
            '  -h, --help     Show help message.\n'
 
53
            '\n'
 
54
            'See also: bar, foo\n')
 
55
 
 
56
    def test_get_help_text(self):
 
57
        """Commands have a get_help_text method which returns their help."""
 
58
        class cmd_Demo(commands.Command):
 
59
            """A sample command."""
 
60
        cmd = cmd_Demo()
 
61
        helptext = cmd.get_help_text()
 
62
        self.assertStartsWith(helptext,
 
63
            'Purpose: A sample command.\n'
 
64
            'Usage:   bzr Demo')
 
65
        self.assertEndsWith(helptext,
 
66
            '  -h, --help     Show help message.\n\n')
 
67
 
 
68
    def test_command_with_additional_see_also(self):
 
69
        class cmd_WithSeeAlso(commands.Command):
 
70
            """A sample command."""
 
71
            _see_also = ['foo', 'bar']
 
72
        cmd = cmd_WithSeeAlso()
 
73
        helptext = cmd.get_help_text(['gam'])
 
74
        self.assertEndsWith(
 
75
            helptext,
 
76
            '  -v, --verbose  Display more information.\n'
 
77
            '  -q, --quiet    Only display errors and warnings.\n'
 
78
            '  -h, --help     Show help message.\n'
 
79
            '\n'
 
80
            'See also: bar, foo, gam\n')
 
81
 
 
82
    def test_command_only_additional_see_also(self):
 
83
        class cmd_WithSeeAlso(commands.Command):
 
84
            """A sample command."""
 
85
        cmd = cmd_WithSeeAlso()
 
86
        helptext = cmd.get_help_text(['gam'])
 
87
        self.assertEndsWith(
 
88
            helptext,
 
89
            '  -v, --verbose  Display more information.\n'
 
90
            '  -q, --quiet    Only display errors and warnings.\n'
 
91
            '  -h, --help     Show help message.\n'
 
92
            '\n'
 
93
            'See also: gam\n')
 
94
 
 
95
    def test_get_help_topic(self):
 
96
        """The help topic for a Command is its name()."""
 
97
        class cmd_foo_bar(commands.Command):
 
98
            """A sample command."""
 
99
        cmd = cmd_foo_bar()
 
100
        self.assertEqual(cmd.name(), cmd.get_help_topic())
 
101
 
 
102
    def test_formatted_help_text(self):
 
103
        """Help text should be plain text by default."""
 
104
        class cmd_Demo(commands.Command):
 
105
            """A sample command.
 
106
 
 
107
            :Examples:
 
108
                Example 1::
 
109
 
 
110
                    cmd arg1
 
111
 
 
112
                Example 2::
 
113
 
 
114
                    cmd arg2
 
115
            """
 
116
        cmd = cmd_Demo()
 
117
        helptext = cmd.get_help_text()
 
118
        self.assertEquals(
 
119
            helptext,
 
120
            'Purpose: A sample command.\n'
 
121
            'Usage:   bzr Demo\n'
 
122
            '\n'
 
123
            'Options:\n'
 
124
            '  --usage        Show usage message and options.\n'
 
125
            '  -v, --verbose  Display more information.\n'
 
126
            '  -q, --quiet    Only display errors and warnings.\n'
 
127
            '  -h, --help     Show help message.\n'
 
128
            '\n'
 
129
            'Examples:\n'
 
130
            '    Example 1:\n'
 
131
            '\n'
 
132
            '        cmd arg1\n'
 
133
            '\n'
 
134
            '    Example 2:\n'
 
135
            '\n'
 
136
            '        cmd arg2\n'
 
137
            '\n')
 
138
        helptext = cmd.get_help_text(plain=False)
 
139
        self.assertEquals(helptext,
 
140
            ':Purpose: A sample command.\n'
 
141
            ':Usage:   bzr Demo\n'
 
142
            '\n'
 
143
            ':Options:\n'
 
144
            '  --usage        Show usage message and options.\n'
 
145
            '  -v, --verbose  Display more information.\n'
 
146
            '  -q, --quiet    Only display errors and warnings.\n'
 
147
            '  -h, --help     Show help message.\n'
 
148
            '\n'
 
149
            ':Examples:\n'
 
150
            '    Example 1::\n'
 
151
            '\n'
 
152
            '        cmd arg1\n'
 
153
            '\n'
 
154
            '    Example 2::\n'
 
155
            '\n'
 
156
            '        cmd arg2\n'
 
157
            '\n')
 
158
 
 
159
    def test_concise_help_text(self):
 
160
        """Concise help text excludes the descriptive sections."""
 
161
        class cmd_Demo(commands.Command):
 
162
            """A sample command.
 
163
 
 
164
            Blah blah blah.
 
165
 
 
166
            :Examples:
 
167
                Example 1::
 
168
 
 
169
                    cmd arg1
 
170
            """
 
171
        cmd = cmd_Demo()
 
172
        helptext = cmd.get_help_text()
 
173
        self.assertEqualDiff(
 
174
            helptext,
 
175
            'Purpose: A sample command.\n'
 
176
            'Usage:   bzr Demo\n'
 
177
            '\n'
 
178
            'Options:\n'
 
179
            '  --usage        Show usage message and options.\n'
 
180
            '  -v, --verbose  Display more information.\n'
 
181
            '  -q, --quiet    Only display errors and warnings.\n'
 
182
            '  -h, --help     Show help message.\n'
 
183
            '\n'
 
184
            'Description:\n'
 
185
            '  Blah blah blah.\n'
 
186
            '\n'
 
187
            'Examples:\n'
 
188
            '    Example 1:\n'
 
189
            '\n'
 
190
            '        cmd arg1\n'
 
191
            '\n')
 
192
        helptext = cmd.get_help_text(verbose=False)
 
193
        self.assertEquals(helptext,
 
194
            'Purpose: A sample command.\n'
 
195
            'Usage:   bzr Demo\n'
 
196
            '\n'
 
197
            'Options:\n'
 
198
            '  --usage        Show usage message and options.\n'
 
199
            '  -v, --verbose  Display more information.\n'
 
200
            '  -q, --quiet    Only display errors and warnings.\n'
 
201
            '  -h, --help     Show help message.\n'
 
202
            '\n'
 
203
            'See bzr help Demo for more details and examples.\n'
 
204
            '\n')
 
205
 
 
206
    def test_help_custom_section_ordering(self):
 
207
        """Custom descriptive sections should remain in the order given."""
 
208
        class cmd_Demo(commands.Command):
 
209
            """A sample command.
 
210
 
 
211
            Blah blah blah.
 
212
 
 
213
            :Formats:
 
214
              Interesting stuff about formats.
 
215
 
 
216
            :Examples:
 
217
              Example 1::
 
218
 
 
219
                cmd arg1
 
220
 
 
221
            :Tips:
 
222
              Clever things to keep in mind.
 
223
            """
 
224
        cmd = cmd_Demo()
 
225
        helptext = cmd.get_help_text()
 
226
        self.assertEqualDiff(
 
227
            helptext,
 
228
            'Purpose: A sample command.\n'
 
229
            'Usage:   bzr Demo\n'
 
230
            '\n'
 
231
            'Options:\n'
 
232
            '  --usage        Show usage message and options.\n'
 
233
            '  -v, --verbose  Display more information.\n'
 
234
            '  -q, --quiet    Only display errors and warnings.\n'
 
235
            '  -h, --help     Show help message.\n'
 
236
            '\n'
 
237
            'Description:\n'
 
238
            '  Blah blah blah.\n'
 
239
            '\n'
 
240
            'Formats:\n'
 
241
            '  Interesting stuff about formats.\n'
 
242
            '\n'
 
243
            'Examples:\n'
 
244
            '  Example 1:\n'
 
245
            '\n'
 
246
            '    cmd arg1\n'
 
247
            '\n'
 
248
            'Tips:\n'
 
249
            '  Clever things to keep in mind.\n'
 
250
            '\n')
 
251
 
 
252
    def test_help_text_custom_usage(self):
 
253
        """Help text may contain a custom usage section."""
 
254
        class cmd_Demo(commands.Command):
 
255
            """A sample command.
 
256
 
 
257
            :Usage:
 
258
                cmd Demo [opts] args
 
259
 
 
260
                cmd Demo -h
 
261
 
 
262
            Blah blah blah.
 
263
            """
 
264
        cmd = cmd_Demo()
 
265
        helptext = cmd.get_help_text()
 
266
        self.assertEquals(helptext,
 
267
            'Purpose: A sample command.\n'
 
268
            'Usage:\n'
 
269
            '    cmd Demo [opts] args\n'
 
270
            '\n'
 
271
            '    cmd Demo -h\n'
 
272
            '\n'
 
273
            '\n'
 
274
            'Options:\n'
 
275
            '  --usage        Show usage message and options.\n'
 
276
            '  -v, --verbose  Display more information.\n'
 
277
            '  -q, --quiet    Only display errors and warnings.\n'
 
278
            '  -h, --help     Show help message.\n'
 
279
            '\n'
 
280
            'Description:\n'
 
281
            '  Blah blah blah.\n\n')
 
282
 
 
283
 
 
284
class TestRegisteredTopic(TestHelp):
 
285
    """Tests for the RegisteredTopic class."""
 
286
 
 
287
    def test_contruct(self):
 
288
        """Construction takes the help topic name for the registered item."""
 
289
        # validate our test
 
290
        self.assertTrue('basic' in help_topics.topic_registry)
 
291
        topic = help_topics.RegisteredTopic('basic')
 
292
        self.assertEqual('basic', topic.topic)
 
293
 
 
294
    def test_get_help_text(self):
 
295
        """A RegisteredTopic returns the get_detail results for get_help_text."""
 
296
        topic = help_topics.RegisteredTopic('commands')
 
297
        self.assertEqual(help_topics.topic_registry.get_detail('commands'),
 
298
            topic.get_help_text())
 
299
 
 
300
    def test_get_help_text_with_additional_see_also(self):
 
301
        topic = help_topics.RegisteredTopic('commands')
 
302
        self.assertEndsWith(
 
303
            topic.get_help_text(['foo', 'bar']),
 
304
            '\n'
 
305
            'See also: bar, foo\n')
 
306
 
 
307
    def test_get_help_text_loaded_from_file(self):
 
308
        # Pick a known topic stored in an external file
 
309
        topic = help_topics.RegisteredTopic('authentication')
 
310
        self.assertStartsWith(topic.get_help_text(),
 
311
            'Authentication Settings\n'
 
312
            '=======================\n'
 
313
            '\n')
 
314
 
 
315
    def test_get_help_topic(self):
 
316
        """The help topic for a RegisteredTopic is its topic from construction."""
 
317
        topic = help_topics.RegisteredTopic('foobar')
 
318
        self.assertEqual('foobar', topic.get_help_topic())
 
319
        topic = help_topics.RegisteredTopic('baz')
 
320
        self.assertEqual('baz', topic.get_help_topic())
 
321
 
 
322
 
 
323
class TestTopicIndex(TestHelp):
 
324
    """Tests for the HelpTopicIndex class."""
 
325
 
 
326
    def test_default_constructable(self):
 
327
        index = help_topics.HelpTopicIndex()
 
328
 
 
329
    def test_get_topics_None(self):
 
330
        """Searching for None returns the basic help topic."""
 
331
        index = help_topics.HelpTopicIndex()
 
332
        topics = index.get_topics(None)
 
333
        self.assertEqual(1, len(topics))
 
334
        self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
 
335
        self.assertEqual('basic', topics[0].topic)
 
336
 
 
337
    def test_get_topics_topics(self):
 
338
        """Searching for a string returns the matching string."""
 
339
        index = help_topics.HelpTopicIndex()
 
340
        topics = index.get_topics('topics')
 
341
        self.assertEqual(1, len(topics))
 
342
        self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
 
343
        self.assertEqual('topics', topics[0].topic)
 
344
 
 
345
    def test_get_topics_no_topic(self):
 
346
        """Searching for something not registered returns []."""
 
347
        index = help_topics.HelpTopicIndex()
 
348
        self.assertEqual([], index.get_topics('nothing by this name'))
 
349
 
 
350
    def test_prefix(self):
 
351
        """TopicIndex has a prefix of ''."""
 
352
        index = help_topics.HelpTopicIndex()
 
353
        self.assertEqual('', index.prefix)
 
354
 
 
355
 
 
356
class TestCommandIndex(TestHelp):
 
357
    """Tests for the HelpCommandIndex class."""
 
358
 
 
359
    def test_default_constructable(self):
 
360
        index = commands.HelpCommandIndex()
 
361
 
 
362
    def test_get_topics_None(self):
 
363
        """Searching for None returns an empty list."""
 
364
        index = commands.HelpCommandIndex()
 
365
        self.assertEqual([], index.get_topics(None))
 
366
 
 
367
    def test_get_topics_rocks(self):
 
368
        """Searching for 'rocks' returns the cmd_rocks command instance."""
 
369
        index = commands.HelpCommandIndex()
 
370
        topics = index.get_topics('rocks')
 
371
        self.assertEqual(1, len(topics))
 
372
        self.assertIsInstance(topics[0], builtins.cmd_rocks)
 
373
 
 
374
    def test_get_topics_no_topic(self):
 
375
        """Searching for something that is not a command returns []."""
 
376
        index = commands.HelpCommandIndex()
 
377
        self.assertEqual([], index.get_topics('nothing by this name'))
 
378
 
 
379
    def test_prefix(self):
 
380
        """CommandIndex has a prefix of 'commands/'."""
 
381
        index = commands.HelpCommandIndex()
 
382
        self.assertEqual('commands/', index.prefix)
 
383
 
 
384
    def test_get_topic_with_prefix(self):
 
385
        """Searching for commands/rocks returns the rocks command object."""
 
386
        index = commands.HelpCommandIndex()
 
387
        topics = index.get_topics('commands/rocks')
 
388
        self.assertEqual(1, len(topics))
 
389
        self.assertIsInstance(topics[0], builtins.cmd_rocks)
 
390
 
 
391
 
 
392
class TestHelpIndices(tests.TestCase):
 
393
    """Tests for the HelpIndices class."""
 
394
 
 
395
    def test_default_search_path(self):
 
396
        """The default search path should include internal indexs."""
 
397
        indices = help.HelpIndices()
 
398
        self.assertEqual(3, len(indices.search_path))
 
399
        # help topics should be searched in first.
 
400
        self.assertIsInstance(indices.search_path[0],
 
401
            help_topics.HelpTopicIndex)
 
402
        # with commands being search second.
 
403
        self.assertIsInstance(indices.search_path[1],
 
404
            commands.HelpCommandIndex)
 
405
        # and plugins are a third index.
 
406
        self.assertIsInstance(indices.search_path[2],
 
407
            plugin.PluginsHelpIndex)
 
408
 
 
409
    def test_search_for_unknown_topic_raises(self):
 
410
        """Searching for an unknown topic should raise NoHelpTopic."""
 
411
        indices = help.HelpIndices()
 
412
        indices.search_path = []
 
413
        error = self.assertRaises(errors.NoHelpTopic, indices.search, 'foo')
 
414
        self.assertEqual('foo', error.topic)
 
415
 
 
416
    def test_search_calls_get_topic(self):
 
417
        """Searching should call get_topics in all indexes in order."""
 
418
        calls = []
 
419
        class RecordingIndex(object):
 
420
            def __init__(self, name):
 
421
                self.prefix = name
 
422
            def get_topics(self, topic):
 
423
                calls.append(('get_topics', self.prefix, topic))
 
424
                return ['something']
 
425
        index = help.HelpIndices()
 
426
        index.search_path = [RecordingIndex('1'), RecordingIndex('2')]
 
427
        # try with None
 
428
        index.search(None)
 
429
        self.assertEqual([
 
430
            ('get_topics', '1', None),
 
431
            ('get_topics', '2', None),
 
432
            ],
 
433
            calls)
 
434
        # and with a string
 
435
        del calls[:]
 
436
        index.search('bar')
 
437
        self.assertEqual([
 
438
            ('get_topics', '1', 'bar'),
 
439
            ('get_topics', '2', 'bar'),
 
440
            ],
 
441
            calls)
 
442
 
 
443
    def test_search_returns_index_and_results(self):
 
444
        """Searching should return help topics with their index"""
 
445
        class CannedIndex(object):
 
446
            def __init__(self, prefix, search_result):
 
447
                self.prefix = prefix
 
448
                self.result = search_result
 
449
            def get_topics(self, topic):
 
450
                return self.result
 
451
        index = help.HelpIndices()
 
452
        index_one = CannedIndex('1', ['a'])
 
453
        index_two = CannedIndex('2', ['b', 'c'])
 
454
        index.search_path = [index_one, index_two]
 
455
        self.assertEqual([(index_one, 'a'), (index_two, 'b'), (index_two, 'c')],
 
456
            index.search(None))
 
457
 
 
458
    def test_search_checks_for_duplicate_prefixes(self):
 
459
        """Its an error when there are multiple indices with the same prefix."""
 
460
        indices = help.HelpIndices()
 
461
        indices.search_path = [help_topics.HelpTopicIndex(),
 
462
            help_topics.HelpTopicIndex()]
 
463
        self.assertRaises(errors.DuplicateHelpPrefix, indices.search, None)