~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-08-24 23:20:14 UTC
  • mfrom: (5365.5.29 2.3-btree-chk-leaf)
  • Revision ID: pqm@pqm.ubuntu.com-20100824232014-nu9owzel2zym2jk2
(jam) Use a custom C type for CHK index entries, saves memory

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2014, 2016, 2017 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
import os
18
18
from cStringIO import StringIO
19
19
import subprocess
 
20
import sys
20
21
import tempfile
21
22
 
22
23
from bzrlib import (
31
32
    tests,
32
33
    transform,
33
34
    )
34
 
from bzrlib.tests import (
35
 
    features,
36
 
    EncodingAdapter,
37
 
)
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import features
38
37
from bzrlib.tests.blackbox.test_diff import subst_dates
39
 
from bzrlib.tests.scenarios import load_tests_apply_scenarios
40
 
 
41
 
 
42
 
load_tests = load_tests_apply_scenarios
 
38
 
 
39
 
 
40
class _AttribFeature(tests.Feature):
 
41
 
 
42
    def _probe(self):
 
43
        if (sys.platform not in ('cygwin', 'win32')):
 
44
            return False
 
45
        try:
 
46
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
 
47
        except OSError, e:
 
48
            return False
 
49
        return (0 == proc.wait())
 
50
 
 
51
    def feature_name(self):
 
52
        return 'attrib Windows command-line tool'
 
53
 
 
54
AttribFeature = _AttribFeature()
 
55
 
 
56
 
 
57
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
 
58
                                    'bzrlib._patiencediff_c')
43
59
 
44
60
 
45
61
def udiff_lines(old, new, allow_binary=False):
65
81
    return lines
66
82
 
67
83
 
68
 
class TestDiffOptions(tests.TestCase):
69
 
 
70
 
    def test_unified_added(self):
71
 
        """Check for default style '-u' only if no other style specified
72
 
        in 'diff-options'.
73
 
        """
74
 
        # Verify that style defaults to unified, id est '-u' appended
75
 
        # to option list, in the absence of an alternative style.
76
 
        self.assertEqual(['-a', '-u'], diff.default_style_unified(['-a']))
77
 
 
78
 
 
79
 
class TestDiffOptionsScenarios(tests.TestCase):
80
 
 
81
 
    scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
82
 
    style = None # Set by load_tests_apply_scenarios from scenarios
83
 
 
84
 
    def test_unified_not_added(self):
85
 
        # Verify that for all valid style options, '-u' is not
86
 
        # appended to option list.
87
 
        ret_opts = diff.default_style_unified(diff_opts=["%s" % (self.style,)])
88
 
        self.assertEqual(["%s" % (self.style,)], ret_opts)
89
 
 
90
 
 
91
84
class TestDiff(tests.TestCase):
92
85
 
93
86
    def test_add_nl(self):
94
87
        """diff generates a valid diff for patches that add a newline"""
95
88
        lines = udiff_lines(['boo'], ['boo\n'])
96
89
        self.check_patch(lines)
97
 
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
 
90
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
98
91
            ## "expected no-nl, got %r" % lines[4]
99
92
 
100
93
    def test_add_nl_2(self):
103
96
        """
104
97
        lines = udiff_lines(['boo'], ['goo\n'])
105
98
        self.check_patch(lines)
106
 
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
 
99
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
107
100
            ## "expected no-nl, got %r" % lines[4]
108
101
 
109
102
    def test_remove_nl(self):
112
105
        """
113
106
        lines = udiff_lines(['boo\n'], ['boo'])
114
107
        self.check_patch(lines)
115
 
        self.assertEqual(lines[5], '\\ No newline at end of file\n')
 
108
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
116
109
            ## "expected no-nl, got %r" % lines[5]
117
110
 
118
111
    def check_patch(self, lines):
119
 
        self.assertTrue(len(lines) > 1)
 
112
        self.assert_(len(lines) > 1)
120
113
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
121
 
        self.assertTrue(lines[0].startswith ('---'))
 
