/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_diff.py

  • Committer: Jelmer Vernooij
  • Date: 2019-03-04 00:16:27 UTC
  • mfrom: (7293 work)
  • mto: This revision was merged to the branch mainline in revision 7318.
  • Revision ID: jelmer@jelmer.uk-20190304001627-v6u7o6pf97tukhek
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import os
18
18
import re
19
19
import subprocess
 
20
import sys
20
21
import tempfile
21
22
 
22
23
from .. import (
104
105
class TestDiffOptionsScenarios(tests.TestCase):
105
106
 
106
107
    scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
107
 
    style = None # Set by load_tests_apply_scenarios from scenarios
 
108
    style = None  # Set by load_tests_apply_scenarios from scenarios
108
109
 
109
110
    def test_unified_not_added(self):
110
111
        # Verify that for all valid style options, '-u' is not
120
121
        lines = udiff_lines([b'boo'], [b'boo\n'])
121
122
        self.check_patch(lines)
122
123
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
123
 
            ## "expected no-nl, got %r" % lines[4]
 
124
        ## "expected no-nl, got %r" % lines[4]
124
125
 
125
126
    def test_add_nl_2(self):
126
127
        """diff generates a valid diff for patches that change last line and
129
130
        lines = udiff_lines([b'boo'], [b'goo\n'])
130
131
        self.check_patch(lines)
131
132
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
132
 
            ## "expected no-nl, got %r" % lines[4]
 
133
        ## "expected no-nl, got %r" % lines[4]
133
134
 
134
135
    def test_remove_nl(self):
135
136
        """diff generates a valid diff for patches that change last line and
138
139
        lines = udiff_lines([b'boo\n'], [b'boo'])
139
140
        self.check_patch(lines)
140
141
        self.assertEqual(lines[5], b'\\ No newline at end of file\n')
141
 
            ## "expected no-nl, got %r" % lines[5]
 
142
        ## "expected no-nl, got %r" % lines[5]
142
143
 
143
144
    def check_patch(self, lines):
144
145
        self.assertTrue(len(lines) > 1)
145
 
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
146
 
        self.assertTrue(lines[0].startswith (b'---'))
147
 
            ## 'No orig line for patch:\n%s' % "".join(lines)
148
 
        self.assertTrue(lines[1].startswith (b'+++'))
149
 
            ## 'No mod line for patch:\n%s' % "".join(lines)
 
146
        ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
 
147
        self.assertTrue(lines[0].startswith(b'---'))
 
148
        ## 'No orig line for patch:\n%s' % "".join(lines)
 
149
        self.assertTrue(lines[1].startswith(b'+++'))
 
150
        ## 'No mod line for patch:\n%s' % "".join(lines)
150
151
        self.assertTrue(len(lines) > 2)
151
 
            ## "No hunks for patch:\n%s" % "".join(lines)
 
152
        ## "No hunks for patch:\n%s" % "".join(lines)
152
153
        self.assertTrue(lines[2].startswith(b'@@'))
153
 
            ## "No hunk header for patch:\n%s" % "".join(lines)
 
154
        ## "No hunk header for patch:\n%s" % "".join(lines)
154
155
        self.assertTrue(b'@@' in lines[2][2:])
155
 
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
 
156
        ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
156
157
 
157
158
    def test_binary_lines(self):
158
159
        empty = []
170
171
    def test_external_diff_no_fileno(self):
171
172
        # Make sure that we can handle not having a fileno, even
172
173
        # if the diff is large
173
 
        lines = external_udiff_lines([b'boo\n']*10000,
174
 
                                     [b'goo\n']*10000,
 
174
        lines = external_udiff_lines([b'boo\n'] * 10000,
 
175
                                     [b'goo\n'] * 10000,
175
176
                                     use_stringio=True)
176
177
        self.check_patch(lines)
177
178
 
181
182
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
182
183
        # Older versions of diffutils say "Binary files", newer
183
184
        # versions just say "Files".
184
 
        self.assertContainsRe(lines[0], b'(Binary f|F)iles old and new differ\n')
 
185
        self.assertContainsRe(
 
186
            lines[0], b'(Binary f|F)iles old and new differ\n')
185
187
        self.assertEqual(lines[1:], [b'\n'])
186
188
 
187
189
    def test_no_external_diff(self):
201
203
        lines = output.getvalue().splitlines(True)
202
204
        self.check_patch(lines)
203
205
        self.assertEqual([b'--- old_\xc2\xb5\n',
204
 
                           b'+++ new_\xc3\xa5\n',
205
 
                           b'@@ -1,1 +1,1 @@\n',
206
 
                           b'-old_text\n',
207
 
                           b'+new_text\n',
208
 
                           b'\n',
209
 
                          ]
210
 
                          , lines)
 
206
                          b'+++ new_\xc3\xa5\n',
 
207
                          b'@@ -1,1 +1,1 @@\n',
 
208
                          b'-old_text\n',
 
209
                          b'+new_text\n',
 
210
                          b'\n',
 
211
                          ], lines)
211
212
 
212
213
    def test_internal_diff_utf8(self):
213
214
        output = BytesIO()
217
218
        lines = output.getvalue().splitlines(True)
218
219
        self.check_patch(lines)
