~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: 2011-01-14 23:41:14 UTC
  • mfrom: (5611.1.3 bzr.dev)
  • Revision ID: pqm@pqm.ubuntu.com-20110114234114-r4hdusue691ekeg6
(jelmer) Cope with IPv6 addresses in ``bzr serve`` (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2014, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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):
157
150
        # Older versions of diffutils say "Binary files", newer
158
151
        # versions just say "Files".
159
152
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
160
 
        self.assertEqual(lines[1:], ['\n'])
 
153
        self.assertEquals(lines[1:], ['\n'])
161
154
 
162
155
    def test_no_external_diff(self):
163
156
        """Check that NoDiff is raised when diff is not available"""
175
168
                           u'new_\xe5', ['new_text\n'], output)
176
169
        lines = output.getvalue().splitlines(True)
177
170
        self.check_patch(lines)
178
 
        self.assertEqual(['--- old_\xc2\xb5\n',
 
171
        self.assertEquals(['--- old_\xc2\xb5\n',
179
172
                           '+++ new_\xc3\xa5\n',
180
173
                           '@@ -1,1 +1,1 @@\n',
181
174
                           '-old_text\n',
191
184
                           path_encoding='utf8')
192
185
        lines = output.getvalue().splitlines(True)
193
186
        self.check_patch(lines)
194
 
        self.assertEqual(['--- old_\xc2\xb5\n',
 
187
        self.assertEquals(['--- old_\xc2\xb5\n',
195
188
                           '+++ new_\xc3\xa5\n',
196
189
                           '@@ -1,1 +1,1 @@\n',
197
190
                           '-old_text\n',
207
200
                           path_encoding='iso-8859-1')
208
201
        lines = output.getvalue().splitlines(True)
209
202
        self.check_patch(lines)
210
 
        self.assertEqual(['--- old_\xb5\n',
 
203
        self.assertEquals(['--- old_\xb5\n',
211
204
                           '+++ new_\xe5\n',
212
205
                           '@@ -1,1 +1,1 @@\n',
213
206
                           '-old_text\n',
233
226
        output = StringIO.StringIO()
234
227
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
235
228
                            u'new_\xe5', ['new_text\n'], output)
236
 
        self.assertIsInstance(output.getvalue(), str,
 
229
        self.failUnless(isinstance(output.getvalue(), str),
237
230
            'internal_diff should return bytestrings')
238
231
 
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
232
 
303
233
class TestDiffFiles(tests.TestCaseInTempDir):
304
234
 
308
238
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
309
239
 
310
240
        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')
 
241
        open('old', 'wb').write('\x00foobar\n')
 
242
        open('new', 'wb').write('foo\x00bar\n')
313
243
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
314
244
                                     stdin=subprocess.PIPE)
315
245
        out, err = pipe.communicate()
319
249
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
320
250
 
321
251
 
322
 
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
323
 
    output = StringIO()
324
 
    if working_tree is not None:
325
 
        extra_trees = (working_tree,)
326
 
    else:
327
 
        extra_trees = ()
328
 
    diff.show_diff_trees(tree1, tree2, output,
329
 
        specific_files=specific_files,
330
 
        extra_trees=extra_trees, old_label='old/',
331
 
        new_label='new/')
332
 
    return output.getvalue()
333
 
 
334
 
 
335
 
class TestDiffDates(tests.TestCaseWithTransport):
 
252
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
 
253
    """Has a helper for running show_diff_trees"""
 
254
 
 
255
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
 
256
        output = StringIO()
 
257
        if working_tree is not None:
 
258
            extra_trees = (working_tree,)
 
259
        else:
 
260
            extra_trees = ()
 
261
        diff.show_diff_trees(tree1, tree2, output,
 
262
                             specific_files=specific_files,
 
263
                             extra_trees=extra_trees, old_label='old/',
 
264
                             new_label='new/')
 
265
        return output.getvalue()
 
266
 
 
267
 
 
268
class TestDiffDates(TestShowDiffTreesHelper):
336
269
 
337
270
    def setUp(self):
338
271
        super(TestDiffDates, self).setUp()
373
306
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
374
307
 
375
308
    def test_diff_rev_tree_working_tree(self):
376
 
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
 
309
        output = self.get_diff(self.wt.basis_tree(), self.wt)
377
310
        # note that the date for old/file1 is from rev 2 rather than from
378
311
        # the basis revision (rev 4)
379
312
        self.assertEqualDiff(output, '''\
389
322
    def test_diff_rev_tree_rev_tree(self):
390
323
        tree1 = self.b.repository.revision_tree('rev-2')
391
324
        tree2 = self.b.repository.revision_tree('rev-3')
392
 
        output = get_diff_as_string(tree1, tree2)
 
325
        output = self.get_diff(tree1, tree2)
393
326
        self.assertEqualDiff(output, '''\
394
327
=== modified file 'file2'
395
328
--- old/file2\t2006-04-01 00:00:00 +0000
403
336
    def test_diff_add_files(self):
404
337
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
405
338
        tree2 = self.b.repository.revision_tree('rev-1')
406
 
        output = get_diff_as_string(tree1, tree2)
 
339
        output = self.get_diff(tree1, tree2)
407
340
        # the files have the epoch time stamp for the tree in which
408
341
        # they don't exist.
409
342
        self.assertEqualDiff(output, '''\
424
357
    def test_diff_remove_files(self):
425
358
        tree1 = self.b.repository.revision_tree('rev-3')
426
359
        tree2 = self.b.repository.revision_tree('rev-4')
427
 
        output = get_diff_as_string(tree1, tree2)
 
360
        output = self.get_diff(tree1, tree2)
428
361
        # the file has the epoch time stamp for the tree in which
429
362
        # it doesn't exist.
430
363
        self.assertEqualDiff(output, '''\
441
374
        self.wt.rename_one('file1', 'file1b')
442
375
        old_tree = self.b.repository.revision_tree('rev-1')
443
376
        new_tree = self.b.repository.revision_tree('rev-4')
444
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
 
377
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
445
378
                            working_tree=self.wt)
446
379
        self.assertContainsRe(out, 'file1\t')
447
380
 
453
386
        self.wt.rename_one('file1', 'dir1/file1')
454
387
        old_tree = self.b.repository.revision_tree('rev-1')
455
388
        new_tree = self.b.repository.revision_tree('rev-4')
456
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
 
389
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
457
390
                            working_tree=self.wt)
458
391
        self.assertContainsRe(out, 'file1\t')
459
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
 
392
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
460
393
                            working_tree=self.wt)
461
394
        self.assertNotContainsRe(out, 'file1\t')
462
395
 
463
396
 
464
 
class TestShowDiffTrees(tests.TestCaseWithTransport):
 
397
 
 
398
class TestShowDiffTrees(TestShowDiffTreesHelper):
465
399
    """Direct tests for show_diff_trees"""
466
400
 
467
401
    def test_modified_file(self):
472
406
        tree.commit('one', rev_id='rev-1')
473
407
 
474
408
        self.build_tree_contents([('tree/file', 'new contents\n')])
475
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
409
        d = self.get_diff(tree.basis_tree(), tree)
476
410
        self.assertContainsRe(d, "=== modified file 'file'\n")
477
411
        self.assertContainsRe(d, '--- old/file\t')
478
412
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
489
423
 
490
424
        tree.rename_one('dir', 'other')
491
425
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
492
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
426
        d = self.get_diff(tree.basis_tree(), tree)
493
427
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
494
428
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
495
429
        # XXX: This is technically incorrect, because it used to be at another
508
442
        tree.commit('one', rev_id='rev-1')
509
443
 
510
444
        tree.rename_one('dir', 'newdir')
511
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
445
        d = self.get_diff(tree.basis_tree(), tree)
512
446
        # Renaming a directory should be a single "you renamed this dir" even
513
447
        # when there are files inside.
514
448
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
521
455
        tree.commit('one', rev_id='rev-1')
522
456
 
523
457
        tree.rename_one('file', 'newname')
524
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
458
        d = self.get_diff(tree.basis_tree(), tree)
525
459
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
526
460
        # We shouldn't have a --- or +++ line, because there is no content
527
461
        # change
536
470
 
537
471
        tree.rename_one('file', 'newname')
538
472
        self.build_tree_contents([('tree/newname', 'new contents\n')])
539
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
473
        d = self.get_diff(tree.basis_tree(), tree)
540
474
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
541
475
        self.assertContainsRe(d, '--- old/file\t')
542
476
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
566
500
        tree.rename_one('c', 'new-c')
567
501
        tree.rename_one('d', 'new-d')
568
502
 
569
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
503
        d = self.get_diff(tree.basis_tree(), tree)
570
504
 
571
505
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
572
506
                                  ".*\+x to -x.*\)")
584
518
        is a binary file in the diff.
585
519
        """
586
520
        # See https://bugs.launchpad.net/bugs/110092.
587
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
521
        self.requireFeature(tests.UnicodeFilenameFeature)
588
522
 
589
523
        # This bug isn't triggered with cStringIO.
590
524
        from StringIO import StringIO
609
543
 
610
544
    def test_unicode_filename(self):
611
545
        """Test when the filename are unicode."""
612
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
546
        self.requireFeature(tests.UnicodeFilenameFeature)
613
547
 
614
548
        alpha, omega = u'\u03b1', u'\u03c9'
615
549
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
630
564
        tree.add(['add_'+alpha], ['file-id'])
631
565
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
632
566
 
633
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
567
        d = self.get_diff(tree.basis_tree(), tree)
634
568
        self.assertContainsRe(d,
635
569
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
636
570
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
641
575
        """Test for bug #382699: unicode filenames on Windows should be shown
642
576
        in user encoding.
643
577
        """
644
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
578
        self.requireFeature(tests.UnicodeFilenameFeature)
645
579
        # The word 'test' in Russian
646
580
        _russian_test = u'\u0422\u0435\u0441\u0442'
647
581
        directory = _russian_test + u'/'
778
712
             ' \@\@\n-old\n\+new\n\n')
779
713
 
780
714
    def test_diff_kind_change(self):
781
 
        self.requireFeature(features.SymlinkFeature)
 
715
        self.requireFeature(tests.SymlinkFeature)
782
716
        self.build_tree_contents([('old-tree/olddir/',),
783
717
                                  ('old-tree/olddir/oldfile', 'old\n')])
784
718
        self.old_tree.add('olddir')
864
798
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
865
799
        sm = self._PatienceSequenceMatcher(None, a, b)
866
800
        mb = sm.get_matching_blocks()
867
 
        self.assertEqual(35, len(mb))
 
801
        self.assertEquals(35, len(mb))
868
802
 
869
803
    def test_unique_lcs(self):
870
804
        unique_lcs = self._unique_lcs
871
 
        self.assertEqual(unique_lcs('', ''), [])
872
 
        self.assertEqual(unique_lcs('', 'a'), [])
873
 
        self.assertEqual(unique_lcs('a', ''), [])
874
 
        self.assertEqual(unique_lcs('a', 'a'), [(0,0)])
875
 
        self.assertEqual(unique_lcs('a', 'b'), [])
876
 
        self.assertEqual(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
877
 
        self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
878
 
        self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
879
 
        self.assertEqual(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
 
805
        self.assertEquals(unique_lcs('', ''), [])
 
806
        self.assertEquals(unique_lcs('', 'a'), [])
 
807
        self.assertEquals(unique_lcs('a', ''), [])
 
808
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
 
809
        self.assertEquals(unique_lcs('a', 'b'), [])
 
810
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
 
811
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
 
812
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
 
813
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
880
814
                                                         (3,3), (4,4)])
881
 
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2,1)])
 
815
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
882
816
 
883
817
    def test_recurse_matches(self):
884
818
        def test_one(a, b, matches):
885
819
            test_matches = []
886
820
            self._recurse_matches(
887
821
                a, b, 0, 0, len(a), len(b), test_matches, 10)
888
 
            self.assertEqual(test_matches, matches)
 
822
            self.assertEquals(test_matches, matches)
889
823
 
890
824
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
891
825
                 [(0, 0), (2, 2), (4, 4)])
996
930
    def test_opcodes(self):
997
931
        def chk_ops(a, b, expected_codes):
998
932
            s = self._PatienceSequenceMatcher(None, a, b)
999
 
            self.assertEqual(expected_codes, s.get_opcodes())
 
933
            self.assertEquals(expected_codes, s.get_opcodes())
1000
934
 
1001
935
        chk_ops('', '', [])
1002
936
        chk_ops([], [], [])
1072
1006
    def test_grouped_opcodes(self):
1073
1007
        def chk_ops(a, b, expected_codes, n=3):
1074
1008
            s = self._PatienceSequenceMatcher(None, a, b)
1075
 
            self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
 
1009
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
1076
1010
 
1077
1011
        chk_ops('', '', [])
1078
1012
        chk_ops([], [], [])
1172
1106
                 'how are you today?\n']
1173
1107
        unified_diff = patiencediff.unified_diff
1174
1108
        psm = self._PatienceSequenceMatcher
1175
 
        self.assertEqual(['--- \n',
 
1109
        self.assertEquals(['--- \n',
1176
1110
                           '+++ \n',
1177
1111
                           '@@ -1,3 +1,2 @@\n',
1178
1112
                           ' hello there\n',
1184
1118
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1185
1119
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1186
1120
        # This is the result with LongestCommonSubstring matching
1187
 
        self.assertEqual(['--- \n',
 
1121
        self.assertEquals(['--- \n',
1188
1122
                           '+++ \n',
1189
1123
                           '@@ -1,6 +1,11 @@\n',
1190
1124
                           ' a\n',
1200
1134
                           ' f\n']
1201
1135
                          , list(unified_diff(txt_a, txt_b)))
1202
1136
        # And the patience diff
1203
 
        self.assertEqual(['--- \n',
 
1137
        self.assertEquals(['--- \n',
1204
1138
                           '+++ \n',
1205
1139
                           '@@ -4,6 +4,11 @@\n',
1206
1140
                           ' d\n',
1226
1160
                 'how are you today?\n']
1227
1161
        unified_diff = patiencediff.unified_diff
1228
1162
        psm = self._PatienceSequenceMatcher
1229
 
        self.assertEqual(['--- a\t2008-08-08\n',
 
1163
        self.assertEquals(['--- a\t2008-08-08\n',
1230
1164
                           '+++ b\t2008-09-09\n',
1231
1165
                           '@@ -1,3 +1,2 @@\n',
1232
1166
                           ' hello there\n',
1242
1176
 
1243
1177
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1244
1178
 
1245
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1179
    _test_needs_features = [compiled_patiencediff_feature]
1246
1180
 
1247
1181
    def setUp(self):
1248
1182
        super(TestPatienceDiffLib_c, self).setUp()
1279
1213
                 'how are you today?\n']
1280
1214
        txt_b = ['hello there\n',
1281
1215
                 'how are you today?\n']
1282
 
        with open('a1', 'wb') as f: f.writelines(txt_a)
1283
 
        with open('b1', 'wb') as f: f.writelines(txt_b)
 
1216
        open('a1', 'wb').writelines(txt_a)
 
1217
        open('b1', 'wb').writelines(txt_b)
1284
1218
 
1285
1219
        unified_diff_files = patiencediff.unified_diff_files
1286
1220
        psm = self._PatienceSequenceMatcher
1287
 
        self.assertEqual(['--- a1\n',
 
1221
        self.assertEquals(['--- a1\n',
1288
1222
                           '+++ b1\n',
1289
1223
                           '@@ -1,3 +1,2 @@\n',
1290
1224
                           ' hello there\n',
1296
1230
 
1297
1231
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1298
1232
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1299
 
        with open('a2', 'wb') as f: f.writelines(txt_a)
1300
 
        with open('b2', 'wb') as f: f.writelines(txt_b)
 
1233
        open('a2', 'wb').writelines(txt_a)
 
1234
        open('b2', 'wb').writelines(txt_b)
1301
1235
 
1302
1236
        # This is the result with LongestCommonSubstring matching
1303
 
        self.assertEqual(['--- a2\n',
 
1237
        self.assertEquals(['--- a2\n',
1304
1238
                           '+++ b2\n',
1305
1239
                           '@@ -1,6 +1,11 @@\n',
1306
1240
                           ' a\n',
1317
1251
                          , list(unified_diff_files('a2', 'b2')))
1318
1252
 
1319
1253
        # And the patience diff
1320
 
        self.assertEqual(['--- a2\n',
1321
 
                          '+++ b2\n',
1322
 
                          '@@ -4,6 +4,11 @@\n',
1323
 
                          ' d\n',
1324
 
                          ' e\n',
1325
 
                          ' f\n',
1326
 
                          '+x\n',
1327
 
                          '+y\n',
1328
 
                          '+d\n',
1329
 
                          '+e\n',
1330
 
                          '+f\n',
1331
 
                          ' g\n',
1332
 
                          ' h\n',
1333
 
                          ' i\n'],
1334
 
                         list(unified_diff_files('a2', 'b2',
1335
 
                                                 sequencematcher=psm)))
 
1254
        self.assertEquals(['--- a2\n',
 
1255
                           '+++ b2\n',
 
1256
                           '@@ -4,6 +4,11 @@\n',
 
1257
                           ' d\n',
 
1258
                           ' e\n',
 
1259
                           ' f\n',
 
1260
                           '+x\n',
 
1261
                           '+y\n',
 
1262
                           '+d\n',
 
1263
                           '+e\n',
 
1264
                           '+f\n',
 
1265
                           ' g\n',
 
1266
                           ' h\n',
 
1267
                           ' i\n',
 
1268
                          ]
 
1269
                          , list(unified_diff_files('a2', 'b2',
 
1270
                                 sequencematcher=psm)))
1336
1271
 
1337
1272
 
1338
1273
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1339
1274
 
1340
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1275
    _test_needs_features = [compiled_patiencediff_feature]
1341
1276
 
1342
1277
    def setUp(self):
1343
1278
        super(TestPatienceDiffLibFiles_c, self).setUp()
1349
1284
class TestUsingCompiledIfAvailable(tests.TestCase):
1350
1285
 
1351
1286
    def test_PatienceSequenceMatcher(self):
1352
 
        if features.compiled_patiencediff_feature.available():
 
1287
        if compiled_patiencediff_feature.available():
1353
1288
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1354
1289
            self.assertIs(PatienceSequenceMatcher_c,
1355
1290
                          patiencediff.PatienceSequenceMatcher)
1359
1294
                          patiencediff.PatienceSequenceMatcher)
1360
1295
 
1361
1296
    def test_unique_lcs(self):
1362
 
        if features.compiled_patiencediff_feature.available():
 
1297
        if compiled_patiencediff_feature.available():
1363
1298
            from bzrlib._patiencediff_c import unique_lcs_c
1364
1299
            self.assertIs(unique_lcs_c,
1365
1300
                          patiencediff.unique_lcs)
1369
1304
                          patiencediff.unique_lcs)
1370
1305
 
1371
1306
    def test_recurse_matches(self):
1372
 
        if features.compiled_patiencediff_feature.available():
 
1307
        if compiled_patiencediff_feature.available():
1373
1308
            from bzrlib._patiencediff_c import recurse_matches_c
1374
1309
            self.assertIs(recurse_matches_c,
1375
1310
                          patiencediff.recurse_matches)
1415
1350
        diff_obj._execute('old', 'new')
1416
1351
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1417
1352
 
1418
 
    def test_execute_missing(self):
 
1353
    def test_excute_missing(self):
1419
1354
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1420
1355
                                     None, None, None)
1421
1356
        self.addCleanup(diff_obj.finish)
1425
1360
                         ' on this machine', str(e))
1426
1361
 
1427
1362
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1428
 
        self.requireFeature(features.AttribFeature)
 
1363
        self.requireFeature(AttribFeature)
1429
1364
        output = StringIO()
1430
1365
        tree = self.make_branch_and_tree('tree')
1431
1366
        self.build_tree_contents([('tree/file', 'content')])
1490
1425
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1491
1426
 
1492
1427
 
1493
 
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
1494
 
 
1495
 
    def test_encodable_filename(self):
1496
 
        # Just checks file path for external diff tool.
1497
 
        # We cannot change CPython's internal encoding used by os.exec*.
1498
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1499
 
                                    None, None, None)
1500
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1501
 
            encoding = scenario['encoding']
1502
 
            dirname = scenario['info']['directory']
1503
 
            filename = scenario['info']['filename']
1504
 
 
1505
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1506
 
            relpath = dirname + u'/' + filename
1507
 
            fullpath = diffobj._safe_filename('safe', relpath)
1508
 
            self.assertEqual(fullpath,
1509
 
                             fullpath.encode(encoding).decode(encoding))
1510
 
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1511
 
 
1512
 
    def test_unencodable_filename(self):
1513
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1514
 
                                    None, None, None)
1515
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1516
 
            encoding = scenario['encoding']
1517
 
            dirname = scenario['info']['directory']
1518
 
            filename = scenario['info']['filename']
1519
 
 
1520
 
            if encoding == 'iso-8859-1':
1521
 
                encoding = 'iso-8859-2'
1522
 
            else:
1523
 
                encoding = 'iso-8859-1'
1524
 
 
1525
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1526
 
            relpath = dirname + u'/' + filename
1527
 
            fullpath = diffobj._safe_filename('safe', relpath)
1528
 
            self.assertEqual(fullpath,
1529
 
                             fullpath.encode(encoding).decode(encoding))
1530
 
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1531
 
 
1532
 
 
1533
1428
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
1534
1429
 
1535
1430
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1536
 
        """Call get_trees_and_branches_to_diff_locked."""
 
1431
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1432
        TestGetTreesAndBranchesToDiff.
 
1433
        """
1537
1434
        return diff.get_trees_and_branches_to_diff_locked(
1538
1435
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1539
1436
 
1576
1473
        self.assertEqual(tree.branch.base, new_branch.base)
1577
1474
        self.assertIs(None, specific_files)
1578
1475
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
 
1476
 
 
1477
 
 
1478
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
 
1479
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
 
1480
    deprecated get_trees_and_branches_to_diff function.
 
1481
    """
 
1482
 
 
1483
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1484
        return self.applyDeprecated(
 
1485
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
 
1486
            path_list, revision_specs, old_url, new_url)
 
1487