/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-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    diff,
25
25
    errors,
26
26
    osutils,
27
 
    patiencediff,
28
 
    _patiencediff_py,
29
27
    revision as _mod_revision,
30
28
    revisionspec,
31
29
    revisiontree,
105
103
class TestDiffOptionsScenarios(tests.TestCase):
106
104
 
107
105
    scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
108
 
    style = None # Set by load_tests_apply_scenarios from scenarios
 
106
    style = None  # Set by load_tests_apply_scenarios from scenarios
109
107
 
110
108
    def test_unified_not_added(self):
111
109
        # Verify that for all valid style options, '-u' is not
121
119
        lines = udiff_lines([b'boo'], [b'boo\n'])
122
120
        self.check_patch(lines)
123
121
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
124
 
            ## "expected no-nl, got %r" % lines[4]
 
122
        ## "expected no-nl, got %r" % lines[4]
125
123
 
126
124
    def test_add_nl_2(self):
127
125
        """diff generates a valid diff for patches that change last line and
130
128
        lines = udiff_lines([b'boo'], [b'goo\n'])
131
129
        self.check_patch(lines)
132
130
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
133
 
            ## "expected no-nl, got %r" % lines[4]
 
131
        ## "expected no-nl, got %r" % lines[4]
134
132
 
135
133
    def test_remove_nl(self):
136
134
        """diff generates a valid diff for patches that change last line and
139
137
        lines = udiff_lines([b'boo\n'], [b'boo'])
140
138
        self.check_patch(lines)
141
139
        self.assertEqual(lines[5], b'\\ No newline at end of file\n')
142
 
            ## "expected no-nl, got %r" % lines[5]
 
140
        ## "expected no-nl, got %r" % lines[5]
143
141
 
144
142
    def check_patch(self, lines):
145
143
        self.assertTrue(len(lines) > 1)
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)
 
144
        ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
 
145
        self.assertTrue(lines[0].startswith(b'---'))
 
146
        ## 'No orig line for patch:\n%s' % "".join(lines)
 
147
        self.assertTrue(lines[1].startswith(b'+++'))
 
148
        ## 'No mod line for patch:\n%s' % "".join(lines)
151
149
        self.assertTrue(len(lines) > 2)
152
 
            ## "No hunks for patch:\n%s" % "".join(lines)
 
150
        ## "No hunks for patch:\n%s" % "".join(lines)
153
151
        self.assertTrue(lines[2].startswith(b'@@'))
154
 
            ## "No hunk header for patch:\n%s" % "".join(lines)
 
152
        ## "No hunk header for patch:\n%s" % "".join(lines)
155
153
        self.assertTrue(b'@@' in lines[2][2:])
156
 
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
 
154
        ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
157
155
 
158
156
    def test_binary_lines(self):
159
157
        empty = []
171
169
    def test_external_diff_no_fileno(self):
172
170
        # Make sure that we can handle not having a fileno, even
173
171
        # if the diff is large
174
 
        lines = external_udiff_lines([b'boo\n']*10000,
175
 
                                     [b'goo\n']*10000,
 
172
        lines = external_udiff_lines([b'boo\n'] * 10000,
 
173
                                     [b'goo\n'] * 10000,
176
174
                                     use_stringio=True)
177
175
        self.check_patch(lines)
178
176
 
182
180
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
183
181
        # Older versions of diffutils say "Binary files", newer
184
182
        # versions just say "Files".
185
 
        self.assertContainsRe(lines[0], b'(Binary f|F)iles old and new differ\n')
 
183
        self.assertContainsRe(
 
184
            lines[0], b'(Binary f|F)iles old and new differ\n')
186
185
        self.assertEqual(lines[1:], [b'\n'])
187
186
 
188
187
    def test_no_external_diff(self):
202
201
        lines = output.getvalue().splitlines(True)
203
202
        self.check_patch(lines)
204
203
        self.assertEqual([b'--- old_\xc2\xb5\n',
205
 
                           b'+++ new_\xc3\xa5\n',
206
 
                           b'@@ -1,1 +1,1 @@\n',
207
 
                           b'-old_text\n',
208
 
                           b'+new_text\n',
209
 
                           b'\n',
210
 
                          ]
211
 
                          , lines)
 
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
                          ], lines)
212
210
 
213
211
    def test_internal_diff_utf8(self):
214
212
        output = BytesIO()
218
216
        lines = output.getvalue().splitlines(True)
219
217
        self.check_patch(lines)
220
218
        self.assertEqual([b'--- old_\xc2\xb5\n',
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
 
                          ]
227
 
                          , lines)
 
219
                          b'+++ new_\xc3\xa5\n',
 
220
                          b'@@ -1,1 +1,1 @@\n',
 
221
                          b'-old_text\n',
 
222
                          b'+new_text\n',
 
223
                          b'\n',
 
224
                          ], lines)
228
225
 
229
226
    def test_internal_diff_iso_8859_1(self):
230
227
        output = BytesIO()
239
236
                          b'-old_text\n',
240
237
                          b'+new_text\n',
241
238
                          b'\n',
242
 
                          ]
243
 
                          , lines)
 
239
                          ], lines)
244
240
 
245
241
    def test_internal_diff_no_content(self):
246
242
        output = BytesIO()
263
259
    def test_internal_diff_default_context(self):
264
260
        output = BytesIO()
265
261
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
266
 
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
262
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
267
263
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
268
 
                           b'same_text\n', b'same_text\n', b'new_text\n'], output)
 
264
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output)
269
265
        lines = output.getvalue().splitlines(True)
270
266
        self.check_patch(lines)
271
267
        self.assertEqual([b'--- old\n',
272
 
                           b'+++ new\n',
273
 
                           b'@@ -3,4 +3,4 @@\n',
274
 
                           b' same_text\n',
275
 
                           b' same_text\n',
276
 
                           b' same_text\n',
277
 
                           b'-old_text\n',
278
 
                           b'+new_text\n',
279
 
                           b'\n',
280
 
                          ]
281
 
                          , lines)
 