219
220
        self.assertEqual([b'--- old_\xc2\xb5\n',
220
 
                           b'+++ new_\xc3\xa5\n',
221
 
                           b'@@ -1,1 +1,1 @@\n',
222
 
                           b'-old_text\n',
223
 
                           b'+new_text\n',
224
 
                           b'\n',
225
 
                          ]
226
 
                          , lines)
 
221
                          b'+++ new_\xc3\xa5\n',
 
222
                          b'@@ -1,1 +1,1 @@\n',
 
223
                          b'-old_text\n',
 
224
                          b'+new_text\n',
 
225
                          b'\n',
 
226
                          ], lines)
227
227
 
228
228
    def test_internal_diff_iso_8859_1(self):
229
229
        output = BytesIO()
238
238
                          b'-old_text\n',
239
239
                          b'+new_text\n',
240
240
                          b'\n',
241
 
                          ]
242
 
                          , lines)
 
241
                          ], lines)
243
242
 
244
243
    def test_internal_diff_no_content(self):
245
244
        output = BytesIO()
262
261
    def test_internal_diff_default_context(self):
263
262
        output = BytesIO()
264
263
        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'],
 
264
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
266
265
                           '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)
 
266
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output)
268
267
        lines = output.getvalue().splitlines(True)
269
268
        self.check_patch(lines)
270
269
        self.assertEqual([b'--- old\n',
271
 
                           b'+++ new\n',
272
 
                           b'@@ -3,4 +3,4 @@\n',
273
 
                           b' same_text\n',
274
 
                           b' same_text\n',
275
 
                           b' same_text\n',
276
 
                           b'-old_text\n',
277
 
                           b'+new_text\n',
278
 
                           b'\n',
279
 
                          ]
280
 
                          , lines)
 
270
                          b'+++ new\n',
 
271
                          b'@@ -3,4 +3,4 @@\n',
 
272
                          b' same_text\n',
 
273
                          b' same_text\n',
 
274
                          b' same_text\n',
 
275
                          b'-old_text\n',
 
276
                          b'+new_text\n',
 
277
                          b'\n',
 
278
                          ], lines)
281
279
 
282
280
    def test_internal_diff_no_context(self):
283
281
        output = BytesIO()
284
282
        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'],
 
283
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
286
284
                           '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,
 
285
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output,
288
286
                           context_lines=0)
289
287
        lines = output.getvalue().splitlines(True)
290
288
        self.check_patch(lines)
291
289
        self.assertEqual([b'--- old\n',
292
 
                           b'+++ new\n',
293
 
                           b'@@ -6,1 +6,1 @@\n',
294
 
                           b'-old_text\n',
295
 
                           b'+new_text\n',
296
 
                           b'\n',
297
 
                          ]
298
 
                          , lines)
 
290
                          b'+++ new\n',
 
291
                          b'@@ -6,1 +6,1 @@\n',
 
292
                          b'-old_text\n',
 
293
                          b'+new_text\n',
 
294
                          b'\n',
 
295
                          ], lines)
299
296
 
300
297
    def test_internal_diff_more_context(self):
301
298
        output = BytesIO()
302
299
        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'],
 
300
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
304
301
                           '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,
 
302
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output,
306
303
                           context_lines=4)
307
304
        lines = output.getvalue().splitlines(True)
308
305
        self.check_patch(lines)
316
313
                          b'-old_text\n',
317
314
                          b'+new_text\n',
318
315
                          b'\n',
319
 
                          ]
320
 
                          , lines)
321
 
 
 
316
                          ], lines)
322
317
 
323
318
 
324
319
class TestDiffFiles(tests.TestCaseInTempDir):
331
326
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
332
327
 
333
328
        cmd = ['diff', '-u', '--binary', 'old', 'new']
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')
 
329
        with open('old', 'wb') as f:
 
330
            f.write(b'\x00foobar\n')
 
331
        with open('new', 'wb') as f:
 
332
            f.write(b'foo\x00bar\n')
336
333
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
337
 
                                     stdin=subprocess.PIPE)
 
334
                                stdin=subprocess.PIPE)
338
335
        out, err = pipe.communicate()
339
336
        # We should output whatever diff tells us, plus a trailing newline
340
337
        self.assertEqual(out.splitlines(True) + [b'\n'], lines)
347
344
    else:
348
345
        extra_trees = ()
349
346
    diff.show_diff_trees(tree1, tree2, output,
350
 
        specific_files=specific_files,
351
 
        extra_trees=extra_trees, old_label='old/',
352
 
        new_label='new/')
 
347
                         specific_files=specific_files,
 
348
                         extra_trees=extra_trees, old_label='old/',
 
349
                         new_label='new/')
353
350
    return output.getvalue()
354
351
 
355
352
 
366
363
        self.wt.add(['file1', 'file2'])
367
364
        self.wt.commit(
368
365
            message='Revision 1',
369
 
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
 
366
            timestamp=1143849600,  # 2006-04-01 00:00:00 UTC
370
367
            timezone=0,
371
368
            rev_id=b'rev-1')
372
369
        self.build_tree_contents([('file1', b'file1 contents at rev 2\n')])
