~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tests/test_bashcomp.py

  • Committer: Ian Clatworthy
  • Date: 2009-09-02 16:03:51 UTC
  • mto: (4634.39.1 pdf-chm-docs)
  • mto: This revision was merged to the branch mainline in revision 4689.
  • Revision ID: ian.clatworthy@canonical.com-20090902160351-sxptcz3ttc1aencw
first cut at pdf docs via sphinx

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 by 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
 
from bzrlib.tests import TestCase, TestCaseWithTransport, Feature
18
 
from bzrlib import commands
19
 
from StringIO import StringIO
20
 
from ..bashcomp import *
21
 
import bzrlib
22
 
import os
23
 
import subprocess
24
 
 
25
 
 
26
 
class _BashFeature(Feature):
27
 
    """Feature testing whether a bash executable is available."""
28
 
 
29
 
    bash_paths = ['/bin/bash', '/usr/bin/bash']
30
 
 
31
 
    def __init__(self):
32
 
        super(_BashFeature, self).__init__()
33
 
        self.bash_path = None
34
 
 
35
 
    def available(self):
36
 
        if self.bash_path is not None:
37
 
            return self.bash_path is not False
38
 
        for path in self.bash_paths:
39
 
            if os.access(path, os.X_OK):
40
 
                self.bash_path = path
41
 
                return True
42
 
        self.bash_path = False
43
 
        return False
44
 
 
45
 
    def feature_name(self):
46
 
        return 'bash'
47
 
 
48
 
BashFeature = _BashFeature()
49
 
 
50
 
 
51
 
class BashCompletionMixin(object):
52
 
    """Component for testing execution of a bash completion script."""
53
 
 
54
 
    _test_needs_features = [BashFeature]
55
 
 
56
 
    def complete(self, words, cword=-1):
57
 
        """Perform a bash completion.
58
 
 
59
 
        :param words: a list of words representing the current command.
60
 
        :param cword: the current word to complete, defaults to the last one.
61
 
        """
62
 
        if self.script is None:
63
 
            self.script = self.get_script()
64
 
        proc = subprocess.Popen([BashFeature.bash_path, '--noprofile'],
65
 
                                stdin=subprocess.PIPE,
66
 
                                stdout=subprocess.PIPE,
67
 
                                stderr=subprocess.PIPE)
68
 
        if cword < 0:
69
 
            cword = len(words) + cword
70
 
        input = '%s\n' % self.script
71
 
        input += ('COMP_WORDS=( %s )\n' %
72
 
                  ' '.join(["'"+w.replace("'", "'\\''")+"'" for w in words]))
73
 
        input += 'COMP_CWORD=%d\n' % cword
74
 
        input += '%s\n' % getattr(self, 'script_name', '_bzr')
75
 
        input += 'echo ${#COMPREPLY[*]}\n'
76
 
        input += "IFS=$'\\n'\n"
77
 
        input += 'echo "${COMPREPLY[*]}"\n'
78
 
        (out, err) = proc.communicate(input)
79
 
        if '' != err:
80
 
            raise AssertionError('Unexpected error message:\n%s' % err)
81
 
        self.assertEqual('', err, 'No messages to standard error')
82
 
        #import sys
83
 
        #print >>sys.stdout, '---\n%s\n---\n%s\n---\n' % (input, out)
84
 
        lines = out.split('\n')
85
 
        nlines = int(lines[0])
86
 
        del lines[0]
87
 
        self.assertEqual('', lines[-1], 'Newline at end')
88
 
        del lines[-1]
89
 
        if nlines == 0 and len(lines) == 1 and lines[0] == '':
90
 
            del lines[0]
91
 
        self.assertEqual(nlines, len(lines), 'No newlines in generated words')
92
 
        self.completion_result = set(lines)
93
 
        return self.completion_result
94
 
 
95
 
    def assertCompletionEquals(self, *words):
96
 
        self.assertEqual(set(words), self.completion_result)
97
 
 
98
 
    def assertCompletionContains(self, *words):
99
 
        missing = set(words) - self.completion_result
100
 
        if missing:
101
 
            raise AssertionError('Completion should contain %r but it has %r'
102
 
                                 % (missing, self.completion_result))
103
 
 
104
 
    def assertCompletionOmits(self, *words):
105
 
        surplus = set(words) & self.completion_result
106
 
        if surplus:
107
 
            raise AssertionError('Completion should omit %r but it has %r'
108
 
                                 % (surplus, res, self.completion_result))
109
 
 
110
 
    def get_script(self):
111
 
        out = StringIO()
112
 
        bash_completion_function(out, function_only=True)
113
 
        return out.getvalue()
114
 
 
115
 
 
116
 
class TestBashCompletion(TestCase, BashCompletionMixin):
117
 
    """Test bash completions that don't execute bzr."""
