~bzr-pqm/bzr/bzr.dev

2425.2.2 by Robert Collins
``bzr help`` now provides cross references to other help topics using the
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Unit tests for the bzrlib.help module."""
18
19
from cStringIO import StringIO
20
21
from bzrlib import (
2432.1.13 by Robert Collins
HelpCommandContext now implementes get_topics.
22
    builtins,
2425.2.2 by Robert Collins
``bzr help`` now provides cross references to other help topics using the
23
    commands,
2432.1.5 by Robert Collins
Initial stub for topic searching.
24
    errors,
2425.2.2 by Robert Collins
``bzr help`` now provides cross references to other help topics using the
25
    help,
2432.1.1 by Robert Collins
Add a HelpTopicContext object.
26
    help_topics,
2432.1.24 by Robert Collins
Add plugins as a help index.
27
    plugin,
2425.2.2 by Robert Collins
``bzr help`` now provides cross references to other help topics using the
28
    tests,
29
    )
30
31
32
class TestCommandHelp(tests.TestCase):
33
    """Tests for help on commands."""
34
35
    def test_command_help_includes_see_also(self):
36
        class cmd_WithSeeAlso(commands.Command):
37
            """A sample command."""
38
            _see_also = ['foo', 'bar']
39
        cmd = cmd_WithSeeAlso()
2432.1.12 by Robert Collins
Relocate command help onto Command.
40
        helptext = cmd.get_help_text()
2425.1.3 by Robert Collins
Python 2.4 compatability change for the new help see-also tests.
41
        self.assertEndsWith(
2432.1.12 by Robert Collins
Relocate command help onto Command.
42
            helptext,
2425.2.2 by Robert Collins
``bzr help`` now provides cross references to other help topics using the
43
            '  -h, --help  show help message\n'
44
            '\n'
2425.1.3 by Robert Collins
Python 2.4 compatability change for the new help see-also tests.
45
            'See also: bar, foo\n')
2432.1.1 by Robert Collins
Add a HelpTopicContext object.
46
2432.1.12 by Robert Collins
Relocate command help onto Command.
47
    def test_get_help_text(self):
48
        """Commands have a get_help_text method which returns their help."""
49
        class cmd_Demo(commands.Command):
50
            """A sample command."""
51
        cmd = cmd_Demo()
52
        helptext = cmd.get_help_text()
2432.1.31 by Robert Collins
Review feedback and put help.command_usage back in as a deprecated function.
53
        self.assertStartsWith(helptext, 'usage: bzr Demo')
2432.1.12 by Robert Collins
Relocate command help onto Command.
54
        self.assertEndsWith(helptext, 'show help message\n')
2432.1.21 by Robert Collins
Teach Command.get_help_text to show additional help cross references when supplied.
55
56
    def test_command_with_additional_see_also(self):
57
        class cmd_WithSeeAlso(commands.Command):
58
            """A sample command."""
59
            _see_also = ['foo', 'bar']
60
        cmd = cmd_WithSeeAlso()
61
        helptext = cmd.get_help_text(['gam'])
62
        self.assertEndsWith(
63
            helptext,
64
            '  -h, --help  show help message\n'
65
            '\n'
66
            'See also: bar, foo, gam\n')
67
68
    def test_command_only_additional_see_also(self):
69
        class cmd_WithSeeAlso(commands.Command):
70
            """A sample command."""
71
        cmd = cmd_WithSeeAlso()
72
        helptext = cmd.get_help_text(['gam'])
73
        self.assertEndsWith(
74
            helptext,
75
            '  -h, --help  show help message\n'
76
            '\n'
77
            'See also: gam\n')
2432.1.28 by Robert Collins
Add a get_help_topic method to commands.Command.
78
79
    def test_get_help_topic(self):
80
        """The help topic for a Command is its name()."""
81
        class cmd_foo_bar(commands.Command):
82
            """A sample command."""
83
        cmd = cmd_foo_bar()
84
        self.assertEqual(cmd.name(), cmd.get_help_topic())
2432.1.12 by Robert Collins
Relocate command help onto Command.
85
    
2432.1.1 by Robert Collins
Add a HelpTopicContext object.
86
2432.1.8 by Robert Collins
HelpTopicContext now returns RegisteredTopic objects for get_topics calls.
87
class TestRegisteredTopic(tests.TestCase):
88
    """Tests for the RegisteredTopic class."""
89
90
    def test_contruct(self):
91
        """Construction takes the help topic name for the registered item."""
92
        # validate our test 
93
        self.assertTrue('basic' in help_topics.topic_registry)
94
        topic = help_topics.RegisteredTopic('basic')
95
        self.assertEqual('basic', topic.topic)
96
2432.1.10 by Robert Collins
Add get_help_text() to RegisteredTopic to get the help as a string.
97
    def test_get_help_text(self):
98
        """A RegisteredTopic returns the get_detail results for get_help_text."""
99
        topic = help_topics.RegisteredTopic('commands')
100
        self.assertEqual(help_topics.topic_registry.get_detail('commands'),
101
            topic.get_help_text())
102
2432.1.22 by Robert Collins
Teach RegisteredTopic to support the additional_see_also list of related help terms.
103
    def test_get_help_text_with_additional_see_also(self):
104
        topic = help_topics.RegisteredTopic('commands')
105
        self.assertEndsWith(
106
            topic.get_help_text(['foo', 'bar']),
107
            '\n'
108
            'See also: bar, foo\n')
109
2432.1.27 by Robert Collins
Add a get_help_topic method to RegisteredTopic.
110
    def test_get_help_topic(self):
111
        """The help topic for a RegisteredTopic is its topic from construction."""
112
        topic = help_topics.RegisteredTopic('foobar')
113
        self.assertEqual('foobar', topic.get_help_topic())
114
        topic = help_topics.RegisteredTopic('baz')
115
        self.assertEqual('baz', topic.get_help_topic())
116
2432.1.8 by Robert Collins
HelpTopicContext now returns RegisteredTopic objects for get_topics calls.
117
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
118
class TestTopicIndex(tests.TestCase):
119
    """Tests for the HelpTopicIndex class."""
2432.1.1 by Robert Collins
Add a HelpTopicContext object.
120
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
121
    def test_default_constructable(self):
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
122
        index = help_topics.HelpTopicIndex()
2432.1.1 by Robert Collins
Add a HelpTopicContext object.
123
2432.1.8 by Robert Collins
HelpTopicContext now returns RegisteredTopic objects for get_topics calls.
124
    def test_get_topics_None(self):
125
        """Searching for None returns the basic help topic."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