373
370
        self.wt.commit(
374
371
            message='Revision 2',
375
 
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
 
372
            timestamp=1143936000,  # 2006-04-02 00:00:00 UTC
376
373
            timezone=28800,
377
374
            rev_id=b'rev-2')
378
375
        self.build_tree_contents([('file2', b'file2 contents at rev 3\n')])
379
376
        self.wt.commit(
380
377
            message='Revision 3',
381
 
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
 
378
            timestamp=1144022400,  # 2006-04-03 00:00:00 UTC
382
379
            timezone=-3600,
383
380
            rev_id=b'rev-3')
384
381
        self.wt.remove(['file2'])
385
382
        self.wt.commit(
386
383
            message='Revision 4',
387
 
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
 
384
            timestamp=1144108800,  # 2006-04-04 00:00:00 UTC
388
385
            timezone=0,
389
386
            rev_id=b'rev-4')
390
387
        self.build_tree_contents([
391
388
            ('file1', b'file1 contents in working tree\n')
392
389
            ])
393
390
        # set the date stamps for files in the working tree to known values
394
 
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
 
391
        os.utime('file1', (1144195200, 1144195200))  # 2006-04-05 00:00:00 UTC
395
392
 
396
393
    def test_diff_rev_tree_working_tree(self):
397
394
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
463
460
        old_tree = self.b.repository.revision_tree(b'rev-1')
464
461
        new_tree = self.b.repository.revision_tree(b'rev-4')
465
462
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
466
 
                            working_tree=self.wt)
 
463
                                 working_tree=self.wt)
467
464
        self.assertContainsRe(out, b'file1\t')
468
465
 
469
466
    def test_recursive_diff(self):
475
472
        old_tree = self.b.repository.revision_tree(b'rev-1')
476
473
        new_tree = self.b.repository.revision_tree(b'rev-4')
477
474
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
478
 
                            working_tree=self.wt)
 
475
                                 working_tree=self.wt)
479
476
        self.assertContainsRe(out, b'file1\t')
480
477
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
481
 
                            working_tree=self.wt)
 
478
                                 working_tree=self.wt)
482
479
        self.assertNotContainsRe(out, b'file1\t')
483
480
 
484
481
 
564
561
        self.assertContainsRe(d, b'-contents\n'
565
562
                                 b'\\+new contents\n')
566
563
 
567
 
 
568
564
    def test_internal_diff_exec_property(self):
569
565
        tree = self.make_branch_and_tree('tree')
570
566
 
635
631
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
636
632
 
637
633
        tree = self.make_branch_and_tree('tree')
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'])
 
634
        self.build_tree_contents([('tree/ren_' + alpha, b'contents\n')])
 
635
        tree.add(['ren_' + alpha], [b'file-id-2'])
 
636
        self.build_tree_contents([('tree/del_' + alpha, b'contents\n')])
 
637
        tree.add(['del_' + alpha], [b'file-id-3'])
 
638
        self.build_tree_contents([('tree/mod_' + alpha, b'contents\n')])
 
639
        tree.add(['mod_' + alpha], [b'file-id-4'])
644
640
 
645
641
        tree.commit('one', rev_id=b'rev-1')
646
642
 
647
 
        tree.rename_one('ren_'+alpha, 'ren_'+omega)
648
 
        tree.remove('del_'+alpha)
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')])
 
643
        tree.rename_one('ren_' + alpha, 'ren_' + omega)
 
644
        tree.remove('del_' + alpha)
 
645
        self.build_tree_contents([('tree/add_' + alpha, b'contents\n')])
 
646
        tree.add(['add_' + alpha], [b'file-id'])
 
647
        self.build_tree_contents([('tree/mod_' + alpha, b'contents_mod\n')])
652
648
 
653
649
        d = get_diff_as_string(tree.basis_tree(), tree)
654
650
        self.assertContainsRe(d,
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)
 
651
                              b"=== renamed file 'ren_%s' => 'ren_%s'\n" % (autf8, outf8))
 
652
        self.assertContainsRe(d, b"=== added file 'add_%s'" % autf8)
 
653
        self.assertContainsRe(d, b"=== modified file 'mod_%s'" % autf8)
 
654
        self.assertContainsRe(d, b"=== removed file 'del_%s'" % autf8)
659
655
 
660
656
    def test_unicode_filename_path_encoding(self):
