/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: 2018-07-11 21:06:20 UTC
  • mfrom: (7033 work)
  • mto: This revision was merged to the branch mainline in revision 7036.
  • Revision ID: jelmer@jelmer.uk-20180711210620-pj0v9i3xe48qnsb2
merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
 
18
import re
18
19
import subprocess
19
20
import tempfile
20
21
 
32
33
    )
33
34
from ..sixish import (
34
35
    BytesIO,
 
36
    unichr,
35
37
    )
36
38
from ..tests import (
37
39
    features,
38
40
    EncodingAdapter,
39
41
    )
40
 
from ..tests.blackbox.test_diff import subst_dates
41
42
from ..tests.scenarios import load_tests_apply_scenarios
42
43
 
43
44
 
44
45
load_tests = load_tests_apply_scenarios
45
46
 
46
47
 
 
48
def subst_dates(string):
 
49
    """Replace date strings with constant values."""
 
50
    return re.sub(br'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
 
51
                  b'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
 
52
 
 
53
 
47
54
def udiff_lines(old, new, allow_binary=False):
48
55
    output = BytesIO()
49
56
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
110
117
 
111
118
    def test_add_nl(self):
112
119
        """diff generates a valid diff for patches that add a newline"""
113
 
        lines = udiff_lines(['boo'], ['boo\n'])
 
120
        lines = udiff_lines([b'boo'], [b'boo\n'])
114
121
        self.check_patch(lines)
115
 
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
 
122
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
116
123
            ## "expected no-nl, got %r" % lines[4]
117
124
 
118
125
    def test_add_nl_2(self):
119
126
        """diff generates a valid diff for patches that change last line and
120
127
        add a newline.
121
128
        """
122
 
        lines = udiff_lines(['boo'], ['goo\n'])
 
129
        lines = udiff_lines([b'boo'], [b'goo\n'])
123
130
        self.check_patch(lines)
124
 
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
 
131
        self.assertEqual(lines[4], b'\\ No newline at end of file\n')
125
132
            ## "expected no-nl, got %r" % lines[4]
126
133
 
127
134
    def test_remove_nl(self):
128
135
        """diff generates a valid diff for patches that change last line and
129
136
        add a newline.
130
137
        """
131
 
        lines = udiff_lines(['boo\n'], ['boo'])
 
138
        lines = udiff_lines([b'boo\n'], [b'boo'])
132
139
        self.check_patch(lines)
133
 
        self.assertEqual(lines[5], '\\ No newline at end of file\n')
 
140
        self.assertEqual(lines[5], b'\\ No newline at end of file\n')
134
141
            ## "expected no-nl, got %r" % lines[5]
135
142
 
136
143
    def check_patch(self, lines):
137
144
        self.assertTrue(len(lines) > 1)
138
145
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
139
 
        self.assertTrue(lines[0].startswith ('---'))
 
146
        self.assertTrue(lines[0].startswith (b'---'))
140
147
            ## 'No orig line for patch:\n%s' % "".join(lines)
141
 
        self.assertTrue(lines[1].startswith ('+++'))
 
148
        self.assertTrue(lines[1].startswith (b'+++'))
142
149
            ## 'No mod line for patch:\n%s' % "".join(lines)
143
150
        self.assertTrue(len(lines) > 2)
144
151
            ## "No hunks for patch:\n%s" % "".join(lines)
145
 
        self.assertTrue(lines[2].startswith('@@'))
 
152
        self.assertTrue(lines[2].startswith(b'@@'))
146
153
            ## "No hunk header for patch:\n%s" % "".join(lines)
147
 
        self.assertTrue('@@' in lines[2][2:])
 
154
        self.assertTrue(b'@@' in lines[2][2:])
148
155
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
149
156
 
150
157
    def test_binary_lines(self):
151
158
        empty = []
152
 
        uni_lines = [1023 * 'a' + '\x00']
 
159
        uni_lines = [1023 * b'a' + b'\x00']
153
160
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines, empty)
154
161
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
155
162
        udiff_lines(uni_lines, empty, allow_binary=True)