118
 
 
119
 
    def __init__(self, methodName='testMethod'):
120
 
        super(TestBashCompletion, self).__init__(methodName)
121
 
        self.script = None
122
 
 
123
 
    def setUp(self):
124
 
        super(TestBashCompletion, self).setUp()
125
 
        commands.install_bzr_command_hooks()
126
 
 
127
 
    def test_simple_scipt(self):
128
 
        """Ensure that the test harness works as expected"""
129
 
        self.script = """
130
 
_bzr() {
131
 
    COMPREPLY=()
132
 
    # add all words in reverse order, with some markup around them
133
 
    for ((i = ${#COMP_WORDS[@]}; i > 0; --i)); do
134
 
        COMPREPLY+=( "-${COMP_WORDS[i-1]}+" )
135
 
    done
136
 
    # and append the current word
137
 
    COMPREPLY+=( "+${COMP_WORDS[COMP_CWORD]}-" )
138
 
}
139
 
"""
140
 
        self.complete(['foo', '"bar', "'baz"], cword=1)
141
 
        self.assertCompletionEquals("-'baz+", '-"bar+', '-foo+', '+"bar-')
142
 
 
143
 
    def test_cmd_ini(self):
144
 
        self.complete(['bzr', 'ini'])
145
 
        self.assertCompletionContains('init', 'init-repo', 'init-repository')
146
 
        self.assertCompletionOmits('commit')
147
 
 
148
 
    def test_init_opts(self):
149
 
        self.complete(['bzr', 'init', '-'])
150
 
        self.assertCompletionContains('-h', '--2a', '--format=2a')
151
 
 
152
 
    def test_global_opts(self):
153
 
        self.complete(['bzr', '-', 'init'], cword=1)
154
 
        self.assertCompletionContains('--no-plugins', '--builtin')
155
 
 
156
 
    def test_commit_dashm(self):
157
 
        self.complete(['bzr', 'commit', '-m'])
158
 
        self.assertCompletionEquals('-m')
159
 
 
160
 
    def test_status_negated(self):
161
 
        self.complete(['bzr', 'status', '--n'])
162
 
        self.assertCompletionContains('--no-versioned', '--no-verbose')
163
 
 
164
 
    def test_init_format_any(self):
165
 
        self.complete(['bzr', 'init', '--format', '=', 'directory'], cword=3)
166
 
        self.assertCompletionContains('1.9', '2a')
167
 
 
168
 
    def test_init_format_2(self):
169
 
        self.complete(['bzr', 'init', '--format', '=', '2', 'directory'],
170
 
                      cword=4)
171
 
        self.assertCompletionContains('2a')
172
 
        self.assertCompletionOmits('1.9')
173
 
 
174
 
 
175
 
class TestBashCompletionInvoking(TestCaseWithTransport, BashCompletionMixin):
176
 
    """Test bash completions that might execute bzr.
177
 
 
178
 
    Only the syntax ``$(bzr ...`` is supported so far. The bzr command
179
 
    will be replaced by the bzr instance running this selftest.
180
 
    """
181
 
 
182
 
    def __init__(self, methodName='testMethod'):
183
 
        super(TestBashCompletionInvoking, self).__init__(methodName)
184
 
        self.script = None
185
 
 
186
 
    def setUp(self):
187
 
        super(TestBashCompletionInvoking, self).setUp()
188
 
        commands.install_bzr_command_hooks()
189
 
 
190
 
    def get_script(self):
191
 
        s = super(TestBashCompletionInvoking, self).get_script()
192
 
        return s.replace("$(bzr ", "$('%s' " % self.get_bzr_path())
193
 
 
194
 
    def test_revspec_tag_all(self):
195
 
        wt = self.make_branch_and_tree('.', format='dirstate-tags')
196
 
        wt.branch.tags.set_tag('tag1', 'null:')
197
 
        wt.branch.tags.set_tag('tag2', 'null:')
198
 
        wt.branch.tags.set_tag('3tag', 'null:')
199
 
        self.complete(['bzr', 'log', '-r', 'tag', ':'])
200
 
        self.assertCompletionEquals('tag1', 'tag2', '3tag')
201
 
 
202
 
    def test_revspec_tag_prefix(self):
203
 
        wt = self.make_branch_and_tree('.', format='dirstate-tags')
204
 
        wt.branch.tags.set_tag('tag1', 'null:')
205
 
        wt.branch.tags.set_tag('tag2', 'null:')
206
 
        wt.branch.tags.set_tag('3tag', 'null:')
207
 
        self.complete(['bzr', 'log', '-r', 'tag', ':', 't'])
208
 
        self.assertCompletionEquals('tag1', 'tag2')
209
 
 
210
 
 
211
 
class TestBashCodeGen(TestCase):
212
 
 
213
 
    def test_command_names(self):