114
        self.assert_(lines[0].startswith ('---'))
122
115
            ## 'No orig line for patch:\n%s' % "".join(lines)
123
 
        self.assertTrue(lines[1].startswith ('+++'))
 
116
        self.assert_(lines[1].startswith ('+++'))
124
117
            ## 'No mod line for patch:\n%s' % "".join(lines)
125
 
        self.assertTrue(len(lines) > 2)
 
118
        self.assert_(len(lines) > 2)
126
119
            ## "No hunks for patch:\n%s" % "".join(lines)
127
 
        self.assertTrue(lines[2].startswith('@@'))
 
120
        self.assert_(lines[2].startswith('@@'))
128
121
            ## "No hunk header for patch:\n%s" % "".join(lines)
129
 
        self.assertTrue('@@' in lines[2][2:])
 
122
        self.assert_('@@' in lines[2][2:])
130
123
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
131
124
 
132
125
    def test_binary_lines(self):
151
144
        self.check_patch(lines)
152
145
 
153
146
    def test_external_diff_binary_lang_c(self):
 
147
        old_env = {}
154
148
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
155
 
            self.overrideEnv(lang, 'C')
156
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
157
 
        # Older versions of diffutils say "Binary files", newer
158
 
        # versions just say "Files".
159
 
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
160
 
        self.assertEqual(lines[1:], ['\n'])
 
149
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
 
150
        try:
 
151
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
152
            # Older versions of diffutils say "Binary files", newer
 
153
            # versions just say "Files".
 
154
            self.assertContainsRe(lines[0],
 
155
                                  '(Binary f|F)iles old and new differ\n')
 
156
            self.assertEquals(lines[1:], ['\n'])
 
157
        finally:
 
158
            for lang, old_val in old_env.iteritems():
 
159
                osutils.set_or_unset_env(lang, old_val)
161
160
 
162
161
    def test_no_external_diff(self):
163
162
        """Check that NoDiff is raised when diff is not available"""
164
 
        # Make sure no 'diff' command is available
165
 
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
166
 
        self.overrideEnv('PATH', '')
167
 
        self.assertRaises(errors.NoDiff, diff.external_diff,
168
 
                          'old', ['boo\n'], 'new', ['goo\n'],
169
 
                          StringIO(), diff_opts=['-u'])
 
163
        # Use os.environ['PATH'] to make sure no 'diff' command is available
 
164
        orig_path = os.environ['PATH']
 
165
        try:
 
166
            os.environ['PATH'] = ''
 
167
            self.assertRaises(errors.NoDiff, diff.external_diff,
 
168
                              'old', ['boo\n'], 'new', ['goo\n'],
 
169
                              StringIO(), diff_opts=['-u'])
 
170
        finally:
 
171
            os.environ['PATH'] = orig_path
170
172
 
171
173
    def test_internal_diff_default(self):
172
174
        # Default internal diff encoding is utf8
175
177
                           u'new_\xe5', ['new_text\n'], output)
176
178
        lines = output.getvalue().splitlines(True)
177
179
        self.check_patch(lines)