268
                          b'+++ new\n',
 
269
                          b'@@ -3,4 +3,4 @@\n',
 
270
                          b' same_text\n',
 
271
                          b' same_text\n',
 
272
                          b' same_text\n',
 
273
                          b'-old_text\n',
 
274
                          b'+new_text\n',
 
275
                          b'\n',
 
276
                          ], lines)
282
277
 
283
278
    def test_internal_diff_no_context(self):
284
279
        output = BytesIO()
285
280
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
286
 
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
281
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
287
282
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
288
 
                           b'same_text\n', b'same_text\n', b'new_text\n'], output,
 
283
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output,
289
284
                           context_lines=0)
290
285
        lines = output.getvalue().splitlines(True)
291
286
        self.check_patch(lines)
292
287
        self.assertEqual([b'--- old\n',
293
 
                           b'+++ new\n',
294
 
                           b'@@ -6,1 +6,1 @@\n',
295
 
                           b'-old_text\n',
296
 
                           b'+new_text\n',
297
 
                           b'\n',
298
 
                          ]
299
 
                          , lines)
 
288
                          b'+++ new\n',
 
289
                          b'@@ -6,1 +6,1 @@\n',
 
290
                          b'-old_text\n',
 
291
                          b'+new_text\n',
 
292
                          b'\n',
 
293
                          ], lines)
300
294
 
301
295
    def test_internal_diff_more_context(self):
302
296
        output = BytesIO()
303
297
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
304
 
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
298
                                   b'same_text\n', b'same_text\n', b'old_text\n'],
305
299
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
306
 
                           b'same_text\n', b'same_text\n', b'new_text\n'], output,
 
300
                                   b'same_text\n', b'same_text\n', b'new_text\n'], output,
307
301
                           context_lines=4)
308
302
        lines = output.getvalue().splitlines(True)
309
303
        self.check_patch(lines)
317
311
                          b'-old_text\n',
318
312
                          b'+new_text\n',
319
313
                          b'\n',
320
 
                          ]
321
 
                          , lines)
322
 
 
 
314
                          ], lines)
323
315
 
324
316
 
325
317
class TestDiffFiles(tests.TestCaseInTempDir):
332
324
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
333
325
 
334
326
        cmd = ['diff', '-u', '--binary', 'old', 'new']
335
 
        with open('old', 'wb') as f: f.write(b'\x00foobar\n')
336
 
        with open('new', 'wb') as f: f.write(b'foo\x00bar\n')
 
327
        with open('old', 'wb') as f:
 
328
            f.write(b'\x00foobar\n')
 
329
        with open('new', 'wb') as f:
 
330
            f.write(b'foo\x00bar\n')
337
331
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
338
 
                                     stdin=subprocess.PIPE)
 
332
                                stdin=subprocess.PIPE)
339
333
        out, err = pipe.communicate()
340
334
        # We should output whatever diff tells us, plus a trailing newline
341
335
        self.assertEqual(out.splitlines(True) + [b'\n'], lines)
348
342
    else:
349
343
        extra_trees = ()
350
344
    diff.show_diff_trees(tree1, tree2, output,
351
 
        specific_files=specific_files,
352
 
        extra_trees=extra_trees, old_label='old/',
353
 
        new_label='new/')
 
345
                         specific_files=specific_files,
 
346
                         extra_trees=extra_trees, old_label='old/',
 
347
                         new_label='new/')
354
348
    return output.getvalue()
355
349
 
356
350
 
367
361
        self.wt.add(['file1', 'file2'])
368
362
        self.wt.commit(
369
363
            message='Revision 1',
370
 
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
 
364
            timestamp=1143849600,  # 2006-04-01 00:00:00 UTC
371
365
            timezone=0,
372
366
            rev_id=b'rev-1')
373
367
        self.build_tree_contents([('file1', b'file1 contents at rev 2\n')])
374
368
        self.wt.commit(
375
369
            message='Revision 2',
376
 
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
 
370
            timestamp=1143936000,  # 2006-04-02 00:00:00 UTC
377
371
            timezone=28800,
378
372
            rev_id=b'rev-2')
379
373
        self.build_tree_contents([('file2', b'file2 contents at rev 3\n')])
380
374
        self.wt.commit(
381
375
            message='Revision 3',
382
 
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
 
376
            timestamp=1144022400,  # 2006-04-03 00:00:00 UTC
383
377
            timezone=-3600,
384
378
            rev_id=b'rev-3')
385
379
        self.wt.remove(['file2'])
386
380
        self.wt.commit(
387
381
            message='Revision 4',
388
 
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
 
382
            timestamp=1144108800,  # 2006-04-04 00:00:00 UTC
389
383
            timezone=0,
390
384
            rev_id=b'rev-4')
391
385
        self.build_tree_contents([
392
386
            ('file1', b'file1 contents in working tree\n')
393
387
            ])
394
388
        # set the date stamps for files in the working tree to known values
395
 
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
 
389
        os.utime('file1', (1144195200, 1144195200))  # 2006-04-05 00:00:00 UTC
396
390
 
397
391
    def test_diff_rev_tree_working_tree(self):
398
392
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
464
458
        old_tree = self.b.repository.revision_tree(b'rev-1')
465
459
        new_tree = self.b.repository.revision_tree(b'rev-4')
466
460
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
467
 
                            working_tree=self.wt)
 
461
                                 working_tree=self.wt)
468
462
        self.assertContainsRe(out, b'file1\t')
469
463
 
470
464
    def test_recursive_diff(self):
476
470
        old_tree = self.b.repository.revision_tree(b'rev-1')
477
471
        new_tree = self.b.repository.revision_tree(b'rev-4')
