~michael-ellerman/bzr/mpe

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_non_ascii.py

[merge] bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006 by Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""Black-box tests for bzr handling non-ascii characters."""
 
19
 
 
20
import sys
 
21
import os
 
22
 
 
23
import bzrlib
 
24
import bzrlib.osutils as osutils
 
25
from bzrlib.tests import TestCaseInTempDir, TestSkipped
 
26
from bzrlib.trace import mutter, note
 
27
import bzrlib.urlutils as urlutils
 
28
 
 
29
 
 
30
class TestNonAscii(TestCaseInTempDir):
 
31
    """Test that bzr handles files/committers/etc which are non-ascii."""
 
32
 
 
33
    def setUp(self):
 
34
        super(TestNonAscii, self).setUp()
 
35
        self._orig_email = os.environ.get('BZREMAIL', None)
 
36
        self._orig_encoding = bzrlib.user_encoding
 
37
 
 
38
        bzrlib.user_encoding = self.encoding
 
39
        email = self.info['committer'] + ' <joe@foo.com>'
 
40
        os.environ['BZREMAIL'] = email.encode(bzrlib.user_encoding)
 
41
        self.create_base()
 
42
 
 
43
    def tearDown(self):
 
44
        if self._orig_email is not None:
 
45
            os.environ['BZREMAIL'] = self._orig_email
 
46
        else:
 
47
            if os.environ.get('BZREMAIL', None) is not None:
 
48
                del os.environ['BZREMAIL']
 
49
        bzrlib.user_encoding = self._orig_encoding
 
50
        super(TestNonAscii, self).tearDown()
 
51
 
 
52
    def create_base(self):
 
53
        bzr = self.run_bzr
 
54
 
 
55
        fs_enc = sys.getfilesystemencoding()
 
56
        terminal_enc = osutils.get_terminal_encoding()
 
57
        fname = self.info['filename']
 
58
        dir_name = self.info['directory']
 
59
        for thing in [fname, dir_name]:
 
60
            try:
 
61
                thing.encode(fs_enc)
 
62
            except UnicodeEncodeError:
 
63
                raise TestSkipped(('Unable to represent path %r'
 
64
                                   ' in filesystem encoding "%s"')
 
65
                                    % (thing, fs_enc))
 
66
            try:
 
67
                thing.encode(terminal_enc)
 
68
            except UnicodeEncodeError:
 
69
                raise TestSkipped(('Unable to represent path %r'
 
70
                                   ' in terminal encoding "%s"'
 
71
                                   ' (even though it is valid in'
 
72
                                   ' filesystem encoding "%s")')
 
73
                                   % (thing, terminal_enc, fs_enc))
 
74
 
 
75
        bzr('init')
 
76
        open('a', 'wb').write('foo\n')
 
77
        bzr('add', 'a')
 
78
        bzr('commit', '-m', 'adding a')
 
79
 
 
80
        open('b', 'wb').write('non-ascii \xFF\xFF\xFC\xFB\x00 in b\n')
 
81
        bzr('add', 'b')
 
82
        bzr('commit', '-m', self.info['message'])
 
83
 
 
84
        open(fname, 'wb').write('unicode filename\n')
 
85
        bzr('add', fname)
 
86
        bzr('commit', '-m', u'And a unicode file\n')
 
87
 
 
88
    def test_status(self):
 
89
        bzr = self.run_bzr_decode
 
90
 
 
91
        open(self.info['filename'], 'ab').write('added something\n')
 
92
        txt = bzr('status')
 
93
        self.assertEqual(u'modified:\n  %s\n' % (self.info['filename'],), txt)
 
94
 
 
95
        txt = bzr('status', encoding='ascii')
 
96
        expected = u'modified:\n  %s\n' % (
 
97
                    self.info['filename'].encode('ascii', 'replace'),)
 
98
        self.assertEqual(expected, txt)
 
99
 
 
100
    def test_cat(self):
 
101
        # bzr cat shouldn't change the contents
 
102
        # using run_bzr since that doesn't decode
 
103
        txt = self.run_bzr('cat', 'b')[0]
 
104
        self.assertEqual('non-ascii \xFF\xFF\xFC\xFB\x00 in b\n', txt)
 
105
 
 
106
        txt = self.run_bzr('cat', self.info['filename'])[0]
 
107
        self.assertEqual('unicode filename\n', txt)
 
108
 
 
109
    def test_cat_revision(self):
 
110
        bzr = self.run_bzr_decode
 
111
 
 
112
        committer = self.info['committer']
 
113
        txt = bzr('cat-revision', '-r', '1')
 
114
        self.failUnless(committer in txt,
 
115
                        'failed to find %r in %r' % (committer, txt))
 
116
 
 
117
        msg = self.info['message']
 
118
        txt = bzr('cat-revision', '-r', '2')
 
119
        self.failUnless(msg in txt, 'failed to find %r in %r' % (msg, txt))
 
120
 
 
121
    def test_mkdir(self):
 
122
        bzr = self.run_bzr_decode
 
123
 
 
124
        txt = bzr('mkdir', self.info['directory'])
 
125
        self.assertEqual(u'added %s\n' % self.info['directory'], txt)
 
126
 
 
127
        # The text should be garbled, but the command should succeed
 
128
        txt = bzr('mkdir', self.info['directory'] + '2', encoding='ascii')
 
129
        expected = u'added %s2\n' % (self.info['directory'],)
 
130
        expected = expected.encode('ascii', 'replace')
 
131
        self.assertEqual(expected, txt)
 
132
 
 
133
    def test_relpath(self):
 
134
        bzr = self.run_bzr_decode
 
135
 
 
136
        txt = bzr('relpath', self.info['filename'])
 
137
        self.assertEqual(self.info['filename'] + '\n', txt)
 
138
 
 
139
        bzr('relpath', self.info['filename'], encoding='ascii', retcode=3)
 
140
 
 
141
    def test_inventory(self):
 
142
        bzr = self.run_bzr_decode
 
143
 
 
144
        txt = bzr('inventory')
 
145
        self.assertEqual(['a', 'b', self.info['filename']],
 
146
                         txt.splitlines())
 
147
 
 
148
        # inventory should fail if unable to encode
 
149
        bzr('inventory', encoding='ascii', retcode=3)
 
150
 
 
151
        # We don't really care about the ids themselves,
 
152
        # but the command shouldn't fail
 
153
        txt = bzr('inventory', '--show-ids')
 
154
 
 
155
    def test_revno(self):
 
156
        # There isn't a lot to test here, since revno should always
 
157
        # be an integer
 
158
        bzr = self.run_bzr_decode
 
159
 
 
160
        self.assertEqual('3\n', bzr('revno'))
 
161
        self.assertEqual('3\n', bzr('revno', encoding='ascii'))
 
162
 
 
163
    def test_revision_info(self):
 
164
        bzr = self.run_bzr_decode
 
165
 
 
166
        bzr('revision-info', '-r', '1')
 
167
 
 
168
        # TODO: jam 20060105 If we support revisions with non-ascii characters,
 
169
        # this should be strict and fail.
 
170
        bzr('revision-info', '-r', '1', encoding='ascii')
 
171
 
 
172
    def test_mv(self):
 
173
        bzr = self.run_bzr_decode
 
174
 
 
175
        fname1 = self.info['filename']
 
176
        fname2 = self.info['filename'] + '2'
 
177
        dirname = self.info['directory']
 
178
 
 
179
        # fname1 already exists
 
180
        bzr('mv', 'a', fname1, retcode=3)
 
181
 
 
182
        txt = bzr('mv', 'a', fname2)
 
183
        self.assertEqual(u'a => %s\n' % fname2, txt)
 
184
        self.failIfExists('a')
 
185
        self.failUnlessExists(fname2)
 
186
 
 
187
        bzr('commit', '-m', 'renamed to non-ascii')
 
188
 
 
189
        bzr('mkdir', dirname)
 
190
        txt = bzr('mv', fname1, fname2, dirname)
 
191
        self.assertEqual([u'%s => %s/%s' % (fname1, dirname, fname1),
 
192
                          u'%s => %s/%s' % (fname2, dirname, fname2)]
 
193
                         , txt.splitlines())
 
194
 
 
195
        # The rename should still succeed
 
196
        newpath = u'%s/%s' % (dirname, fname2)
 
197
        txt = bzr('mv', newpath, 'a', encoding='ascii')
 
198
        self.failUnlessExists('a')
 
199
        self.assertEqual(newpath.encode('ascii', 'replace') + ' => a\n', txt)
 
200
 
 
201
    def test_branch(self):
 
202
        # We should be able to branch into a directory that
 
203
        # has a unicode name, even if we can't display the name
 
204
        bzr = self.run_bzr_decode
 
205
        bzr('branch', u'.', self.info['directory'])
 
206
        bzr('branch', u'.', self.info['directory'] + '2', encoding='ascii')
 
207
 
 
208
    def test_pull(self):
 
209
        # Make sure we can pull from paths that can't be encoded
 
210
        bzr = self.run_bzr_decode
 
211
 
 
212
        dirname1 = self.info['directory']
 
213
        dirname2 = self.info['directory'] + '2'
 
214
        bzr('branch', '.', dirname1)
 
215
        bzr('branch', dirname1, dirname2)
 
216
 
 
217
        os.chdir(dirname1)
 
218
        open('a', 'ab').write('more text\n')
 
219
        bzr('commit', '-m', 'mod a')
 
220
 
 
221
        pwd = osutils.getcwd()
 
222
 
 
223
        os.chdir(u'../' + dirname2)
 
224
        txt = bzr('pull')
 
225
 
 
226
        self.assertEqual(u'Using saved location: %s/\n' % (pwd,), txt)
 
227
 
 
228
        os.chdir('../' + dirname1)
 
229
        open('a', 'ab').write('and yet more\n')
 
230
        bzr('commit', '-m', 'modifying a by ' + self.info['committer'])
 
231
 
 
232
        os.chdir('../' + dirname2)
 
233
        # We should be able to pull, even if our encoding is bad
 
234
        bzr('pull', '--verbose', encoding='ascii')
 
235
 
 
236
    def test_push(self):
 
237
        # TODO: Test push to an SFTP location
 
238
        # Make sure we can pull from paths that can't be encoded
 
239
        bzr = self.run_bzr_decode
 
240
 
 
241
        # TODO: jam 20060427 For drastically improving performance, we probably
 
242
        #       could create a local repository, so it wouldn't have to copy
 
243
        #       the files around as much.
 
244
 
 
245
        dirname = self.info['directory']
 
246
        bzr('push', dirname)
 
247
 
 
248
        open('a', 'ab').write('adding more text\n')
 
249
        bzr('commit', '-m', 'added some stuff')
 
250
 
 
251
        # TODO: check the output text is properly encoded
 
252
        bzr('push')
 
253
 
 
254
        f = open('a', 'ab')
 
255
        f.write('and a bit more: ')
 
256
        f.write(dirname.encode('utf-8'))
 
257
        f.write('\n')
 
258
        f.close()
 
259
 
 
260
        bzr('commit', '-m', u'Added some ' + dirname)
 
261
        bzr('push', '--verbose', encoding='ascii')
 
262
 
 
263
        bzr('push', '--verbose', dirname + '2')
 
264
 
 
265
        bzr('push', '--verbose', dirname + '3', encoding='ascii')
 
266
 
 
267
        bzr('push', '--verbose', '--create-prefix', dirname + '4/' + dirname + '5')
 
268
        bzr('push', '--verbose', '--create-prefix', dirname + '6/' + dirname + '7', encoding='ascii')
 
269
 
 
270
    def test_renames(self):
 
271
        bzr = self.run_bzr_decode
 
272
 
 
273
        fname = self.info['filename'] + '2'
 
274
        bzr('mv', 'a', fname)
 
275
        txt = bzr('renames')
 
276
        self.assertEqual(u'a => %s\n' % fname, txt)
 
277
 
 
278
        bzr('renames', retcode=3, encoding='ascii')
 
279
 
 
280
    def test_remove(self):
 
281
        bzr = self.run_bzr_decode
 
282
 
 
283
        fname = self.info['filename']
 
284
        txt = bzr('remove', fname, encoding='ascii')
 
285
 
 
286
    def test_remove_verbose(self):
 
287
        bzr = self.run_bzr_decode
 
288
 
 
289
        fname = self.info['filename']
 
290
        txt = bzr('remove', '--verbose', fname, encoding='ascii')
 
291
 
 
292
    def test_file_id(self):
 
293
        bzr = self.run_bzr_decode
 
294
 
 
295
        fname = self.info['filename']
 
296
        txt = bzr('file-id', fname)
 
297
 
 
298
        # TODO: jam 20060106 We don't support non-ascii file ids yet, 
 
299
        #       so there is nothing which would fail in ascii encoding
 
300
        #       This *should* be retcode=3
 
301
        txt = bzr('file-id', fname, encoding='ascii')
 
302
 
 
303
    def test_file_path(self):
 
304
        bzr = self.run_bzr_decode
 
305
 
 
306
        # Create a directory structure
 
307
        fname = self.info['filename']
 
308
        dirname = self.info['directory']
 
309
        bzr('mkdir', 'base')
 
310
        bzr('mkdir', 'base/' + dirname)
 
311
        path = '/'.join(['base', dirname, fname])
 
312
        bzr('mv', fname, path)
 
313
        bzr('commit', '-m', 'moving things around')
 
314
 
 
315
        txt = bzr('file-path', path)
 
316
 
 
317
        # TODO: jam 20060106 We don't support non-ascii file ids yet, 
 
318
        #       so there is nothing which would fail in ascii encoding
 
319
        #       This *should* be retcode=3
 
320
        txt = bzr('file-path', path, encoding='ascii')
 
321
 
 
322
    def test_revision_history(self):
 
323
        bzr = self.run_bzr_decode
 
324
 
 
325
        # TODO: jam 20060106 We don't support non-ascii revision ids yet, 
 
326
        #       so there is nothing which would fail in ascii encoding
 
327
        txt = bzr('revision-history')
 
328
 
 
329
    def test_ancestry(self):
 
330
        bzr = self.run_bzr_decode
 
331
 
 
332
        # TODO: jam 20060106 We don't support non-ascii revision ids yet, 
 
333
        #       so there is nothing which would fail in ascii encoding
 
334
        txt = bzr('ancestry')
 
335
 
 
336
    def test_diff(self):
 
337
        # TODO: jam 20060106 diff is a difficult one to test, because it 
 
338
        #       shouldn't encode the file contents, but it needs some sort
 
339
        #       of encoding for the paths, etc which are displayed.
 
340
        open(self.info['filename'], 'ab').write('newline\n')
 
341
        txt = self.run_bzr('diff', retcode=1)[0]
 
342
 
 
343
    def test_deleted(self):
 
344
        bzr = self.run_bzr_decode
 
345
 
 
346
        fname = self.info['filename']
 
347
        os.remove(fname)
 
348
        bzr('rm', fname)
 
349
 
 
350
        txt = bzr('deleted')
 
351
        self.assertEqual(fname+'\n', txt)
 
352
 
 
353
        txt = bzr('deleted', '--show-ids')
 
354
        self.failUnless(txt.startswith(fname))
 
355
 
 
356
        # Deleted should fail if cannot decode
 
357
        # Because it is giving the exact paths
 
358
        # which might be used by a front end
 
359
        bzr('deleted', encoding='ascii', retcode=3)
 
360
 
 
361
    def test_modified(self):
 
362
        bzr = self.run_bzr_decode
 
363
 
 
364
        fname = self.info['filename']
 
365
        open(fname, 'ab').write('modified\n')
 
366
 
 
367
        txt = bzr('modified')
 
368
        self.assertEqual(fname+'\n', txt)
 
369
 
 
370
        bzr('modified', encoding='ascii', retcode=3)
 
371
 
 
372
    def test_added(self):
 
373
        bzr = self.run_bzr_decode
 
374
 
 
375
        fname = self.info['filename'] + '2'
 
376
        open(fname, 'wb').write('added\n')
 
377
        bzr('add', fname)
 
378
 
 
379
        txt = bzr('added')
 
380
        self.assertEqual(fname+'\n', txt)
 
381
 
 
382
        bzr('added', encoding='ascii', retcode=3)
 
383
 
 
384
    def test_root(self):
 
385
        bzr = self.run_bzr_decode
 
386
 
 
387
        dirname = self.info['directory']
 
388
        bzr('root')
 
389
 
 
390
        bzr('branch', u'.', dirname)
 
391
 
 
392
        os.chdir(dirname)
 
393
 
 
394
        txt = bzr('root')
 
395
        self.failUnless(txt.endswith(dirname+'\n'))
 
396
 
 
397
        txt = bzr('root', encoding='ascii', retcode=3)
 
398
 
 
399
    def test_log(self):
 
400
        bzr = self.run_bzr_decode
 
401
 
 
402
        fname = self.info['filename']
 
403
 
 
404
        txt = bzr('log')
 
405
        self.assertNotEqual(-1, txt.find(self.info['committer']))
 
406
        self.assertNotEqual(-1, txt.find(self.info['message']))
 
407
 
 
408
        txt = bzr('log', '--verbose')
 
409
        self.assertNotEqual(-1, txt.find(fname))
 
410
 
 
411
        # Make sure log doesn't fail even if we can't write out
 
412
        txt = bzr('log', '--verbose', encoding='ascii')
 
413
        self.assertEqual(-1, txt.find(fname))
 
414
        self.assertNotEqual(-1, txt.find(fname.encode('ascii', 'replace')))
 
415
 
 
416
    def test_touching_revisions(self):
 
417
        bzr = self.run_bzr_decode
 
418
 
 
419
        fname = self.info['filename']
 
420
        txt = bzr('touching-revisions', fname)
 
421
        self.assertEqual(u'     3 added %s\n' % (fname,), txt)
 
422
 
 
423
        fname2 = self.info['filename'] + '2'
 
424
        bzr('mv', fname, fname2)
 
425
        bzr('commit', '-m', u'Renamed %s => %s' % (fname, fname2))
 
426
 
 
427
        txt = bzr('touching-revisions', fname2)
 
428
        expected_txt = (u'     3 added %s\n' 
 
429
                        u'     4 renamed %s => %s\n'
 
430
                        % (fname, fname, fname2))
 
431
        self.assertEqual(expected_txt, txt)
 
432
 
 
433
        bzr('touching-revisions', fname2, encoding='ascii', retcode=3)
 
434
 
 
435
    def test_ls(self):
 
436
        bzr = self.run_bzr_decode
 
437
 
 
438
        txt = bzr('ls')
 
439
        self.assertEqual(['a', 'b', self.info['filename']],
 
440
                         txt.splitlines())
 
441
        txt = bzr('ls', '--null')
 
442
        self.assertEqual(['a', 'b', self.info['filename'], ''],
 
443
                         txt.split('\0'))
 
444
 
 
445
        txt = bzr('ls', encoding='ascii', retcode=3)
 
446
        txt = bzr('ls', '--null', encoding='ascii', retcode=3)
 
447
 
 
448
    def test_unknowns(self):
 
449
        bzr = self.run_bzr_decode
 
450
 
 
451
        fname = self.info['filename'] + '2'
 
452
        open(fname, 'wb').write('unknown\n')
 
453
 
 
454
        # TODO: jam 20060112 bzr unknowns is the only one which 
 
455
        #       quotes paths do we really want it to?
 
456
        txt = bzr('unknowns')
 
457
        self.assertEqual(u'"%s"\n' % (fname,), txt)
 
458
 
 
459
        bzr('unknowns', encoding='ascii', retcode=3)
 
460
 
 
461
    def test_ignore(self):
 
462
        bzr = self.run_bzr_decode
 
463
 
 
464
        fname2 = self.info['filename'] + '2.txt'
 
465
        open(fname2, 'wb').write('ignored\n')
 
466
 
 
467
        txt = bzr('unknowns')
 
468
        self.assertEqual(u'"%s"\n' % (fname2,), txt)
 
469
 
 
470
        bzr('ignore', './' + fname2)
 
471
        txt = bzr('unknowns')
 
472
        self.assertEqual(u'', txt)
 
473
 
 
474
        fname3 = self.info['filename'] + '3.txt'
 
475
        open(fname3, 'wb').write('unknown 3\n')
 
476
        txt = bzr('unknowns')
 
477
        self.assertEqual(u'"%s"\n' % (fname3,), txt)
 
478
 
 
479
        # Ignore should not care what the encoding is
 
480
        # (right now it doesn't print anything)
 
481
        bzr('ignore', fname3, encoding='ascii')
 
482
        txt = bzr('unknowns')
 
483
        self.assertEqual('', txt)
 
484
 
 
485
        # Now try a wildcard match
 
486
        fname4 = self.info['filename'] + '4.txt'
 
487
        open(fname4, 'wb').write('unknown 4\n')
 
488
        bzr('ignore', '*.txt')
 
489
        txt = bzr('unknowns')
 
490
        self.assertEqual('', txt)
 
491
 
 
492
        os.remove('.bzrignore')
 
493
        bzr('ignore', self.info['filename'] + '*')
 
494
        txt = bzr('unknowns')
 
495
        self.assertEqual('', txt)
 
496
 
 
497