156
163
        udiff_lines(empty, uni_lines, allow_binary=True)
157
164
 
158
165
    def test_external_diff(self):
159
 
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
 
166
        lines = external_udiff_lines([b'boo\n'], [b'goo\n'])
160
167
        self.check_patch(lines)
161
 
        self.assertEqual('\n', lines[-1])
 
168
        self.assertEqual(b'\n', lines[-1])
162
169
 
163
170
    def test_external_diff_no_fileno(self):
164
171
        # Make sure that we can handle not having a fileno, even
165
172
        # if the diff is large
166
 
        lines = external_udiff_lines(['boo\n']*10000,
167
 
                                     ['goo\n']*10000,
 
173
        lines = external_udiff_lines([b'boo\n']*10000,
 
174
                                     [b'goo\n']*10000,
168
175
                                     use_stringio=True)
169
176
        self.check_patch(lines)
170
177
 
171
178
    def test_external_diff_binary_lang_c(self):
172
179
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
173
180
            self.overrideEnv(lang, 'C')
174
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
181
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
175
182
        # Older versions of diffutils say "Binary files", newer
176
183
        # versions just say "Files".
177
 
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
178
 
        self.assertEqual(lines[1:], ['\n'])
 
184
        self.assertContainsRe(lines[0], b'(Binary f|F)iles old and new differ\n')
 
185
        self.assertEqual(lines[1:], [b'\n'])
179
186
 
180
187
    def test_no_external_diff(self):
181
188
        """Check that NoDiff is raised when diff is not available"""
183
190
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
184
191
        self.overrideEnv('PATH', '')
185
192
        self.assertRaises(errors.NoDiff, diff.external_diff,
186
 
                          'old', ['boo\n'], 'new', ['goo\n'],
 
193
                          b'old', [b'boo\n'], b'new', [b'goo\n'],
187
194
                          BytesIO(), diff_opts=['-u'])
188
195
 
189
196
    def test_internal_diff_default(self):
190
197
        # Default internal diff encoding is utf8
191
198
        output = BytesIO()
192
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
193
 
                           u'new_\xe5', ['new_text\n'], output)
 
199
        diff.internal_diff(u'old_\xb5', [b'old_text\n'],
 
200
                           u'new_\xe5', [b'new_text\n'], output)
194
201
        lines = output.getvalue().splitlines(True)
195
202
        self.check_patch(lines)
196
 
        self.assertEqual(['--- old_\xc2\xb5\n',
197
 
                           '+++ new_\xc3\xa5\n',
198
 
                           '@@ -1,1 +1,1 @@\n',
199
 
                           '-old_text\n',
200
 
                           '+new_text\n',
201
 
                           '\n',
 
203
        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',
202
209
                          ]
203
210
                          , lines)
204
211
 
205
212
    def test_internal_diff_utf8(self):
206
213
        output = BytesIO()
207
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
208
 
                           u'new_\xe5', ['new_text\n'], output,
 
214
        diff.internal_diff(u'old_\xb5', [b'old_text\n'],
 
215
                           u'new_\xe5', [b'new_text\n'], output,
209
216
                           path_encoding='utf8')
210
217
        lines = output.getvalue().splitlines(True)
211
218
        self.check_patch(lines)
212
 
        self.assertEqual(['--- old_\xc2\xb5\n',
213
 
                           '+++ new_\xc3\xa5\n',
214
 
                           '@@ -1,1 +1,1 @@\n',
215
 
                           '-old_text\n',
216
 
                           '+new_text\n',
217
 
                           '\n',
 
219
        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',
218
225
                          ]
219
226
                          , lines)
220
227
 
249
256
    def test_internal_diff_returns_bytes(self):
250
257
        output = StubO()
251
258
        diff.internal_diff(u'old_\xb5', [b'old_text\n'],
252
 
                            u'new_\xe5', [b'new_text\n'], output)
 
259
                           u'new_\xe5', [b'new_text\n'], output)
253
260
        output.check_types(self, bytes)
254
261
 
255
262
    def test_internal_diff_default_context(self):
256
263
        output = BytesIO()
257
 
        diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