478
472
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
479
 
                            working_tree=self.wt)
 
473
                                 working_tree=self.wt)
480
474
        self.assertContainsRe(out, b'file1\t')
481
475
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
482
 
                            working_tree=self.wt)
 
476
                                 working_tree=self.wt)
483
477
        self.assertNotContainsRe(out, b'file1\t')
484
478
 
485
479
 
565
559
        self.assertContainsRe(d, b'-contents\n'
566
560
                                 b'\\+new contents\n')
567
561
 
568
 
 
569
562
    def test_internal_diff_exec_property(self):
570
563
        tree = self.make_branch_and_tree('tree')
571
564
 
636
629
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
637
630
 
638
631
        tree = self.make_branch_and_tree('tree')
639
 
        self.build_tree_contents([('tree/ren_'+alpha, b'contents\n')])
640
 
        tree.add(['ren_'+alpha], [b'file-id-2'])
641
 
        self.build_tree_contents([('tree/del_'+alpha, b'contents\n')])
642
 
        tree.add(['del_'+alpha], [b'file-id-3'])
643
 
        self.build_tree_contents([('tree/mod_'+alpha, b'contents\n')])
644
 
        tree.add(['mod_'+alpha], [b'file-id-4'])
 
632
        self.build_tree_contents([('tree/ren_' + alpha, b'contents\n')])
 
633
        tree.add(['ren_' + alpha], [b'file-id-2'])
 
634
        self.build_tree_contents([('tree/del_' + alpha, b'contents\n')])
 
635
        tree.add(['del_' + alpha], [b'file-id-3'])
 
636
        self.build_tree_contents([('tree/mod_' + alpha, b'contents\n')])
 
637
        tree.add(['mod_' + alpha], [b'file-id-4'])
645
638
 
646
639
        tree.commit('one', rev_id=b'rev-1')
647
640
 
648
 
        tree.rename_one('ren_'+alpha, 'ren_'+omega)
649
 
        tree.remove('del_'+alpha)
650
 
        self.build_tree_contents([('tree/add_'+alpha, b'contents\n')])
651
 
        tree.add(['add_'+alpha], [b'file-id'])
652
 
        self.build_tree_contents([('tree/mod_'+alpha, b'contents_mod\n')])
 
641
        tree.rename_one('ren_' + alpha, 'ren_' + omega)
 
642
        tree.remove('del_' + alpha)
 
643
        self.build_tree_contents([('tree/add_' + alpha, b'contents\n')])
 
644
        tree.add(['add_' + alpha], [b'file-id'])
 
645
        self.build_tree_contents([('tree/mod_' + alpha, b'contents_mod\n')])
653
646
 
654
647
        d = get_diff_as_string(tree.basis_tree(), tree)
655
648
        self.assertContainsRe(d,
656
 
                b"=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
657
 
        self.assertContainsRe(d, b"=== added file 'add_%s'"%autf8)
658
 
        self.assertContainsRe(d, b"=== modified file 'mod_%s'"%autf8)
659
 
        self.assertContainsRe(d, b"=== removed file 'del_%s'"%autf8)
 
649
                              b"=== renamed file 'ren_%s' => 'ren_%s'\n" % (autf8, outf8))
 
650
        self.assertContainsRe(d, b"=== added file 'add_%s'" % autf8)
 
651
        self.assertContainsRe(d, b"=== modified file 'mod_%s'" % autf8)
 
652
        self.assertContainsRe(d, b"=== removed file 'del_%s'" % autf8)
660
653
 
661
654
    def test_unicode_filename_path_encoding(self):