661
657
        """Test for bug #382699: unicode filenames on Windows should be shown
678
674
 
679
675
        sio = BytesIO()
680
676
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
681
 
            path_encoding='cp1251')
 
677
                             path_encoding='cp1251')
682
678
 
683
679
        output = subst_dates(sio.getvalue())
684
680
        shouldbe = (b'''\
696
692
+foo
697
693
 
698
694
''' % {b'directory': _russian_test.encode('cp1251'),
699
 
       b'test_txt': test_txt.encode('cp1251'),
700
 
      })
 
695
            b'test_txt': test_txt.encode('cp1251'),
 
696
       })
701
697
        self.assertEqualDiff(output, shouldbe)
702
698
 
703
699
 
704
700
class DiffWasIs(diff.DiffPath):
705
701
 
706
 
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
 
702
    def diff(self, old_path, new_path, old_kind, new_kind):
707
703
        self.to_file.write(b'was: ')
708
704
        self.to_file.write(self.old_tree.get_file(old_path).read())
709
705
        self.to_file.write(b'is: ')
732
728
        self.new_tree.add('newdir')
733
729
        self.new_tree.add('newdir/newfile', b'file-id')
734
730
        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)
 
731
        differ.diff_text('olddir/oldfile', None, 'old label', 'new label')
737
732
        self.assertEqual(
738
733
            b'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
739
734
            differ.to_file.getvalue())
740
735
        differ.to_file.seek(0)
741
736
        differ.diff_text(None, 'newdir/newfile',
742
 
                         'old label', 'new label', None, b'file-id')
 
737
                         'old label', 'new label')
743
738
        self.assertEqual(
744
739
            b'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
745
740
            differ.to_file.getvalue())
746
741
        differ.to_file.seek(0)
747
742
        differ.diff_text('olddir/oldfile', 'newdir/newfile',
748
 
                         'old label', 'new label', b'file-id', b'file-id')
 
743
                         'old label', 'new label')
749
744
        self.assertEqual(
750
745
            b'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
751
746
            differ.to_file.getvalue())
793
788
                                  ('new-tree/newdir/newfile', b'new\n')])
794
789
        self.new_tree.add('newdir')
795
790
        self.new_tree.add('newdir/newfile', b'file-id')
796
 
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
791
        self.differ.diff('olddir/oldfile', 'newdir/newfile')
797
792
        self.assertContainsRe(
798
793
            self.differ.to_file.getvalue(),
799
794
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
809
804
        os.symlink('new', 'new-tree/newdir/newfile')
810
805
        self.new_tree.add('newdir')
811
806
        self.new_tree.add('newdir/newfile', b'file-id')
812
 
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
807
        self.differ.diff('olddir/oldfile', 'newdir/newfile')
813
808
        self.assertContainsRe(
814
809
            self.differ.to_file.getvalue(),
815
810
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
820
815
    def test_diff_directory(self):
821
816
        self.build_tree(['new-tree/new-dir/'])
822
817
        self.new_tree.add('new-dir', b'new-dir-id')
823
 
        self.differ.diff(b'new-dir-id', None, 'new-dir')
 
818
        self.differ.diff(None, 'new-dir')
824
819
        self.assertEqual(self.differ.to_file.getvalue(), b'')
825
820
 
826
821
    def create_old_new(self):
836
831
    def test_register_diff(self):
837
832
        self.create_old_new()
838
833
        old_diff_factories = diff.DiffTree.diff_factories
839
 
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
834
        diff.DiffTree.diff_factories = old_diff_factories[:]
840
835
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
841
836
        try:
842
837
            differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
843
838
        finally:
844
839
            diff.DiffTree.diff_factories = old_diff_factories
845
 
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
840
        differ.diff('olddir/oldfile', 'newdir/newfile')
846
841
        self.assertNotContainsRe(
847
842
            differ.to_file.getvalue(),
848
843
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
854
849
        self.create_old_new()
855
850
        differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO(),
856
851
                               extra_factories=[DiffWasIs.from_diff_tree])
857
 
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
852
        differ.diff('olddir/oldfile', 'newdir/newfile')
858
853
        self.assertNotContainsRe(
859
854
            differ.to_file.getvalue(),
860
855
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
869
864
        self.old_tree.add('b-file')
870
865
        self.differ.show_diff(None)
871
866
        self.assertContainsRe(self.differ.to_file.getvalue(),
872
 
            b'.*a-file(.|\n)*b-file')
 
867
                              b'.*a-file(.|\n)*b-file')
873
868
 
874
869
 
875
870
class TestPatienceDiffLib(tests.TestCase):
896
891
        self.assertEqual(unique_lcs('a', 'a'), [(0, 0)])
897
892
        self.assertEqual(unique_lcs('a', 'b'), [])
898
893
        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)])
 
894
        self.assertEqual(unique_lcs('abcde', 'cdeab'),
 
895
                         [(2, 0), (3, 1), (4, 2)])
 
896
        self.assertEqual(unique_lcs('cdeab', 'abcde'),
 
897
                         [(0, 2), (1, 3), (2, 4)])
901
898
        self.assertEqual(unique_lcs('abXde', 'abYde'), [(0, 0), (1, 1),
902
 
                                                         (3, 3), (4, 4)])
 
899
                                                        (3, 3), (4, 4)])
903
900
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2, 1)])
904
901
 
905
902
    def test_recurse_matches(self):
966
963
 
967
964
        # make sure it supports passing in lists
968
965
        self.assertDiffBlocks(
969
 
                   ['hello there\n',
970
 
                    'world\n',
971
 
                    'how are you today?\n'],
972
 
                   ['hello there\n',
973
 
                    'how are you today?\n'],
974
 
                [(0, 0, 1), (2, 1, 1)])
 
966
            ['hello there\n',
 
967
             'world\n',
 
968
             'how are you today?\n'],
 
969
            ['hello there\n',
 
970
             'how are you today?\n'],
 
971
            [(0, 0, 1), (2, 1, 1)])
975
972
 
976
973
        # non unique lines surrounded by non-matching lines
977
974
        # won't be found
978
975
        self.assertDiffBlocks('aBccDe', 'abccde', [(0, 0, 1), (5, 5, 1)])
979
976
 
980
977
        # But they only need to be locally unique
981
 
        self.assertDiffBlocks('aBcDec', 'abcdec', [(0, 0, 1), (2, 2, 1), (4, 4, 2)])
 
978
        self.assertDiffBlocks('aBcDec', 'abcdec', [
 
979
                              (0, 0, 1), (2, 2, 1), (4, 4, 2)])
982
980
 
983
981
        # non unique blocks won't be matched
984
982
        self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0, 0, 1), (8, 8, 1)])
985
983
 
986
984
        # but locally unique ones will
987
985
        self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0, 0, 1), (2, 2, 2),
988
 
                                              (5, 4, 1), (7, 5, 2), (10, 8, 1)])
 
986
                                                           (5, 4, 1), (7, 5, 2), (10, 8, 1)])
989
987
 
990
988
        self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7, 7, 1)])
991
989
        self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
1024
1022
        chk_ops([], [], [])
1025
1023
        chk_ops('abc', '', [('delete', 0, 3, 0, 0)])
1026
1024
        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),
 
1025
        chk_ops('abcd', 'abcd', [('equal', 0, 4, 0, 4)])
 
1026
        chk_ops('abcd', 'abce', [('equal', 0, 3, 0, 3),
1029
1027
                                 ('replace', 3, 4, 3, 4)
1030
 
                                ])
 
1028
                                 ])
1031
1029
        chk_ops('eabc', 'abce', [('delete', 0, 1, 0, 0),
1032
 
                                 ('equal',  1, 4, 0, 3),
 
1030
                                 ('equal', 1, 4, 0, 3),
1033
1031
                                 ('insert', 4, 4, 3, 4)
1034
 
                                ])
 
1032
                                 ])
1035
1033
        chk_ops('eabce', 'abce', [('delete', 0, 1, 0, 0),
1036
 
                                  ('equal',  1, 5, 0, 4)
1037
 
                                 ])
1038
 
        chk_ops('abcde', 'abXde', [('equal',   0, 2, 0, 2),
 
1034
                                  ('equal', 1, 5, 0, 4)
 
1035
                                  ])
 
1036
        chk_ops('abcde', 'abXde', [('equal', 0, 2, 0, 2),
1039
1037
                                   ('replace', 2, 3, 2, 3),
1040
 
                                   ('equal',   3, 5, 3, 5)
1041
 
                                  ])
1042
 
        chk_ops('abcde', 'abXYZde', [('equal',   0, 2, 0, 2),
 
1038
                                   ('equal', 3, 5, 3, 5)
 
1039
                                   ])
 
1040
        chk_ops('abcde', 'abXYZde', [('equal', 0, 2, 0, 2),
1043
1041
                                     ('replace', 2, 3, 2, 5),
1044
 
                                     ('equal',   3, 5, 5, 7)
 
1042
                                     ('equal', 3, 5, 5, 7)
 
1043
                                     ])
 
1044
        chk_ops('abde', 'abXYZde', [('equal', 0, 2, 0, 2),
 
1045
                                    ('insert', 2, 2, 2, 5),
 
1046
                                    ('equal', 2, 4, 5, 7)
1045
1047
                                    ])
1046
 
        chk_ops('abde', 'abXYZde', [('equal',  0, 2, 0, 2),
1047
 
                                    ('insert', 2, 2, 2, 5),
1048
 
                                    ('equal',  2, 4, 5, 7)
1049
 
                                   ])
1050
1048
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1051
 
                [('equal',  0, 6,  0, 6),
1052
 
                 ('insert', 6, 6,  6, 11),
1053
 
                 ('equal',  6, 16, 11, 21)
1054
 
                ])
 
1049
                [('equal', 0, 6, 0, 6),
 
1050
                 ('insert', 6, 6, 6, 11),
 
1051
                 ('equal', 6, 16, 11, 21)
 
1052
                 ])
1055
1053
        chk_ops(
1056
 
                [ 'hello there\n'
1057
 
                , 'world\n'
1058
 
                , 'how are you today?\n'],
1059
 
                [ 'hello there\n'
1060
 
                , 'how are you today?\n'],
1061
 
                [('equal',  0, 1, 0, 1),
1062
 
                 ('delete', 1, 2, 1, 1),
1063
 
                 ('equal',  2, 3, 1, 2),
1064
 
                ])
 
1054
            ['hello there\n', 'world\n', 'how are you today?\n'],
 
1055
            ['hello there\n', 'how are you today?\n'],
 
1056
            [('equal', 0, 1, 0, 1),
 
1057
             ('delete', 1, 2, 1, 1),
 
1058
             ('equal', 2, 3, 1, 2),
 
1059
             ])
1065
1060
        chk_ops('aBccDe', 'abccde',
1066
 
                [('equal',   0, 1, 0, 1),
 
1061
                [('equal', 0, 1, 0, 1),
1067
1062
                 ('replace', 1, 5, 1, 5),
1068
 
                 ('equal',   5, 6, 5, 6),
1069
 
                ])
 
1063
                 ('equal', 5, 6, 5, 6),
 
1064
                 ])
1070
1065
        chk_ops('aBcDec', 'abcdec',
1071
 
                [('equal',   0, 1, 0, 1),
 
1066
                [('equal', 0, 1, 0, 1),
1072
1067
                 ('replace', 1, 2, 1, 2),
1073
 
                 ('equal',   2, 3, 2, 3),
 
1068
                 ('equal', 2, 3, 2, 3),
1074
1069
                 ('replace', 3, 4, 3, 4),
1075
 
                 ('equal',   4, 6, 4, 6),
1076
 
                ])
 
1070
                 ('equal', 4, 6, 4, 6),
 
1071
                 ])
1077
1072
        chk_ops('aBcdEcdFg', 'abcdecdfg',
1078
 
                [('equal',   0, 1, 0, 1),
 
1073
                [('equal', 0, 1, 0, 1),
1079
1074
                 ('replace', 1, 8, 1, 8),
1080
 
                 ('equal',   8, 9, 8, 9)
1081
 
                ])
 
1075
                 ('equal', 8, 9, 8, 9)
 
1076
                 ])
1082
1077
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
1083
 
                [('equal',   0, 1, 0, 1),
 
1078
                [('equal', 0, 1, 0, 1),
1084
1079
                 ('replace', 1, 2, 1, 2),
1085
 
                 ('equal',   2, 4, 2, 4),
 
1080
                 ('equal', 2, 4, 2, 4),
1086
1081
                 ('delete', 4, 5, 4, 4),
1087
 
                 ('equal',   5, 6, 4, 5),
 
1082
                 ('equal', 5, 6, 4, 5),
1088
1083
                 ('delete', 6, 7, 5, 5),
1089
 
                 ('equal',   7, 9, 5, 7),
 
1084
                 ('equal', 7, 9, 5, 7),
1090
1085
                 ('replace', 9, 10, 7, 8),
1091
 
                 ('equal',   10, 11, 8, 9)
1092
 
                ])
 
1086
                 ('equal', 10, 11, 8, 9)
 
1087
                 ])
1093
1088
 
1094
1089
    def test_grouped_opcodes(self):
1095
1090
        def chk_ops(a, b, expected_codes, n=3):
1101
1096
        chk_ops('abc', '', [[('delete', 0, 3, 0, 0)]])
1102
1097
        chk_ops('', 'abc', [[('insert', 0, 0, 0, 3)]])
1103
1098
        chk_ops('abcd', 'abcd', [])
1104
 
        chk_ops('abcd', 'abce', [[('equal',   0, 3, 0, 3),
 
1099
        chk_ops('abcd', 'abce', [[('equal', 0, 3, 0, 3),
1105
1100
                                  ('replace', 3, 4, 3, 4)
1106
 
                                 ]])
 
1101
                                  ]])
1107
1102
        chk_ops('eabc', 'abce', [[('delete', 0, 1, 0, 0),
1108
 
                                 ('equal',  1, 4, 0, 3),
1109
 
                                 ('insert', 4, 4, 3, 4)
1110
 
                                ]])
 
1103
                                  ('equal', 1, 4, 0, 3),
 
1104
                                  ('insert', 4, 4, 3, 4)
 
1105
                                  ]])
1111
1106
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1112
 
                [[('equal',  3, 6, 3, 6),
 
1107
                [[('equal', 3, 6, 3, 6),
1113
1108
                  ('insert', 6, 6, 6, 11),
1114
 
                  ('equal',  6, 9, 11, 14)
 
1109
                  ('equal', 6, 9, 11, 14)
1115
1110
                  ]])
1116
1111
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1117
 
                [[('equal',  2, 6, 2, 6),
 
1112
                [[('equal', 2, 6, 2, 6),
1118
1113
                  ('insert', 6, 6, 6, 11),
1119
 
                  ('equal',  6, 10, 11, 15)
 
1114
                  ('equal', 6, 10, 11, 15)
1120
1115
                  ]], 4)
1121
1116
        chk_ops('Xabcdef', 'abcdef',
1122
1117
                [[('delete', 0, 1, 0, 0),
1123
 
                  ('equal',  1, 4, 0, 3)
 
1118
                  ('equal', 1, 4, 0, 3)
1124
1119
                  ]])
1125
1120
        chk_ops('abcdef', 'abcdefX',
1126
 
                [[('equal',  3, 6, 3, 6),
 
1121
                [[('equal', 3, 6, 3, 6),
1127
1122
                  ('insert', 6, 6, 6, 7)
1128
1123
                  ]])
1129
1124
 
1130
 
 
1131
1125
    def test_multiple_ranges(self):
1132
1126
        # There was an earlier bug where we used a bad set of ranges,
1133
1127
        # this triggers that specific bug, to make sure it doesn't regress
1183
1177
 
1184
1178
 
1185
1179
pynff pzq_zxqve(Pbzznaq):
1186
 
'''.splitlines(True)
1187
 
, [(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
 
1180
'''.splitlines(True), [(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1188
1181
 
1189
1182
    def test_patience_unified_diff(self):
1190
1183
        txt_a = ['hello there\n',
1195
1188
        unified_diff = patiencediff.unified_diff
1196
1189
        psm = self._PatienceSequenceMatcher
1197
1190
        self.assertEqual(['--- \n',
1198
 
                           '+++ \n',
1199
 
                           '@@ -1,3 +1,2 @@\n',
1200
 
                           ' hello there\n',
1201
 
                           '-world\n',
1202
 
                           ' how are you today?\n'
1203
 
                          ]
1204
 
                          , list(unified_diff(txt_a, txt_b,
1205
 
                                 sequencematcher=psm)))
1206
 
        txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1207
 
        txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
 
1191
                          '+++ \n',
 
1192
                          '@@ -1,3 +1,2 @@\n',
 
1193
                          ' hello there\n',
 
1194
                          '-world\n',
 
1195
                          ' how are you today?\n'
 
1196
                          ], list(unified_diff(txt_a, txt_b,
 
1197
                                               sequencematcher=psm)))
 
1198
        txt_a = [x + '\n' for x in 'abcdefghijklmnop']
 
1199
        txt_b = [x + '\n' for x in 'abcdefxydefghijklmnop']
1208
1200
        # This is the result with LongestCommonSubstring matching
1209
1201
        self.assertEqual(['--- \n',
1210
 
                           '+++ \n',
1211
 
                           '@@ -1,6 +1,11 @@\n',
1212
 
                           ' a\n',
1213
 
                           ' b\n',
1214
 
                           ' c\n',
1215
 
                           '+d\n',
1216
 
                           '+e\n',
1217
 
                           '+f\n',
1218
 
                           '+x\n',
1219
 
                           '+y\n',
1220
 
                           ' d\n',
1221
 
                           ' e\n',
1222
 
                           ' f\n']
1223
 
                          , list(unified_diff(txt_a, txt_b)))
 
1202
                          '+++ \n',
 
1203
                          '@@ -1,6 +1,11 @@\n',
 
1204
                          ' a\n',
 
1205
                          ' b\n',
 
1206
                          ' c\n',
 
1207
                          '+d\n',
 
1208
                          '+e\n',
 
1209
                          '+f\n',
 
1210
                          '+x\n',
 
1211
                          '+y\n',
 
1212
                          ' d\n',
 
1213
                          ' e\n',
 
1214
                          ' f\n'], list(unified_diff(txt_a, txt_b)))
1224
1215
        # And the patience diff
1225
1216
        self.assertEqual(['--- \n',
1226
 
                           '+++ \n',
1227
 
                           '@@ -4,6 +4,11 @@\n',
1228
 
                           ' d\n',
1229
 
                           ' e\n',
1230
 
                           ' f\n',
1231
 
                           '+x\n',
1232
 
                           '+y\n',
1233
 
                           '+d\n',
1234
 
                           '+e\n',
1235
 
                           '+f\n',
1236
 
                           ' g\n',
1237
 
                           ' h\n',
1238
 
                           ' i\n',
1239
 
                          ]
1240
 
                          , list(unified_diff(txt_a, txt_b,
1241
 
                                 sequencematcher=psm)))
 
1217
                          '+++ \n',
 
1218
                          '@@ -4,6 +4,11 @@\n',
 
1219
                          ' d\n',
 
1220
                          ' e\n',
 
1221
                          ' f\n',
 
1222
                          '+x\n',
 
1223
                          '+y\n',
 
1224
                          '+d\n',
 
1225
                          '+e\n',
 
1226
                          '+f\n',
 
1227
                          ' g\n',
 
1228
                          ' h\n',
 
1229
                          ' i\n',
 
1230
                          ], list(unified_diff(txt_a, txt_b,
 
1231
                                               sequencematcher=psm)))
1242
1232
 
1243
1233
    def test_patience_unified_diff_with_dates(self):
1244
1234
        txt_a = ['hello there\n',
1249
1239
        unified_diff = patiencediff.unified_diff
1250
1240
        psm = self._PatienceSequenceMatcher
1251
1241
        self.assertEqual(['--- a\t2008-08-08\n',
1252
 
                           '+++ b\t2008-09-09\n',
1253
 
                           '@@ -1,3 +1,2 @@\n',
1254
 
                           ' hello there\n',
1255
 
                           '-world\n',
1256
 
                           ' how are you today?\n'
1257
 
                          ]
1258
 
                          , list(unified_diff(txt_a, txt_b,
1259
 
                                 fromfile='a', tofile='b',
1260
 
                                 fromfiledate='2008-08-08',
1261
 
                                 tofiledate='2008-09-09',
1262
 
                                 sequencematcher=psm)))
 
1242
                          '+++ b\t2008-09-09\n',
 
1243
                          '@@ -1,3 +1,2 @@\n',
 
1244
                          ' hello there\n',
 
1245
                          '-world\n',
 
1246
                          ' how are you today?\n'
 
1247
                          ], list(unified_diff(txt_a, txt_b,
 
1248
                                               fromfile='a', tofile='b',
 
1249
                                               fromfiledate='2008-08-08',
 
1250
                                               tofiledate='2008-09-09',
 
1251
                                               sequencematcher=psm)))
1263
1252
 
1264
1253
 
1265
1254
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1279
1268
        # We need to be able to hash items in the sequence, lists are
1280
1269
        # unhashable, and thus cannot be diffed
1281
1270
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1282
 
                                         None, [[]], [])
1283
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1284
 
                                         None, ['valid', []], [])
1285
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1286
 
                                         None, ['valid'], [[]])
1287
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1288
 
                                         None, ['valid'], ['valid', []])
 
1271
                              None, [[]], [])
 
1272
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1273
                              None, ['valid', []], [])
 
1274
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1275
                              None, ['valid'], [[]])
 
1276
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1277
                              None, ['valid'], ['valid', []])
1289
1278
 
1290
1279
 
1291
1280
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1301
1290
                 b'how are you today?\n']
1302
1291
        txt_b = [b'hello there\n',
1303
1292
                 b'how are you today?\n']
1304
 
        with open('a1', 'wb') as f: f.writelines(txt_a)
1305
 
        with open('b1', 'wb') as f: f.writelines(txt_b)
 
1293
        with open('a1', 'wb') as f:
 
1294
            f.writelines(txt_a)
 
1295
        with open('b1', 'wb') as f:
 
1296
            f.writelines(txt_b)
1306
1297
 
1307
1298
        unified_diff_files = patiencediff.unified_diff_files
1308
1299
        psm = self._PatienceSequenceMatcher
1312
1303
                          b' hello there\n',
1313
1304
                          b'-world\n',
1314
1305
                          b' how are you today?\n',
1315
 
                          ]
1316
 
                          , list(unified_diff_files(b'a1', b'b1',
1317
 
                                 sequencematcher=psm)))
 
1306
                          ], list(unified_diff_files(b'a1', b'b1',
 
1307
                                                     sequencematcher=psm)))
1318
1308
 
1319
 
        txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1320
 
        txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1321
 
        with open('a2', 'wt') as f: f.writelines(txt_a)
1322
 
        with open('b2', 'wt') as f: f.writelines(txt_b)
 
1309
        txt_a = [x + '\n' for x in 'abcdefghijklmnop']
 
1310
        txt_b = [x + '\n' for x in 'abcdefxydefghijklmnop']
 
1311
        with open('a2', 'wt') as f:
 
1312
            f.writelines(txt_a)
 
1313
        with open('b2', 'wt') as f:
 
1314
            f.writelines(txt_b)
1323
1315
 
1324
1316
        # This is the result with LongestCommonSubstring matching
1325
1317
        self.assertEqual([b'--- a2\n',
1335
1327
                          b'+y\n',
1336
1328
                          b' d\n',
1337
1329
                          b' e\n',
1338
 
                          b' f\n']
1339
 
                          , list(unified_diff_files(b'a2', b'b2')))
 
1330
                          b' f\n'], list(unified_diff_files(b'a2', b'b2')))
1340
1331
 
1341
1332
        # And the patience diff
1342
1333
        self.assertEqual([b'--- a2\n',
1407
1398
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1408
1399
        self.addCleanup(diff_obj.finish)
1409
1400
        self.assertEqual(['diff', '@old_path', '@new_path'],
1410
 
            diff_obj.command_template)
 
1401
                         diff_obj.command_template)
1411
1402
 
1412
1403
    def test_from_string_u5(self):
1413
1404
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1430
1421
 
1431
1422
    def test_execute(self):
1432
1423
        output = BytesIO()
1433
 
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1424
        diff_obj = diff.DiffFromTool([sys.executable, '-c',
1434
1425
                                      'print("@old_path @new_path")'],
1435
1426
                                     None, None, output)
1436
1427
        self.addCleanup(diff_obj.finish)
1458
1449
        basis_tree = tree.basis_tree()
1459
1450
        basis_tree.lock_read()
1460
1451
        self.addCleanup(basis_tree.unlock)
1461
 
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1452
        diff_obj = diff.DiffFromTool([sys.executable, '-c',
1462
1453
                                      'print "@old_path @new_path"'],
1463
1454
                                     basis_tree, tree, output)
1464
1455
        diff_obj._prepare_files('file', 'file', file_id=b'file-id')
1494
1485
        self.addCleanup(old_tree.unlock)
1495
1486
        tree.lock_read()
1496
1487
        self.addCleanup(tree.unlock)
1497
 
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1488
        diff_obj = diff.DiffFromTool([sys.executable, '-c',
1498
1489
                                      'print "@old_path @new_path"'],
1499
1490
                                     old_tree, tree, output)
1500
1491
        self.addCleanup(diff_obj.finish)
1501
1492
        self.assertContainsRe(diff_obj._root, 'brz-diff-[^/]*')
1502
1493
        old_path, new_path = diff_obj._prepare_files(
1503
 
                'oldname', 'newname', file_id=b'file-id')
 
1494
            'oldname', 'newname')
1504
1495
        self.assertContainsRe(old_path, 'old/oldname$')
1505
1496
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1506
1497
        self.assertContainsRe(new_path, 'tree/newname$')
1509
1500
        if osutils.host_os_dereferences_symlinks():
1510
1501
            self.assertTrue(os.path.samefile('tree/newname', new_path))
1511
1502
        # make sure we can create files with the same parent directories
1512
 
        diff_obj._prepare_files('oldname2', 'newname2', file_id=b'file2-id')
 
1503
        diff_obj._prepare_files('oldname2', 'newname2')
1513
1504
 
1514
1505
 
1515
1506
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):