258
 
                           'same_text\n', 'same_text\n', 'old_text\n'],
259
 
                           'new', ['same_text\n', 'same_text\n', 'same_text\n',
260
 
                           'same_text\n', 'same_text\n', 'new_text\n'], output)
 
264
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
 
265
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
266
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
 
267
                           b'same_text\n', b'same_text\n', b'new_text\n'], output)
261
268
        lines = output.getvalue().splitlines(True)
262
269
        self.check_patch(lines)
263
 
        self.assertEqual(['--- old\n',
264
 
                           '+++ new\n',
265
 
                           '@@ -3,4 +3,4 @@\n',
266
 
                           ' same_text\n',
267
 
                           ' same_text\n',
268
 
                           ' same_text\n',
269
 
                           '-old_text\n',
270
 
                           '+new_text\n',
271
 
                           '\n',
 
270
        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',
272
279
                          ]
273
280
                          , lines)
274
281
 
275
282
    def test_internal_diff_no_context(self):
276
283
        output = BytesIO()
277
 
        diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
278
 
                           'same_text\n', 'same_text\n', 'old_text\n'],
279
 
                           'new', ['same_text\n', 'same_text\n', 'same_text\n',
280
 
                           'same_text\n', 'same_text\n', 'new_text\n'], output,
 
284
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
 
285
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
286
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
 
287
                           b'same_text\n', b'same_text\n', b'new_text\n'], output,
281
288
                           context_lines=0)
282
289
        lines = output.getvalue().splitlines(True)
283
290
        self.check_patch(lines)
284
 
        self.assertEqual(['--- old\n',
285
 
                           '+++ new\n',
286
 
                           '@@ -6,1 +6,1 @@\n',
287
 
                           '-old_text\n',
288
 
                           '+new_text\n',
289
 
                           '\n',
 
291
        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',
290
297
                          ]
291
298
                          , lines)
292
299
 
293
300
    def test_internal_diff_more_context(self):
294
301
        output = BytesIO()