214
 
        data = CompletionData()
215
 
        bar = CommandData('bar')
216
 
        bar.aliases.append('baz')
217
 
        data.commands.append(bar)
218
 
        data.commands.append(CommandData('foo'))
219
 
        cg = BashCodeGen(data)
220
 
        self.assertEqual('bar baz foo', cg.command_names())
221
 
 
222
 
    def test_debug_output(self):
223
 
        data = CompletionData()
224
 
        self.assertEqual('', BashCodeGen(data, debug=False).debug_output())
225
 
        self.assertTrue(BashCodeGen(data, debug=True).debug_output())
226
 
 
227
 
    def test_bzr_version(self):
228
 
        data = CompletionData()
229
 
        cg = BashCodeGen(data)
230
 
        self.assertEqual('%s.' % bzrlib.version_string, cg.bzr_version())
231
 
        data.plugins['foo'] = PluginData('foo', '1.0')
232
 
        data.plugins['bar'] = PluginData('bar', '2.0')
233
 
        cg = BashCodeGen(data)
234
 
        self.assertEqual('''\
235
 
%s and the following plugins:
236
 
# bar 2.0
237
 
# foo 1.0''' % bzrlib.version_string, cg.bzr_version())
238
 
 
239
 
    def test_global_options(self):
240
 
        data = CompletionData()
241
 
        data.global_options.add('--foo')
242
 
        data.global_options.add('--bar')
243
 
        cg = BashCodeGen(data)
244
 
        self.assertEqual('--bar --foo', cg.global_options())
245
 
 
246
 
    def test_command_cases(self):
247
 
        data = CompletionData()
248
 
        bar = CommandData('bar')
249
 
        bar.aliases.append('baz')
250
 
        bar.options.append(OptionData('--opt'))
251
 
        data.commands.append(bar)
252
 
        data.commands.append(CommandData('foo'))
253
 
        cg = BashCodeGen(data)
254
 
        self.assertEqualDiff('''\
255
 
\tbar|baz)
256
 
\t\tcmdOpts='--opt'
257
 
\t\t;;
258
 
\tfoo)
259
 
\t\tcmdOpts=''
260
 
\t\t;;
261
 
''', cg.command_cases())
262
 
 
263
 
    def test_command_case(self):
264
 
        cmd = CommandData('cmd')
265
 
        cmd.plugin = PluginData('plugger', '1.0')
266
 
        bar = OptionData('--bar')
267
 
        bar.registry_keys = ['that', 'this']
268
 
        bar.error_messages.append('Some error message')
269
 
        cmd.options.append(bar)
270
 
        cmd.options.append(OptionData('--foo'))
271
 
        data = CompletionData()
272
 
        data.commands.append(cmd)
273
 
        cg = BashCodeGen(data)
274
 
        self.assertEqualDiff('''\
275
 
\tcmd)
276
 
\t\t# plugin "plugger 1.0"
277
 
\t\t# Some error message
278
 
\t\tcmdOpts='--bar=that --bar=this --foo'
279
 
\t\tcase $curOpt in
280
 
\t\t\t--bar) optEnums='that this' ;;
281
 
\t\tesac
282
 
\t\t;;
283
 
''', cg.command_case(cmd))
284
 
 
285
 
 
286
 
class TestDataCollector(TestCase):
287
 
 
288
 
    def setUp(self):
289
 
        super(TestDataCollector, self).setUp()
290
 
        commands.install_bzr_command_hooks()
291
 
 
292
 
    def test_global_options(self):
293
 
        dc = DataCollector()
294
 
        dc.global_options()
295
 
        self.assertSubset(['--no-plugins', '--builtin'],
296
 
                           dc.data.global_options)
297
 
 
298
 
    def test_commands(self):
299
 
        dc = DataCollector()
300
 
        dc.commands()
301
 
        self.assertSubset(['init', 'init-repo', 'init-repository'],
302
 
                           dc.data.all_command_aliases())
303
 
 
304
 
    def test_commit_dashm(self):
305
 
        dc = DataCollector()
306
 
        cmd = dc.command('commit')
307
 
        self.assertSubset(['-m'],
308
 
                           [str(o) for o in cmd.options])
309
 
 
310
 
    def test_status_negated(self):
311
 
        dc = DataCollector()
312
 
        cmd = dc.command('status')
313
 
        self.assertSubset(['--no-versioned', '--no-verbose'],
314
 
                           [str(o) for o in cmd.options])
315
 
 
316
 
    def test_init_format(self):
317
 
        dc = DataCollector()
318
 
        cmd = dc.command('init')
319
 
        for opt in cmd.options:
320
 
            if opt.name == '--format':
321
 
                self.assertSubset(['2a'], opt.registry_keys)
322
 
                return
323
 
        raise AssertionError('Option --format not found')