1
# Copyright (C) 2006 by Canonical Ltd
2
# -*- coding: utf-8 -*-
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.
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.
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
18
"""Black-box tests for bzr handling non-ascii characters."""
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
30
class TestNonAscii(TestCaseInTempDir):
31
"""Test that bzr handles files/committers/etc which are non-ascii."""
34
super(TestNonAscii, self).setUp()
35
self._orig_email = os.environ.get('BZREMAIL', None)
36
self._orig_encoding = bzrlib.user_encoding
38
bzrlib.user_encoding = self.encoding
39
email = self.info['committer'] + ' <joe@foo.com>'
40
os.environ['BZREMAIL'] = email.encode(bzrlib.user_encoding)
44
if self._orig_email is not None:
45
os.environ['BZREMAIL'] = self._orig_email
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()
52
def create_base(self):
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]:
62
except UnicodeEncodeError:
63
raise TestSkipped(('Unable to represent path %r'
64
' in filesystem encoding "%s"')
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))
76
open('a', 'wb').write('foo\n')
78
bzr('commit', '-m', 'adding a')
80
open('b', 'wb').write('non-ascii \xFF\xFF\xFC\xFB\x00 in b\n')
82
bzr('commit', '-m', self.info['message'])
84
open(fname, 'wb').write('unicode filename\n')
86
bzr('commit', '-m', u'And a unicode file\n')
88
def test_status(self):
89
bzr = self.run_bzr_decode
91
open(self.info['filename'], 'ab').write('added something\n')
93
self.assertEqual(u'modified:\n %s\n' % (self.info['filename'],), txt)
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)
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)
106
txt = self.run_bzr('cat', self.info['filename'])[0]
107
self.assertEqual('unicode filename\n', txt)
109
def test_cat_revision(self):
110
bzr = self.run_bzr_decode
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))
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))
121
def test_mkdir(self):
122
bzr = self.run_bzr_decode
124
txt = bzr('mkdir', self.info['directory'])
125
self.assertEqual(u'added %s\n' % self.info['directory'], txt)
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)
133
def test_relpath(self):
134
bzr = self.run_bzr_decode
136
txt = bzr('relpath', self.info['filename'])
137
self.assertEqual(self.info['filename'] + '\n', txt)
139
bzr('relpath', self.info['filename'], encoding='ascii', retcode=3)
141
def test_inventory(self):
142
bzr = self.run_bzr_decode
144
txt = bzr('inventory')
145
self.assertEqual(['a', 'b', self.info['filename']],
148
# inventory should fail if unable to encode
149
bzr('inventory', encoding='ascii', retcode=3)
151
# We don't really care about the ids themselves,
152
# but the command shouldn't fail
153
txt = bzr('inventory', '--show-ids')
155
def test_revno(self):
156
# There isn't a lot to test here, since revno should always
158
bzr = self.run_bzr_decode
160
self.assertEqual('3\n', bzr('revno'))
161
self.assertEqual('3\n', bzr('revno', encoding='ascii'))
163
def test_revision_info(self):
164
bzr = self.run_bzr_decode
166
bzr('revision-info', '-r', '1')
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')
173
bzr = self.run_bzr_decode
175
fname1 = self.info['filename']
176
fname2 = self.info['filename'] + '2'
177
dirname = self.info['directory']
179
# fname1 already exists
180
bzr('mv', 'a', fname1, retcode=3)
182
txt = bzr('mv', 'a', fname2)
183
self.assertEqual(u'a => %s\n' % fname2, txt)
184
self.failIfExists('a')
185
self.failUnlessExists(fname2)
187
bzr('commit', '-m', 'renamed to non-ascii')
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)]
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)
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')
209
# Make sure we can pull from paths that can't be encoded
210
bzr = self.run_bzr_decode
212
dirname1 = self.info['directory']
213
dirname2 = self.info['directory'] + '2'
214
bzr('branch', '.', dirname1)
215
bzr('branch', dirname1, dirname2)
218
open('a', 'ab').write('more text\n')
219
bzr('commit', '-m', 'mod a')
221
pwd = osutils.getcwd()
223
os.chdir(u'../' + dirname2)
226
self.assertEqual(u'Using saved location: %s/\n' % (pwd,), txt)
228
os.chdir('../' + dirname1)
229
open('a', 'ab').write('and yet more\n')
230
bzr('commit', '-m', 'modifying a by ' + self.info['committer'])
232
os.chdir('../' + dirname2)
233
# We should be able to pull, even if our encoding is bad
234
bzr('pull', '--verbose', encoding='ascii')
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
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.
245
dirname = self.info['directory']
248
open('a', 'ab').write('adding more text\n')
249
bzr('commit', '-m', 'added some stuff')
251
# TODO: check the output text is properly encoded
255
f.write('and a bit more: ')
256
f.write(dirname.encode('utf-8'))
260
bzr('commit', '-m', u'Added some ' + dirname)
261
bzr('push', '--verbose', encoding='ascii')
263
bzr('push', '--verbose', dirname + '2')
265
bzr('push', '--verbose', dirname + '3', encoding='ascii')
267
bzr('push', '--verbose', '--create-prefix', dirname + '4/' + dirname + '5')
268
bzr('push', '--verbose', '--create-prefix', dirname + '6/' + dirname + '7', encoding='ascii')
270
def test_renames(self):
271
bzr = self.run_bzr_decode
273
fname = self.info['filename'] + '2'
274
bzr('mv', 'a', fname)
276
self.assertEqual(u'a => %s\n' % fname, txt)
278
bzr('renames', retcode=3, encoding='ascii')
280
def test_remove(self):
281
bzr = self.run_bzr_decode
283
fname = self.info['filename']
284
txt = bzr('remove', fname, encoding='ascii')
286
def test_remove_verbose(self):
287
bzr = self.run_bzr_decode
289
fname = self.info['filename']
290
txt = bzr('remove', '--verbose', fname, encoding='ascii')
292
def test_file_id(self):
293
bzr = self.run_bzr_decode
295
fname = self.info['filename']
296
txt = bzr('file-id', fname)
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')
303
def test_file_path(self):
304
bzr = self.run_bzr_decode
306
# Create a directory structure
307
fname = self.info['filename']
308
dirname = self.info['directory']
310
bzr('mkdir', 'base/' + dirname)
311
path = '/'.join(['base', dirname, fname])
312
bzr('mv', fname, path)
313
bzr('commit', '-m', 'moving things around')
315
txt = bzr('file-path', path)
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')
322
def test_revision_history(self):
323
bzr = self.run_bzr_decode
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')
329
def test_ancestry(self):
330
bzr = self.run_bzr_decode
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')
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]
343
def test_deleted(self):
344
bzr = self.run_bzr_decode
346
fname = self.info['filename']
351
self.assertEqual(fname+'\n', txt)
353
txt = bzr('deleted', '--show-ids')
354
self.failUnless(txt.startswith(fname))
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)
361
def test_modified(self):
362
bzr = self.run_bzr_decode
364
fname = self.info['filename']
365
open(fname, 'ab').write('modified\n')
367
txt = bzr('modified')
368
self.assertEqual(fname+'\n', txt)
370
bzr('modified', encoding='ascii', retcode=3)
372
def test_added(self):
373
bzr = self.run_bzr_decode
375
fname = self.info['filename'] + '2'
376
open(fname, 'wb').write('added\n')
380
self.assertEqual(fname+'\n', txt)
382
bzr('added', encoding='ascii', retcode=3)
385
bzr = self.run_bzr_decode
387
dirname = self.info['directory']
390
bzr('branch', u'.', dirname)
395
self.failUnless(txt.endswith(dirname+'\n'))
397
txt = bzr('root', encoding='ascii', retcode=3)
400
bzr = self.run_bzr_decode
402
fname = self.info['filename']
405
self.assertNotEqual(-1, txt.find(self.info['committer']))
406
self.assertNotEqual(-1, txt.find(self.info['message']))
408
txt = bzr('log', '--verbose')
409
self.assertNotEqual(-1, txt.find(fname))
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')))
416
def test_touching_revisions(self):
417
bzr = self.run_bzr_decode
419
fname = self.info['filename']
420
txt = bzr('touching-revisions', fname)
421
self.assertEqual(u' 3 added %s\n' % (fname,), txt)
423
fname2 = self.info['filename'] + '2'
424
bzr('mv', fname, fname2)
425
bzr('commit', '-m', u'Renamed %s => %s' % (fname, fname2))
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)
433
bzr('touching-revisions', fname2, encoding='ascii', retcode=3)
436
bzr = self.run_bzr_decode
439
self.assertEqual(['a', 'b', self.info['filename']],
441
txt = bzr('ls', '--null')
442
self.assertEqual(['a', 'b', self.info['filename'], ''],
445
txt = bzr('ls', encoding='ascii', retcode=3)
446
txt = bzr('ls', '--null', encoding='ascii', retcode=3)
448
def test_unknowns(self):
449
bzr = self.run_bzr_decode
451
fname = self.info['filename'] + '2'
452
open(fname, 'wb').write('unknown\n')
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)
459
bzr('unknowns', encoding='ascii', retcode=3)
461
def test_ignore(self):
462
bzr = self.run_bzr_decode
464
fname2 = self.info['filename'] + '2.txt'
465
open(fname2, 'wb').write('ignored\n')
467
txt = bzr('unknowns')
468
self.assertEqual(u'"%s"\n' % (fname2,), txt)
470
bzr('ignore', './' + fname2)
471
txt = bzr('unknowns')
472
self.assertEqual(u'', txt)
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)
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)
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)
492
os.remove('.bzrignore')
493
bzr('ignore', self.info['filename'] + '*')
494
txt = bzr('unknowns')
495
self.assertEqual('', txt)