295
 
        diff.internal_diff('old', ['same_text\n', 'same_text\n', 'same_text\n',
296
 
                           'same_text\n', 'same_text\n', 'old_text\n'],
297
 
                           'new', ['same_text\n', 'same_text\n', 'same_text\n',
298
 
                           'same_text\n', 'same_text\n', 'new_text\n'], output,
 
302
        diff.internal_diff('old', [b'same_text\n', b'same_text\n', b'same_text\n',
 
303
                           b'same_text\n', b'same_text\n', b'old_text\n'],
 
304
                           'new', [b'same_text\n', b'same_text\n', b'same_text\n',
 
305
                           b'same_text\n', b'same_text\n', b'new_text\n'], output,
299
306
                           context_lines=4)
300
307
        lines = output.getvalue().splitlines(True)
301
308
        self.check_patch(lines)
302
 
        self.assertEqual(['--- old\n',
303
 
                           '+++ new\n',
304
 
                           '@@ -2,5 +2,5 @@\n',
305
 
                           ' same_text\n',
306
 
                           ' same_text\n',
307
 
                           ' same_text\n',
308
 
                           ' same_text\n',
309
 
                           '-old_text\n',
310
 
                           '+new_text\n',
311
 
                           '\n',
 
309
        self.assertEqual([b'--- old\n',
 
310
                          b'+++ new\n',
 
311
                          b'@@ -2,5 +2,5 @@\n',
 
312
                          b' same_text\n',
 
313
                          b' same_text\n',
 
314
                          b' same_text\n',
 
315
                          b' same_text\n',
 
316
                          b'-old_text\n',
 
317
                          b'+new_text\n',
 
318
                          b'\n',
312
319
                          ]
313
320
                          , lines)
314
321
 
321
328
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
322
329
            self.overrideEnv(lang, 'C')
323
330
        # Make sure external_diff doesn't fail in the current LANG
324
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
331
        lines = external_udiff_lines([b'\x00foobar\n'], [b'foo\x00bar\n'])
325
332
 
326
333
        cmd = ['diff', '-u', '--binary', 'old', 'new']
327
334
        with open('old', 'wb') as f: f.write(b'\x00foobar\n')
330
337
                                     stdin=subprocess.PIPE)
331
338
        out, err = pipe.communicate()
332
339
        # We should output whatever diff tells us, plus a trailing newline
333
 
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
 
340
        self.assertEqual(out.splitlines(True) + [b'\n'], lines)
334
341
 
335
342
 
336
343
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
390
397
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
391
398
        # note that the date for old/file1 is from rev 2 rather than from
392
399
        # the basis revision (rev 4)
393
 
        self.assertEqualDiff(output, '''\
 
400
        self.assertEqualDiff(output, b'''\
394
401
=== modified file 'file1'
395
402
--- old/file1\t2006-04-02 00:00:00 +0000
396
403
+++ new/file1\t2006-04-05 00:00:00 +0000
404
411
        tree1 = self.b.repository.revision_tree(b'rev-2')
405
412
        tree2 = self.b.repository.revision_tree(b'rev-3')
406
413
        output = get_diff_as_string(tree1, tree2)
407
 
        self.assertEqualDiff(output, '''\
 
414
        self.assertEqualDiff(output, b'''\
408
415
=== modified file 'file2'
409
416
--- old/file2\t2006-04-01 00:00:00 +0000
410
417
+++ new/file2\t2006-04-03 00:00:00 +0000
420
427
        output = get_diff_as_string(tree1, tree2)
421
428
        # the files have the epoch time stamp for the tree in which
422
429
        # they don't exist.
423
 
        self.assertEqualDiff(output, '''\
 
430
        self.assertEqualDiff(output, b'''\
424
431
=== added file 'file1'
425
432
--- old/file1\t1970-01-01 00:00:00 +0000
426
433
+++ new/file1\t2006-04-01 00:00:00 +0000
441
448
        output = get_diff_as_string(tree1, tree2)
442
449
        # the file has the epoch time stamp for the tree in which
443
450
        # it doesn't exist.
444
 
        self.assertEqualDiff(output, '''\
 
451
        self.assertEqualDiff(output, b'''\
445
452
=== removed file 'file2'
446
453
--- old/file2\t2006-04-03 00:00:00 +0000
447
454
+++ new/file2\t1970-01-01 00:00:00 +0000
457
464
        new_tree = self.b.repository.revision_tree(b'rev-4')
458
465
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
459
466
                            working_tree=self.wt)
460
 
        self.assertContainsRe(out, 'file1\t')
 
467
        self.assertContainsRe(out, b'file1\t')
461
468
 
462
469
    def test_recursive_diff(self):
463
470
        """Children of directories are matched"""
487
494
 
488
495
        self.build_tree_contents([('tree/file', b'new contents\n')])
489
496
        d = get_diff_as_string(tree.basis_tree(), tree)
490
 
        self.assertContainsRe(d, "=== modified file 'file'\n")
491
 
        self.assertContainsRe(d, '--- old/file\t')
492
 
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
493
 
        self.assertContainsRe(d, '-contents\n'
494
 
                                 '\\+new contents\n')
 
497
        self.assertContainsRe(d, b"=== modified file 'file'\n")
 
498
        self.assertContainsRe(d, b'--- old/file\t')
 
499
        self.assertContainsRe(d, b'\\+\\+\\+ new/file\t')
 
500
        self.assertContainsRe(d, b'-contents\n'
 
501
                                 b'\\+new contents\n')
495
502
 
496
503
    def test_modified_file_in_renamed_dir(self):
497
504
        """Test when a file is modified in a renamed directory."""
504
511
        tree.rename_one('dir', 'other')
505
512
        self.build_tree_contents([('tree/other/file', b'new contents\n')])
506
513
        d = get_diff_as_string(tree.basis_tree(), tree)
507
 
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
508
 
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
 
514
        self.assertContainsRe(d, b"=== renamed directory 'dir' => 'other'\n")
 
515
        self.assertContainsRe(d, b"=== modified file 'other/file'\n")
509
516
        # XXX: This is technically incorrect, because it used to be at another
510
517
        # location. What to do?
511
 
        self.assertContainsRe(d, '--- old/dir/file\t')
512
 
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
513
 
        self.assertContainsRe(d, '-contents\n'
514
 
                                 '\\+new contents\n')
 
518
        self.assertContainsRe(d, b'--- old/dir/file\t')
 
519
        self.assertContainsRe(d, b'\\+\\+\\+ new/other/file\t')
 
520
        self.assertContainsRe(d, b'-contents\n'
 
521
                                 b'\\+new contents\n')
515
522
 
516
523
    def test_renamed_directory(self):
517
524
        """Test when only a directory is only renamed."""
525
532
        d = get_diff_as_string(tree.basis_tree(), tree)
526
533
        # Renaming a directory should be a single "you renamed this dir" even
527
534
        # when there are files inside.
528
 
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
 
535
        self.assertEqual(d, b"=== renamed directory 'dir' => 'newdir'\n")
529
536
 
530
537
    def test_renamed_file(self):
531
538
        """Test when a file is only renamed."""
536
543
 
537
544
        tree.rename_one('file', 'newname')
538
545
        d = get_diff_as_string(tree.basis_tree(), tree)
539
 
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
546
        self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
540
547
        # We shouldn't have a --- or +++ line, because there is no content
541
548
        # change
542
 
        self.assertNotContainsRe(d, '---')
 
549
        self.assertNotContainsRe(d, b'---')
543
550
 
544
551
    def test_renamed_and_modified_file(self):
545
552
        """Test when a file is only renamed."""
551
558
        tree.rename_one('file', 'newname')
552
559
        self.build_tree_contents([('tree/newname', b'new contents\n')])
553
560
        d = get_diff_as_string(tree.basis_tree(), tree)
554
 
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
555
 
        self.assertContainsRe(d, '--- old/file\t')
556
 
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
557
 
        self.assertContainsRe(d, '-contents\n'
558
 
                                 '\\+new contents\n')
 
561
        self.assertContainsRe(d, b"=== renamed file 'file' => 'newname'\n")
 
562
        self.assertContainsRe(d, b'--- old/file\t')
 
563
        self.assertContainsRe(d, b'\\+\\+\\+ new/newname\t')
 
564
        self.assertContainsRe(d, b'-contents\n'
 
565
                                 b'\\+new contents\n')
559
566
 
560
567
 
561
568
    def test_internal_diff_exec_property(self):
582
589
 
583
590
        d = get_diff_as_string(tree.basis_tree(), tree)
584
591
 
585
 
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
586
 
                                 r".*\+x to -x.*\)")
587
 
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
588
 
                                 r".*-x to \+x.*\)")
589
 
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
590
 
                                 r".*\+x to -x.*\)")
591
 
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
592
 
                                 r".*-x to \+x.*\)")
593
 
        self.assertNotContainsRe(d, r"file 'e'")
594
 
        self.assertNotContainsRe(d, r"file 'f'")
 
592
        self.assertContainsRe(d, br"file 'a'.*\(properties changed:"
 
593
                                 br".*\+x to -x.*\)")
 
594
        self.assertContainsRe(d, br"file 'b'.*\(properties changed:"
 
595
                                 br".*-x to \+x.*\)")
 
596
        self.assertContainsRe(d, br"file 'c'.*\(properties changed:"
 
597
                                 br".*\+x to -x.*\)")
 
598
        self.assertContainsRe(d, br"file 'd'.*\(properties changed:"
 
599
                                 br".*-x to \+x.*\)")
 
600
        self.assertNotContainsRe(d, br"file 'e'")
 
601
        self.assertNotContainsRe(d, br"file 'f'")
595
602
 
596
603
    def test_binary_unicode_filenames(self):
597
604
        """Test that contents of files are *not* encoded in UTF-8 when there
604
611
        alpha, omega = u'\u03b1', u'\u03c9'
605
612
        alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
606
613
        self.build_tree_contents(
607
 
            [('tree/' + alpha, chr(0)),
 
614
            [('tree/' + alpha, b'\0'),
608
615
             ('tree/' + omega,
609
 
              ('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
 
616
              (b'The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
610
617
        tree.add([alpha], [b'file-id'])
611
618
        tree.add([omega], [b'file-id-2'])
612
619
        diff_content = StubO()
613
620
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
614
621
        diff_content.check_types(self, bytes)
615
622
        d = b''.join(diff_content.write_record)
616
 
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
617
 
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
 
623
        self.assertContainsRe(d, br"=== added file '%s'" % alpha_utf8)
 
624
        self.assertContainsRe(d, b"Binary files a/%s.*and b/%s.* differ\n"
618
625
                              % (alpha_utf8, alpha_utf8))
619
 
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
620
 
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
621
 
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
 
626
        self.assertContainsRe(d, br"=== added file '%s'" % omega_utf8)
 
627
        self.assertContainsRe(d, br"--- a/%s" % (omega_utf8,))
 
628
        self.assertContainsRe(d, br"\+\+\+ b/%s" % (omega_utf8,))
622
629
 
623
630
    def test_unicode_filename(self):
624
631
        """Test when the filename are unicode."""
645
652
 
646
653
        d = get_diff_as_string(tree.basis_tree(), tree)
647
654
        self.assertContainsRe(d,
648
 
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
649
 
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
650
 
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
651
 
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
 
655
                b"=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
 
656
        self.assertContainsRe(d, b"=== added file 'add_%s'"%autf8)
 
657
        self.assertContainsRe(d, b"=== modified file 'mod_%s'"%autf8)
 
658
        self.assertContainsRe(d, b"=== removed file 'del_%s'"%autf8)
652
659
 
653
660
    def test_unicode_filename_path_encoding(self):
654
661
        """Test for bug #382699: unicode filenames on Windows should be shown
674
681
            path_encoding='cp1251')
