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
from bzrlib.tests import TestCaseInTempDir, TestSkipped
25
from bzrlib.trace import mutter, note
26
import bzrlib.urlutils as urlutils
29
class TestNonAscii(TestCaseInTempDir):
30
"""Test that bzr handles files/committers/etc which are non-ascii."""
33
super(TestNonAscii, self).setUp()
34
self._orig_email = os.environ.get('BZREMAIL', None)
35
self._orig_encoding = bzrlib.user_encoding
37
bzrlib.user_encoding = self.encoding
38
email = self.info['committer'] + ' <joe@foo.com>'
39
os.environ['BZREMAIL'] = email.encode(bzrlib.user_encoding)
43
if self._orig_email is not None:
44
os.environ['BZREMAIL'] = self._orig_email
46
if os.environ.get('BZREMAIL', None) is not None:
47
del os.environ['BZREMAIL']
48
bzrlib.user_encoding = self._orig_encoding
49
super(TestNonAscii, self).tearDown()
51
def create_base(self):
54
fs_enc = sys.getfilesystemencoding()
55
fname = self.info['filename']
56
dir_name = self.info['directory']
57
for thing in [fname, dir_name]:
60
except UnicodeEncodeError:
61
raise TestSkipped(('Unable to represent path %r'
62
' in filesystem encoding %s')
66
open('a', 'wb').write('foo\n')
68
bzr('commit', '-m', 'adding a')
70
open('b', 'wb').write('non-ascii \xFF\xFF\xFC\xFB\x00 in b\n')
72
bzr('commit', '-m', self.info['message'])
74
open(fname, 'wb').write('unicode filename\n')
76
bzr('commit', '-m', u'And a unicode file\n')
78
def test_status(self):
79
bzr = self.run_bzr_decode
81
open(self.info['filename'], 'ab').write('added something\n')
83
self.assertEqual(u'modified:\n %s\n' % (self.info['filename'],), txt)
85
txt = bzr('status', encoding='ascii')
86
expected = u'modified:\n %s\n' % (
87
self.info['filename'].encode('ascii', 'replace'),)
88
self.assertEqual(expected, txt)
91
# bzr cat shouldn't change the contents
92
# using run_bzr since that doesn't decode
93
txt = self.run_bzr('cat', 'b')[0]
94
self.assertEqual('non-ascii \xFF\xFF\xFC\xFB\x00 in b\n', txt)
96
txt = self.run_bzr('cat', self.info['filename'])[0]
97
self.assertEqual('unicode filename\n', txt)
99
def test_cat_revision(self):
100
bzr = self.run_bzr_decode
102
committer = self.info['committer']
103
txt = bzr('cat-revision', '-r', '1')
104
self.failUnless(committer in txt,
105
'failed to find %r in %r' % (committer, txt))
107
msg = self.info['message']
108
txt = bzr('cat-revision', '-r', '2')
109
self.failUnless(msg in txt, 'failed to find %r in %r' % (msg, txt))
111
def test_mkdir(self):
112
bzr = self.run_bzr_decode
114
txt = bzr('mkdir', self.info['directory'])
115
self.assertEqual(u'added %s\n' % self.info['directory'], txt)
117
# The text should be garbled, but the command should succeed
118
txt = bzr('mkdir', self.info['directory'] + '2', encoding='ascii')
119
expected = u'added %s2\n' % (self.info['directory'],)
120
expected = expected.encode('ascii', 'replace')
121
self.assertEqual(expected, txt)
123
def test_relpath(self):
124
bzr = self.run_bzr_decode
126
txt = bzr('relpath', self.info['filename'])
127
self.assertEqual(self.info['filename'] + '\n', txt)
129
bzr('relpath', self.info['filename'], encoding='ascii', retcode=3)
131
def test_inventory(self):
132
bzr = self.run_bzr_decode
134
txt = bzr('inventory')
135
self.assertEqual(['a', 'b', self.info['filename']],
138
# inventory should fail if unable to encode
139
bzr('inventory', encoding='ascii', retcode=3)
141
# We don't really care about the ids themselves,
142
# but the command shouldn't fail
143
txt = bzr('inventory', '--show-ids')
145
def test_revno(self):
146
# There isn't a lot to test here, since revno should always
148
bzr = self.run_bzr_decode
150
self.assertEqual('3\n', bzr('revno'))
151
self.assertEqual('3\n', bzr('revno', encoding='ascii'))
153
def test_revision_info(self):
154
bzr = self.run_bzr_decode
156
bzr('revision-info', '-r', '1')
158
# TODO: jam 20060105 If we support revisions with non-ascii characters,
159
# this should be strict and fail.
160
bzr('revision-info', '-r', '1', encoding='ascii')
163
bzr = self.run_bzr_decode
165
fname1 = self.info['filename']
166
fname2 = self.info['filename'] + '2'
167
dirname = self.info['directory']
169
# fname1 already exists
170
bzr('mv', 'a', fname1, retcode=3)
172
txt = bzr('mv', 'a', fname2)
173
self.assertEqual(u'a => %s\n' % fname2, txt)
174
self.failIfExists('a')
175
self.failUnlessExists(fname2)
177
bzr('commit', '-m', 'renamed to non-ascii')
179
bzr('mkdir', dirname)
180
txt = bzr('mv', fname1, fname2, dirname)
181
self.assertEqual([u'%s => %s/%s' % (fname1, dirname, fname1),
182
u'%s => %s/%s' % (fname2, dirname, fname2)]
185
# The rename should still succeed
186
newpath = u'%s/%s' % (dirname, fname2)
187
txt = bzr('mv', newpath, 'a', encoding='ascii')
188
self.failUnlessExists('a')
189
self.assertEqual(newpath.encode('ascii', 'replace') + ' => a\n', txt)
191
def test_branch(self):
192
# We should be able to branch into a directory that
193
# has a unicode name, even if we can't display the name
194
bzr = self.run_bzr_decode
195
bzr('branch', u'.', self.info['directory'])
196
bzr('branch', u'.', self.info['directory'] + '2', encoding='ascii')
199
# Make sure we can pull from paths that can't be encoded
200
bzr = self.run_bzr_decode
202
dirname1 = self.info['directory']
203
dirname2 = self.info['directory'] + '2'
204
bzr('branch', '.', dirname1)
205
bzr('branch', dirname1, dirname2)
208
open('a', 'ab').write('more text\n')
209
bzr('commit', '-m', 'mod a')
213
os.chdir(u'../' + dirname2)
216
self.assertEqual(u'Using saved location: %s/\n' % (pwd,), txt)
218
os.chdir('../' + dirname1)
219
open('a', 'ab').write('and yet more\n')
220
bzr('commit', '-m', 'modifying a by ' + self.info['committer'])
222
os.chdir('../' + dirname2)
223
# We should be able to pull, even if our encoding is bad
224
bzr('pull', '--verbose', encoding='ascii')
227
# TODO: Test push to an SFTP location
228
# Make sure we can pull from paths that can't be encoded
229
bzr = self.run_bzr_decode
231
# TODO: jam 20060427 For drastically improving performance, we probably
232
# could create a local repository, so it wouldn't have to copy
233
# the files around as much.
235
dirname = self.info['directory']
238
open('a', 'ab').write('adding more text\n')
239
bzr('commit', '-m', 'added some stuff')
241
# TODO: check the output text is properly encoded
245
f.write('and a bit more: ')
246
f.write(dirname.encode('utf-8'))
250
bzr('commit', '-m', u'Added some ' + dirname)
251
bzr('push', '--verbose', encoding='ascii')
253
bzr('push', '--verbose', dirname + '2')
255
bzr('push', '--verbose', dirname + '3', encoding='ascii')
257
bzr('push', '--verbose', '--create-prefix', dirname + '4/' + dirname + '5')
258
bzr('push', '--verbose', '--create-prefix', dirname + '6/' + dirname + '7', encoding='ascii')
260
def test_renames(self):
261
bzr = self.run_bzr_decode
263
fname = self.info['filename'] + '2'
264
bzr('mv', 'a', fname)
266
self.assertEqual(u'a => %s\n' % fname, txt)
268
bzr('renames', retcode=3, encoding='ascii')
270
def test_remove(self):
271
bzr = self.run_bzr_decode
273
fname = self.info['filename']
274
txt = bzr('remove', fname, encoding='ascii')
276
def test_remove_verbose(self):
277
bzr = self.run_bzr_decode
279
fname = self.info['filename']
280
txt = bzr('remove', '--verbose', fname, encoding='ascii')
282
def test_file_id(self):
283
bzr = self.run_bzr_decode
285
fname = self.info['filename']
286
txt = bzr('file-id', fname)
288
# TODO: jam 20060106 We don't support non-ascii file ids yet,
289
# so there is nothing which would fail in ascii encoding
290
# This *should* be retcode=3
291
txt = bzr('file-id', fname, encoding='ascii')
293
def test_file_path(self):
294
bzr = self.run_bzr_decode
296
# Create a directory structure
297
fname = self.info['filename']
298
dirname = self.info['directory']
300
bzr('mkdir', 'base/' + dirname)
301
path = '/'.join(['base', dirname, fname])
302
bzr('mv', fname, path)
303
bzr('commit', '-m', 'moving things around')
305
txt = bzr('file-path', path)
307
# TODO: jam 20060106 We don't support non-ascii file ids yet,
308
# so there is nothing which would fail in ascii encoding
309
# This *should* be retcode=3
310
txt = bzr('file-path', path, encoding='ascii')
312
def test_revision_history(self):
313
bzr = self.run_bzr_decode
315
# TODO: jam 20060106 We don't support non-ascii revision ids yet,
316
# so there is nothing which would fail in ascii encoding
317
txt = bzr('revision-history')
319
def test_ancestry(self):
320
bzr = self.run_bzr_decode
322
# TODO: jam 20060106 We don't support non-ascii revision ids yet,
323
# so there is nothing which would fail in ascii encoding
324
txt = bzr('ancestry')
327
# TODO: jam 20060106 diff is a difficult one to test, because it
328
# shouldn't encode the file contents, but it needs some sort
329
# of encoding for the paths, etc which are displayed.
330
open(self.info['filename'], 'ab').write('newline\n')
331
txt = self.run_bzr('diff', retcode=1)[0]
333
def test_deleted(self):
334
bzr = self.run_bzr_decode
336
fname = self.info['filename']
341
self.assertEqual(fname+'\n', txt)
343
txt = bzr('deleted', '--show-ids')
344
self.failUnless(txt.startswith(fname))
346
# Deleted should fail if cannot decode
347
# Because it is giving the exact paths
348
# which might be used by a front end
349
bzr('deleted', encoding='ascii', retcode=3)
351
def test_modified(self):
352
bzr = self.run_bzr_decode
354
fname = self.info['filename']
355
open(fname, 'ab').write('modified\n')
357
txt = bzr('modified')
358
self.assertEqual(fname+'\n', txt)
360
bzr('modified', encoding='ascii', retcode=3)
362
def test_added(self):
363
bzr = self.run_bzr_decode
365
fname = self.info['filename'] + '2'
366
open(fname, 'wb').write('added\n')
370
self.assertEqual(fname+'\n', txt)
372
bzr('added', encoding='ascii', retcode=3)
375
bzr = self.run_bzr_decode
377
dirname = self.info['directory']
380
bzr('branch', u'.', dirname)
385
self.failUnless(txt.endswith(dirname+'\n'))
387
txt = bzr('root', encoding='ascii', retcode=3)
390
bzr = self.run_bzr_decode
392
fname = self.info['filename']
395
self.assertNotEqual(-1, txt.find(self.info['committer']))
396
self.assertNotEqual(-1, txt.find(self.info['message']))
398
txt = bzr('log', '--verbose')
399
self.assertNotEqual(-1, txt.find(fname))
401
# Make sure log doesn't fail even if we can't write out
402
txt = bzr('log', '--verbose', encoding='ascii')
403
self.assertEqual(-1, txt.find(fname))
404
self.assertNotEqual(-1, txt.find(fname.encode('ascii', 'replace')))
406
def test_touching_revisions(self):
407
bzr = self.run_bzr_decode
409
fname = self.info['filename']
410
txt = bzr('touching-revisions', fname)
411
self.assertEqual(u' 3 added %s\n' % (fname,), txt)
413
fname2 = self.info['filename'] + '2'
414
bzr('mv', fname, fname2)
415
bzr('commit', '-m', u'Renamed %s => %s' % (fname, fname2))
417
txt = bzr('touching-revisions', fname2)
418
expected_txt = (u' 3 added %s\n'
419
u' 4 renamed %s => %s\n'
420
% (fname, fname, fname2))
421
self.assertEqual(expected_txt, txt)
423
bzr('touching-revisions', fname2, encoding='ascii', retcode=3)
426
bzr = self.run_bzr_decode
429
self.assertEqual(['a', 'b', self.info['filename']],
431
txt = bzr('ls', '--null')
432
self.assertEqual(['a', 'b', self.info['filename'], ''],
435
txt = bzr('ls', encoding='ascii', retcode=3)
436
txt = bzr('ls', '--null', encoding='ascii', retcode=3)
438
def test_unknowns(self):
439
bzr = self.run_bzr_decode
441
fname = self.info['filename'] + '2'
442
open(fname, 'wb').write('unknown\n')
444
# TODO: jam 20060112 bzr unknowns is the only one which
445
# quotes paths do we really want it to?
446
txt = bzr('unknowns')
447
self.assertEqual(u'"%s"\n' % (fname,), txt)
449
bzr('unknowns', encoding='ascii', retcode=3)
451
def test_ignore(self):
452
bzr = self.run_bzr_decode
454
fname2 = self.info['filename'] + '2.txt'
455
open(fname2, 'wb').write('ignored\n')
457
txt = bzr('unknowns')
458
self.assertEqual(u'"%s"\n' % (fname2,), txt)
460
bzr('ignore', './' + fname2)
461
txt = bzr('unknowns')
462
self.assertEqual(u'', txt)
464
fname3 = self.info['filename'] + '3.txt'
465
open(fname3, 'wb').write('unknown 3\n')
466
txt = bzr('unknowns')
467
self.assertEqual(u'"%s"\n' % (fname3,), txt)
469
# Ignore should not care what the encoding is
470
# (right now it doesn't print anything)
471
bzr('ignore', fname3, encoding='ascii')
472
txt = bzr('unknowns')
473
self.assertEqual('', txt)
475
# Now try a wildcard match
476
fname4 = self.info['filename'] + '4.txt'
477
open(fname4, 'wb').write('unknown 4\n')
478
bzr('ignore', '*.txt')
479
txt = bzr('unknowns')
480
self.assertEqual('', txt)
482
os.remove('.bzrignore')
483
bzr('ignore', self.info['filename'] + '*')
484
txt = bzr('unknowns')
485
self.assertEqual('', txt)