662
655
        """Test for bug #382699: unicode filenames on Windows should be shown
679
672
 
680
673
        sio = BytesIO()
681
674
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
682
 
            path_encoding='cp1251')
 
675
                             path_encoding='cp1251')
683
676
 
684
677
        output = subst_dates(sio.getvalue())
685
678
        shouldbe = (b'''\
697
690
+foo
698
691
 
699
692
''' % {b'directory': _russian_test.encode('cp1251'),
700
 
       b'test_txt': test_txt.encode('cp1251'),
701
 
      })
 
693
            b'test_txt': test_txt.encode('cp1251'),
 
694
       })
702
695
        self.assertEqualDiff(output, shouldbe)
703
696
 
704
697
 
705
698
class DiffWasIs(diff.DiffPath):
706
699
 
707
 
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
 
700
    def diff(self, old_path, new_path, old_kind, new_kind):
708
701
        self.to_file.write(b'was: ')
709
702
        self.to_file.write(self.old_tree.get_file(old_path).read())
710
703
        self.to_file.write(b'is: ')
733
726
        self.new_tree.add('newdir')
734
727
        self.new_tree.add('newdir/newfile', b'file-id')
735
728
        differ = diff.DiffText(self.old_tree, self.new_tree, BytesIO())
736
 
        differ.diff_text('olddir/oldfile', None, 'old label',
737
 
                         'new label', b'file-id', None)
 
729
        differ.diff_text('olddir/oldfile', None, 'old label', 'new label')
738
730
        self.assertEqual(
739
731
            b'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
740
732
            differ.to_file.getvalue())
741
733
        differ.to_file.seek(0)
742
734
        differ.diff_text(None, 'newdir/newfile',
743
 
                         'old label', 'new label', None, b'file-id')
 
735
                         'old label', 'new label')
744
736
        self.assertEqual(
745
737
            b'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
746
738
            differ.to_file.getvalue())
747
739
        differ.to_file.seek(0)
748
740
        differ.diff_text('olddir/oldfile', 'newdir/newfile',
749
 
                         'old label', 'new label', b'file-id', b'file-id')
 
741
                         'old label', 'new label')
750
742
        self.assertEqual(
751
743
            b'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
752
744
            differ.to_file.getvalue())
794
786
                                  ('new-tree/newdir/newfile', b'new\n')])
795
787
        self.new_tree.add('newdir')
796
788
        self.new_tree.add('newdir/newfile', b'file-id')
797
 
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
789
        self.differ.diff('olddir/oldfile', 'newdir/newfile')
798
790
        self.assertContainsRe(
799
791
            self.differ.to_file.getvalue(),
800
792
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
810
802
        os.symlink('new', 'new-tree/newdir/newfile')
811
803
        self.new_tree.add('newdir')
812
804
        self.new_tree.add('newdir/newfile', b'file-id')
813
 
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
805
        self.differ.diff('olddir/oldfile', 'newdir/newfile')
814
806
        self.assertContainsRe(
815
807
            self.differ.to_file.getvalue(),
816
808
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
821
813
    def test_diff_directory(self):
822
814
        self.build_tree(['new-tree/new-dir/'])
823
815
        self.new_tree.add('new-dir', b'new-dir-id')
824
 
        self.differ.diff(b'new-dir-id', None, 'new-dir')
 
816
        self.differ.diff(None, 'new-dir')
825
817
        self.assertEqual(self.differ.to_file.getvalue(), b'')
826
818
 
827
819
    def create_old_new(self):
837
829
    def test_register_diff(self):
838
830
        self.create_old_new()
839
831
        old_diff_factories = diff.DiffTree.diff_factories
840
 
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
832
        diff.DiffTree.diff_factories = old_diff_factories[:]
841
833
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
842
834
        try:
843
835
            differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
844
836
        finally:
845
837
            diff.DiffTree.diff_factories = old_diff_factories
846
 
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
838
        differ.diff('olddir/oldfile', 'newdir/newfile')
847
839
        self.assertNotContainsRe(
848
840
            differ.to_file.getvalue(),
849
841
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
855
847
        self.create_old_new()
856
848
        differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO(),
857
849
                               extra_factories=[DiffWasIs.from_diff_tree])
858
 
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
 
850
        differ.diff('olddir/oldfile', 'newdir/newfile')
859
851
        self.assertNotContainsRe(
860
852
            differ.to_file.getvalue(),
861
853
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
870
862
        self.old_tree.add('b-file')
871
863
        self.differ.show_diff(None)
872
864
        self.assertContainsRe(self.differ.to_file.getvalue(),
873
 
            b'.*a-file(.|\n)*b-file')
874
 
 
875
 
 
876
 
class TestPatienceDiffLib(tests.TestCase):
877
 
 
878
 
    def setUp(self):
879
 
        super(TestPatienceDiffLib, self).setUp()
880
 
        self._unique_lcs = _patiencediff_py.unique_lcs_py
881
 
        self._recurse_matches = _patiencediff_py.recurse_matches_py
882
 
        self._PatienceSequenceMatcher = \
883
 
            _patiencediff_py.PatienceSequenceMatcher_py
884
 
 
885
 
    def test_diff_unicode_string(self):
886
 
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
887
 
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
888
 
        sm = self._PatienceSequenceMatcher(None, a, b)
889
 
        mb = sm.get_matching_blocks()
890
 
        self.assertEqual(35, len(mb))
891
 
 
892
 
    def test_unique_lcs(self):
893
 
        unique_lcs = self._unique_lcs
894
 
        self.assertEqual(unique_lcs('', ''), [])
895
 
        self.assertEqual(unique_lcs('', 'a'), [])
896
 
        self.assertEqual(unique_lcs('a', ''), [])
897
 
        self.assertEqual(unique_lcs('a', 'a'), [(0, 0)])
898
 
        self.assertEqual(unique_lcs('a', 'b'), [])
899
 
        self.assertEqual(unique_lcs('ab', 'ab'), [(0, 0), (1, 1)])
900
 
        self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2, 0), (3, 1), (4, 2)])
901
 
        self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0, 2), (1, 3), (2, 4)])
902
 
        self.assertEqual(unique_lcs('abXde', 'abYde'), [(0, 0), (1, 1),
903
 
                                                         (3, 3), (4, 4)])
904
 
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2, 1)])
905
 
 
906
 
    def test_recurse_matches(self):
907
 
        def test_one(a, b, matches):
908
 
            test_matches = []
909
 
            self._recurse_matches(
910
 
                a, b, 0, 0, len(a), len(b), test_matches, 10)
911
 
            self.assertEqual(test_matches, matches)
912
 
 
913
 
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
914
 
                 [(0, 0), (2, 2), (4, 4)])
915
 
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
916
 
                 [(0, 0), (2, 1), (4, 2)])
917
 
        # Even though 'bc' is not unique globally, and is surrounded by
918
 
        # non-matching lines, we should still match, because they are locally
919
 
        # unique
920
 
        test_one('abcdbce', 'afbcgdbce', [(0, 0), (1, 2), (2, 3), (3, 5),
921
 
                                          (4, 6), (5, 7), (6, 8)])
922
 
 
923
 
        # recurse_matches doesn't match non-unique
924
 
        # lines surrounded by bogus text.
925
 
        # The update has been done in patiencediff.SequenceMatcher instead
926
 
 
927
 
        # This is what it could be
928
 
        #test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
929
 
 
930
 
        # This is what it currently gives:
931
 
        test_one('aBccDe', 'abccde', [(0, 0), (5, 5)])
932
 
 
933
 
    def assertDiffBlocks(self, a, b, expected_blocks):
934
 
        """Check that the sequence matcher returns the correct blocks.
935
 
 
936
 
        :param a: A sequence to match
937
 
        :param b: Another sequence to match
938
 
        :param expected_blocks: The expected output, not including the final
939
 
            matching block (len(a), len(b), 0)