675
682
 
676
683
        output = subst_dates(sio.getvalue())
677
 
        shouldbe = ('''\
 
684
        shouldbe = (b'''\
678
685
=== added directory '%(directory)s'
679
686
=== added file '%(test_txt)s'
680
687
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
688
695
@@ -0,0 +1,1 @@
689
696
+foo
690
697
 
691
 
''' % {'directory': _russian_test.encode('cp1251'),
692
 
       'test_txt': test_txt.encode('cp1251'),
 
698
''' % {b'directory': _russian_test.encode('cp1251'),
 
699
       b'test_txt': test_txt.encode('cp1251'),
693
700
      })
694
701
        self.assertEqualDiff(output, shouldbe)
695
702
 
697
704
class DiffWasIs(diff.DiffPath):
698
705
 
699
706
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
700
 
        self.to_file.write('was: ')
 
707
        self.to_file.write(b'was: ')
701
708
        self.to_file.write(self.old_tree.get_file(old_path).read())
702
 
        self.to_file.write('is: ')
 
709
        self.to_file.write(b'is: ')
703
710
        self.to_file.write(self.new_tree.get_file(new_path).read())
704
711
 
705
712
 
728
735
        differ.diff_text('olddir/oldfile', None, 'old label',
729
736
                         'new label', b'file-id', None)