178
 
        self.assertEqual(['--- old_\xc2\xb5\n',
 
180
        self.assertEquals(['--- old_\xc2\xb5\n',
179
181
                           '+++ new_\xc3\xa5\n',
180
182
                           '@@ -1,1 +1,1 @@\n',
181
183
                           '-old_text\n',
191
193
                           path_encoding='utf8')
192
194
        lines = output.getvalue().splitlines(True)
193
195
        self.check_patch(lines)
194
 
        self.assertEqual(['--- old_\xc2\xb5\n',
 
196
        self.assertEquals(['--- old_\xc2\xb5\n',
195
197
                           '+++ new_\xc3\xa5\n',
196
198
                           '@@ -1,1 +1,1 @@\n',
197
199
                           '-old_text\n',
207
209
                           path_encoding='iso-8859-1')
208
210
        lines = output.getvalue().splitlines(True)
209
211
        self.check_patch(lines)
210
 
        self.assertEqual(['--- old_\xb5\n',
 
212
        self.assertEquals(['--- old_\xb5\n',
211
213
                           '+++ new_\xe5\n',
212
214
                           '@@ -1,1 +1,1 @@\n',
213
215
                           '-old_text\n',
233
235
        output = StringIO.StringIO()
234
236
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
235
237
                            u'new_\xe5', ['new_text\n'], output)
236
 
        self.assertIsInstance(output.getvalue(), str,
 
238
        self.failUnless(isinstance(output.getvalue(), str),
237
239
            'internal_diff should return bytestrings')
238
240
 
239
 
    def test_internal_diff_default_context(self):
240
 
        output = StringIO()
241
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
242
 
                           'same_text\n','same_text\n','old_text\n'],
243
 
                           'new', ['same_text\n','same_text\n','same_text\n',
244
 
                           'same_text\n','same_text\n','new_text\n'], output)
245
 
        lines = output.getvalue().splitlines(True)
246
 
        self.check_patch(lines)
247
 
        self.assertEqual(['--- old\n',
248
 
                           '+++ new\n',
249
 
                           '@@ -3,4 +3,4 @@\n',
250
 
                           ' same_text\n',
251
 
                           ' same_text\n',
252
 
                           ' same_text\n',
253
 
                           '-old_text\n',
254
 
                           '+new_text\n',
255
 
                           '\n',
256
 
                          ]
257
 
                          , lines)
258
 
 
259
 
    def test_internal_diff_no_context(self):
260
 
        output = StringIO()
261
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
262
 
                           'same_text\n','same_text\n','old_text\n'],
263
 
                           'new', ['same_text\n','same_text\n','same_text\n',
264
 
                           'same_text\n','same_text\n','new_text\n'], output,
265
 
                           context_lines=0)
266
 
        lines = output.getvalue().splitlines(True)
267
 
        self.check_patch(lines)
268
 
        self.assertEqual(['--- old\n',
269
 
                           '+++ new\n',
270
 
                           '@@ -6,1 +6,1 @@\n',
271
 
                           '-old_text\n',
272
 
                           '+new_text\n',
273
 
                           '\n',
274
 
                          ]
275
 
                          , lines)
276
 
 
277
 
    def test_internal_diff_more_context(self):
278
 
        output = StringIO()
279
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
280
 
                           'same_text\n','same_text\n','old_text\n'],
281
 
                           'new', ['same_text\n','same_text\n','same_text\n',
282
 
                           'same_text\n','same_text\n','new_text\n'], output,
283
 
                           context_lines=4)
284
 
        lines = output.getvalue().splitlines(True)
285
 
        self.check_patch(lines)
286
 
        self.assertEqual(['--- old\n',
287
 
                           '+++ new\n',
288
 
                           '@@ -2,5 +2,5 @@\n',
289
 
                           ' same_text\n',
290
 
                           ' same_text\n',
291
 
                           ' same_text\n',
292
 
                           ' same_text\n',
293
 
                           '-old_text\n',
294
 
                           '+new_text\n',
295
 
                           '\n',
296
 
                          ]
297
 
                          , lines)
298
 
 
299
 
 
300
 
 
301
 
 
302
241
 
303
242
class TestDiffFiles(tests.TestCaseInTempDir):
304
243
 
308
247
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
309
248
 
310
249
        cmd = ['diff', '-u', '--binary', 'old', 'new']
311
 
        with open('old', 'wb') as f: f.write('\x00foobar\n')
312
 
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
 
250
        open('old', 'wb').write('\x00foobar\n')
 
251
        open('new', 'wb').write('foo\x00bar\n')
313
252
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
314
253
                                     stdin=subprocess.PIPE)
315
254
        out, err = pipe.communicate()
 
255
        # Diff returns '2' on Binary files.
 
256
        self.assertEqual(2, pipe.returncode)
316
257
        # We should output whatever diff tells us, plus a trailing newline
317
258
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
318
259
 
319
260
 
320
 
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
321
 
    output = StringIO()
322
 
    if working_tree is not None:
323
 
        extra_trees = (working_tree,)
324
 
    else:
325
 
        extra_trees = ()
326
 
    diff.show_diff_trees(tree1, tree2, output,
327
 
        specific_files=specific_files,
328
 
        extra_trees=extra_trees, old_label='old/',
329
 
        new_label='new/')
330
 
    return output.getvalue()
331
 
 
332
 
 
333
 
class TestDiffDates(tests.TestCaseWithTransport):
 
261
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
 
262
    """Has a helper for running show_diff_trees"""
 
263
 
 
264
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
 
265
        output = StringIO()
 
266
        if working_tree is not None:
 
267
            extra_trees = (working_tree,)
 
268
        else:
 
269
            extra_trees = ()
 
270
        diff.show_diff_trees(tree1, tree2, output,
 
271
                             specific_files=specific_files,
 
272
                             extra_trees=extra_trees, old_label='old/',
 
273
                             new_label='new/')
 
274
        return output.getvalue()
 
275
 
 
276
 
 
277
class TestDiffDates(TestShowDiffTreesHelper):
334
278
 
335
279
    def setUp(self):
336
280
        super(TestDiffDates, self).setUp()
371
315
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
372
316
 
373
317
    def test_diff_rev_tree_working_tree(self):
374
 
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
 
318
        output = self.get_diff(self.wt.basis_tree(), self.wt)
375
319
        # note that the date for old/file1 is from rev 2 rather than from
376
320
        # the basis revision (rev 4)
377
321
        self.assertEqualDiff(output, '''\
387
331
    def test_diff_rev_tree_rev_tree(self):
388
332
        tree1 = self.b.repository.revision_tree('rev-2')
389
333
        tree2 = self.b.repository.revision_tree('rev-3')
390
 
        output = get_diff_as_string(tree1, tree2)
 
334
        output = self.get_diff(tree1, tree2)
391
335
        self.assertEqualDiff(output, '''\
392
336
=== modified file 'file2'
393
337
--- old/file2\t2006-04-01 00:00:00 +0000
401
345
    def test_diff_add_files(self):
402
346
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
403
347
        tree2 = self.b.repository.revision_tree('rev-1')
404
 
        output = get_diff_as_string(tree1, tree2)
 
348
        output = self.get_diff(tree1, tree2)
405
349
        # the files have the epoch time stamp for the tree in which
406
350
        # they don't exist.
407
351
        self.assertEqualDiff(output, '''\
422
366
    def test_diff_remove_files(self):
423
367
        tree1 = self.b.repository.revision_tree('rev-3')
424
368
        tree2 = self.b.repository.revision_tree('rev-4')
425
 
        output = get_diff_as_string(tree1, tree2)
 
369
        output = self.get_diff(tree1, tree2)
426
370
        # the file has the epoch time stamp for the tree in which
427
371
        # it doesn't exist.
428
372
        self.assertEqualDiff(output, '''\
439
383
        self.wt.rename_one('file1', 'file1b')
440
384
        old_tree = self.b.repository.revision_tree('rev-1')
441
385
        new_tree = self.b.repository.revision_tree('rev-4')
442
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
 
386
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
443
387
                            working_tree=self.wt)
444
388
        self.assertContainsRe(out, 'file1\t')
445
389
 
451
395
        self.wt.rename_one('file1', 'dir1/file1')
452
396
        old_tree = self.b.repository.revision_tree('rev-1')
453
397
        new_tree = self.b.repository.revision_tree('rev-4')
454
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
 
398
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
455
399
                            working_tree=self.wt)
456
400
        self.assertContainsRe(out, 'file1\t')
457
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
 
401
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
458
402
                            working_tree=self.wt)
459
403
        self.assertNotContainsRe(out, 'file1\t')
460
404
 
461
405
 
462
 
class TestShowDiffTrees(tests.TestCaseWithTransport):
 
406
 
 
407
class TestShowDiffTrees(TestShowDiffTreesHelper):
463
408
    """Direct tests for show_diff_trees"""
464
409
 
465
410
    def test_modified_file(self):
470
415
        tree.commit('one', rev_id='rev-1')
471
416
 
472
417
        self.build_tree_contents([('tree/file', 'new contents\n')])
473
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
418
        d = self.get_diff(tree.basis_tree(), tree)
474
419
        self.assertContainsRe(d, "=== modified file 'file'\n")
475
420
        self.assertContainsRe(d, '--- old/file\t')
476
421
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
487
432
 
488
433
        tree.rename_one('dir', 'other')
489
434
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
490
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
435
        d = self.get_diff(tree.basis_tree(), tree)
491
436
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
492
437
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
493
438
        # XXX: This is technically incorrect, because it used to be at another
506
451
        tree.commit('one', rev_id='rev-1')
507
452
 
508
453
        tree.rename_one('dir', 'newdir')
509
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
454
        d = self.get_diff(tree.basis_tree(), tree)
510
455
        # Renaming a directory should be a single "you renamed this dir" even
511
456
        # when there are files inside.
512
457
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
519
464
        tree.commit('one', rev_id='rev-1')
520
465
 
521
466
        tree.rename_one('file', 'newname')
522
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
467
        d = self.get_diff(tree.basis_tree(), tree)
523
468
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
524
469
        # We shouldn't have a --- or +++ line, because there is no content
525
470
        # change
534
479
 
535
480
        tree.rename_one('file', 'newname')
536
481
        self.build_tree_contents([('tree/newname', 'new contents\n')])
537
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
482
        d = self.get_diff(tree.basis_tree(), tree)
538
483
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
539
484
        self.assertContainsRe(d, '--- old/file\t')
540
485
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
564
509
        tree.rename_one('c', 'new-c')
565
510
        tree.rename_one('d', 'new-d')
566
511
 
567
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
512
        d = self.get_diff(tree.basis_tree(), tree)
568
513
 
569
514
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
570
515
                                  ".*\+x to -x.*\)")
582
527
        is a binary file in the diff.
583
528
        """
584
529
        # See https://bugs.launchpad.net/bugs/110092.
585
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
530
        self.requireFeature(tests.UnicodeFilenameFeature)
586
531
 
587
532
        # This bug isn't triggered with cStringIO.
588
533
        from StringIO import StringIO
607
552
 
608
553
    def test_unicode_filename(self):
609
554
        """Test when the filename are unicode."""
610
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
555
        self.requireFeature(tests.UnicodeFilenameFeature)
611
556
 
612
557
        alpha, omega = u'\u03b1', u'\u03c9'
613
558
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
628
573
        tree.add(['add_'+alpha], ['file-id'])
629
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
630
575
 
631
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
576
        d = self.get_diff(tree.basis_tree(), tree)
632
577
        self.assertContainsRe(d,
633
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
634
579
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
639
584
        """Test for bug #382699: unicode filenames on Windows should be shown
640
585
        in user encoding.
641
586
        """
642
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
587
        self.requireFeature(tests.UnicodeFilenameFeature)
643
588
        # The word 'test' in Russian
644
589
        _russian_test = u'\u0422\u0435\u0441\u0442'
645
590
        directory = _russian_test + u'/'
776
721
             ' \@\@\n-old\n\+new\n\n')
777
722
 
778
723
    def test_diff_kind_change(self):
779
 
        self.requireFeature(features.SymlinkFeature)
 
724
        self.requireFeature(tests.SymlinkFeature)
780
725
        self.build_tree_contents([('old-tree/olddir/',),
781
726
                                  ('old-tree/olddir/oldfile', 'old\n')])
782
727
        self.old_tree.add('olddir')
862
807
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
863
808
        sm = self._PatienceSequenceMatcher(None, a, b)
864
809
        mb = sm.get_matching_blocks()
865
 
        self.assertEqual(35, len(mb))
 
810
        self.assertEquals(35, len(mb))
866
811
 
867
812
    def test_unique_lcs(self):
868
813
        unique_lcs = self._unique_lcs
869
 
        self.assertEqual(unique_lcs('', ''), [])
870
 
        self.assertEqual(unique_lcs('', 'a'), [])
871
 
        self.assertEqual(unique_lcs('a', ''), [])
872
 
        self.assertEqual(unique_lcs('a', 'a'), [(0,0)])
873
 
        self.assertEqual(unique_lcs('a', 'b'), [])
874
 
        self.assertEqual(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
875
 
        self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
876
 
        self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
877
 
        self.assertEqual(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
 
814
        self.assertEquals(unique_lcs('', ''), [])
 
815
        self.assertEquals(unique_lcs('', 'a'), [])
 
816
        self.assertEquals(unique_lcs('a', ''), [])
 
817
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
 
818
        self.assertEquals(unique_lcs('a', 'b'), [])
 
819
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
 
820
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
 
821
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
 
822
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
878
823
                                                         (3,3), (4,4)])
879
 
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2,1)])
 
824
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
880
825
 
881
826
    def test_recurse_matches(self):
882
827
        def test_one(a, b, matches):
883
828
            test_matches = []
884
829
            self._recurse_matches(
885
830
                a, b, 0, 0, len(a), len(b), test_matches, 10)
886
 
            self.assertEqual(test_matches, matches)
 
831
            self.assertEquals(test_matches, matches)
887
832
 
888
833
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
889
834
                 [(0, 0), (2, 2), (4, 4)])
994
939
    def test_opcodes(self):
995
940
        def chk_ops(a, b, expected_codes):
996
941
            s = self._PatienceSequenceMatcher(None, a, b)
997
 
            self.assertEqual(expected_codes, s.get_opcodes())
 
942
            self.assertEquals(expected_codes, s.get_opcodes())
998
943
 
999
944
        chk_ops('', '', [])
1000
945
        chk_ops([], [], [])
1070
1015
    def test_grouped_opcodes(self):
1071
1016
        def chk_ops(a, b, expected_codes, n=3):
1072
1017
            s = self._PatienceSequenceMatcher(None, a, b)
1073
 
            self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
 
1018
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
1074
1019
 
1075
1020
        chk_ops('', '', [])
1076
1021
        chk_ops([], [], [])
1170
1115
                 'how are you today?\n']
1171
1116
        unified_diff = patiencediff.unified_diff
1172
1117
        psm = self._PatienceSequenceMatcher
1173
 
        self.assertEqual(['--- \n',
 
1118
        self.assertEquals(['--- \n',
1174
1119
                           '+++ \n',
1175
1120
                           '@@ -1,3 +1,2 @@\n',
1176
1121
                           ' hello there\n',
1182
1127
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1183
1128
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1184
1129
        # This is the result with LongestCommonSubstring matching
1185
 
        self.assertEqual(['--- \n',
 
1130
        self.assertEquals(['--- \n',
1186
1131
                           '+++ \n',
1187
1132
                           '@@ -1,6 +1,11 @@\n',
1188
1133
                           ' a\n',
1198
1143
                           ' f\n']
1199
1144
                          , list(unified_diff(txt_a, txt_b)))
1200
1145
        # And the patience diff
1201
 
        self.assertEqual(['--- \n',
 
1146
        self.assertEquals(['--- \n',
1202
1147
                           '+++ \n',
1203
1148
                           '@@ -4,6 +4,11 @@\n',
1204
1149
                           ' d\n',
1224
1169
                 'how are you today?\n']
1225
1170
        unified_diff = patiencediff.unified_diff
1226
1171
        psm = self._PatienceSequenceMatcher
1227
 
        self.assertEqual(['--- a\t2008-08-08\n',
 
1172
        self.assertEquals(['--- a\t2008-08-08\n',
1228
1173
                           '+++ b\t2008-09-09\n',
1229
1174
                           '@@ -1,3 +1,2 @@\n',
1230
1175
                           ' hello there\n',
1240
1185
 
1241
1186
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1242
1187
 
1243
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1188
    _test_needs_features = [compiled_patiencediff_feature]
1244
1189
 
1245
1190
    def setUp(self):
1246
1191
        super(TestPatienceDiffLib_c, self).setUp()
1277
1222
                 'how are you today?\n']
1278
1223
        txt_b = ['hello there\n',
1279
1224
                 'how are you today?\n']
1280
 
        with open('a1', 'wb') as f: f.writelines(txt_a)
1281
 
        with open('b1', 'wb') as f: f.writelines(txt_b)
 
1225
        open('a1', 'wb').writelines(txt_a)
 
1226
        open('b1', 'wb').writelines(txt_b)
1282
1227
 
1283
1228
        unified_diff_files = patiencediff.unified_diff_files
1284
1229
        psm = self._PatienceSequenceMatcher
1285
 
        self.assertEqual(['--- a1\n',
 
1230
        self.assertEquals(['--- a1\n',
1286
1231
                           '+++ b1\n',
1287
1232
                           '@@ -1,3 +1,2 @@\n',
1288
1233
                           ' hello there\n',
1294
1239
 
1295
1240
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1296
1241
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1297
 
        with open('a2', 'wb') as f: f.writelines(txt_a)
1298
 
        with open('b2', 'wb') as f: f.writelines(txt_b)
 
1242
        open('a2', 'wb').writelines(txt_a)
 
1243
        open('b2', 'wb').writelines(txt_b)
1299
1244
 
1300
1245
        # This is the result with LongestCommonSubstring matching
1301
 
        self.assertEqual(['--- a2\n',
 
1246
        self.assertEquals(['--- a2\n',
1302
1247
                           '+++ b2\n',
1303
1248
                           '@@ -1,6 +1,11 @@\n',
1304
1249
                           ' a\n',
1315
1260
                          , list(unified_diff_files('a2', 'b2')))
1316
1261
 
1317
1262
        # And the patience diff
1318
 
        self.assertEqual(['--- a2\n',
1319
 
                          '+++ b2\n',
1320
 
                          '@@ -4,6 +4,11 @@\n',
1321
 
                          ' d\n',
1322
 
                          ' e\n',
1323
 
                          ' f\n',
1324
 
                          '+x\n',
1325
 
                          '+y\n',
1326
 
                          '+d\n',
1327
 
                          '+e\n',
1328
 
                          '+f\n',
1329
 
                          ' g\n',
1330
 
                          ' h\n',
1331
 
                          ' i\n'],
1332
 
                         list(unified_diff_files('a2', 'b2',
1333
 
                                                 sequencematcher=psm)))
 
1263
        self.assertEquals(['--- a2\n',
 
1264
                           '+++ b2\n',
 
1265
                           '@@ -4,6 +4,11 @@\n',
 
1266
                           ' d\n',
 
1267
                           ' e\n',
 
1268
                           ' f\n',
 
1269
                           '+x\n',
 
1270
                           '+y\n',
 
1271
                           '+d\n',
 
1272
                           '+e\n',
 
1273
                           '+f\n',
 
1274
                           ' g\n',
 
1275
                           ' h\n',
 
1276
                           ' i\n',
 
1277
                          ]
 
1278
                          , list(unified_diff_files('a2', 'b2',
 
1279
                                 sequencematcher=psm)))
1334
1280
 
1335
1281
 
1336
1282
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1337
1283
 
1338
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1284
    _test_needs_features = [compiled_patiencediff_feature]
1339
1285
 
1340
1286
    def setUp(self):
1341
1287
        super(TestPatienceDiffLibFiles_c, self).setUp()
1347
1293
class TestUsingCompiledIfAvailable(tests.TestCase):
1348
1294
 
1349
1295
    def test_PatienceSequenceMatcher(self):
1350
 
        if features.compiled_patiencediff_feature.available():
 
1296
        if compiled_patiencediff_feature.available():
1351
1297
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1352
1298
            self.assertIs(PatienceSequenceMatcher_c,
1353
1299
                          patiencediff.PatienceSequenceMatcher)
1357
1303
                          patiencediff.PatienceSequenceMatcher)
1358
1304
 
1359
1305
    def test_unique_lcs(self):
1360
 
        if features.compiled_patiencediff_feature.available():
 
1306
        if compiled_patiencediff_feature.available():
1361
1307
            from bzrlib._patiencediff_c import unique_lcs_c
1362
1308
            self.assertIs(unique_lcs_c,
1363
1309
                          patiencediff.unique_lcs)
1367
1313
                          patiencediff.unique_lcs)
1368
1314
 
1369
1315
    def test_recurse_matches(self):
1370
 
        if features.compiled_patiencediff_feature.available():
 
1316
        if compiled_patiencediff_feature.available():
1371
1317
            from bzrlib._patiencediff_c import recurse_matches_c
1372
1318
            self.assertIs(recurse_matches_c,
1373
1319
                          patiencediff.recurse_matches)
1413
1359
        diff_obj._execute('old', 'new')
1414
1360
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1415
1361
 
1416
 
    def test_execute_missing(self):
 
1362
    def test_excute_missing(self):
1417
1363
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1418
1364
                                     None, None, None)
1419
1365
        self.addCleanup(diff_obj.finish)
1423
1369
                         ' on this machine', str(e))
1424
1370
 
1425
1371
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1426
 
        self.requireFeature(features.AttribFeature)
 
1372
        self.requireFeature(AttribFeature)
1427
1373
        output = StringIO()
1428
1374
        tree = self.make_branch_and_tree('tree')
1429
1375
        self.build_tree_contents([('tree/file', 'content')])
1488
1434
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1489
1435
 
1490
1436
 
1491
 
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
1492
 
 
1493
 
    def test_encodable_filename(self):
1494
 
        # Just checks file path for external diff tool.
1495
 
        # We cannot change CPython's internal encoding used by os.exec*.
1496
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1497
 
                                    None, None, None)
1498
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1499
 
            encoding = scenario['encoding']
1500
 
            dirname = scenario['info']['directory']
1501
 
            filename = scenario['info']['filename']
1502
 
 
1503
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1504
 
            relpath = dirname + u'/' + filename
1505
 
            fullpath = diffobj._safe_filename('safe', relpath)
1506
 
            self.assertEqual(fullpath,
1507
 
                             fullpath.encode(encoding).decode(encoding))
1508
 
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1509
 
 
1510
 
    def test_unencodable_filename(self):
1511
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1512
 
                                    None, None, None)
1513
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1514
 
            encoding = scenario['encoding']
1515
 
            dirname = scenario['info']['directory']
1516
 
            filename = scenario['info']['filename']
1517
 
 
1518
 
            if encoding == 'iso-8859-1':
1519
 
                encoding = 'iso-8859-2'
1520
 
            else:
1521
 
                encoding = 'iso-8859-1'
1522
 
 
1523
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1524
 
            relpath = dirname + u'/' + filename
1525
 
            fullpath = diffobj._safe_filename('safe', relpath)
1526
 
            self.assertEqual(fullpath,
1527
 
                             fullpath.encode(encoding).decode(encoding))
1528
 
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1529
 
 
1530
 
 
1531
1437
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
1532
1438
 
1533
1439
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1534
 
        """Call get_trees_and_branches_to_diff_locked."""
 
1440
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1441
        TestGetTreesAndBranchesToDiff.
 
1442
        """
1535
1443
        return diff.get_trees_and_branches_to_diff_locked(
1536
1444
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1537
1445
 
1574
1482
        self.assertEqual(tree.branch.base, new_branch.base)
1575
1483
        self.assertIs(None, specific_files)
1576
1484
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
 
1485
 
 
1486
 
 
1487
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
 
1488
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
 
1489
    deprecated get_trees_and_branches_to_diff function.
 
1490
    """
 
1491
 
 
1492
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1493
        return self.applyDeprecated(
 
1494
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
 
1495
            path_list, revision_specs, old_url, new_url)
 
1496