940
 
        """
941
 
        matcher = self._PatienceSequenceMatcher(None, a, b)
942
 
        blocks = matcher.get_matching_blocks()
943
 
        last = blocks.pop()
944
 
        self.assertEqual((len(a), len(b), 0), last)
945
 
        self.assertEqual(expected_blocks, blocks)
946
 
 
947
 
    def test_matching_blocks(self):
948
 
        # Some basic matching tests
949
 
        self.assertDiffBlocks('', '', [])
950
 
        self.assertDiffBlocks([], [], [])
951
 
        self.assertDiffBlocks('abc', '', [])
952
 
        self.assertDiffBlocks('', 'abc', [])
953
 
        self.assertDiffBlocks('abcd', 'abcd', [(0, 0, 4)])
954
 
        self.assertDiffBlocks('abcd', 'abce', [(0, 0, 3)])
955
 
        self.assertDiffBlocks('eabc', 'abce', [(1, 0, 3)])
956
 
        self.assertDiffBlocks('eabce', 'abce', [(1, 0, 4)])
957
 
        self.assertDiffBlocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
958
 
        self.assertDiffBlocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
959
 
        self.assertDiffBlocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
960
 
        # This may check too much, but it checks to see that
961
 
        # a copied block stays attached to the previous section,
962
 
        # not the later one.
963
 
        # difflib would tend to grab the trailing longest match
964
 
        # which would make the diff not look right
965
 
        self.assertDiffBlocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
966
 
                              [(0, 0, 6), (6, 11, 10)])
967
 
 
968
 
        # make sure it supports passing in lists
969
 
        self.assertDiffBlocks(
970
 
                   ['hello there\n',
971
 
                    'world\n',
972
 
                    'how are you today?\n'],
973
 
                   ['hello there\n',
974
 
                    'how are you today?\n'],
975
 
                [(0, 0, 1), (2, 1, 1)])
976
 
 
977
 
        # non unique lines surrounded by non-matching lines
978
 
        # won't be found
979
 
        self.assertDiffBlocks('aBccDe', 'abccde', [(0, 0, 1), (5, 5, 1)])
980
 
 
981
 
        # But they only need to be locally unique
982
 
        self.assertDiffBlocks('aBcDec', 'abcdec', [(0, 0, 1), (2, 2, 1), (4, 4, 2)])
983
 
 
984
 
        # non unique blocks won't be matched
985
 
        self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0, 0, 1), (8, 8, 1)])
986
 
 
987
 
        # but locally unique ones will
988
 
        self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0, 0, 1), (2, 2, 2),
989
 
                                              (5, 4, 1), (7, 5, 2), (10, 8, 1)])
990
 
 
991
 
        self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7, 7, 1)])
992
 
        self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
993
 
        self.assertDiffBlocks('bbbbbbbb', 'cbbbbbbc', [])
994
 
 
995
 
    def test_matching_blocks_tuples(self):
996
 
        # Some basic matching tests
997
 
        self.assertDiffBlocks([], [], [])
998
 
        self.assertDiffBlocks([('a',), ('b',), ('c,')], [], [])
999
 
        self.assertDiffBlocks([], [('a',), ('b',), ('c,')], [])
1000
 
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
1001
 
                              [('a',), ('b',), ('c,')],
1002
 
                              [(0, 0, 3)])
1003
 
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
1004
 
                              [('a',), ('b',), ('d,')],
1005
 
                              [(0, 0, 2)])
1006
 
        self.assertDiffBlocks([('d',), ('b',), ('c,')],
1007
 
                              [('a',), ('b',), ('c,')],
1008
 
                              [(1, 1, 2)])
1009
 
        self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
1010
 
                              [('a',), ('b',), ('c,')],
1011
 
                              [(1, 0, 3)])
1012
 
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
1013
 
                              [('a', 'b'), ('c', 'X'), ('e', 'f')],
1014
 
                              [(0, 0, 1), (2, 2, 1)])
1015
 
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
1016
 
                              [('a', 'b'), ('c', 'dX'), ('e', 'f')],
1017
 
                              [(0, 0, 1), (2, 2, 1)])
1018
 
 
1019
 
    def test_opcodes(self):
1020
 
        def chk_ops(a, b, expected_codes):
1021
 
            s = self._PatienceSequenceMatcher(None, a, b)
1022
 
            self.assertEqual(expected_codes, s.get_opcodes())
1023
 
 
1024
 
        chk_ops('', '', [])
1025
 
        chk_ops([], [], [])
1026
 
        chk_ops('abc', '', [('delete', 0, 3, 0, 0)])
1027
 
        chk_ops('', 'abc', [('insert', 0, 0, 0, 3)])
1028
 
        chk_ops('abcd', 'abcd', [('equal',    0, 4, 0, 4)])
1029
 
        chk_ops('abcd', 'abce', [('equal',   0, 3, 0, 3),
1030
 
                                 ('replace', 3, 4, 3, 4)
1031
 
                                ])
1032
 
        chk_ops('eabc', 'abce', [('delete', 0, 1, 0, 0),
1033
 
                                 ('equal',  1, 4, 0, 3),
1034
 
                                 ('insert', 4, 4, 3, 4)
1035
 
                                ])
1036
 
        chk_ops('eabce', 'abce', [('delete', 0, 1, 0, 0),
1037
 
                                  ('equal',  1, 5, 0, 4)
1038
 
                                 ])
1039
 
        chk_ops('abcde', 'abXde', [('equal',   0, 2, 0, 2),
1040
 
                                   ('replace', 2, 3, 2, 3),
1041
 
                                   ('equal',   3, 5, 3, 5)
1042
 
                                  ])
1043
 
        chk_ops('abcde', 'abXYZde', [('equal',   0, 2, 0, 2),
1044
 
                                     ('replace', 2, 3, 2, 5),
1045
 
                                     ('equal',   3, 5, 5, 7)
1046
 
                                    ])
1047
 
        chk_ops('abde', 'abXYZde', [('equal',  0, 2, 0, 2),
1048
 
                                    ('insert', 2, 2, 2, 5),
1049
 
                                    ('equal',  2, 4, 5, 7)
1050
 
                                   ])
1051
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1052
 
                [('equal',  0, 6,  0, 6),
1053
 
                 ('insert', 6, 6,  6, 11),
1054
 
                 ('equal',  6, 16, 11, 21)
1055
 
                ])
1056
 
        chk_ops(
1057
 
                [ 'hello there\n'
1058
 
                , 'world\n'
1059
 
                , 'how are you today?\n'],
1060
 
                [ 'hello there\n'
1061
 
                , 'how are you today?\n'],
1062
 
                [('equal',  0, 1, 0, 1),
1063
 
                 ('delete', 1, 2, 1, 1),
1064
 
                 ('equal',  2, 3, 1, 2),
1065
 
                ])
1066
 
        chk_ops('aBccDe', 'abccde',
1067
 
                [('equal',   0, 1, 0, 1),
1068
 
                 ('replace', 1, 5, 1, 5),
1069
 
                 ('equal',   5, 6, 5, 6),
1070
 
                ])
1071
 
        chk_ops('aBcDec', 'abcdec',
1072
 
                [('equal',   0, 1, 0, 1),
1073
 
                 ('replace', 1, 2, 1, 2),
1074
 
                 ('equal',   2, 3, 2, 3),
1075
 
                 ('replace', 3, 4, 3, 4),
1076
 
                 ('equal',   4, 6, 4, 6),
1077
 
                ])
1078
 
        chk_ops('aBcdEcdFg', 'abcdecdfg',
1079
 
                [('equal',   0, 1, 0, 1),
1080
 
                 ('replace', 1, 8, 1, 8),
1081
 
                 ('equal',   8, 9, 8, 9)
1082
 
                ])
1083
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
1084
 
                [('equal',   0, 1, 0, 1),
1085
 
                 ('replace', 1, 2, 1, 2),
1086
 
                 ('equal',   2, 4, 2, 4),
1087
 
                 ('delete', 4, 5, 4, 4),
1088
 
                 ('equal',   5, 6, 4, 5),
1089
 
                 ('delete', 6, 7, 5, 5),
1090
 
                 ('equal',   7, 9, 5, 7),
1091
 
                 ('replace', 9, 10, 7, 8),
1092
 
                 ('equal',   10, 11, 8, 9)
1093
 
                ])
1094
 
 
1095
 
    def test_grouped_opcodes(self):
1096
 
        def chk_ops(a, b, expected_codes, n=3):
1097
 
            s = self._PatienceSequenceMatcher(None, a, b)
1098
 
            self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
1099
 
 
1100
 
        chk_ops('', '', [])
1101
 
        chk_ops([], [], [])
1102
 
        chk_ops('abc', '', [[('delete', 0, 3, 0, 0)]])
1103
 
        chk_ops('', 'abc', [[('insert', 0, 0, 0, 3)]])
1104
 
        chk_ops('abcd', 'abcd', [])
1105
 
        chk_ops('abcd', 'abce', [[('equal',   0, 3, 0, 3),
1106
 
                                  ('replace', 3, 4, 3, 4)
1107
 
                                 ]])
1108
 
        chk_ops('eabc', 'abce', [[('delete', 0, 1, 0, 0),
1109
 
                                 ('equal',  1, 4, 0, 3),
1110
 
                                 ('insert', 4, 4, 3, 4)
1111
 
                                ]])
1112
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1113
 
                [[('equal',  3, 6, 3, 6),
1114
 
                  ('insert', 6, 6, 6, 11),
1115
 
                  ('equal',  6, 9, 11, 14)
1116
 
                  ]])
1117
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1118
 
                [[('equal',  2, 6, 2, 6),
1119
 
                  ('insert', 6, 6, 6, 11),
1120
 
                  ('equal',  6, 10, 11, 15)
1121
 
                  ]], 4)
1122
 
        chk_ops('Xabcdef', 'abcdef',
1123
 
                [[('delete', 0, 1, 0, 0),
1124
 
                  ('equal',  1, 4, 0, 3)
1125
 
                  ]])
1126
 
        chk_ops('abcdef', 'abcdefX',
1127
 
                [[('equal',  3, 6, 3, 6),
1128
 
                  ('insert', 6, 6, 6, 7)
1129
 
                  ]])
1130
 
 
1131
 
 
1132
 
    def test_multiple_ranges(self):
1133
 
        # There was an earlier bug where we used a bad set of ranges,
1134
 
        # this triggers that specific bug, to make sure it doesn't regress
1135
 
        self.assertDiffBlocks('abcdefghijklmnop',
1136
 
                              'abcXghiYZQRSTUVWXYZijklmnop',
1137
 
                              [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
1138
 
 
1139
 
        self.assertDiffBlocks('ABCd efghIjk  L',
1140
 
                              'AxyzBCn mo pqrstuvwI1 2  L',
1141
 
                              [(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1142
 
 
1143
 
        # These are rot13 code snippets.
1144
 
        self.assertDiffBlocks('''\
1145
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1146
 
    """