730
737
        self.assertEqual(
731
 
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
 
738
            b'--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
732
739
            differ.to_file.getvalue())
733
740
        differ.to_file.seek(0)
734
741
        differ.diff_text(None, 'newdir/newfile',
735
742
                         'old label', 'new label', None, b'file-id')
736
743
        self.assertEqual(
737
 
            '--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
 
744
            b'--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
738
745
            differ.to_file.getvalue())
739
746
        differ.to_file.seek(0)
740
747
        differ.diff_text('olddir/oldfile', 'newdir/newfile',
741
748
                         'old label', 'new label', b'file-id', b'file-id')
742
749
        self.assertEqual(
743
 
            '--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
 
750
            b'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
744
751
            differ.to_file.getvalue())
745
752
 
746
753
    def test_diff_deletion(self):
750
757
        self.new_tree.add('file', b'file-id')
751
758
        os.unlink('new-tree/file')
752
759
        self.differ.show_diff(None)
753
 
        self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
 
760
        self.assertContainsRe(self.differ.to_file.getvalue(), b'-contents')
754
761
 
755
762
    def test_diff_creation(self):
756
763
        self.build_tree_contents([('old-tree/file', b'contents'),
759
766
        self.new_tree.add('file', b'file-id')
760
767
        os.unlink('old-tree/file')
761
768
        self.differ.show_diff(None)
762
 
        self.assertContainsRe(self.differ.to_file.getvalue(), r'\+contents')
 
769
        self.assertContainsRe(self.differ.to_file.getvalue(), br'\+contents')
763
770
 
764
771
    def test_diff_symlink(self):
765
772
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
766
773
        differ.diff_symlink('old target', None)
767
 
        self.assertEqual("=== target was 'old target'\n",
 
774
        self.assertEqual(b"=== target was 'old target'\n",
768
775
                         differ.to_file.getvalue())
769
776
 
770
777
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
771
778
        differ.diff_symlink(None, 'new target')
772
 
        self.assertEqual("=== target is 'new target'\n",
 
779
        self.assertEqual(b"=== target is 'new target'\n",
773
780
                         differ.to_file.getvalue())
774
781
 
775
782
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
776
783
        differ.diff_symlink('old target', 'new target')
777
 
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
 
784
        self.assertEqual(b"=== target changed 'old target' => 'new target'\n",
778
785
                         differ.to_file.getvalue())
779
786
 
780
787
    def test_diff(self):
789
796
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
790
797
        self.assertContainsRe(
791
798
            self.differ.to_file.getvalue(),
792
 
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
793
 
            r' \@\@\n-old\n\+new\n\n')
 
799
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
800
            br' \@\@\n-old\n\+new\n\n')
794
801
 
795
802
    def test_diff_kind_change(self):
796
803
        self.requireFeature(features.SymlinkFeature)
805
812
        self.differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
806
813
        self.assertContainsRe(
807
814
            self.differ.to_file.getvalue(),
808
 
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
809
 
            r' \@\@\n-old\n\n')
 
815
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
 
816
            br' \@\@\n-old\n\n')
810
817
        self.assertContainsRe(self.differ.to_file.getvalue(),
811
 
                              "=== target is u'new'\n")
 
818
                              b"=== target is 'new'\n")
812
819
 
813
820
    def test_diff_directory(self):
814
821
        self.build_tree(['new-tree/new-dir/'])
838
845
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
839
846
        self.assertNotContainsRe(
840
847
            differ.to_file.getvalue(),
841
 
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
842
 
            r' \@\@\n-old\n\+new\n\n')
 
848
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
849
            br' \@\@\n-old\n\+new\n\n')