126
        index = help_topics.HelpTopicIndex()
127
        topics = index.get_topics(None)
2432.1.8 by Robert Collins
HelpTopicContext now returns RegisteredTopic objects for get_topics calls.
128
        self.assertEqual(1, len(topics))
129
        self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
130
        self.assertEqual('basic', topics[0].topic)
131
132
    def test_get_topics_topics(self):
133
        """Searching for a string returns the matching string."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
134
        index = help_topics.HelpTopicIndex()
135
        topics = index.get_topics('topics')
2432.1.8 by Robert Collins
HelpTopicContext now returns RegisteredTopic objects for get_topics calls.
136
        self.assertEqual(1, len(topics))
137
        self.assertIsInstance(topics[0], help_topics.RegisteredTopic)
138
        self.assertEqual('topics', topics[0].topic)
139
140
    def test_get_topics_no_topic(self):
141
        """Searching for something not registered returns []."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
142
        index = help_topics.HelpTopicIndex()
143
        self.assertEqual([], index.get_topics('nothing by this name'))
144
2432.1.17 by Robert Collins
Add prefixes to HelpIndexes.
145
    def test_prefix(self):
146
        """TopicIndex has a prefix of ''."""
147
        index = help_topics.HelpTopicIndex()
148
        self.assertEqual('', index.prefix)
149
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
150
151
class TestCommandIndex(tests.TestCase):
152
    """Tests for the HelpCommandIndex class."""
2432.1.2 by Robert Collins
Add a HelpCommandContext class for help from commands.
153
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
154
    def test_default_constructable(self):
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
155
        index = commands.HelpCommandIndex()
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
156
2432.1.13 by Robert Collins
HelpCommandContext now implementes get_topics.
157
    def test_get_topics_None(self):
158
        """Searching for None returns an empty list."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
159
        index = commands.HelpCommandIndex()
160
        self.assertEqual([], index.get_topics(None))
2432.1.13 by Robert Collins
HelpCommandContext now implementes get_topics.
161
162
    def test_get_topics_rocks(self):
163
        """Searching for 'rocks' returns the cmd_rocks command instance."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
164
        index = commands.HelpCommandIndex()
165
        topics = index.get_topics('rocks')
2432.1.13 by Robert Collins
HelpCommandContext now implementes get_topics.
166
        self.assertEqual(1, len(topics))
167
        self.assertIsInstance(topics[0], builtins.cmd_rocks)
168
169
    def test_get_topics_no_topic(self):
170
        """Searching for something that is not a command returns []."""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
171
        index = commands.HelpCommandIndex()
172
        self.assertEqual([], index.get_topics('nothing by this name'))
173
2432.1.17 by Robert Collins
Add prefixes to HelpIndexes.
174
    def test_prefix(self):
175
        """CommandIndex has a prefix of 'commands/'."""
176
        index = commands.HelpCommandIndex()
177
        self.assertEqual('commands/', index.prefix)