1147
 
    gnxrf_netf = ['svyr*']
1148
 
    gnxrf_bcgvbaf = ['ab-erphefr']
1149
 
 
1150
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1151
 
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1152
 
        vs vf_dhvrg():
1153
 
            ercbegre = nqq_ercbegre_ahyy
1154
 
        ryfr:
1155
 
            ercbegre = nqq_ercbegre_cevag
1156
 
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
1157
 
 
1158
 
 
1159
 
pynff pzq_zxqve(Pbzznaq):
1160
 
'''.splitlines(True), '''\
1161
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1162
 
 
1163
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
1164
 
    nqq gurz.
1165
 
    """
1166
 
    gnxrf_netf = ['svyr*']
1167
 
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
1168
 
 
1169
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
1170
 
        vzcbeg omeyvo.nqq
1171
 
 
1172
 
        vs qel_eha:
1173
 
            vs vf_dhvrg():
1174
 
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
1175
 
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
1176
 
            ryfr:
1177
 
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
1178
 
        ryvs vf_dhvrg():
1179
 
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
1180
 
        ryfr:
1181
 
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
1182
 
 
1183
 
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
1184
 
 
1185
 
 
1186
 
pynff pzq_zxqve(Pbzznaq):
1187
 
'''.splitlines(True)
1188
 
, [(0, 0, 1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1189
 
 
1190
 
    def test_patience_unified_diff(self):
1191
 
        txt_a = ['hello there\n',
1192
 
                 'world\n',
1193
 
                 'how are you today?\n']
1194
 
        txt_b = ['hello there\n',
1195
 
                 'how are you today?\n']
1196
 
        unified_diff = patiencediff.unified_diff
1197
 
        psm = self._PatienceSequenceMatcher
1198
 
        self.assertEqual(['--- \n',
1199
 
                           '+++ \n',
1200
 
                           '@@ -1,3 +1,2 @@\n',
1201
 
                           ' hello there\n',
1202
 
                           '-world\n',
1203
 
                           ' how are you today?\n'
1204
 
                          ]
1205
 
                          , list(unified_diff(txt_a, txt_b,
1206
 
                                 sequencematcher=psm)))
1207
 
        txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1208
 
        txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1209
 
        # This is the result with LongestCommonSubstring matching
1210
 
        self.assertEqual(['--- \n',
1211
 
                           '+++ \n',
1212
 
                           '@@ -1,6 +1,11 @@\n',
1213
 
                           ' a\n',
1214
 
                           ' b\n',
1215
 
                           ' c\n',
1216
 
                           '+d\n',
1217
 
                           '+e\n',
1218
 
                           '+f\n',
1219
 
                           '+x\n',
1220
 
                           '+y\n',
1221
 
                           ' d\n',
1222
 
                           ' e\n',
1223
 
                           ' f\n']
1224
 
                          , list(unified_diff(txt_a, txt_b)))
1225
 
        # And the patience diff
1226
 
        self.assertEqual(['--- \n',
1227
 
                           '+++ \n',
1228
 
                           '@@ -4,6 +4,11 @@\n',
1229
 
                           ' d\n',
1230
 
                           ' e\n',
1231
 
                           ' f\n',
1232
 
                           '+x\n',
1233
 
                           '+y\n',
1234
 
                           '+d\n',
1235
 
                           '+e\n',
1236
 
                           '+f\n',
1237
 
                           ' g\n',
1238
 
                           ' h\n',
1239
 
                           ' i\n',
1240
 
                          ]
1241
 
                          , list(unified_diff(txt_a, txt_b,
1242
 
                                 sequencematcher=psm)))
1243
 
 
1244
 
    def test_patience_unified_diff_with_dates(self):
1245
 
        txt_a = ['hello there\n',
1246
 
                 'world\n',
1247
 
                 'how are you today?\n']
1248
 
        txt_b = ['hello there\n',
1249
 
                 'how are you today?\n']
1250
 
        unified_diff = patiencediff.unified_diff
1251
 
        psm = self._PatienceSequenceMatcher
1252
 
        self.assertEqual(['--- a\t2008-08-08\n',
1253
 
                           '+++ b\t2008-09-09\n',
1254
 
                           '@@ -1,3 +1,2 @@\n',
1255
 
                           ' hello there\n',
1256
 
                           '-world\n',
1257
 
                           ' how are you today?\n'
1258
 
                          ]
1259
 
                          , list(unified_diff(txt_a, txt_b,
1260
 
                                 fromfile='a', tofile='b',
1261
 
                                 fromfiledate='2008-08-08',
1262
 
                                 tofiledate='2008-09-09',
1263
 
                                 sequencematcher=psm)))
1264
 
 
1265
 
 
1266
 
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1267
 
 
1268
 
    _test_needs_features = [features.compiled_patiencediff_feature]
1269
 
 
1270
 
    def setUp(self):
1271
 
        super(TestPatienceDiffLib_c, self).setUp()
1272
 
        from breezy import _patiencediff_c
1273
 
        self._unique_lcs = _patiencediff_c.unique_lcs_c
1274
 
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1275
 
        self._PatienceSequenceMatcher = \
1276
 
            _patiencediff_c.PatienceSequenceMatcher_c
1277
 
 
1278
 
    def test_unhashable(self):
1279
 
        """We should get a proper exception here."""
1280
 
        # We need to be able to hash items in the sequence, lists are
1281
 
        # unhashable, and thus cannot be diffed
1282
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1283
 
                                         None, [[]], [])
1284
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1285
 
                                         None, ['valid', []], [])
1286
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1287
 
                                         None, ['valid'], [[]])
1288
 
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1289
 
                                         None, ['valid'], ['valid', []])
1290
 
 
1291
 
 
1292
 
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1293
 
 
1294
 
    def setUp(self):
1295
 
        super(TestPatienceDiffLibFiles, self).setUp()
1296
 
        self._PatienceSequenceMatcher = \
1297
 
            _patiencediff_py.PatienceSequenceMatcher_py
1298
 
 
1299
 
    def test_patience_unified_diff_files(self):
1300
 
        txt_a = [b'hello there\n',
1301
 
                 b'world\n',
1302
 
                 b'how are you today?\n']
1303
 
        txt_b = [b'hello there\n',
1304
 
                 b'how are you today?\n']
1305
 
        with open('a1', 'wb') as f: f.writelines(txt_a)
1306
 
        with open('b1', 'wb') as f: f.writelines(txt_b)
1307
 
 
1308
 
        unified_diff_files = patiencediff.unified_diff_files
1309
 
        psm = self._PatienceSequenceMatcher
1310
 
        self.assertEqual([b'--- a1\n',
1311
 
                          b'+++ b1\n',
1312
 
                          b'@@ -1,3 +1,2 @@\n',
1313
 
                          b' hello there\n',
1314
 
                          b'-world\n',
1315
 
                          b' how are you today?\n',
1316
 
                          ]
1317
 
                          , list(unified_diff_files(b'a1', b'b1',
1318
 
                                 sequencematcher=psm)))
1319
 
 
1320
 
        txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1321
 
        txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1322
 
        with open('a2', 'wt') as f: f.writelines(txt_a)
1323
 
        with open('b2', 'wt') as f: f.writelines(txt_b)
1324
 
 
1325
 
        # This is the result with LongestCommonSubstring matching
1326
 
        self.assertEqual([b'--- a2\n',
1327
 
                          b'+++ b2\n',
1328
 
                          b'@@ -1,6 +1,11 @@\n',
1329
 
                          b' a\n',
1330
 
                          b' b\n',
1331
 
                          b' c\n',
1332
 
                          b'+d\n',
1333
 
                          b'+e\n',
1334
 
                          b'+f\n',
1335
 
                          b'+x\n',
1336
 
                          b'+y\n',
1337
 
                          b' d\n',
1338
 
                          b' e\n',
1339
 
                          b' f\n']
1340
 
                          , list(unified_diff_files(b'a2', b'b2')))
1341
 
 
1342
 
        # And the patience diff
1343
 
        self.assertEqual([b'--- a2\n',
1344
 
                          b'+++ b2\n',
1345
 
                          b'@@ -4,6 +4,11 @@\n',
1346
 
                          b' d\n',
1347
 
                          b' e\n',
1348
 
                          b' f\n',
1349
 
                          b'+x\n',
1350
 
                          b'+y\n',
1351
 
                          b'+d\n',
1352
 
                          b'+e\n',
1353
 
                          b'+f\n',
1354
 
                          b' g\n',
1355
 
                          b' h\n',
1356
 
                          b' i\n'],
1357
 
                         list(unified_diff_files(b'a2', b'b2',
1358
 
                                                 sequencematcher=psm)))
1359
 
 
1360
 
 
1361
 
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1362
 
 
1363
 
    _test_needs_features = [features.compiled_patiencediff_feature]
1364
 
 
1365
 
    def setUp(self):
1366
 
        super(TestPatienceDiffLibFiles_c, self).setUp()
1367
 
        from breezy import _patiencediff_c
1368
 
        self._PatienceSequenceMatcher = \
1369
 
            _patiencediff_c.PatienceSequenceMatcher_c
1370
 
 
1371
 
 
1372
 
class TestUsingCompiledIfAvailable(tests.TestCase):
1373
 
 
1374
 
    def test_PatienceSequenceMatcher(self):
1375
 
        if features.compiled_patiencediff_feature.available():
1376
 
            from breezy._patiencediff_c import PatienceSequenceMatcher_c
1377
 
            self.assertIs(PatienceSequenceMatcher_c,
1378
 
                          patiencediff.PatienceSequenceMatcher)
1379
 
        else:
1380
 
            from breezy._patiencediff_py import PatienceSequenceMatcher_py
1381
 
            self.assertIs(PatienceSequenceMatcher_py,
1382
 
                          patiencediff.PatienceSequenceMatcher)
1383
 
 
1384
 
    def test_unique_lcs(self):
1385
 
        if features.compiled_patiencediff_feature.available():
1386
 
            from breezy._patiencediff_c import unique_lcs_c
1387
 
            self.assertIs(unique_lcs_c,
1388
 
                          patiencediff.unique_lcs)
1389
 
        else:
1390
 
            from breezy._patiencediff_py import unique_lcs_py
1391
 
            self.assertIs(unique_lcs_py,
1392
 
                          patiencediff.unique_lcs)
1393
 
 
1394
 
    def test_recurse_matches(self):
1395
 
        if features.compiled_patiencediff_feature.available():
1396
 
            from breezy._patiencediff_c import recurse_matches_c
1397
 
            self.assertIs(recurse_matches_c,
1398
 
                          patiencediff.recurse_matches)
1399
 
        else:
1400
 
            from breezy._patiencediff_py import recurse_matches_py
1401
 
            self.assertIs(recurse_matches_py,
1402
 
                          patiencediff.recurse_matches)
 
865
                              b'.*a-file(.|\n)*b-file')
1403
866
 
1404
867
 
1405
868
class TestDiffFromTool(tests.TestCaseWithTransport):
1408
871
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1409
872
        self.addCleanup(diff_obj.finish)
1410
873
        self.assertEqual(['diff', '@old_path', '@new_path'],
1411
 
            diff_obj.command_template)
 
874
                         diff_obj.command_template)
1412
875
 
1413
876
    def test_from_string_u5(self):
1414
877
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1501
964
        self.addCleanup(diff_obj.finish)
1502
965
        self.assertContainsRe(diff_obj._root, 'brz-diff-[^/]*')
1503
966
        old_path, new_path = diff_obj._prepare_files(
1504
 
                'oldname', 'newname', file_id=b'file-id')
 
967
            'oldname', 'newname')
1505
968
        self.assertContainsRe(old_path, 'old/oldname$')
1506
969
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1507
970
        self.assertContainsRe(new_path, 'tree/newname$')
1510
973
        if osutils.host_os_dereferences_symlinks():
1511
974
            self.assertTrue(os.path.samefile('tree/newname', new_path))
1512
975
        # make sure we can create files with the same parent directories
1513
 
        diff_obj._prepare_files('oldname2', 'newname2', file_id=b'file2-id')
 
976
        diff_obj._prepare_files('oldname2', 'newname2')
1514
977
 
1515
978
 
1516
979
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):