843
850
        self.assertContainsRe(differ.to_file.getvalue(),
844
 
                              'was: old\nis: new\n')
 
851
                              b'was: old\nis: new\n')
845
852
 
846
853
    def test_extra_factories(self):
847
854
        self.create_old_new()
850
857
        differ.diff(b'file-id', 'olddir/oldfile', 'newdir/newfile')
851
858
        self.assertNotContainsRe(
852
859
            differ.to_file.getvalue(),
853
 
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
854
 
            r' \@\@\n-old\n\+new\n\n')
 
860
            br'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
861
            br' \@\@\n-old\n\+new\n\n')
855
862
        self.assertContainsRe(differ.to_file.getvalue(),
856
 
                              'was: old\nis: new\n')
 
863
                              b'was: old\nis: new\n')
857
864
 
858
865
    def test_alphabetical_order(self):
859
866
        self.build_tree(['new-tree/a-file'])
862
869
        self.old_tree.add('b-file')
863
870
        self.differ.show_diff(None)
864
871
        self.assertContainsRe(self.differ.to_file.getvalue(),
865
 
            '.*a-file(.|\n)*b-file')
 
872
            b'.*a-file(.|\n)*b-file')
866
873
 
867
874
 
868
875
class TestPatienceDiffLib(tests.TestCase):
1299
1306
 
1300
1307
        unified_diff_files = patiencediff.unified_diff_files
1301
1308
        psm = self._PatienceSequenceMatcher
