183
187
# XXX: Weird, using None instead of '' breaks the test -- vila 20101216
184
188
self.overrideEnv('PATH', '')
185
189
self.assertRaises(errors.NoDiff, diff.external_diff,
186
'old', ['boo\n'], 'new', ['goo\n'],
190
b'old', [b'boo\n'], b'new', [b'goo\n'],
187
191
BytesIO(), diff_opts=['-u'])
189
193
def test_internal_diff_default(self):
190
194
# Default internal diff encoding is utf8
191
195
output = BytesIO()
192
diff.internal_diff(u'old_\xb5', ['old_text\n'],
193
u'new_\xe5', ['new_text\n'], output)
196
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
197
u'new_\xe5', [b'new_text\n'], output)
194
198
lines = output.getvalue().splitlines(True)
195
199
self.check_patch(lines)
196
self.assertEqual(['--- old_\xc2\xb5\n',
197
'+++ new_\xc3\xa5\n',
200
self.assertEqual([b'--- old_\xc2\xb5\n',
201
b'+++ new_\xc3\xa5\n',
202
b'@@ -1,1 +1,1 @@\n',
205
208
def test_internal_diff_utf8(self):
206
209
output = BytesIO()
207
diff.internal_diff(u'old_\xb5', ['old_text\n'],
208
u'new_\xe5', ['new_text\n'], output,
210
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
211
u'new_\xe5', [b'new_text\n'], output,
209
212
path_encoding='utf8')
210
213
lines = output.getvalue().splitlines(True)
211
214
self.check_patch(lines)
212
self.assertEqual(['--- old_\xc2\xb5\n',
213
'+++ new_\xc3\xa5\n',
215
self.assertEqual([b'--- old_\xc2\xb5\n',
216
b'+++ new_\xc3\xa5\n',
217
b'@@ -1,1 +1,1 @@\n',
221
223
def test_internal_diff_iso_8859_1(self):
222
224
output = BytesIO()
223
diff.internal_diff(u'old_\xb5', ['old_text\n'],
224
u'new_\xe5', ['new_text\n'], output,
225
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
226
u'new_\xe5', [b'new_text\n'], output,
225
227
path_encoding='iso-8859-1')
226
228
lines = output.getvalue().splitlines(True)
227
229
self.check_patch(lines)
228
self.assertEqual(['--- old_\xb5\n',
230
self.assertEqual([b'--- old_\xb5\n',
232
b'@@ -1,1 +1,1 @@\n',
237
238
def test_internal_diff_no_content(self):
238
239
output = BytesIO()
239
240
diff.internal_diff(u'old', [], u'new', [], output)
240
self.assertEqual('', output.getvalue())
241
self.assertEqual(b'', output.getvalue())
242
243
def test_internal_diff_no_changes(self):
243
244
output = BytesIO()
244
diff.internal_diff(u'old', ['text\n', 'contents\n'],
245
u'new', ['text\n', 'contents\n'],
245
diff.internal_diff(u'old', [b'text\n', b'contents\n'],
246
u'new', [b'text\n', b'contents\n'],
247
self.assertEqual('', output.getvalue())
248
self.assertEqual(b'', output.getvalue())
249
250
def test_internal_diff_returns_bytes(self):
251
diff.internal_diff(u'old_\xb5', ['old_text\n'],
252
u'new_\xe5', ['new_text\n'], output)
252
diff.internal_diff(u'old_\xb5', [b'old_text\n'],
253
u'new_\xe5', [b'new_text\n'], output)
253
254
output.check_types(self, bytes)
255
256
def test_internal_diff_default_context(self):
256
257
output = BytesIO()
257
diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
258
'same_text\n', 'same_text\n', 'old_text\n'],
259
'new', ['same_text\n', 'same_text\n', 'same_text\n',
260
'same_text\n', 'same_text\n', 'new_text\n'], output)
258
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
259
b'same_text\n', b'same_text\n', b'old_text\n'],
260
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
261
b'same_text\n', b'same_text\n', b'new_text\n'], output)
261
262
lines = output.getvalue().splitlines(True)
262
263
self.check_patch(lines)
263
self.assertEqual(['--- old\n',
264
self.assertEqual([b'--- old\n',
266
b'@@ -3,4 +3,4 @@\n',
275
275
def test_internal_diff_no_context(self):
276
276
output = BytesIO()
277
diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
278
'same_text\n', 'same_text\n', 'old_text\n'],
279
'new', ['same_text\n', 'same_text\n', 'same_text\n',
280
'same_text\n', 'same_text\n', 'new_text\n'], output,
277
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
278
b'same_text\n', b'same_text\n', b'old_text\n'],
279
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
280
b'same_text\n', b'same_text\n', b'new_text\n'], output,
282
282
lines = output.getvalue().splitlines(True)
283
283
self.check_patch(lines)
284
self.assertEqual(['--- old\n',
284
self.assertEqual([b'--- old\n',
286
b'@@ -6,1 +6,1 @@\n',
293
292
def test_internal_diff_more_context(self):
294
293
output = BytesIO()
295
diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
296
'same_text\n', 'same_text\n', 'old_text\n'],
297
'new', ['same_text\n', 'same_text\n', 'same_text\n',
298
'same_text\n', 'same_text\n', 'new_text\n'], output,
294
diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
295
b'same_text\n', b'same_text\n', b'old_text\n'],
296
'new', [b'same_text\n', b'same_text\n', b'same_text\n',
297
b'same_text\n', b'same_text\n', b'new_text\n'], output,
300
299
lines = output.getvalue().splitlines(True)
301
300
self.check_patch(lines)
302
self.assertEqual(['--- old\n',
301
self.assertEqual([b'--- old\n',
303
b'@@ -2,5 +2,5 @@\n',
319
314
class TestDiffFiles(tests.TestCaseInTempDir):
483
480
def test_modified_file(self):
484
481
"""Test when a file is modified."""
485
482
tree = self.make_branch_and_tree('tree')
486
self.build_tree_contents([('tree/file', 'contents\n')])
487
tree.add(['file'], ['file-id'])
488
tree.commit('one', rev_id='rev-1')
483
self.build_tree_contents([('tree/file', b'contents\n')])
484
tree.add(['file'], [b'file-id'])
485
tree.commit('one', rev_id=b'rev-1')
490
self.build_tree_contents([('tree/file', 'new contents\n')])
487
self.build_tree_contents([('tree/file', b'new contents\n')])
491
488
d = get_diff_as_string(tree.basis_tree(), tree)
492
self.assertContainsRe(d, "=== modified file 'file'\n")
493
self.assertContainsRe(d, '--- old/file\t')
494
self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
495
self.assertContainsRe(d, '-contents\n'
489
self.assertContainsRe(d, b"=== modified file 'file'\n")
490
self.assertContainsRe(d, b'--- old/file\t')
491
self.assertContainsRe(d, b'\\+\\+\\+ new/file\t')
492
self.assertContainsRe(d, b'-contents\n'
493
b'\\+new contents\n')
498
495
def test_modified_file_in_renamed_dir(self):
499
496
"""Test when a file is modified in a renamed directory."""
500
497
tree = self.make_branch_and_tree('tree')
501
498
self.build_tree(['tree/dir/'])
502
self.build_tree_contents([('tree/dir/file', 'contents\n')])
503
tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
504
tree.commit('one', rev_id='rev-1')
499
self.build_tree_contents([('tree/dir/file', b'contents\n')])
500
tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
501
tree.commit('one', rev_id=b'rev-1')
506
503
tree.rename_one('dir', 'other')
507
self.build_tree_contents([('tree/other/file', 'new contents\n')])
504
self.build_tree_contents([('tree/other/file', b'new contents\n')])
508
505
d = get_diff_as_string(tree.basis_tree(), tree)
509
self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
510
self.assertContainsRe(d, "=== modified file 'other/file'\n")
506
self.assertContainsRe(d, b"=== renamed directory 'dir' => 'other'\n")
507
self.assertContainsRe(d, b"=== modified file 'other/file'\n")
511
508
# XXX: This is technically incorrect, because it used to be at another
512
509
# location. What to do?
513
self.assertContainsRe(d, '--- old/dir/file\t')
514
self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
515
self.assertContainsRe(d, '-contents\n'
510
self.assertContainsRe(d, b'--- old/dir/file\t')
511
self.assertContainsRe(d, b'\\+\\+\\+ new/other/file\t')
512
self.assertContainsRe(d, b'-contents\n'
513
b'\\+new contents\n')
518
515
def test_renamed_directory(self):
519
516
"""Test when only a directory is only renamed."""
520
517
tree = self.make_branch_and_tree('tree')
521
518
self.build_tree(['tree/dir/'])
522
self.build_tree_contents([('tree/dir/file', 'contents\n')])
523
tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
524
tree.commit('one', rev_id='rev-1')
519
self.build_tree_contents([('tree/dir/file', b'contents\n')])
520
tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
521
tree.commit('one', rev_id=b'rev-1')
526
523
tree.rename_one('dir', 'newdir')
527
524
d = get_diff_as_string(tree.basis_tree(), tree)
528
525
# Renaming a directory should be a single "you renamed this dir" even
529
526
# when there are files inside.
530
self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
527
self.assertEqual(d, b"=== renamed directory 'dir' => 'newdir'\n")
532
529
def test_renamed_file(self):
533
530
"""Test when a file is only renamed."""
534
531
tree = self.make_branch_and_tree('tree')
535
self.build_tree_contents([('tree/file', 'contents\n')])
536
tree.add(['file'], ['file-id'])
537
tree.commit('one', rev_id='rev-1')
532
self.build_tree_contents([('tree/file', b'contents\n')])
533
tree.add(['file'], [b'file-id'])
534
tree.commit('one', rev_id=b'rev-1')
539
536
tree.rename_one('file', 'newname')
540
537
d = get_diff_as_string(tree.basis_tree(), tree)
541
self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
538
self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
542
539
# We shouldn't have a --- or +++ line, because there is no content
544
self.assertNotContainsRe(d, '---')
541
self.assertNotContainsRe(d, b'---')
546
543
def test_renamed_and_modified_file(self):
547
544
"""Test when a file is only renamed."""
548
545
tree = self.make_branch_and_tree('tree')
549
self.build_tree_contents([('tree/file', 'contents\n')])
550
tree.add(['file'], ['file-id'])
551
tree.commit('one', rev_id='rev-1')
546
self.build_tree_contents([('tree/file', b'contents\n')])
547
tree.add(['file'], [b'file-id'])
548
tree.commit('one', rev_id=b'rev-1')
553
550
tree.rename_one('file', 'newname')
554
self.build_tree_contents([('tree/newname', 'new contents\n')])
551
self.build_tree_contents([('tree/newname', b'new contents\n')])
555
552
d = get_diff_as_string(tree.basis_tree(), tree)
556
self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
557
self.assertContainsRe(d, '--- old/file\t')
558
self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
559
self.assertContainsRe(d, '-contents\n'
553
self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
554
self.assertContainsRe(d, b'--- old/file\t')
555
self.assertContainsRe(d, b'\\+\\+\\+ new/newname\t')
556
self.assertContainsRe(d, b'-contents\n'
557
b'\\+new contents\n')
563
559
def test_internal_diff_exec_property(self):
564
560
tree = self.make_branch_and_tree('tree')
566
tt = transform.TreeTransform(tree)
567
tt.new_file('a', tt.root, 'contents\n', 'a-id', True)
568
tt.new_file('b', tt.root, 'contents\n', 'b-id', False)
569
tt.new_file('c', tt.root, 'contents\n', 'c-id', True)
570
tt.new_file('d', tt.root, 'contents\n', 'd-id', False)
571
tt.new_file('e', tt.root, 'contents\n', 'control-e-id', True)
572
tt.new_file('f', tt.root, 'contents\n', 'control-f-id', False)
562
tt = tree.get_transform()
563
tt.new_file('a', tt.root, [b'contents\n'], b'a-id', True)
564
tt.new_file('b', tt.root, [b'contents\n'], b'b-id', False)
565
tt.new_file('c', tt.root, [b'contents\n'], b'c-id', True)
566
tt.new_file('d', tt.root, [b'contents\n'], b'd-id', False)
567
tt.new_file('e', tt.root, [b'contents\n'], b'control-e-id', True)
568
tt.new_file('f', tt.root, [b'contents\n'], b'control-f-id', False)
574
tree.commit('one', rev_id='rev-1')
570
tree.commit('one', rev_id=b'rev-1')
576
tt = transform.TreeTransform(tree)
577
tt.set_executability(False, tt.trans_id_file_id('a-id'))
578
tt.set_executability(True, tt.trans_id_file_id('b-id'))
579
tt.set_executability(False, tt.trans_id_file_id('c-id'))
580
tt.set_executability(True, tt.trans_id_file_id('d-id'))
572
tt = tree.get_transform()
573
tt.set_executability(False, tt.trans_id_file_id(b'a-id'))
574
tt.set_executability(True, tt.trans_id_file_id(b'b-id'))
575
tt.set_executability(False, tt.trans_id_file_id(b'c-id'))
576
tt.set_executability(True, tt.trans_id_file_id(b'd-id'))
582
578
tree.rename_one('c', 'new-c')
583
579
tree.rename_one('d', 'new-d')
585
581
d = get_diff_as_string(tree.basis_tree(), tree)
587
self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
589
self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
591
self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
593
self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
595
self.assertNotContainsRe(d, r"file 'e'")
596
self.assertNotContainsRe(d, r"file 'f'")
583
self.assertContainsRe(d, br"file 'a'.*\(properties changed:"
585
self.assertContainsRe(d, br"file 'b'.*\(properties changed:"
587
self.assertContainsRe(d, br"file 'c'.*\(properties changed:"
589
self.assertContainsRe(d, br"file 'd'.*\(properties changed:"
591
self.assertNotContainsRe(d, br"file 'e'")
592
self.assertNotContainsRe(d, br"file 'f'")
598
594
def test_binary_unicode_filenames(self):
599
595
"""Test that contents of files are *not* encoded in UTF-8 when there
720
716
def test_diff_text(self):
721
717
self.build_tree_contents([('old-tree/olddir/',),
722
('old-tree/olddir/oldfile', 'old\n')])
718
('old-tree/olddir/oldfile', b'old\n')])
723
719
self.old_tree.add('olddir')
724
self.old_tree.add('olddir/oldfile', 'file-id')
720
self.old_tree.add('olddir/oldfile', b'file-id')
725
721
self.build_tree_contents([('new-tree/newdir/',),
726
('new-tree/newdir/newfile', 'new\n')])
722
('new-tree/newdir/newfile', b'new\n')])
727
723
self.new_tree.add('newdir')
728
self.new_tree.add('newdir/newfile', 'file-id')
724
self.new_tree.add('newdir/newfile', b'file-id')
729
725
differ = diff.DiffText(self.old_tree, self.new_tree, BytesIO())
730
differ.diff_text('olddir/oldfile', None, 'old label',
731
'new label', 'file-id', None)
726
differ.diff_text('olddir/oldfile', None, 'old label', 'new label')
732
727
self.assertEqual(
733
'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
728
b'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
734
729
differ.to_file.getvalue())
735
730
differ.to_file.seek(0)
736
731
differ.diff_text(None, 'newdir/newfile',
737
'old label', 'new label', None, 'file-id')
732
'old label', 'new label')
738
733
self.assertEqual(
739
'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
734
b'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
740
735
differ.to_file.getvalue())
741
736
differ.to_file.seek(0)
742
737
differ.diff_text('olddir/oldfile', 'newdir/newfile',
743
'old label', 'new label', 'file-id', 'file-id')
738
'old label', 'new label')
744
739
self.assertEqual(
745
'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
740
b'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
746
741
differ.to_file.getvalue())
748
743
def test_diff_deletion(self):
749
self.build_tree_contents([('old-tree/file', 'contents'),
750
('new-tree/file', 'contents')])
751
self.old_tree.add('file', 'file-id')
752
self.new_tree.add('file', 'file-id')
744
self.build_tree_contents([('old-tree/file', b'contents'),
745
('new-tree/file', b'contents')])
746
self.old_tree.add('file', b'file-id')
747
self.new_tree.add('file', b'file-id')
753
748
os.unlink('new-tree/file')
754
749
self.differ.show_diff(None)
755
self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
750
self.assertContainsRe(self.differ.to_file.getvalue(), b'-contents')
757
752
def test_diff_creation(self):
758
self.build_tree_contents([('old-tree/file', 'contents'),
759
('new-tree/file', 'contents')])
760
self.old_tree.add('file', 'file-id')
761
self.new_tree.add('file', 'file-id')
753
self.build_tree_contents([('old-tree/file', b'contents'),
754
('new-tree/file', b'contents')])
755
self.old_tree.add('file', b'file-id')
756
self.new_tree.add('file', b'file-id')
762
757
os.unlink('old-tree/file')
763
758
self.differ.show_diff(None)
764
self.assertContainsRe(self.differ.to_file.getvalue(), r'\+contents')
759
self.assertContainsRe(self.differ.to_file.getvalue(), br'\+contents')
766
761
def test_diff_symlink(self):
767
762
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
768
763
differ.diff_symlink('old target', None)
769
self.assertEqual("=== target was 'old target'\n",
764
self.assertEqual(b"=== target was 'old target'\n",
770
765
differ.to_file.getvalue())
772
767
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
773
768
differ.diff_symlink(None, 'new target')
774
self.assertEqual("=== target is 'new target'\n",
769
self.assertEqual(b"=== target is 'new target'\n",
775
770
differ.to_file.getvalue())
777
772
differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
778
773
differ.diff_symlink('old target', 'new target')
779
self.assertEqual("=== target changed 'old target' => 'new target'\n",
774
self.assertEqual(b"=== target changed 'old target' => 'new target'\n",
780
775
differ.to_file.getvalue())
782
777
def test_diff(self):
783
778
self.build_tree_contents([('old-tree/olddir/',),
784
('old-tree/olddir/oldfile', 'old\n')])
779
('old-tree/olddir/oldfile', b'old\n')])
785
780
self.old_tree.add('olddir')
786
self.old_tree.add('olddir/oldfile', 'file-id')
781
self.old_tree.add('olddir/oldfile', b'file-id')
787
782
self.build_tree_contents([('new-tree/newdir/',),
788
('new-tree/newdir/newfile', 'new\n')])
783
('new-tree/newdir/newfile', b'new\n')])
789
784
self.new_tree.add('newdir')
790
self.new_tree.add('newdir/newfile', 'file-id')
791
self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
785
self.new_tree.add('newdir/newfile', b'file-id')
786
self.differ.diff('olddir/oldfile', 'newdir/newfile')
792
787
self.assertContainsRe(
793
788
self.differ.to_file.getvalue(),
794
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
795
r' \@\@\n-old\n\+new\n\n')
789
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
790
br' \@\@\n-old\n\+new\n\n')
797
792
def test_diff_kind_change(self):
798
793
self.requireFeature(features.SymlinkFeature)
799
794
self.build_tree_contents([('old-tree/olddir/',),
800
('old-tree/olddir/oldfile', 'old\n')])
795
('old-tree/olddir/oldfile', b'old\n')])
801
796
self.old_tree.add('olddir')
802
self.old_tree.add('olddir/oldfile', 'file-id')
797
self.old_tree.add('olddir/oldfile', b'file-id')
803
798
self.build_tree(['new-tree/newdir/'])
804
799
os.symlink('new', 'new-tree/newdir/newfile')
805
800
self.new_tree.add('newdir')
806
self.new_tree.add('newdir/newfile', 'file-id')
807
self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
801
self.new_tree.add('newdir/newfile', b'file-id')
802
self.differ.diff('olddir/oldfile', 'newdir/newfile')
808
803
self.assertContainsRe(
809
804
self.differ.to_file.getvalue(),
810
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
805
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
812
807
self.assertContainsRe(self.differ.to_file.getvalue(),
813
"=== target is u'new'\n")
808
b"=== target is 'new'\n")
815
810
def test_diff_directory(self):
816
811
self.build_tree(['new-tree/new-dir/'])
817
self.new_tree.add('new-dir', 'new-dir-id')
818
self.differ.diff('new-dir-id', None, 'new-dir')
819
self.assertEqual(self.differ.to_file.getvalue(), '')
812
self.new_tree.add('new-dir', b'new-dir-id')
813
self.differ.diff(None, 'new-dir')
814
self.assertEqual(self.differ.to_file.getvalue(), b'')
821
816
def create_old_new(self):
822
817
self.build_tree_contents([('old-tree/olddir/',),
823
('old-tree/olddir/oldfile', 'old\n')])
818
('old-tree/olddir/oldfile', b'old\n')])
824
819
self.old_tree.add('olddir')
825
self.old_tree.add('olddir/oldfile', 'file-id')
820
self.old_tree.add('olddir/oldfile', b'file-id')
826
821
self.build_tree_contents([('new-tree/newdir/',),
827
('new-tree/newdir/newfile', 'new\n')])
822
('new-tree/newdir/newfile', b'new\n')])
828
823
self.new_tree.add('newdir')
829
self.new_tree.add('newdir/newfile', 'file-id')
824
self.new_tree.add('newdir/newfile', b'file-id')
831
826
def test_register_diff(self):
832
827
self.create_old_new()
833
828
old_diff_factories = diff.DiffTree.diff_factories
834
diff.DiffTree.diff_factories=old_diff_factories[:]
829
diff.DiffTree.diff_factories = old_diff_factories[:]
835
830
diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
837
832
differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
839
834
diff.DiffTree.diff_factories = old_diff_factories
840
differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
835
differ.diff('olddir/oldfile', 'newdir/newfile')
841
836
self.assertNotContainsRe(
842
837
differ.to_file.getvalue(),
843
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
844
r' \@\@\n-old\n\+new\n\n')
838
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
839
br' \@\@\n-old\n\+new\n\n')
845
840
self.assertContainsRe(differ.to_file.getvalue(),
846
'was: old\nis: new\n')
841
b'was: old\nis: new\n')
848
843
def test_extra_factories(self):
849
844
self.create_old_new()
850
845
differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO(),
851
846
extra_factories=[DiffWasIs.from_diff_tree])
852
differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
847
differ.diff('olddir/oldfile', 'newdir/newfile')
853
848
self.assertNotContainsRe(
854
849
differ.to_file.getvalue(),
855
r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
856
r' \@\@\n-old\n\+new\n\n')
850
br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
851
br' \@\@\n-old\n\+new\n\n')
857
852
self.assertContainsRe(differ.to_file.getvalue(),
858
'was: old\nis: new\n')
853
b'was: old\nis: new\n')
860
855
def test_alphabetical_order(self):
861
856
self.build_tree(['new-tree/a-file'])
864
859
self.old_tree.add('b-file')
865
860
self.differ.show_diff(None)
866
861
self.assertContainsRe(self.differ.to_file.getvalue(),
867
'.*a-file(.|\n)*b-file')
870
class TestPatienceDiffLib(tests.TestCase):
873
super(TestPatienceDiffLib, self).setUp()
874
self._unique_lcs = _patiencediff_py.unique_lcs_py
875
self._recurse_matches = _patiencediff_py.recurse_matches_py
876
self._PatienceSequenceMatcher = \
877
_patiencediff_py.PatienceSequenceMatcher_py
879
def test_diff_unicode_string(self):
880
a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
881
b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
882
sm = self._PatienceSequenceMatcher(None, a, b)
883
mb = sm.get_matching_blocks()
884
self.assertEqual(35, len(mb))
886
def test_unique_lcs(self):
887
unique_lcs = self._unique_lcs
888
self.assertEqual(unique_lcs('', ''), [])
889
self.assertEqual(unique_lcs('', 'a'), [])
890
self.assertEqual(unique_lcs('a', ''), [])
891
self.assertEqual(unique_lcs('a', 'a'), [(0, 0)])
892
self.assertEqual(unique_lcs('a', 'b'), [])
893
self.assertEqual(unique_lcs('ab', 'ab'), [(0, 0), (1, 1)])
894
self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2, 0), (3, 1), (4, 2)])
895
self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0, 2), (1, 3), (2, 4)])
896
self.assertEqual(unique_lcs('abXde', 'abYde'), [(0, 0), (1, 1),
898
self.assertEqual(unique_lcs('acbac', 'abc'), [(2, 1)])
900
def test_recurse_matches(self):
901
def test_one(a, b, matches):
903
self._recurse_matches(
904
a, b, 0, 0, len(a), len(b), test_matches, 10)
905
self.assertEqual(test_matches, matches)
907
test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
908
[(0, 0), (2, 2), (4, 4)])
909
test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
910
[(0, 0), (2, 1), (4, 2)])
911
# Even though 'bc' is not unique globally, and is surrounded by
912
# non-matching lines, we should still match, because they are locally
914
test_one('abcdbce', 'afbcgdbce', [(0, 0), (1, 2), (2, 3), (3, 5),
915
(4, 6), (5, 7), (6, 8)])
917
# recurse_matches doesn't match non-unique
918
# lines surrounded by bogus text.
919
# The update has been done in patiencediff.SequenceMatcher instead
921
# This is what it could be
922
#test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
924
# This is what it currently gives:
925
test_one('aBccDe', 'abccde', [(0, 0), (5, 5)])
927
def assertDiffBlocks(self, a, b, expected_blocks):
928
"""Check that the sequence matcher returns the correct blocks.
930
:param a: A sequence to match
931
:param b: Another sequence to match
932
:param expected_blocks: The expected output, not including the final
933
matching block (len(a), len(b), 0)
935
matcher = self._PatienceSequenceMatcher(None, a, b)
936
blocks = matcher.get_matching_blocks()
938
self.assertEqual((len(a), len(b), 0), last)
939
self.assertEqual(expected_blocks, blocks)
941
def test_matching_blocks(self):
942
# Some basic matching tests
943
self.assertDiffBlocks('', '', [])
944
self.assertDiffBlocks([], [], [])
945
self.assertDiffBlocks('abc', '', [])
946
self.assertDiffBlocks('', 'abc', [])
947
self.assertDiffBlocks('abcd', 'abcd', [(0, 0, 4)])
948
self.assertDiffBlocks('abcd', 'abce', [(0, 0, 3)])
949
self.assertDiffBlocks('eabc', 'abce', [(1, 0, 3)])
950
self.assertDiffBlocks('eabce', 'abce', [(1, 0, 4)])
951
self.assertDiffBlocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
952
self.assertDiffBlocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
953
self.assertDiffBlocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
954
# This may check too much, but it checks to see that
955
# a copied block stays attached to the previous section,
957
# difflib would tend to grab the trailing longest match
958
# which would make the diff not look right
959
self.assertDiffBlocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
960
[(0, 0, 6), (6, 11, 10)])
962
# make sure it supports passing in lists
963
self.assertDiffBlocks(
966
'how are you today?\n'],
968
'how are you today?\n'],
969
[(0, 0, 1), (2, 1, 1)])
971
# non unique lines surrounded by non-matching lines
973
self.assertDiffBlocks('aBccDe', 'abccde', [(0, 0, 1), (5, 5, 1)])
975
# But they only need to be locally unique
976
self.assertDiffBlocks('aBcDec', 'abcdec', [(0, 0, 1), (2, 2, 1), (4, 4, 2)])
978
# non unique blocks won't be matched
979
self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0, 0, 1), (8, 8, 1)])
981
# but locally unique ones will
982
self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0, 0, 1), (2, 2, 2),
983
(5, 4, 1), (7, 5, 2), (10, 8, 1)])
985
self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7, 7, 1)])
986
self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
987
self.assertDiffBlocks('bbbbbbbb', 'cbbbbbbc', [])
989
def test_matching_blocks_tuples(self):
990
# Some basic matching tests
991
self.assertDiffBlocks([], [], [])
992
self.assertDiffBlocks([('a',), ('b',), ('c,')], [], [])
993
self.assertDiffBlocks([], [('a',), ('b',), ('c,')], [])
994
self.assertDiffBlocks([('a',), ('b',), ('c,')],
995
[('a',), ('b',), ('c,')],
997
self.assertDiffBlocks([('a',), ('b',), ('c,')],
998
[('a',), ('b',), ('d,')],
1000
self.assertDiffBlocks([('d',), ('b',), ('c,')],
1001
[('a',), ('b',), ('c,')],
1003
self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
1004
[('a',), ('b',), ('c,')],
1006
self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
1007
[('a', 'b'), ('c', 'X'), ('e', 'f')],
1008
[(0, 0, 1), (2, 2, 1)])
1009
self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
1010
[('a', 'b'), ('c', 'dX'), ('e', 'f')],
1011
[(0, 0, 1), (2, 2, 1)])
1013
def test_opcodes(self):
1014
def chk_ops(a, b, expected_codes):
1015
s = self._PatienceSequenceMatcher(None, a, b)
1016
self.assertEqual(expected_codes, s.get_opcodes())
1020
chk_ops('abc', '', [('delete', 0, 3, 0, 0)])
1021
chk_ops('', 'abc', [('insert', 0, 0, 0, 3)])
1022
chk_ops('abcd', 'abcd', [('equal', 0, 4, 0, 4)])
1023
chk_ops('abcd', 'abce', [('equal', 0, 3, 0, 3),
1024
('replace', 3, 4, 3, 4)
1026
chk_ops('eabc', 'abce', [('delete', 0, 1, 0, 0),
1027
('equal', 1, 4, 0, 3),
1028
('insert', 4, 4, 3, 4)
1030
chk_ops('eabce', 'abce', [('delete', 0, 1, 0, 0),
1031
('equal', 1, 5, 0, 4)
1033
chk_ops('abcde', 'abXde', [('equal', 0, 2, 0, 2),
1034
('replace', 2, 3, 2, 3),
1035
('equal', 3, 5, 3, 5)
1037
chk_ops('abcde', 'abXYZde', [('equal', 0, 2, 0, 2),
1038
('replace', 2, 3, 2, 5),
1039
('equal', 3, 5, 5, 7)
1041
chk_ops('abde', 'abXYZde', [('equal', 0, 2, 0, 2),
1042
('insert', 2, 2, 2, 5),
1043
('equal', 2, 4, 5, 7)
1045
chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1046
[('equal', 0, 6, 0, 6),
1047
('insert', 6, 6, 6, 11),
1048
('equal', 6, 16, 11, 21)
1053
, 'how are you today?\n'],
1055
, 'how are you today?\n'],
1056
[('equal', 0, 1, 0, 1),
1057
('delete', 1, 2, 1, 1),
1058
('equal', 2, 3, 1, 2),
1060
chk_ops('aBccDe', 'abccde',
1061
[('equal', 0, 1, 0, 1),
1062
('replace', 1, 5, 1, 5),
1063
('equal', 5, 6, 5, 6),
1065
chk_ops('aBcDec', 'abcdec',
1066
[('equal', 0, 1, 0, 1),
1067
('replace', 1, 2, 1, 2),
1068
('equal', 2, 3, 2, 3),
1069
('replace', 3, 4, 3, 4),
1070
('equal', 4, 6, 4, 6),
1072
chk_ops('aBcdEcdFg', 'abcdecdfg',
1073
[('equal', 0, 1, 0, 1),
1074
('replace', 1, 8, 1, 8),
1075
('equal', 8, 9, 8, 9)
1077
chk_ops('aBcdEeXcdFg', 'abcdecdfg',
1078
[('equal', 0, 1, 0, 1),
1079
('replace', 1, 2, 1, 2),
1080
('equal', 2, 4, 2, 4),
1081
('delete', 4, 5, 4, 4),
1082
('equal', 5, 6, 4, 5),
1083
('delete', 6, 7, 5, 5),
1084
('equal', 7, 9, 5, 7),
1085
('replace', 9, 10, 7, 8),
1086
('equal', 10, 11, 8, 9)
1089
def test_grouped_opcodes(self):
1090
def chk_ops(a, b, expected_codes, n=3):
1091
s = self._PatienceSequenceMatcher(None, a, b)
1092
self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
1096
chk_ops('abc', '', [[('delete', 0, 3, 0, 0)]])
1097
chk_ops('', 'abc', [[('insert', 0, 0, 0, 3)]])
1098
chk_ops('abcd', 'abcd', [])
1099
chk_ops('abcd', 'abce', [[('equal', 0, 3, 0, 3),
1100
('replace', 3, 4, 3, 4)
1102
chk_ops('eabc', 'abce', [[('delete', 0, 1, 0, 0),
1103
('equal', 1, 4, 0, 3),
1104
('insert', 4, 4, 3, 4)
1106
chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1107
[[('equal', 3, 6, 3, 6),
1108
('insert', 6, 6, 6, 11),
1109
('equal', 6, 9, 11, 14)
1111
chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1112
[[('equal', 2, 6, 2, 6),
1113
('insert', 6, 6, 6, 11),
1114
('equal', 6, 10, 11, 15)
1116
chk_ops('Xabcdef', 'abcdef',
1117
[[('delete', 0, 1, 0, 0),
1118
('equal', 1, 4, 0, 3)
1120
chk_ops('abcdef', 'abcdefX',
1121
[[('equal', 3, 6, 3, 6),
1122
('insert', 6, 6, 6, 7)
1126
def test_multiple_ranges(self):
1127
# There was an earlier bug where we used a bad set of ranges,
1128
# this triggers that specific bug, to make sure it doesn't regress
1129
self.assertDiffBlocks('abcdefghijklmnop',
1130
'abcXghiYZQRSTUVWXYZijklmnop',
1131
[(0, 0, 3), (6, 4, 3), (9, 20, 7)])
1133
self.assertDiffBlocks('ABCd efghIjk L',
1134
'AxyzBCn mo pqrstuvwI1 2 L',
1135
[(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1137
# These are rot13 code snippets.
1138
self.assertDiffBlocks('''\
1139
trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1141
gnxrf_netf = ['svyr*']
1142
gnxrf_bcgvbaf = ['ab-erphefr']
1144
qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1145
sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1147
ercbegre = nqq_ercbegre_ahyy
1149
ercbegre = nqq_ercbegre_cevag
1150
fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
1153
pynff pzq_zxqve(Pbzznaq):
1154
'''.splitlines(True), '''\
1155
trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1157
--qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
1160
gnxrf_netf = ['svyr*']
1161
gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
1163
qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
1168
# Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
1169
npgvba = omeyvo.nqq.nqq_npgvba_ahyy
1171
npgvba = omeyvo.nqq.nqq_npgvba_cevag
1173
npgvba = omeyvo.nqq.nqq_npgvba_nqq
1175
npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
1177
omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
1180
pynff pzq_zxqve(Pbzznaq):
1181
'''.splitlines(True)
1182
, [(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1184
def test_patience_unified_diff(self):
1185
txt_a = ['hello there\n',
1187
'how are you today?\n']
1188
txt_b = ['hello there\n',
1189
'how are you today?\n']
1190
unified_diff = patiencediff.unified_diff
1191
psm = self._PatienceSequenceMatcher
1192
self.assertEqual(['--- \n',
1194
'@@ -1,3 +1,2 @@\n',
1197
' how are you today?\n'
1199
, list(unified_diff(txt_a, txt_b,
1200
sequencematcher=psm)))
1201
txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1202
txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1203
# This is the result with LongestCommonSubstring matching
1204
self.assertEqual(['--- \n',
1206
'@@ -1,6 +1,11 @@\n',
1218
, list(unified_diff(txt_a, txt_b)))
1219
# And the patience diff
1220
self.assertEqual(['--- \n',
1222
'@@ -4,6 +4,11 @@\n',
1235
, list(unified_diff(txt_a, txt_b,
1236
sequencematcher=psm)))
1238
def test_patience_unified_diff_with_dates(self):
1239
txt_a = ['hello there\n',
1241
'how are you today?\n']
1242
txt_b = ['hello there\n',
1243
'how are you today?\n']
1244
unified_diff = patiencediff.unified_diff
1245
psm = self._PatienceSequenceMatcher
1246
self.assertEqual(['--- a\t2008-08-08\n',
1247
'+++ b\t2008-09-09\n',
1248
'@@ -1,3 +1,2 @@\n',
1251
' how are you today?\n'
1253
, list(unified_diff(txt_a, txt_b,
1254
fromfile='a', tofile='b',
1255
fromfiledate='2008-08-08',
1256
tofiledate='2008-09-09',
1257
sequencematcher=psm)))
1260
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1262
_test_needs_features = [features.compiled_patiencediff_feature]
1265
super(TestPatienceDiffLib_c, self).setUp()
1266
from breezy import _patiencediff_c
1267
self._unique_lcs = _patiencediff_c.unique_lcs_c
1268
self._recurse_matches = _patiencediff_c.recurse_matches_c
1269
self._PatienceSequenceMatcher = \
1270
_patiencediff_c.PatienceSequenceMatcher_c
1272
def test_unhashable(self):
1273
"""We should get a proper exception here."""
1274
# We need to be able to hash items in the sequence, lists are
1275
# unhashable, and thus cannot be diffed
1276
e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1278
e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1279
None, ['valid', []], [])
1280
e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1281
None, ['valid'], [[]])
1282
e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1283
None, ['valid'], ['valid', []])
1286
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1289
super(TestPatienceDiffLibFiles, self).setUp()
1290
self._PatienceSequenceMatcher = \
1291
_patiencediff_py.PatienceSequenceMatcher_py
1293
def test_patience_unified_diff_files(self):
1294
txt_a = ['hello there\n',
1296
'how are you today?\n']
1297
txt_b = ['hello there\n',
1298
'how are you today?\n']
1299
with open('a1', 'wb') as f: f.writelines(txt_a)
1300
with open('b1', 'wb') as f: f.writelines(txt_b)
1302
unified_diff_files = patiencediff.unified_diff_files
1303
psm = self._PatienceSequenceMatcher
1304
self.assertEqual(['--- a1\n',
1306
'@@ -1,3 +1,2 @@\n',
1309
' how are you today?\n',
1311
, list(unified_diff_files('a1', 'b1',
1312
sequencematcher=psm)))
1314
txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1315
txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1316
with open('a2', 'wb') as f: f.writelines(txt_a)
1317
with open('b2', 'wb') as f: f.writelines(txt_b)
1319
# This is the result with LongestCommonSubstring matching
1320
self.assertEqual(['--- a2\n',
1322
'@@ -1,6 +1,11 @@\n',
1334
, list(unified_diff_files('a2', 'b2')))
1336
# And the patience diff
1337
self.assertEqual(['--- a2\n',
1339
'@@ -4,6 +4,11 @@\n',
1351
list(unified_diff_files('a2', 'b2',
1352
sequencematcher=psm)))
1355
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1357
_test_needs_features = [features.compiled_patiencediff_feature]
1360
super(TestPatienceDiffLibFiles_c, self).setUp()
1361
from breezy import _patiencediff_c
1362
self._PatienceSequenceMatcher = \
1363
_patiencediff_c.PatienceSequenceMatcher_c
1366
class TestUsingCompiledIfAvailable(tests.TestCase):
1368
def test_PatienceSequenceMatcher(self):
1369
if features.compiled_patiencediff_feature.available():
1370
from breezy._patiencediff_c import PatienceSequenceMatcher_c
1371
self.assertIs(PatienceSequenceMatcher_c,
1372
patiencediff.PatienceSequenceMatcher)
1374
from breezy._patiencediff_py import PatienceSequenceMatcher_py
1375
self.assertIs(PatienceSequenceMatcher_py,
1376
patiencediff.PatienceSequenceMatcher)
1378
def test_unique_lcs(self):
1379
if features.compiled_patiencediff_feature.available():
1380
from breezy._patiencediff_c import unique_lcs_c
1381
self.assertIs(unique_lcs_c,
1382
patiencediff.unique_lcs)
1384
from breezy._patiencediff_py import unique_lcs_py
1385
self.assertIs(unique_lcs_py,
1386
patiencediff.unique_lcs)
1388
def test_recurse_matches(self):
1389
if features.compiled_patiencediff_feature.available():
1390
from breezy._patiencediff_c import recurse_matches_c
1391
self.assertIs(recurse_matches_c,
1392
patiencediff.recurse_matches)
1394
from breezy._patiencediff_py import recurse_matches_py
1395
self.assertIs(recurse_matches_py,
1396
patiencediff.recurse_matches)
862
b'.*a-file(.|\n)*b-file')
1399
865
class TestDiffFromTool(tests.TestCaseWithTransport):
1401
867
def test_from_string(self):
1402
diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1403
self.addCleanup(diff_obj.finish)
1404
self.assertEqual(['diff', '@old_path', '@new_path'],
1405
diff_obj.command_template)
868
diff_obj = diff.DiffFromTool.from_string(
869
['diff', '{old_path}', '{new_path}'],
871
self.addCleanup(diff_obj.finish)
872
self.assertEqual(['diff', '{old_path}', '{new_path}'],
873
diff_obj.command_template)
875
def test_from_string_no_paths(self):
876
diff_obj = diff.DiffFromTool.from_string(
877
['diff', "-u5"], None, None, None)
878
self.addCleanup(diff_obj.finish)
879
self.assertEqual(['diff', '-u5'],
880
diff_obj.command_template)
881
self.assertEqual(['diff', '-u5', 'old-path', 'new-path'],
882
diff_obj._get_command('old-path', 'new-path'))
1407
884
def test_from_string_u5(self):
1408
diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
885
diff_obj = diff.DiffFromTool.from_string(
886
['diff', "-u 5", '{old_path}', '{new_path}'], None, None, None)
1410
887
self.addCleanup(diff_obj.finish)
1411
self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
888
self.assertEqual(['diff', '-u 5', '{old_path}', '{new_path}'],
1412
889
diff_obj.command_template)
1413
890
self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1414
891
diff_obj._get_command('old-path', 'new-path'))
1416
893
def test_from_string_path_with_backslashes(self):
1417
894
self.requireFeature(features.backslashdir_feature)
1418
tool = 'C:\\Tools\\Diff.exe'
895
tool = ['C:\\Tools\\Diff.exe', '{old_path}', '{new_path}']
1419
896
diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1420
897
self.addCleanup(diff_obj.finish)
1421
self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
898
self.assertEqual(['C:\\Tools\\Diff.exe', '{old_path}', '{new_path}'],
1422
899
diff_obj.command_template)
1423
900
self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
1424
901
diff_obj._get_command('old-path', 'new-path'))
1426
903
def test_execute(self):
1427
904
output = BytesIO()
1428
diff_obj = diff.DiffFromTool(['python', '-c',
1429
'print "@old_path @new_path"'],
905
diff_obj = diff.DiffFromTool([sys.executable, '-c',
906
'print("{old_path} {new_path}")'],
1430
907
None, None, output)
1431
908
self.addCleanup(diff_obj.finish)
1432
909
diff_obj._execute('old', 'new')
1433
self.assertEqual(output.getvalue().rstrip(), 'old new')
910
self.assertEqual(output.getvalue().rstrip(), b'old new')
1435
912
def test_execute_missing(self):
1436
913
diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],