78
"""Simple file-like object that allows writes with any type and records."""
81
self.write_record = []
83
def write(self, data):
84
self.write_record.append(data)
86
def check_types(self, testcase, expected_type):
88
any(not isinstance(o, expected_type) for o in self.write_record),
89
"Not all writes of type %s: %r" % (
90
expected_type.__name__, self.write_record))
93
class TestDiffOptions(tests.TestCase):
95
def test_unified_added(self):
96
"""Check for default style '-u' only if no other style specified
99
# Verify that style defaults to unified, id est '-u' appended
100
# to option list, in the absence of an alternative style.
101
self.assertEqual(['-a', '-u'], diff.default_style_unified(['-a']))
104
class TestDiffOptionsScenarios(tests.TestCase):
106
scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
107
style = None # Set by load_tests_apply_scenarios from scenarios
109
def test_unified_not_added(self):
110
# Verify that for all valid style options, '-u' is not
111
# appended to option list.
112
ret_opts = diff.default_style_unified(diff_opts=["%s" % (self.style,)])
113
self.assertEqual(["%s" % (self.style,)], ret_opts)
83
116
class TestDiff(tests.TestCase):
85
118
def test_add_nl(self):
86
119
"""diff generates a valid diff for patches that add a newline"""
87
lines = udiff_lines(['boo'], ['boo\n'])
120
lines = udiff_lines([b'boo'], [b'boo\n'])
88
121
self.check_patch(lines)
89
self.assertEquals(lines[4], '\\ No newline at end of file\n')
122
self.assertEqual(lines[4], b'\\ No newline at end of file\n')
90
123
## "expected no-nl, got %r" % lines[4]
92
125
def test_add_nl_2(self):
93
126
"""diff generates a valid diff for patches that change last line and
96
lines = udiff_lines(['boo'], ['goo\n'])
129
lines = udiff_lines([b'boo'], [b'goo\n'])
97
130
self.check_patch(lines)
98
self.assertEquals(lines[4], '\\ No newline at end of file\n')
131
self.assertEqual(lines[4], b'\\ No newline at end of file\n')
99
132
## "expected no-nl, got %r" % lines[4]
101
134
def test_remove_nl(self):
102
135
"""diff generates a valid diff for patches that change last line and
105
lines = udiff_lines(['boo\n'], ['boo'])
138
lines = udiff_lines([b'boo\n'], [b'boo'])
106
139
self.check_patch(lines)
107
self.assertEquals(lines[5], '\\ No newline at end of file\n')
140
self.assertEqual(lines[5], b'\\ No newline at end of file\n')
108
141
## "expected no-nl, got %r" % lines[5]
110
143
def check_patch(self, lines):
111
self.assert_(len(lines) > 1)
144
self.assertTrue(len(lines) > 1)
112
145
## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
113
self.assert_(lines[0].startswith ('---'))
146
self.assertTrue(lines[0].startswith (b'---'))
114
147
## 'No orig line for patch:\n%s' % "".join(lines)
115
self.assert_(lines[1].startswith ('+++'))
148
self.assertTrue(lines[1].startswith (b'+++'))
116
149
## 'No mod line for patch:\n%s' % "".join(lines)
117
self.assert_(len(lines) > 2)
150
self.assertTrue(len(lines) > 2)
118
151
## "No hunks for patch:\n%s" % "".join(lines)
119
self.assert_(lines[2].startswith('@@'))
152
self.assertTrue(lines[2].startswith(b'@@'))
120
153
## "No hunk header for patch:\n%s" % "".join(lines)
121
self.assert_('@@' in lines[2][2:])
154
self.assertTrue(b'@@' in lines[2][2:])
122
155
## "Unterminated hunk header for patch:\n%s" % "".join(lines)
124
157
def test_binary_lines(self):
126
uni_lines = [1023 * 'a' + '\x00']
127
self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
159
uni_lines = [1023 * b'a' + b'\x00']
160
self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines, empty)
128
161
self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
129
udiff_lines(uni_lines , empty, allow_binary=True)
162
udiff_lines(uni_lines, empty, allow_binary=True)
130
163
udiff_lines(empty, uni_lines, allow_binary=True)
132
165
def test_external_diff(self):
133
lines = external_udiff_lines(['boo\n'], ['goo\n'])
166
lines = external_udiff_lines([b'boo\n'], [b'goo\n'])
134
167
self.check_patch(lines)
135
self.assertEqual('\n', lines[-1])
168
self.assertEqual(b'\n', lines[-1])
137
170
def test_external_diff_no_fileno(self):
138
171
# Make sure that we can handle not having a fileno, even
139
172
# if the diff is large
140
lines = external_udiff_lines(['boo\n']*10000,
173
lines = external_udiff_lines([b'boo\n']*10000,
142
175
use_stringio=True)
143
176
self.check_patch(lines)
145
178
def test_external_diff_binary_lang_c(self):
147
179
for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
148
old_env[lang] = osutils.set_or_unset_env(lang, 'C')
150
lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
151
# Older versions of diffutils say "Binary files", newer
152
# versions just say "Files".
153
self.assertContainsRe(lines[0],
154
'(Binary f|F)iles old and new differ\n')
155
self.assertEquals(lines[1:], ['\n'])
157
for lang, old_val in old_env.iteritems():
158
osutils.set_or_unset_env(lang, old_val)
180
self.overrideEnv(lang, 'C')
181
lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
182
# Older versions of diffutils say "Binary files", newer
183
# versions just say "Files".
184
self.assertContainsRe(lines[0], b'(Binary f|F)iles old and new differ\n')
185
self.assertEqual(lines[1:], [b'\n'])
160
187
def test_no_external_diff(self):
161
188
"""Check that NoDiff is raised when diff is not available"""
162
# Use os.environ['PATH'] to make sure no 'diff' command is available
163
orig_path = os.environ['PATH']
165
os.environ['PATH'] = ''
166
self.assertRaises(errors.NoDiff, diff.external_diff,
167
'old', ['boo\n'], 'new', ['goo\n'],
168
StringIO(), diff_opts=['-u'])
170
os.environ['PATH'] = orig_path
189
# Make sure no 'diff' command is available
190
# XXX: Weird, using None instead of '' breaks the test -- vila 20101216
191
self.overrideEnv('PATH', '')
192
self.assertRaises(errors.NoDiff, diff.external_diff,
193
b'old', [b'boo\n'], b'new', [b'goo\n'],
194
BytesIO(), diff_opts=['-u'])
172
196
def test_internal_diff_default(self):
173
197
# Default internal diff encoding is utf8
175
diff.internal_diff(u'old_\xb5', ['old_text\n'],
176
u'new_\xe5', ['new_text\n'], output)
199
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
200
u'new_\xe5', [b'new_text\n'], output)
177
201
lines = output.getvalue().splitlines(True)
178
202
self.check_patch(lines)
179
self.assertEquals(['--- old_\xc2\xb5\n',
180
'+++ new_\xc3\xa5\n',
203
self.assertEqual([b'--- old_\xc2\xb5\n',
204
b'+++ new_\xc3\xa5\n',
205
b'@@ -1,1 +1,1 @@\n',
188
212
def test_internal_diff_utf8(self):
190
diff.internal_diff(u'old_\xb5', ['old_text\n'],
191
u'new_\xe5', ['new_text\n'], output,
214
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
215
u'new_\xe5', [b'new_text\n'], output,
192
216
path_encoding='utf8')
193
217
lines = output.getvalue().splitlines(True)
194
218
self.check_patch(lines)
195
self.assertEquals(['--- old_\xc2\xb5\n',
196
'+++ new_\xc3\xa5\n',
219
self.assertEqual([b'--- old_\xc2\xb5\n',
220
b'+++ new_\xc3\xa5\n',
221
b'@@ -1,1 +1,1 @@\n',
204
228
def test_internal_diff_iso_8859_1(self):
206
diff.internal_diff(u'old_\xb5', ['old_text\n'],
207
u'new_\xe5', ['new_text\n'], output,
230
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
231
u'new_\xe5', [b'new_text\n'], output,
208
232
path_encoding='iso-8859-1')
209
233
lines = output.getvalue().splitlines(True)
210
234
self.check_patch(lines)
211
self.assertEquals(['--- old_\xb5\n',
235
self.assertEqual([b'--- old_\xb5\n',
237
b'@@ -1,1 +1,1 @@\n',
220
244
def test_internal_diff_no_content(self):
222
246
diff.internal_diff(u'old', [], u'new', [], output)
223
self.assertEqual('', output.getvalue())
247
self.assertEqual(b'', output.getvalue())
225
249
def test_internal_diff_no_changes(self):
227
diff.internal_diff(u'old', ['text\n', 'contents\n'],
228
u'new', ['text\n', 'contents\n'],
251
diff.internal_diff(u'old', [b'text\n', b'contents\n'],
252
u'new', [b'text\n', b'contents\n'],
230
self.assertEqual('', output.getvalue())
254
self.assertEqual(b'', output.getvalue())
232
256
def test_internal_diff_returns_bytes(self):
234
output = StringIO.StringIO()
235
diff.internal_diff(u'old_\xb5', ['old_text\n'],
236
u'new_\xe5', ['new_text\n'], output)
237
self.failUnless(isinstance(output.getvalue(), str),
238
'internal_diff should return bytestrings')
258
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
259
u'new_\xe5', [b'new_text\n'], output)
260
output.check_types(self, bytes)
262
def test_internal_diff_default_context(self):
264
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
265
b'same_text\n', b'same_text\n', b'old_text\n'],
266
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
267
b'same_text\n', b'same_text\n', b'new_text\n'], output)
268
lines = output.getvalue().splitlines(True)
269
self.check_patch(lines)
270
self.assertEqual([b'--- old\n',
272
b'@@ -3,4 +3,4 @@\n',
282
def test_internal_diff_no_context(self):
284
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
285
b'same_text\n', b'same_text\n', b'old_text\n'],
286
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
287
b'same_text\n', b'same_text\n', b'new_text\n'], output,
289
lines = output.getvalue().splitlines(True)
290
self.check_patch(lines)
291
self.assertEqual([b'--- old\n',
293
b'@@ -6,1 +6,1 @@\n',
300
def test_internal_diff_more_context(self):
302
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
303
b'same_text\n', b'same_text\n', b'old_text\n'],
304
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
305
b'same_text\n', b'same_text\n', b'new_text\n'], output,
307
lines = output.getvalue().splitlines(True)
308
self.check_patch(lines)
309
self.assertEqual([b'--- old\n',
311
b'@@ -2,5 +2,5 @@\n',
241
324
class TestDiffFiles(tests.TestCaseInTempDir):
243
326
def test_external_diff_binary(self):
244
327
"""The output when using external diff should use diff's i18n error"""
328
for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
329
self.overrideEnv(lang, 'C')
245
330
# Make sure external_diff doesn't fail in the current LANG
246
lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
331
lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
248
333
cmd = ['diff', '-u', '--binary', 'old', 'new']
249
open('old', 'wb').write('\x00foobar\n')
250
open('new', 'wb').write('foo\x00bar\n')
334
with open('old', 'wb') as f: f.write(b'\x00foobar\n')
335
with open('new', 'wb') as f: f.write(b'foo\x00bar\n')
251
336
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
252
337
stdin=subprocess.PIPE)
253
338
out, err = pipe.communicate()
254
# Diff returns '2' on Binary files.
255
self.assertEqual(2, pipe.returncode)
256
339
# We should output whatever diff tells us, plus a trailing newline
257
self.assertEqual(out.splitlines(True) + ['\n'], lines)
260
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
261
"""Has a helper for running show_diff_trees"""
263
def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
265
if working_tree is not None:
266
extra_trees = (working_tree,)
269
diff.show_diff_trees(tree1, tree2, output,
270
specific_files=specific_files,
271
extra_trees=extra_trees, old_label='old/',
273
return output.getvalue()
276
class TestDiffDates(TestShowDiffTreesHelper):
340
self.assertEqual(out.splitlines(True) + [b'\n'], lines)
343
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
345
if working_tree is not None:
346
extra_trees = (working_tree,)
349
diff.show_diff_trees(tree1, tree2, output,
350
specific_files=specific_files,
351
extra_trees=extra_trees, old_label='old/',
353
return output.getvalue()
356
class TestDiffDates(tests.TestCaseWithTransport):
279
359
super(TestDiffDates, self).setUp()
280
360
self.wt = self.make_branch_and_tree('.')
281
361
self.b = self.wt.branch
282
362
self.build_tree_contents([
283
('file1', 'file1 contents at rev 1\n'),
284
('file2', 'file2 contents at rev 1\n')
363
('file1', b'file1 contents at rev 1\n'),
364
('file2', b'file2 contents at rev 1\n')
286
366
self.wt.add(['file1', 'file2'])
288
368
message='Revision 1',
289
369
timestamp=1143849600, # 2006-04-01 00:00:00 UTC
292
self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
372
self.build_tree_contents([('file1', b'file1 contents at rev 2\n')])
294
374
message='Revision 2',
295
375
timestamp=1143936000, # 2006-04-02 00:00:00 UTC
298
self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
378
self.build_tree_contents([('file2', b'file2 contents at rev 3\n')])
300
380
message='Revision 3',
301
381
timestamp=1144022400, # 2006-04-03 00:00:00 UTC
304
384
self.wt.remove(['file2'])
306
386
message='Revision 4',
307
387
timestamp=1144108800, # 2006-04-04 00:00:00 UTC
310
390
self.build_tree_contents([
311
('file1', 'file1 contents in working tree\n')
391
('file1', b'file1 contents in working tree\n')
313
393
# set the date stamps for files in the working tree to known values
314
394
os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
316
396
def test_diff_rev_tree_working_tree(self):
317
output = self.get_diff(self.wt.basis_tree(), self.wt)
397
output = get_diff_as_string(self.wt.basis_tree(), self.wt)
318
398
# note that the date for old/file1 is from rev 2 rather than from
319
399
# the basis revision (rev 4)
320
self.assertEqualDiff(output, '''\
400
self.assertEqualDiff(output, b'''\
321
401
=== modified file 'file1'
322
402
--- old/file1\t2006-04-02 00:00:00 +0000
323
403
+++ new/file1\t2006-04-05 00:00:00 +0000
393
473
self.wt.add(['dir1', 'dir2'])
394
474
self.wt.rename_one('file1', 'dir1/file1')
395
old_tree = self.b.repository.revision_tree('rev-1')
396
new_tree = self.b.repository.revision_tree('rev-4')
397
out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
398
working_tree=self.wt)
399
self.assertContainsRe(out, 'file1\t')
400
out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
401
working_tree=self.wt)
402
self.assertNotContainsRe(out, 'file1\t')
406
class TestShowDiffTrees(TestShowDiffTreesHelper):
475
old_tree = self.b.repository.revision_tree(b'rev-1')
476
new_tree = self.b.repository.revision_tree(b'rev-4')
477
out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
478
working_tree=self.wt)
479
self.assertContainsRe(out, b'file1\t')
480
out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
481
working_tree=self.wt)
482
self.assertNotContainsRe(out, b'file1\t')
485
class TestShowDiffTrees(tests.TestCaseWithTransport):
407
486
"""Direct tests for show_diff_trees"""
409
488
def test_modified_file(self):
410
489
"""Test when a file is modified."""
411
490
tree = self.make_branch_and_tree('tree')
412
self.build_tree_contents([('tree/file', 'contents\n')])
413
tree.add(['file'], ['file-id'])
414
tree.commit('one', rev_id='rev-1')
491
self.build_tree_contents([('tree/file', b'contents\n')])
492
tree.add(['file'], [b'file-id'])
493
tree.commit('one', rev_id=b'rev-1')
416
self.build_tree_contents([('tree/file', 'new contents\n')])
417
d = self.get_diff(tree.basis_tree(), tree)
418
self.assertContainsRe(d, "=== modified file 'file'\n")
419
self.assertContainsRe(d, '--- old/file\t')
420
self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
421
self.assertContainsRe(d, '-contents\n'
495
self.build_tree_contents([('tree/file', b'new contents\n')])
496
d = get_diff_as_string(tree.basis_tree(), tree)
497
self.assertContainsRe(d, b"=== modified file 'file'\n")
498
self.assertContainsRe(d, b'--- old/file\t')
499
self.assertContainsRe(d, b'\\+\\+\\+ new/file\t')
500
self.assertContainsRe(d, b'-contents\n'
501
b'\\+new contents\n')
424
503
def test_modified_file_in_renamed_dir(self):
425
504
"""Test when a file is modified in a renamed directory."""
426
505
tree = self.make_branch_and_tree('tree')
427
506
self.build_tree(['tree/dir/'])
428
self.build_tree_contents([('tree/dir/file', 'contents\n')])
429
tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
430
tree.commit('one', rev_id='rev-1')
507
self.build_tree_contents([('tree/dir/file', b'contents\n')])
508
tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
509
tree.commit('one', rev_id=b'rev-1')
432
511
tree.rename_one('dir', 'other')
433
self.build_tree_contents([('tree/other/file', 'new contents\n')])
434
d = self.get_diff(tree.basis_tree(), tree)
435
self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
436
self.assertContainsRe(d, "=== modified file 'other/file'\n")
512
self.build_tree_contents([('tree/other/file', b'new contents\n')])
513
d = get_diff_as_string(tree.basis_tree(), tree)
514
self.assertContainsRe(d, b"=== renamed directory 'dir' => 'other'\n")
515
self.assertContainsRe(d, b"=== modified file 'other/file'\n")
437
516
# XXX: This is technically incorrect, because it used to be at another
438
517
# location. What to do?
439
self.assertContainsRe(d, '--- old/dir/file\t')
440
self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
441
self.assertContainsRe(d, '-contents\n'
518
self.assertContainsRe(d, b'--- old/dir/file\t')
519
self.assertContainsRe(d, b'\\+\\+\\+ new/other/file\t')
520
self.assertContainsRe(d, b'-contents\n'
521
b'\\+new contents\n')
444
523
def test_renamed_directory(self):
445
524
"""Test when only a directory is only renamed."""
446
525
tree = self.make_branch_and_tree('tree')
447
526
self.build_tree(['tree/dir/'])
448
self.build_tree_contents([('tree/dir/file', 'contents\n')])
449
tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
450
tree.commit('one', rev_id='rev-1')
527
self.build_tree_contents([('tree/dir/file', b'contents\n')])
528
tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
529
tree.commit('one', rev_id=b'rev-1')
452
531
tree.rename_one('dir', 'newdir')
453
d = self.get_diff(tree.basis_tree(), tree)
532
d = get_diff_as_string(tree.basis_tree(), tree)
454
533
# Renaming a directory should be a single "you renamed this dir" even
455
534
# when there are files inside.
456
self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
535
self.assertEqual(d, b"=== renamed directory 'dir' => 'newdir'\n")
458
537
def test_renamed_file(self):
459
538
"""Test when a file is only renamed."""
460
539
tree = self.make_branch_and_tree('tree')
461
self.build_tree_contents([('tree/file', 'contents\n')])
462
tree.add(['file'], ['file-id'])
463
tree.commit('one', rev_id='rev-1')
540
self.build_tree_contents([('tree/file', b'contents\n')])
541
tree.add(['file'], [b'file-id'])
542
tree.commit('one', rev_id=b'rev-1')
465
544
tree.rename_one('file', 'newname')
466
d = self.get_diff(tree.basis_tree(), tree)
467
self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
545
d = get_diff_as_string(tree.basis_tree(), tree)
546
self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
468
547
# We shouldn't have a --- or +++ line, because there is no content
470
self.assertNotContainsRe(d, '---')
549
self.assertNotContainsRe(d, b'---')
472
551
def test_renamed_and_modified_file(self):
473
552
"""Test when a file is only renamed."""
474
553
tree = self.make_branch_and_tree('tree')
475
self.build_tree_contents([('tree/file', 'contents\n')])
476
tree.add(['file'], ['file-id'])
477
tree.commit('one', rev_id='rev-1')
554
self.build_tree_contents([('tree/file', b'contents\n')])
555
tree.add(['file'], [b'file-id'])
556
tree.commit('one', rev_id=b'rev-1')
479
558
tree.rename_one('file', 'newname')
480
self.build_tree_contents([('tree/newname', 'new contents\n')])
481
d = self.get_diff(tree.basis_tree(), tree)
482
self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
483
self.assertContainsRe(d, '--- old/file\t')
484
self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
485
self.assertContainsRe(d, '-contents\n'
559
self.build_tree_contents([('tree/newname', b'new contents\n')])
560
d = get_diff_as_string(tree.basis_tree(), tree)
561
self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
562
self.assertContainsRe(d, b'--- old/file\t')
563
self.assertContainsRe(d, b'\\+\\+\\+ new/newname\t')
564
self.assertContainsRe(d, b'-contents\n'
565
b'\\+new contents\n')
489
568
def test_internal_diff_exec_property(self):
490
569
tree = self.make_branch_and_tree('tree')
492
571
tt = transform.TreeTransform(tree)
493
tt.new_file('a', tt.root, 'contents\n', 'a-id', True)
494
tt.new_file('b', tt.root, 'contents\n', 'b-id', False)
495
tt.new_file('c', tt.root, 'contents\n', 'c-id', True)
496
tt.new_file('d', tt.root, 'contents\n', 'd-id', False)
497
tt.new_file('e', tt.root, 'contents\n', 'control-e-id', True)
498
tt.new_file('f', tt.root, 'contents\n', 'control-f-id', False)
572
tt.new_file('a', tt.root, [b'contents\n'], b'a-id', True)
573
tt.new_file('b', tt.root, [b'contents\n'], b'b-id', False)
574
tt.new_file('c', tt.root, [b'contents\n'], b'c-id', True)
575
tt.new_file('d', tt.root, [b'contents\n'], b'd-id', False)
576
tt.new_file('e', tt.root, [b'contents\n'], b'control-e-id', True)
577
tt.new_file('f', tt.root, [b'contents\n'], b'control-f-id', False)
500
tree.commit('one', rev_id='rev-1')
579
tree.commit('one', rev_id=b'rev-1')
502
581
tt = transform.TreeTransform(tree)
503
tt.set_executability(False, tt.trans_id_file_id('a-id'))
504
tt.set_executability(True, tt.trans_id_file_id('b-id'))
505
tt.set_executability(False, tt.trans_id_file_id('c-id'))
506
tt.set_executability(True, tt.trans_id_file_id('d-id'))
582
tt.set_executability(False, tt.trans_id_file_id(b'a-id'))
583
tt.set_executability(True, tt.trans_id_file_id(b'b-id'))
584
tt.set_executability(False, tt.trans_id_file_id(b'c-id'))
585
tt.set_executability(True, tt.trans_id_file_id(b'd-id'))
508
587
tree.rename_one('c', 'new-c')
509
588
tree.rename_one('d', 'new-d')
511
d = self.get_diff(tree.basis_tree(), tree)
513
self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
515
self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
517
self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
519
self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
521
self.assertNotContainsRe(d, r"file 'e'")
522
self.assertNotContainsRe(d, r"file 'f'")
590
d = get_diff_as_string(tree.basis_tree(), tree)
592
self.assertContainsRe(d, br"file 'a'.*\(properties changed:"
594
self.assertContainsRe(d, br"file 'b'.*\(properties changed:"
596
self.assertContainsRe(d, br"file 'c'.*\(properties changed:"
598
self.assertContainsRe(d, br"file 'd'.*\(properties changed:"
600
self.assertNotContainsRe(d, br"file 'e'")
601
self.assertNotContainsRe(d, br"file 'f'")
525
603
def test_binary_unicode_filenames(self):
526
604
"""Test that contents of files are *not* encoded in UTF-8 when there
527
605
is a binary file in the diff.
529
607
# See https://bugs.launchpad.net/bugs/110092.
530
self.requireFeature(tests.UnicodeFilenameFeature)
608
self.requireFeature(features.UnicodeFilenameFeature)
532
# This bug isn't triggered with cStringIO.
533
from StringIO import StringIO
534
610
tree = self.make_branch_and_tree('tree')
535
611
alpha, omega = u'\u03b1', u'\u03c9'
536
612
alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
537
613
self.build_tree_contents(
538
[('tree/' + alpha, chr(0)),
614
[('tree/' + alpha, b'\0'),
539
615
('tree/' + omega,
540
('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
541
tree.add([alpha], ['file-id'])
542
tree.add([omega], ['file-id-2'])
543
diff_content = StringIO()
616
(b'The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
617
tree.add([alpha], [b'file-id'])
618
tree.add([omega], [b'file-id-2'])
619
diff_content = StubO()
544
620
diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
545
d = diff_content.getvalue()
546
self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
547
self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
621
diff_content.check_types(self, bytes)
622
d = b''.join(diff_content.write_record)
623
self.assertContainsRe(d, br"=== added file '%s'" % alpha_utf8)
624
self.assertContainsRe(d, b"Binary files a/%s.*and b/%s.* differ\n"
548
625
% (alpha_utf8, alpha_utf8))
549
self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
550
self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
551
self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
626
self.assertContainsRe(d, br"=== added file '%s'" % omega_utf8)
627
self.assertContainsRe(d, br"--- a/%s" % (omega_utf8,))
628
self.assertContainsRe(d, br"\+\+\+ b/%s" % (omega_utf8,))
553
630
def test_unicode_filename(self):
554
631
"""Test when the filename are unicode."""
555
self.requireFeature(tests.UnicodeFilenameFeature)
632
self.requireFeature(features.UnicodeFilenameFeature)
557
634
alpha, omega = u'\u03b1', u'\u03c9'
558
635
autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
560
637
tree = self.make_branch_and_tree('tree')
561
self.build_tree_contents([('tree/ren_'+alpha, 'contents\n')])
562
tree.add(['ren_'+alpha], ['file-id-2'])
563
self.build_tree_contents([('tree/del_'+alpha, 'contents\n')])
564
tree.add(['del_'+alpha], ['file-id-3'])
565
self.build_tree_contents([('tree/mod_'+alpha, 'contents\n')])
566
tree.add(['mod_'+alpha], ['file-id-4'])
638
self.build_tree_contents([('tree/ren_'+alpha, b'contents\n')])
639
tree.add(['ren_'+alpha], [b'file-id-2'])
640
self.build_tree_contents([('tree/del_'+alpha, b'contents\n')])
641
tree.add(['del_'+alpha], [b'file-id-3'])
642
self.build_tree_contents([('tree/mod_'+alpha, b'contents\n')])
643
tree.add(['mod_'+alpha], [b'file-id-4'])
568
tree.commit('one', rev_id='rev-1')
645
tree.commit('one', rev_id=b'rev-1')
570
647
tree.rename_one('ren_'+alpha, 'ren_'+omega)
571
648
tree.remove('del_'+alpha)
572
self.build_tree_contents([('tree/add_'+alpha, 'contents\n')])
573
tree.add(['add_'+alpha], ['file-id'])
574
self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
649
self.build_tree_contents([('tree/add_'+alpha, b'contents\n')])
650
tree.add(['add_'+alpha], [b'file-id'])
651
self.build_tree_contents([('tree/mod_'+alpha, b'contents_mod\n')])
576
d = self.get_diff(tree.basis_tree(), tree)
653
d = get_diff_as_string(tree.basis_tree(), tree)
577
654
self.assertContainsRe(d,
578
"=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
579
self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
580
self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
581
self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
655
b"=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
656
self.assertContainsRe(d, b"=== added file 'add_%s'"%autf8)
657
self.assertContainsRe(d, b"=== modified file 'mod_%s'"%autf8)
658
self.assertContainsRe(d, b"=== removed file 'del_%s'"%autf8)
660
def test_unicode_filename_path_encoding(self):
661
"""Test for bug #382699: unicode filenames on Windows should be shown
664
self.requireFeature(features.UnicodeFilenameFeature)
665
# The word 'test' in Russian
666
_russian_test = u'\u0422\u0435\u0441\u0442'
667
directory = _russian_test + u'/'
668
test_txt = _russian_test + u'.txt'
669
u1234 = u'\u1234.txt'
671
tree = self.make_branch_and_tree('.')
672
self.build_tree_contents([
673
(test_txt, b'foo\n'),
677
tree.add([test_txt, u1234, directory])
680
diff.show_diff_trees(tree.basis_tree(), tree, sio,
681
path_encoding='cp1251')
683
output = subst_dates(sio.getvalue())
685
=== added directory '%(directory)s'
686
=== added file '%(test_txt)s'
687
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
688
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
692
=== added file '?.txt'
693
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
694
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
698
''' % {b'directory': _russian_test.encode('cp1251'),
699
b'test_txt': test_txt.encode('cp1251'),
701
self.assertEqualDiff(output, shouldbe)
584
704
class DiffWasIs(diff.DiffPath):
586
706
def diff(self, file_id, old_path, new_path, old_kind, new_kind):
587
self.to_file.write('was: ')
588
self.to_file.write(self.old_tree.get_file(file_id).read())
589
self.to_file.write('is: ')
590
self.to_file.write(self.new_tree.get_file(file_id).read())
707
self.to_file.write(b'was: ')
708
self.to_file.write(self.old_tree.get_file(old_path).read())
709
self.to_file.write(b'is: ')
710
self.to_file.write(self.new_tree.get_file(new_path).read())
594
713
class TestDiffTree(tests.TestCaseWithTransport):
601
720
self.new_tree = self.make_branch_and_tree('new-tree')
602
721
self.new_tree.lock_write()
603
722
self.addCleanup(self.new_tree.unlock)
604
self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
723
self.differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
606
725
def test_diff_text(self):
607
726
self.build_tree_contents([('old-tree/olddir/',),
608
('old-tree/olddir/oldfile', 'old\n')])
727
('old-tree/olddir/oldfile', b'old\n')])
609
728
self.old_tree.add('olddir')
610
self.old_tree.add('olddir/oldfile', 'file-id')
729
self.old_tree.add('olddir/oldfile', b'file-id')
611
730
self.build_tree_contents([('new-tree/newdir/',),
612
('new-tree/newdir/newfile', 'new\n')])
731
('new-tree/newdir/newfile', b'new\n')])
613
732
self.new_tree.add('newdir')
614
self.new_tree.add('newdir/newfile', 'file-id')
615
differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
616
differ.diff_text('file-id', None, 'old label', 'new label')
618
'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
619
differ.to_file.getvalue())
620
differ.to_file.seek(0)
621
differ.diff_text(None, 'file-id', 'old label', 'new label')
623
'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
624
differ.to_file.getvalue())
625
differ.to_file.seek(0)
626
differ.diff_text('file-id', 'file-id', 'old label', 'new label')
628
'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
733
self.new_tree.add('newdir/newfile', b'file-id')
734
differ = diff.DiffText(self.old_tree, self.new_tree, BytesIO())
735
differ.diff_text('olddir/oldfile', None, 'old label',
736
'new label', b'file-id', None)
738
b'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
739
differ.to_file.getvalue())
740
differ.to_file.seek(0)
741
differ.diff_text(None, 'newdir/newfile',
742
'old label', 'new label', None, b'file-id')
744
b'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
745
differ.to_file.getvalue())
746
differ.to_file.seek(0)
747
differ.diff_text('olddir/oldfile', 'newdir/newfile',
748
'old label', 'new label', b'file-id', b'file-id')
750
b'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
629
751
differ.to_file.getvalue())
631
753
def test_diff_deletion(self):
632
self.build_tree_contents([('old-tree/file', 'contents'),
633
('new-tree/file', 'contents')])
634
self.old_tree.add('file', 'file-id')
635
self.new_tree.add('file', 'file-id')
754
self.build_tree_contents([('old-tree/file', b'contents'),
755
('new-tree/file', b'contents')])
756
self.old_tree.add('file', b'file-id')
757
self.new_tree.add('file', b'file-id')
636
758
os.unlink('new-tree/file')
637
759
self.differ.show_diff(None)
638
self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
760
self.assertContainsRe(self.differ.to_file.getvalue(), b'-contents')
640
762
def test_diff_creation(self):
641
self.build_tree_contents([('old-tree/file', 'contents'),
642
('new-tree/file', 'contents')])
643
self.old_tree.add('file', 'file-id')
644
self.new_tree.add('file', 'file-id')
763
self.build_tree_contents([('old-tree/file', b'contents'),
764
('new-tree/file', b'contents')])
765
self.old_tree.add('file', b'file-id')
766
self.new_tree.add('file', b'file-id')
645
767
os.unlink('old-tree/file')
646
768
self.differ.show_diff(None)
647
self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
769
self.assertContainsRe(self.differ.to_file.getvalue(), br'\+contents')
649
771
def test_diff_symlink(self):
650
differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
772
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
651
773
differ.diff_symlink('old target', None)
652
self.assertEqual("=== target was 'old target'\n",
774
self.assertEqual(b"=== target was 'old target'\n",
653
775
differ.to_file.getvalue())
655
differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
777
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
656
778
differ.diff_symlink(None, 'new target')
657
self.assertEqual("=== target is 'new target'\n",
779
self.assertEqual(b"=== target is 'new target'\n",
658
780
differ.to_file.getvalue())
660
differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
782
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
661
783
differ.diff_symlink('old target', 'new target')
662
self.assertEqual("=== target changed 'old target' => 'new target'\n",
784
self.assertEqual(b"=== target changed 'old target' => 'new target'\n",
663
785
differ.to_file.getvalue())
665
787
def test_diff(self):
666
788
self.build_tree_contents([('old-tree/olddir/',),
667
('old-tree/olddir/oldfile', 'old\n')])
789
('old-tree/olddir/oldfile', b'old\n')])
668
790
self.old_tree.add('olddir')
669
self.old_tree.add('olddir/oldfile', 'file-id')
791
self.old_tree.add('olddir/oldfile', b'file-id')
670
792
self.build_tree_contents([('new-tree/newdir/',),
671
('new-tree/newdir/newfile', 'new\n')])
793
('new-tree/newdir/newfile', b'new\n')])
672
794
self.new_tree.add('newdir')
673
self.new_tree.add('newdir/newfile', 'file-id')
674
self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
795
self.new_tree.add('newdir/newfile', b'file-id')
796
self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
675
797
self.assertContainsRe(
676
798
self.differ.to_file.getvalue(),
677
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
678
' \@\@\n-old\n\+new\n\n')
799
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
800
br' \@\@\n-old\n\+new\n\n')
680
802
def test_diff_kind_change(self):
681
self.requireFeature(tests.SymlinkFeature)
803
self.requireFeature(features.SymlinkFeature)
682
804
self.build_tree_contents([('old-tree/olddir/',),
683
('old-tree/olddir/oldfile', 'old\n')])
805
('old-tree/olddir/oldfile', b'old\n')])
684
806
self.old_tree.add('olddir')
685
self.old_tree.add('olddir/oldfile', 'file-id')
807
self.old_tree.add('olddir/oldfile', b'file-id')
686
808
self.build_tree(['new-tree/newdir/'])
687
809
os.symlink('new', 'new-tree/newdir/newfile')
688
810
self.new_tree.add('newdir')
689
self.new_tree.add('newdir/newfile', 'file-id')
690
self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
811
self.new_tree.add('newdir/newfile', b'file-id')
812
self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
691
813
self.assertContainsRe(
692
814
self.differ.to_file.getvalue(),
693
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
815
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
695
817
self.assertContainsRe(self.differ.to_file.getvalue(),
696
"=== target is u'new'\n")
818
b"=== target is 'new'\n")
698
820
def test_diff_directory(self):
699
821
self.build_tree(['new-tree/new-dir/'])
700
self.new_tree.add('new-dir', 'new-dir-id')
701
self.differ.diff('new-dir-id', None, 'new-dir')
702
self.assertEqual(self.differ.to_file.getvalue(), '')
822
self.new_tree.add('new-dir', b'new-dir-id')
823
self.differ.diff(b'new-dir-id', None, 'new-dir')
824
self.assertEqual(self.differ.to_file.getvalue(), b'')
704
826
def create_old_new(self):
705
827
self.build_tree_contents([('old-tree/olddir/',),
706
('old-tree/olddir/oldfile', 'old\n')])
828
('old-tree/olddir/oldfile', b'old\n')])
707
829
self.old_tree.add('olddir')
708
self.old_tree.add('olddir/oldfile', 'file-id')
830
self.old_tree.add('olddir/oldfile', b'file-id')
709
831
self.build_tree_contents([('new-tree/newdir/',),
710
('new-tree/newdir/newfile', 'new\n')])
832
('new-tree/newdir/newfile', b'new\n')])
711
833
self.new_tree.add('newdir')
712
self.new_tree.add('newdir/newfile', 'file-id')
834
self.new_tree.add('newdir/newfile', b'file-id')
714
836
def test_register_diff(self):
715
837
self.create_old_new()
764
886
b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
765
887
sm = self._PatienceSequenceMatcher(None, a, b)
766
888
mb = sm.get_matching_blocks()
767
self.assertEquals(35, len(mb))
889
self.assertEqual(35, len(mb))
769
891
def test_unique_lcs(self):
770
892
unique_lcs = self._unique_lcs
771
self.assertEquals(unique_lcs('', ''), [])
772
self.assertEquals(unique_lcs('', 'a'), [])
773
self.assertEquals(unique_lcs('a', ''), [])
774
self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
775
self.assertEquals(unique_lcs('a', 'b'), [])
776
self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
777
self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
778
self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
779
self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
781
self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
893
self.assertEqual(unique_lcs('', ''), [])
894
self.assertEqual(unique_lcs('', 'a'), [])
895
self.assertEqual(unique_lcs('a', ''), [])
896
self.assertEqual(unique_lcs('a', 'a'), [(0, 0)])
897
self.assertEqual(unique_lcs('a', 'b'), [])
898
self.assertEqual(unique_lcs('ab', 'ab'), [(0, 0), (1, 1)])
899
self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2, 0), (3, 1), (4, 2)])
900
self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0, 2), (1, 3), (2, 4)])
901
self.assertEqual(unique_lcs('abXde', 'abYde'), [(0, 0), (1, 1),
903
self.assertEqual(unique_lcs('acbac', 'abc'), [(2, 1)])
783
905
def test_recurse_matches(self):
784
906
def test_one(a, b, matches):
785
907
test_matches = []
786
908
self._recurse_matches(
787
909
a, b, 0, 0, len(a), len(b), test_matches, 10)
788
self.assertEquals(test_matches, matches)
910
self.assertEqual(test_matches, matches)
790
912
test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
791
913
[(0, 0), (2, 2), (4, 4)])
896
1018
def test_opcodes(self):
897
1019
def chk_ops(a, b, expected_codes):
898
1020
s = self._PatienceSequenceMatcher(None, a, b)
899
self.assertEquals(expected_codes, s.get_opcodes())
1021
self.assertEqual(expected_codes, s.get_opcodes())
901
1023
chk_ops('', '', [])
902
1024
chk_ops([], [], [])
903
chk_ops('abc', '', [('delete', 0,3, 0,0)])
904
chk_ops('', 'abc', [('insert', 0,0, 0,3)])
905
chk_ops('abcd', 'abcd', [('equal', 0,4, 0,4)])
906
chk_ops('abcd', 'abce', [('equal', 0,3, 0,3),
907
('replace', 3,4, 3,4)
909
chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
913
chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
1025
chk_ops('abc', '', [('delete', 0, 3, 0, 0)])
1026
chk_ops('', 'abc', [('insert', 0, 0, 0, 3)])
1027
chk_ops('abcd', 'abcd', [('equal', 0, 4, 0, 4)])
1028
chk_ops('abcd', 'abce', [('equal', 0, 3, 0, 3),
1029
('replace', 3, 4, 3, 4)
1031
chk_ops('eabc', 'abce', [('delete', 0, 1, 0, 0),
1032
('equal', 1, 4, 0, 3),
1033
('insert', 4, 4, 3, 4)
1035
chk_ops('eabce', 'abce', [('delete', 0, 1, 0, 0),
1036
('equal', 1, 5, 0, 4)
916
chk_ops('abcde', 'abXde', [('equal', 0,2, 0,2),
917
('replace', 2,3, 2,3),
1038
chk_ops('abcde', 'abXde', [('equal', 0, 2, 0, 2),
1039
('replace', 2, 3, 2, 3),
1040
('equal', 3, 5, 3, 5)
920
chk_ops('abcde', 'abXYZde', [('equal', 0,2, 0,2),
921
('replace', 2,3, 2,5),
1042
chk_ops('abcde', 'abXYZde', [('equal', 0, 2, 0, 2),
1043
('replace', 2, 3, 2, 5),
1044
('equal', 3, 5, 5, 7)
924
chk_ops('abde', 'abXYZde', [('equal', 0,2, 0,2),
925
('insert', 2,2, 2,5),
1046
chk_ops('abde', 'abXYZde', [('equal', 0, 2, 0, 2),
1047
('insert', 2, 2, 2, 5),
1048
('equal', 2, 4, 5, 7)
928
1050
chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
929
[('equal', 0,6, 0,6),
930
('insert', 6,6, 6,11),
931
('equal', 6,16, 11,21)
1051
[('equal', 0, 6, 0, 6),
1052
('insert', 6, 6, 6, 11),
1053
('equal', 6, 16, 11, 21)
934
1056
[ 'hello there\n'
1377
1498
'print "@old_path @new_path"'],
1378
1499
old_tree, tree, output)
1379
1500
self.addCleanup(diff_obj.finish)
1380
self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1381
old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1501
self.assertContainsRe(diff_obj._root, 'brz-diff-[^/]*')
1502
old_path, new_path = diff_obj._prepare_files(
1503
'oldname', 'newname', file_id=b'file-id')
1383
1504
self.assertContainsRe(old_path, 'old/oldname$')
1384
1505
self.assertEqual(315532800, os.stat(old_path).st_mtime)
1385
1506
self.assertContainsRe(new_path, 'tree/newname$')
1386
self.assertFileEqual('oldcontent', old_path)
1387
self.assertFileEqual('newcontent', new_path)
1507
self.assertFileEqual(b'oldcontent', old_path)
1508
self.assertFileEqual(b'newcontent', new_path)
1388
1509
if osutils.host_os_dereferences_symlinks():
1389
1510
self.assertTrue(os.path.samefile('tree/newname', new_path))
1390
1511
# make sure we can create files with the same parent directories
1391
diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1512
diff_obj._prepare_files('oldname2', 'newname2', file_id=b'file2-id')
1515
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
1517
def test_encodable_filename(self):
1518
# Just checks file path for external diff tool.
1519
# We cannot change CPython's internal encoding used by os.exec*.
1520
diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1522
for _, scenario in EncodingAdapter.encoding_scenarios:
1523
encoding = scenario['encoding']
1524
dirname = scenario['info']['directory']
1525
filename = scenario['info']['filename']
1527
self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1528
relpath = dirname + u'/' + filename
1529
fullpath = diffobj._safe_filename('safe', relpath)
1530
self.assertEqual(fullpath,
1531
fullpath.encode(encoding).decode(encoding))
1532
self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1534
def test_unencodable_filename(self):
1535
diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1537
for _, scenario in EncodingAdapter.encoding_scenarios:
1538
encoding = scenario['encoding']
1539
dirname = scenario['info']['directory']
1540
filename = scenario['info']['filename']
1542
if encoding == 'iso-8859-1':
1543
encoding = 'iso-8859-2'
1545
encoding = 'iso-8859-1'
1547
self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1548
relpath = dirname + u'/' + filename
1549
fullpath = diffobj._safe_filename('safe', relpath)
1550
self.assertEqual(fullpath,
1551
fullpath.encode(encoding).decode(encoding))
1552
self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1394
1555
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
1396
1557
def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1397
"""Call get_trees_and_branches_to_diff_locked. Overridden by
1398
TestGetTreesAndBranchesToDiff.
1558
"""Call get_trees_and_branches_to_diff_locked."""
1400
1559
return diff.get_trees_and_branches_to_diff_locked(
1401
1560
path_list, revision_specs, old_url, new_url, self.addCleanup)