1302
 
        self.assertEqual(['--- a1\n',
1303
 
                           '+++ b1\n',
1304
 
                           '@@ -1,3 +1,2 @@\n',
1305
 
                           ' hello there\n',
1306
 
                           '-world\n',
1307
 
                           ' how are you today?\n',
 
1309
        self.assertEqual([b'--- a1\n',
 
1310
                          b'+++ b1\n',
 
1311
                          b'@@ -1,3 +1,2 @@\n',
 
1312
                          b' hello there\n',
 
1313
                          b'-world\n',
 
1314
                          b' how are you today?\n',
1308
1315
                          ]
1309
 
                          , list(unified_diff_files('a1', 'b1',
 
1316
                          , list(unified_diff_files(b'a1', b'b1',
1310
1317
                                 sequencematcher=psm)))
1311
1318
 
1312
1319
        txt_a = [x+'\n' for x in 'abcdefghijklmnop']
1313
1320
        txt_b = [x+'\n' for x in 'abcdefxydefghijklmnop']
1314
 
        with open('a2', 'wb') as f: f.writelines(txt_a)
1315
 
        with open('b2', 'wb') as f: f.writelines(txt_b)
 
1321
        with open('a2', 'wt') as f: f.writelines(txt_a)
 
1322
        with open('b2', 'wt') as f: f.writelines(txt_b)
1316
1323
 
1317
1324
        # This is the result with LongestCommonSubstring matching
1318
 
        self.assertEqual(['--- a2\n',
1319
 
                           '+++ b2\n',
1320
 
                           '@@ -1,6 +1,11 @@\n',
1321
 
                           ' a\n',
1322
 
                           ' b\n',
1323
 
                           ' c\n',
1324
 
                           '+d\n',
1325
 
                           '+e\n',
1326
 
                           '+f\n',
1327
 
                           '+x\n',
1328
 
                           '+y\n',
1329
 
                           ' d\n',
1330
 
                           ' e\n',
1331
 
                           ' f\n']
1332
 
                          , list(unified_diff_files('a2', 'b2')))
 
1325
        self.assertEqual([b'--- a2\n',
 
1326
                          b'+++ b2\n',
 
1327
                          b'@@ -1,6 +1,11 @@\n',
 
1328
                          b' a\n',
 
1329
                          b' b\n',
 
1330
                          b' c\n',
 
1331
                          b'+d\n',
 
1332
                          b'+e\n',
 
1333
                          b'+f\n',
 
1334
                          b'+x\n',
 
1335
                          b'+y\n',
 
1336
                          b' d\n',
 
1337
                          b' e\n',
 
1338
                          b' f\n']
 
1339
                          , list(unified_diff_files(b'a2', b'b2')))
1333
1340
 
1334
1341
        # And the patience diff
1335
 
        self.assertEqual(['--- a2\n',
1336
 
                          '+++ b2\n',
1337
 
                          '@@ -4,6 +4,11 @@\n',
1338
 
                          ' d\n',
1339
 
                          ' e\n',
1340
 
                          ' f\n',
1341
 
                          '+x\n',
1342
 
                          '+y\n',
1343
 
                          '+d\n',
1344
 
                          '+e\n',
1345
 
                          '+f\n',
1346
 
                          ' g\n',
1347
 
                          ' h\n',
1348
 
                          ' i\n'],
1349
 
                         list(unified_diff_files('a2', 'b2',
 
1342
        self.assertEqual([b'--- a2\n',
 
1343
                          b'+++ b2\n',
 
1344
                          b'@@ -4,6 +4,11 @@\n',
 
1345
                          b' d\n',
 
1346
                          b' e\n',
 
1347
                          b' f\n',
 
1348
                          b'+x\n',
 
1349
                          b'+y\n',
 
1350
                          b'+d\n',
 
1351
                          b'+e\n',
 
1352
                          b'+f\n',
 
1353
                          b' g\n',
 
1354
                          b' h\n',
 
1355
                          b' i\n'],
 
1356
                         list(unified_diff_files(b'a2', b'b2',
1350
1357
                                                 sequencematcher=psm)))
1351
1358
 
1352
1359