178
2432.1.18 by Robert Collins
Add support for doing bzr help commands/COMMANDNAME.
179
    def test_get_topic_with_prefix(self):
180
        """Searching for commands/rocks returns the rocks command object."""
181
        index = commands.HelpCommandIndex()
182
        topics = index.get_topics('commands/rocks')
183
        self.assertEqual(1, len(topics))
184
        self.assertIsInstance(topics[0], builtins.cmd_rocks)
185
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
186
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
187
class TestHelpIndices(tests.TestCase):
188
    """Tests for the HelpIndices class."""
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
189
190
    def test_default_search_path(self):
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
191
        """The default search path should include internal indexs."""
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
192
        indices = help.HelpIndices()
2432.1.24 by Robert Collins
Add plugins as a help index.
193
        self.assertEqual(3, len(indices.search_path))
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
194
        # help topics should be searched in first.
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
195
        self.assertIsInstance(indices.search_path[0],
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
196
            help_topics.HelpTopicIndex)
2432.1.3 by Robert Collins
Create a HelpContexts object to do help lookups.
197
        # with commands being search second.
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
198
        self.assertIsInstance(indices.search_path[1],
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
199
            commands.HelpCommandIndex)
2432.1.24 by Robert Collins
Add plugins as a help index.
200
        # and plugins are a third index.
201
        self.assertIsInstance(indices.search_path[2],
202
            plugin.PluginsHelpIndex)
2432.1.5 by Robert Collins
Initial stub for topic searching.
203
204
    def test_search_for_unknown_topic_raises(self):
205
        """Searching for an unknown topic should raise NoHelpTopic."""
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
206
        indices = help.HelpIndices()
207
        indices.search_path = []
208
        error = self.assertRaises(errors.NoHelpTopic, indices.search, 'foo')
2432.1.5 by Robert Collins
Initial stub for topic searching.
209
        self.assertEqual('foo', error.topic)
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
210
211
    def test_search_calls_get_topic(self):
212
        """Searching should call get_topics in all indexes in order."""
213
        calls = []
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
214
        class RecordingIndex(object):
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
215
            def __init__(self, name):
2432.1.19 by Robert Collins
Ensure each HelpIndex has a unique prefix.
216
                self.prefix = name
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
217
            def get_topics(self, topic):
2432.1.19 by Robert Collins
Ensure each HelpIndex has a unique prefix.
218
                calls.append(('get_topics', self.prefix, topic))
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
219
                return ['something']
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
220
        index = help.HelpIndices()
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
221
        index.search_path = [RecordingIndex('1'), RecordingIndex('2')]
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
222
        # try with None
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
223
        index.search(None)
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
224
        self.assertEqual([
225
            ('get_topics', '1', None),
226
            ('get_topics', '2', None),
227
            ],
228
            calls)
229
        # and with a string
230
        del calls[:]
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
231
        index.search('bar')
2432.1.6 by Robert Collins
HelpContexts.search now invokes get_topics on each context.
232
        self.assertEqual([
233
            ('get_topics', '1', 'bar'),
234
            ('get_topics', '2', 'bar'),
235
            ],
236
            calls)
2432.1.7 by Robert Collins
HelpContexts.search now returns the found topics.
237
2432.1.20 by Robert Collins
Modify the result of HelpIndices.search to include the index each result was found in.
238
    def test_search_returns_index_and_results(self):
239
        """Searching should return help topics with their index"""
2432.1.15 by Robert Collins
Rename Context (in bzrlib.help) to Index, for a clearer name.
240
        class CannedIndex(object):
2432.1.19 by Robert Collins
Ensure each HelpIndex has a unique prefix.
241
            def __init__(self, prefix, search_result):
242
                self.prefix = prefix
2432.1.7 by Robert Collins
HelpContexts.search now returns the found topics.
243
                self.result = search_result
244
            def get_topics(self, topic):
245
                return self.result
2432.1.16 by Robert Collins
Correct spelling of Indexs to Indices.
246
        index = help.HelpIndices()
2432.1.20 by Robert Collins
Modify the result of HelpIndices.search to include the index each result was found in.
247
        index_one = CannedIndex('1', ['a'])
248
        index_two = CannedIndex('2', ['b', 'c'])
249
        index.search_path = [index_one, index_two]
250
        self.assertEqual([(index_one, 'a'), (index_two, 'b'), (index_two, 'c')],
251
            index.search(None))
2432.1.19 by Robert Collins
Ensure each HelpIndex has a unique prefix.
252
253
    def test_search_checks_for_duplicate_prefixes(self):
254
        """Its an error when there are multiple indices with the same prefix."""
255
        indices = help.HelpIndices()
256
        indices.search_path = [help_topics.HelpTopicIndex(),
257
            help_topics.HelpTopicIndex()]
258
        self.assertRaises(errors.DuplicateHelpPrefix, indices.search, None)