1
# Copyright (C) 2007-2011 Canonical Ltd
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.
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.
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
17
"""Unit tests for the bzrlib.help module."""
30
class TestHelp(tests.TestCase):
33
tests.TestCase.setUp(self)
34
commands.install_bzr_command_hooks()
37
class TestCommandHelp(tests.TestCase):
38
"""Tests for help on commands."""
40
def test_command_help_includes_see_also(self):
41
class cmd_WithSeeAlso(commands.Command):
42
__doc__ = """A sample command."""
43
_see_also = ['foo', 'bar']
44
cmd = cmd_WithSeeAlso()
45
helptext = cmd.get_help_text()
48
' -v, --verbose Display more information.\n'
49
' -q, --quiet Only display errors and warnings.\n'
50
' -h, --help Show help message.\n'
52
'See also: bar, foo\n')
54
def test_get_help_text(self):
55
"""Commands have a get_help_text method which returns their help."""
56
class cmd_Demo(commands.Command):
57
__doc__ = """A sample command."""
59
helptext = cmd.get_help_text()
60
self.assertStartsWith(helptext,
61
'Purpose: A sample command.\n'
63
self.assertEndsWith(helptext,
64
' -h, --help Show help message.\n\n')
66
def test_command_with_additional_see_also(self):
67
class cmd_WithSeeAlso(commands.Command):
68
__doc__ = """A sample command."""
69
_see_also = ['foo', 'bar']
70
cmd = cmd_WithSeeAlso()
71
helptext = cmd.get_help_text(['gam'])
74
' -v, --verbose Display more information.\n'
75
' -q, --quiet Only display errors and warnings.\n'
76
' -h, --help Show help message.\n'
78
'See also: bar, foo, gam\n')
80
def test_command_only_additional_see_also(self):
81
class cmd_WithSeeAlso(commands.Command):
82
__doc__ = """A sample command."""
83
cmd = cmd_WithSeeAlso()
84
helptext = cmd.get_help_text(['gam'])
87
' -v, --verbose Display more information.\n'
88
' -q, --quiet Only display errors and warnings.\n'
89
' -h, --help Show help message.\n'
93
def test_get_help_topic(self):
94
"""The help topic for a Command is its name()."""
95
class cmd_foo_bar(commands.Command):
96
__doc__ = """A sample command."""
98
self.assertEqual(cmd.name(), cmd.get_help_topic())
100
def test_formatted_help_text(self):
101
"""Help text should be plain text by default."""
102
class cmd_Demo(commands.Command):
103
__doc__ = """A sample command.
114
A code block follows.
121
helptext = cmd.get_help_text()
124
'Purpose: A sample command.\n'
128
' --usage Show usage message and options.\n'
129
' -v, --verbose Display more information.\n'
130
' -q, --quiet Only display errors and warnings.\n'
131
' -h, --help Show help message.\n'
142
' A code block follows.\n'
144
' bzr Demo something\n'
146
helptext = cmd.get_help_text(plain=False)
147
self.assertEquals(helptext,
148
':Purpose: A sample command.\n'
152
' --usage Show usage message and options.\n'
153
' -v, --verbose Display more information.\n'
154
' -q, --quiet Only display errors and warnings.\n'
155
' -h, --help Show help message.\n'
166
' A code block follows.\n'
170
' bzr Demo something\n'
173
def test_concise_help_text(self):
174
"""Concise help text excludes the descriptive sections."""
175
class cmd_Demo(commands.Command):
176
__doc__ = """A sample command.
186
helptext = cmd.get_help_text()
187
self.assertEqualDiff(
189
'Purpose: A sample command.\n'
193
' --usage Show usage message and options.\n'
194
' -v, --verbose Display more information.\n'
195
' -q, --quiet Only display errors and warnings.\n'
196
' -h, --help Show help message.\n'
206
helptext = cmd.get_help_text(verbose=False)
207
self.assertEquals(helptext,
208
'Purpose: A sample command.\n'
212
' --usage Show usage message and options.\n'
213
' -v, --verbose Display more information.\n'
214
' -q, --quiet Only display errors and warnings.\n'
215
' -h, --help Show help message.\n'
217
'See bzr help Demo for more details and examples.\n'
220
def test_help_custom_section_ordering(self):
221
"""Custom descriptive sections should remain in the order given."""
222
class cmd_Demo(commands.Command):
223
__doc__ = """A sample command.
228
Interesting stuff about formats.
236
Clever things to keep in mind.
239
helptext = cmd.get_help_text()
240
self.assertEqualDiff(
242
'Purpose: A sample command.\n'
246
' --usage Show usage message and options.\n'
247
' -v, --verbose Display more information.\n'
248
' -q, --quiet Only display errors and warnings.\n'
249
' -h, --help Show help message.\n'
255
' Interesting stuff about formats.\n'
263
' Clever things to keep in mind.\n'
266
def test_help_text_custom_usage(self):
267
"""Help text may contain a custom usage section."""
268
class cmd_Demo(commands.Command):
269
__doc__ = """A sample command.
279
helptext = cmd.get_help_text()
280
self.assertEquals(helptext,
281
'Purpose: A sample command.\n'
283
' cmd Demo [opts] args\n'
289
' --usage Show usage message and options.\n'
290
' -v, --verbose Display more information.\n'
291
' -q, --quiet Only display errors and warnings.\n'
292
' -h, --help Show help message.\n'
295
' Blah blah blah.\n\n')
298
class TestRegisteredTopic(TestHelp):
299
"""Tests for the RegisteredTopic class."""
301
def test_contruct(self):
302
"""Construction takes the help topic name for the registered item."""
304
self.assertTrue('basic' in help_topics.topic_registry)
305
topic = help_topics.RegisteredTopic('basic')
306
self.assertEqual('basic', topic.topic)
308
def test_get_help_text(self):
309
"""A RegisteredTopic returns the get_detail results for get_help_text."""
310
topic = help_topics.RegisteredTopic('commands')
311
self.assertEqual(help_topics.topic_registry.get_detail('commands'),
312
topic.get_help_text())
314
def test_get_help_text_with_additional_see_also(self):
315
topic = help_topics.RegisteredTopic('commands')
317
topic.get_help_text(['foo', 'bar']),
319
'See also: bar, foo\n')
321
def test_get_help_text_loaded_from_file(self):
322
# Pick a known topic stored in an external file
323
topic = help_topics.RegisteredTopic('authentication')
324
self.assertStartsWith(topic.get_help_text(),
325
'Authentication Settings\n'
326
'=======================\n'
329
def test_get_help_topic(self):
330
"""The help topic for a RegisteredTopic is its topic from construction."""
331
topic = help_topics.RegisteredTopic('foobar')
332
self.assertEqual('foobar', topic.get_help_topic())
333
topic = help_topics.RegisteredTopic('baz')
334
self.assertEqual('baz', topic.get_help_topic())
337
class TestTopicIndex(TestHelp):
338
"""Tests for the HelpTopicIndex class."""
340
def test_default_constructable(self):
341
index = help_topics.HelpTopicIndex()
343
def test_get_topics_None(self):
344
"""Searching for None returns the basic help topic."""
345
index = help_topics.HelpTopicIndex()
346
topics = index.get_topics(None)
347
self.assertEqual(1, len(topics))
348
self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
349
self.assertEqual('basic', topics[0].topic)
351
def test_get_topics_topics(self):
352
"""Searching for a string returns the matching string."""
353
index = help_topics.HelpTopicIndex()
354
topics = index.get_topics('topics')
355
self.assertEqual(1, len(topics))
356
self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
357
self.assertEqual('topics', topics[0].topic)
359
def test_get_topics_no_topic(self):
360
"""Searching for something not registered returns []."""
361
index = help_topics.HelpTopicIndex()
362
self.assertEqual([], index.get_topics('nothing by this name'))
364
def test_prefix(self):
365
"""TopicIndex has a prefix of ''."""
366
index = help_topics.HelpTopicIndex()
367
self.assertEqual('', index.prefix)
370
class TestCommandIndex(TestHelp):
371
"""Tests for the HelpCommandIndex class."""
373
def test_default_constructable(self):
374
index = commands.HelpCommandIndex()
376
def test_get_topics_None(self):
377
"""Searching for None returns an empty list."""
378
index = commands.HelpCommandIndex()
379
self.assertEqual([], index.get_topics(None))
381
def test_get_topics_rocks(self):
382
"""Searching for 'rocks' returns the cmd_rocks command instance."""
383
index = commands.HelpCommandIndex()
384
topics = index.get_topics('rocks')
385
self.assertEqual(1, len(topics))
386
self.assertIsInstance(topics[0], builtins.cmd_rocks)
388
def test_get_topics_no_topic(self):
389
"""Searching for something that is not a command returns []."""
390
index = commands.HelpCommandIndex()
391
self.assertEqual([], index.get_topics('nothing by this name'))
393
def test_prefix(self):
394
"""CommandIndex has a prefix of 'commands/'."""
395
index = commands.HelpCommandIndex()
396
self.assertEqual('commands/', index.prefix)
398
def test_get_topic_with_prefix(self):
399
"""Searching for commands/rocks returns the rocks command object."""
400
index = commands.HelpCommandIndex()
401
topics = index.get_topics('commands/rocks')
402
self.assertEqual(1, len(topics))
403
self.assertIsInstance(topics[0], builtins.cmd_rocks)
406
class TestHelpIndices(tests.TestCase):
407
"""Tests for the HelpIndices class."""
409
def test_default_search_path(self):
410
"""The default search path should include internal indexs."""
411
indices = help.HelpIndices()
412
self.assertEqual(3, len(indices.search_path))
413
# help topics should be searched in first.
414
self.assertIsInstance(indices.search_path[0],
415
help_topics.HelpTopicIndex)
416
# with commands being search second.
417
self.assertIsInstance(indices.search_path[1],
418
commands.HelpCommandIndex)
419
# and plugins are a third index.
420
self.assertIsInstance(indices.search_path[2],
421
plugin.PluginsHelpIndex)
423
def test_search_for_unknown_topic_raises(self):
424
"""Searching for an unknown topic should raise NoHelpTopic."""
425
indices = help.HelpIndices()
426
indices.search_path = []
427
error = self.assertRaises(errors.NoHelpTopic, indices.search, 'foo')
428
self.assertEqual('foo', error.topic)
430
def test_search_calls_get_topic(self):
431
"""Searching should call get_topics in all indexes in order."""
433
class RecordingIndex(object):
434
def __init__(self, name):
436
def get_topics(self, topic):
437
calls.append(('get_topics', self.prefix, topic))
439
index = help.HelpIndices()
440
index.search_path = [RecordingIndex('1'), RecordingIndex('2')]
444
('get_topics', '1', None),
445
('get_topics', '2', None),
452
('get_topics', '1', 'bar'),
453
('get_topics', '2', 'bar'),
457
def test_search_returns_index_and_results(self):
458
"""Searching should return help topics with their index"""
459
class CannedIndex(object):
460
def __init__(self, prefix, search_result):
462
self.result = search_result
463
def get_topics(self, topic):
465
index = help.HelpIndices()
466
index_one = CannedIndex('1', ['a'])
467
index_two = CannedIndex('2', ['b', 'c'])
468
index.search_path = [index_one, index_two]
469
self.assertEqual([(index_one, 'a'), (index_two, 'b'), (index_two, 'c')],
472
def test_search_checks_for_duplicate_prefixes(self):
473
"""Its an error when there are multiple indices with the same prefix."""
474
indices = help.HelpIndices()
475
indices.search_path = [help_topics.HelpTopicIndex(),
476
help_topics.HelpTopicIndex()]
477
self.assertRaises(errors.DuplicateHelpPrefix, indices.search, None)