~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2014, 2016, 2017 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import os.path
19
18
from cStringIO import StringIO
20
 
import errno
21
19
import subprocess
22
 
import sys
23
 
from tempfile import TemporaryFile
 
20
import tempfile
24
21
 
25
 
from bzrlib import tests
26
 
from bzrlib.diff import (
27
 
    DiffFromTool,
28
 
    DiffPath,
29
 
    DiffSymlink,
30
 
    DiffTree,
31
 
    DiffText,
32
 
    external_diff,
33
 
    internal_diff,
34
 
    show_diff_trees,
 
22
from bzrlib import (
 
23
    diff,
 
24
    errors,
 
25
    osutils,
 
26
    patiencediff,
 
27
    _patiencediff_py,
 
28
    revision as _mod_revision,
 
29
    revisionspec,
 
30
    revisiontree,
 
31
    tests,
 
32
    transform,
35
33
    )
36
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
37
 
import bzrlib.osutils as osutils
38
 
import bzrlib.transform as transform
39
 
import bzrlib.patiencediff
40
 
import bzrlib._patiencediff_py
41
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
42
 
                          TestCaseInTempDir, TestSkipped)
43
 
 
44
 
 
45
 
class _AttribFeature(Feature):
46
 
 
47
 
    def _probe(self):
48
 
        if (sys.platform not in ('cygwin', 'win32')):
49
 
            return False
50
 
        try:
51
 
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
52
 
        except OSError, e:
53
 
            return False
54
 
        return (0 == proc.wait())
55
 
 
56
 
    def feature_name(self):
57
 
        return 'attrib Windows command-line tool'
58
 
 
59
 
AttribFeature = _AttribFeature()
60
 
 
61
 
 
62
 
class _CompiledPatienceDiffFeature(Feature):
63
 
 
64
 
    def _probe(self):
65
 
        try:
66
 
            import bzrlib._patiencediff_c
67
 
        except ImportError:
68
 
            return False
69
 
        return True
70
 
 
71
 
    def feature_name(self):
72
 
        return 'bzrlib._patiencediff_c'
73
 
 
74
 
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
 
34
from bzrlib.tests import (
 
35
    features,
 
36
    EncodingAdapter,
 
37
)
 
38
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
75
43
 
76
44
 
77
45
def udiff_lines(old, new, allow_binary=False):
78
46
    output = StringIO()
79
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
47
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
80
48
    output.seek(0, 0)
81
49
    return output.readlines()
82
50
 
86
54
        # StringIO has no fileno, so it tests a different codepath
87
55
        output = StringIO()
88
56
    else:
89
 
        output = TemporaryFile()
 
57
        output = tempfile.TemporaryFile()
90
58
    try:
91
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
92
 
    except NoDiff:
93
 
        raise TestSkipped('external "diff" not present to test')
 
59
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
60
    except errors.NoDiff:
 
61
        raise tests.TestSkipped('external "diff" not present to test')
94
62
    output.seek(0, 0)
95
63
    lines = output.readlines()
96
64
    output.close()
97
65
    return lines
98
66
 
99
67
 
100
 
class TestDiff(TestCase):
 
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
class TestDiff(tests.TestCase):
101
92
 
102
93
    def test_add_nl(self):
103
94
        """diff generates a valid diff for patches that add a newline"""
104
95
        lines = udiff_lines(['boo'], ['boo\n'])
105
96
        self.check_patch(lines)
106
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
 
97
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
107
98
            ## "expected no-nl, got %r" % lines[4]
108
99
 
109
100
    def test_add_nl_2(self):
112
103
        """
113
104
        lines = udiff_lines(['boo'], ['goo\n'])
114
105
        self.check_patch(lines)
115
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
 
106
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
116
107
            ## "expected no-nl, got %r" % lines[4]
117
108
 
118
109
    def test_remove_nl(self):
121
112
        """
122
113
        lines = udiff_lines(['boo\n'], ['boo'])
123
114
        self.check_patch(lines)
124
 
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
 
115
        self.assertEqual(lines[5], '\\ No newline at end of file\n')
125
116
            ## "expected no-nl, got %r" % lines[5]
126
117
 
127
118
    def check_patch(self, lines):
128
 
        self.assert_(len(lines) > 1)
 
119
        self.assertTrue(len(lines) > 1)
129
120
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
130
 
        self.assert_(lines[0].startswith ('---'))
 
121
        self.assertTrue(lines[0].startswith ('---'))
131
122
            ## 'No orig line for patch:\n%s' % "".join(lines)
132
 
        self.assert_(lines[1].startswith ('+++'))
 
123
        self.assertTrue(lines[1].startswith ('+++'))
133
124
            ## 'No mod line for patch:\n%s' % "".join(lines)
134
 
        self.assert_(len(lines) > 2)
 
125
        self.assertTrue(len(lines) > 2)
135
126
            ## "No hunks for patch:\n%s" % "".join(lines)
136
 
        self.assert_(lines[2].startswith('@@'))
 
127
        self.assertTrue(lines[2].startswith('@@'))
137
128
            ## "No hunk header for patch:\n%s" % "".join(lines)
138
 
        self.assert_('@@' in lines[2][2:])
 
129
        self.assertTrue('@@' in lines[2][2:])
139
130
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
140
131
 
141
132
    def test_binary_lines(self):
142
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
143
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
144
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
145
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
 
133
        empty = []
 
134
        uni_lines = [1023 * 'a' + '\x00']
 
135
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
 
136
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
 
137
        udiff_lines(uni_lines , empty, allow_binary=True)
 
138
        udiff_lines(empty, uni_lines, allow_binary=True)
146
139
 
147
140
    def test_external_diff(self):
148
141
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
158
151
        self.check_patch(lines)
159
152
 
160
153
    def test_external_diff_binary_lang_c(self):
161
 
        old_env = {}
162
154
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
163
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
164
 
        try:
165
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
166
 
            # Older versions of diffutils say "Binary files", newer
167
 
            # versions just say "Files".
168
 
            self.assertContainsRe(lines[0],
169
 
                                  '(Binary f|F)iles old and new differ\n')
170
 
            self.assertEquals(lines[1:], ['\n'])
171
 
        finally:
172
 
            for lang, old_val in old_env.iteritems():
173
 
                osutils.set_or_unset_env(lang, old_val)
 
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'])
174
161
 
175
162
    def test_no_external_diff(self):
176
163
        """Check that NoDiff is raised when diff is not available"""
177
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
178
 
        orig_path = os.environ['PATH']
179
 
        try:
180
 
            os.environ['PATH'] = ''
181
 
            self.assertRaises(NoDiff, external_diff,
182
 
                              'old', ['boo\n'], 'new', ['goo\n'],
183
 
                              StringIO(), diff_opts=['-u'])
184
 
        finally:
185
 
            os.environ['PATH'] = orig_path
186
 
        
 
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'])
 
170
 
187
171
    def test_internal_diff_default(self):
188
172
        # Default internal diff encoding is utf8
189
173
        output = StringIO()
190
 
        internal_diff(u'old_\xb5', ['old_text\n'],
191
 
                    u'new_\xe5', ['new_text\n'], output)
 
174
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
175
                           u'new_\xe5', ['new_text\n'], output)
192
176
        lines = output.getvalue().splitlines(True)
193
177
        self.check_patch(lines)
194
 
        self.assertEquals(['--- old_\xc2\xb5\n',
 
178
        self.assertEqual(['--- old_\xc2\xb5\n',
195
179
                           '+++ new_\xc3\xa5\n',
196
180
                           '@@ -1,1 +1,1 @@\n',
197
181
                           '-old_text\n',
202
186
 
203
187
    def test_internal_diff_utf8(self):
204
188
        output = StringIO()
205
 
        internal_diff(u'old_\xb5', ['old_text\n'],
206
 
                    u'new_\xe5', ['new_text\n'], output,
207
 
                    path_encoding='utf8')
 
189
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
190
                           u'new_\xe5', ['new_text\n'], output,
 
191
                           path_encoding='utf8')
208
192
        lines = output.getvalue().splitlines(True)
209
193
        self.check_patch(lines)
210
 
        self.assertEquals(['--- old_\xc2\xb5\n',
 
194
        self.assertEqual(['--- old_\xc2\xb5\n',
211
195
                           '+++ new_\xc3\xa5\n',
212
196
                           '@@ -1,1 +1,1 @@\n',
213
197
                           '-old_text\n',
218
202
 
219
203
    def test_internal_diff_iso_8859_1(self):
220
204
        output = StringIO()
221
 
        internal_diff(u'old_\xb5', ['old_text\n'],
222
 
                    u'new_\xe5', ['new_text\n'], output,
223
 
                    path_encoding='iso-8859-1')
 
205
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
206
                           u'new_\xe5', ['new_text\n'], output,
 
207
                           path_encoding='iso-8859-1')
224
208
        lines = output.getvalue().splitlines(True)
225
209
        self.check_patch(lines)
226
 
        self.assertEquals(['--- old_\xb5\n',
 
210
        self.assertEqual(['--- old_\xb5\n',
227
211
                           '+++ new_\xe5\n',
228
212
                           '@@ -1,1 +1,1 @@\n',
229
213
                           '-old_text\n',
234
218
 
235
219
    def test_internal_diff_no_content(self):
236
220
        output = StringIO()
237
 
        internal_diff(u'old', [], u'new', [], output)
 
221
        diff.internal_diff(u'old', [], u'new', [], output)
238
222
        self.assertEqual('', output.getvalue())
239
223
 
240
224
    def test_internal_diff_no_changes(self):
241
225
        output = StringIO()
242
 
        internal_diff(u'old', ['text\n', 'contents\n'],
243
 
                      u'new', ['text\n', 'contents\n'],
244
 
                      output)
 
226
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
227
                           u'new', ['text\n', 'contents\n'],
 
228
                           output)
245
229
        self.assertEqual('', output.getvalue())
246
230
 
247
231
    def test_internal_diff_returns_bytes(self):
248
232
        import StringIO
249
233
        output = StringIO.StringIO()
250
 
        internal_diff(u'old_\xb5', ['old_text\n'],
251
 
                    u'new_\xe5', ['new_text\n'], output)
252
 
        self.failUnless(isinstance(output.getvalue(), str),
 
234
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
235
                            u'new_\xe5', ['new_text\n'], output)
 
236
        self.assertIsInstance(output.getvalue(), str,
253
237
            'internal_diff should return bytestrings')
254
238
 
255
 
 
256
 
class TestDiffFiles(TestCaseInTempDir):
 
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
 
 
303
class TestDiffFiles(tests.TestCaseInTempDir):
257
304
 
258
305
    def test_external_diff_binary(self):
259
306
        """The output when using external diff should use diff's i18n error"""
261
308
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
262
309
 
263
310
        cmd = ['diff', '-u', '--binary', 'old', 'new']
264
 
        open('old', 'wb').write('\x00foobar\n')
265
 
        open('new', 'wb').write('foo\x00bar\n')
 
311
        with open('old', 'wb') as f: f.write('\x00foobar\n')
 
312
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
266
313
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
267
314
                                     stdin=subprocess.PIPE)
268
315
        out, err = pipe.communicate()
269
 
        # Diff returns '2' on Binary files.
270
 
        self.assertEqual(2, pipe.returncode)
271
316
        # We should output whatever diff tells us, plus a trailing newline
272
317
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
273
318
 
274
319
 
275
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
276
 
    """Has a helper for running show_diff_trees"""
277
 
 
278
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
279
 
        output = StringIO()
280
 
        if working_tree is not None:
281
 
            extra_trees = (working_tree,)
282
 
        else:
283
 
            extra_trees = ()
284
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
285
 
                        extra_trees=extra_trees, old_label='old/',
286
 
                        new_label='new/')
287
 
        return output.getvalue()
288
 
 
289
 
 
290
 
class TestDiffDates(TestShowDiffTreesHelper):
 
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):
291
334
 
292
335
    def setUp(self):
293
336
        super(TestDiffDates, self).setUp()
328
371
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
329
372
 
330
373
    def test_diff_rev_tree_working_tree(self):
331
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
 
374
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
332
375
        # note that the date for old/file1 is from rev 2 rather than from
333
376
        # the basis revision (rev 4)
334
377
        self.assertEqualDiff(output, '''\
344
387
    def test_diff_rev_tree_rev_tree(self):
345
388
        tree1 = self.b.repository.revision_tree('rev-2')
346
389
        tree2 = self.b.repository.revision_tree('rev-3')
347
 
        output = self.get_diff(tree1, tree2)
 
390
        output = get_diff_as_string(tree1, tree2)
348
391
        self.assertEqualDiff(output, '''\
349
392
=== modified file 'file2'
350
393
--- old/file2\t2006-04-01 00:00:00 +0000
354
397
+file2 contents at rev 3
355
398
 
356
399
''')
357
 
        
 
400
 
358
401
    def test_diff_add_files(self):
359
 
        tree1 = self.b.repository.revision_tree(None)
 
402
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
360
403
        tree2 = self.b.repository.revision_tree('rev-1')
361
 
        output = self.get_diff(tree1, tree2)
 
404
        output = get_diff_as_string(tree1, tree2)
362
405
        # the files have the epoch time stamp for the tree in which
363
406
        # they don't exist.
364
407
        self.assertEqualDiff(output, '''\
379
422
    def test_diff_remove_files(self):
380
423
        tree1 = self.b.repository.revision_tree('rev-3')
381
424
        tree2 = self.b.repository.revision_tree('rev-4')
382
 
        output = self.get_diff(tree1, tree2)
 
425
        output = get_diff_as_string(tree1, tree2)
383
426
        # the file has the epoch time stamp for the tree in which
384
427
        # it doesn't exist.
385
428
        self.assertEqualDiff(output, '''\
396
439
        self.wt.rename_one('file1', 'file1b')
397
440
        old_tree = self.b.repository.revision_tree('rev-1')
398
441
        new_tree = self.b.repository.revision_tree('rev-4')
399
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
 
442
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
400
443
                            working_tree=self.wt)
401
444
        self.assertContainsRe(out, 'file1\t')
402
445
 
408
451
        self.wt.rename_one('file1', 'dir1/file1')
409
452
        old_tree = self.b.repository.revision_tree('rev-1')
410
453
        new_tree = self.b.repository.revision_tree('rev-4')
411
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
 
454
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
412
455
                            working_tree=self.wt)
413
456
        self.assertContainsRe(out, 'file1\t')
414
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
 
457
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
415
458
                            working_tree=self.wt)
416
459
        self.assertNotContainsRe(out, 'file1\t')
417
460
 
418
461
 
419
 
 
420
 
class TestShowDiffTrees(TestShowDiffTreesHelper):
 
462
class TestShowDiffTrees(tests.TestCaseWithTransport):
421
463
    """Direct tests for show_diff_trees"""
422
464
 
423
465
    def test_modified_file(self):
428
470
        tree.commit('one', rev_id='rev-1')
429
471
 
430
472
        self.build_tree_contents([('tree/file', 'new contents\n')])
431
 
        diff = self.get_diff(tree.basis_tree(), tree)
432
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
433
 
        self.assertContainsRe(diff, '--- old/file\t')
434
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
435
 
        self.assertContainsRe(diff, '-contents\n'
436
 
                                    '\\+new contents\n')
 
473
        d = get_diff_as_string(tree.basis_tree(), tree)
 
474
        self.assertContainsRe(d, "=== modified file 'file'\n")
 
475
        self.assertContainsRe(d, '--- old/file\t')
 
476
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
 
477
        self.assertContainsRe(d, '-contents\n'
 
478
                                 '\\+new contents\n')
437
479
 
438
480
    def test_modified_file_in_renamed_dir(self):
439
481
        """Test when a file is modified in a renamed directory."""
445
487
 
446
488
        tree.rename_one('dir', 'other')
447
489
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
448
 
        diff = self.get_diff(tree.basis_tree(), tree)
449
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
450
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
 
490
        d = get_diff_as_string(tree.basis_tree(), tree)
 
491
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
 
492
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
451
493
        # XXX: This is technically incorrect, because it used to be at another
452
494
        # location. What to do?
453
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
454
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
455
 
        self.assertContainsRe(diff, '-contents\n'
456
 
                                    '\\+new contents\n')
 
495
        self.assertContainsRe(d, '--- old/dir/file\t')
 
496
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
 
497
        self.assertContainsRe(d, '-contents\n'
 
498
                                 '\\+new contents\n')
457
499
 
458
500
    def test_renamed_directory(self):
459
501
        """Test when only a directory is only renamed."""
464
506
        tree.commit('one', rev_id='rev-1')
465
507
 
466
508
        tree.rename_one('dir', 'newdir')
467
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
509
        d = get_diff_as_string(tree.basis_tree(), tree)
468
510
        # Renaming a directory should be a single "you renamed this dir" even
469
511
        # when there are files inside.
470
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
512
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
471
513
 
472
514
    def test_renamed_file(self):
473
515
        """Test when a file is only renamed."""
477
519
        tree.commit('one', rev_id='rev-1')
478
520
 
479
521
        tree.rename_one('file', 'newname')
480
 
        diff = self.get_diff(tree.basis_tree(), tree)
481
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
522
        d = get_diff_as_string(tree.basis_tree(), tree)
 
523
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
482
524
        # We shouldn't have a --- or +++ line, because there is no content
483
525
        # change
484
 
        self.assertNotContainsRe(diff, '---')
 
526
        self.assertNotContainsRe(d, '---')
485
527
 
486
528
    def test_renamed_and_modified_file(self):
487
529
        """Test when a file is only renamed."""
492
534
 
493
535
        tree.rename_one('file', 'newname')
494
536
        self.build_tree_contents([('tree/newname', 'new contents\n')])
495
 
        diff = self.get_diff(tree.basis_tree(), tree)
496
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
497
 
        self.assertContainsRe(diff, '--- old/file\t')
498
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
499
 
        self.assertContainsRe(diff, '-contents\n'
500
 
                                    '\\+new contents\n')
 
537
        d = get_diff_as_string(tree.basis_tree(), tree)
 
538
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
539
        self.assertContainsRe(d, '--- old/file\t')
 
540
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
 
541
        self.assertContainsRe(d, '-contents\n'
 
542
                                 '\\+new contents\n')
501
543
 
502
544
 
503
545
    def test_internal_diff_exec_property(self):
522
564
        tree.rename_one('c', 'new-c')
523
565
        tree.rename_one('d', 'new-d')
524
566
 
525
 
        diff = self.get_diff(tree.basis_tree(), tree)
526
 
 
527
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
528
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
529
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
530
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
531
 
        self.assertNotContainsRe(diff, r"file 'e'")
532
 
        self.assertNotContainsRe(diff, r"file 'f'")
533
 
 
 
567
        d = get_diff_as_string(tree.basis_tree(), tree)
 
568
 
 
569
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
 
570
                                  ".*\+x to -x.*\)")
 
571
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
 
572
                                  ".*-x to \+x.*\)")
 
573
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
 
574
                                  ".*\+x to -x.*\)")
 
575
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
 
576
                                  ".*-x to \+x.*\)")
 
577
        self.assertNotContainsRe(d, r"file 'e'")
 
578
        self.assertNotContainsRe(d, r"file 'f'")
534
579
 
535
580
    def test_binary_unicode_filenames(self):
536
581
        """Test that contents of files are *not* encoded in UTF-8 when there
537
582
        is a binary file in the diff.
538
583
        """
539
584
        # See https://bugs.launchpad.net/bugs/110092.
540
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
585
        self.requireFeature(features.UnicodeFilenameFeature)
541
586
 
542
587
        # This bug isn't triggered with cStringIO.
543
588
        from StringIO import StringIO
551
596
        tree.add([alpha], ['file-id'])
552
597
        tree.add([omega], ['file-id-2'])
553
598
        diff_content = StringIO()
554
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
555
 
        diff = diff_content.getvalue()
556
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
557
 
        self.assertContainsRe(
558
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
559
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
560
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
561
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
 
599
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
 
600
        d = diff_content.getvalue()
 
601
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
 
602
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
 
603
                              % (alpha_utf8, alpha_utf8))
 
604
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
 
605
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
 
606
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
562
607
 
563
608
    def test_unicode_filename(self):
564
609
        """Test when the filename are unicode."""
565
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
610
        self.requireFeature(features.UnicodeFilenameFeature)
566
611
 
567
612
        alpha, omega = u'\u03b1', u'\u03c9'
568
613
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
583
628
        tree.add(['add_'+alpha], ['file-id'])
584
629
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
585
630
 
586
 
        diff = self.get_diff(tree.basis_tree(), tree)
587
 
        self.assertContainsRe(diff,
 
631
        d = get_diff_as_string(tree.basis_tree(), tree)
 
632
        self.assertContainsRe(d,
588
633
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
589
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
590
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
591
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
592
 
 
593
 
 
594
 
class DiffWasIs(DiffPath):
 
634
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
 
635
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
 
636
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
 
637
 
 
638
    def test_unicode_filename_path_encoding(self):
 
639
        """Test for bug #382699: unicode filenames on Windows should be shown
 
640
        in user encoding.
 
641
        """
 
642
        self.requireFeature(features.UnicodeFilenameFeature)
 
643
        # The word 'test' in Russian
 
644
        _russian_test = u'\u0422\u0435\u0441\u0442'
 
645
        directory = _russian_test + u'/'
 
646
        test_txt = _russian_test + u'.txt'
 
647
        u1234 = u'\u1234.txt'
 
648
 
 
649
        tree = self.make_branch_and_tree('.')
 
650
        self.build_tree_contents([
 
651
            (test_txt, 'foo\n'),
 
652
            (u1234, 'foo\n'),
 
653
            (directory, None),
 
654
            ])
 
655
        tree.add([test_txt, u1234, directory])
 
656
 
 
657
        sio = StringIO()
 
658
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
 
659
            path_encoding='cp1251')
 
660
 
 
661
        output = subst_dates(sio.getvalue())
 
662
        shouldbe = ('''\
 
663
=== added directory '%(directory)s'
 
664
=== added file '%(test_txt)s'
 
665
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
666
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
667
@@ -0,0 +1,1 @@
 
668
+foo
 
669
 
 
670
=== added file '?.txt'
 
671
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
672
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
673
@@ -0,0 +1,1 @@
 
674
+foo
 
675
 
 
676
''' % {'directory': _russian_test.encode('cp1251'),
 
677
       'test_txt': test_txt.encode('cp1251'),
 
678
      })
 
679
        self.assertEqualDiff(output, shouldbe)
 
680
 
 
681
 
 
682
class DiffWasIs(diff.DiffPath):
595
683
 
596
684
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
597
685
        self.to_file.write('was: ')
601
689
        pass
602
690
 
603
691
 
604
 
class TestDiffTree(TestCaseWithTransport):
 
692
class TestDiffTree(tests.TestCaseWithTransport):
605
693
 
606
694
    def setUp(self):
607
 
        TestCaseWithTransport.setUp(self)
 
695
        super(TestDiffTree, self).setUp()
608
696
        self.old_tree = self.make_branch_and_tree('old-tree')
609
697
        self.old_tree.lock_write()
610
698
        self.addCleanup(self.old_tree.unlock)
611
699
        self.new_tree = self.make_branch_and_tree('new-tree')
612
700
        self.new_tree.lock_write()
613
701
        self.addCleanup(self.new_tree.unlock)
614
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
702
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
615
703
 
616
704
    def test_diff_text(self):
617
705
        self.build_tree_contents([('old-tree/olddir/',),
622
710
                                  ('new-tree/newdir/newfile', 'new\n')])
623
711
        self.new_tree.add('newdir')
624
712
        self.new_tree.add('newdir/newfile', 'file-id')
625
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
713
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
626
714
        differ.diff_text('file-id', None, 'old label', 'new label')
627
715
        self.assertEqual(
628
716
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
657
745
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
658
746
 
659
747
    def test_diff_symlink(self):
660
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
748
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
661
749
        differ.diff_symlink('old target', None)
662
750
        self.assertEqual("=== target was 'old target'\n",
663
751
                         differ.to_file.getvalue())
664
752
 
665
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
753
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
666
754
        differ.diff_symlink(None, 'new target')
667
755
        self.assertEqual("=== target is 'new target'\n",
668
756
                         differ.to_file.getvalue())
669
757
 
670
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
758
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
671
759
        differ.diff_symlink('old target', 'new target')
672
760
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
673
761
                         differ.to_file.getvalue())
688
776
             ' \@\@\n-old\n\+new\n\n')
689
777
 
690
778
    def test_diff_kind_change(self):
691
 
        self.requireFeature(tests.SymlinkFeature)
 
779
        self.requireFeature(features.SymlinkFeature)
692
780
        self.build_tree_contents([('old-tree/olddir/',),
693
781
                                  ('old-tree/olddir/oldfile', 'old\n')])
694
782
        self.old_tree.add('olddir')
703
791
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
704
792
             ' \@\@\n-old\n\n')
705
793
        self.assertContainsRe(self.differ.to_file.getvalue(),
706
 
                              "=== target is 'new'\n")
 
794
                              "=== target is u'new'\n")
707
795
 
708
796
    def test_diff_directory(self):
709
797
        self.build_tree(['new-tree/new-dir/'])
723
811
 
724
812
    def test_register_diff(self):
725
813
        self.create_old_new()
726
 
        old_diff_factories = DiffTree.diff_factories
727
 
        DiffTree.diff_factories=old_diff_factories[:]
728
 
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
814
        old_diff_factories = diff.DiffTree.diff_factories
 
815
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
816
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
729
817
        try:
730
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
818
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
731
819
        finally:
732
 
            DiffTree.diff_factories = old_diff_factories
 
820
            diff.DiffTree.diff_factories = old_diff_factories
733
821
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
734
822
        self.assertNotContainsRe(
735
823
            differ.to_file.getvalue(),
740
828
 
741
829
    def test_extra_factories(self):
742
830
        self.create_old_new()
743
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
744
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
831
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
832
                               extra_factories=[DiffWasIs.from_diff_tree])
745
833
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
746
834
        self.assertNotContainsRe(
747
835
            differ.to_file.getvalue(),
760
848
            '.*a-file(.|\n)*b-file')
761
849
 
762
850
 
763
 
class TestPatienceDiffLib(TestCase):
 
851
class TestPatienceDiffLib(tests.TestCase):
764
852
 
765
853
    def setUp(self):
766
854
        super(TestPatienceDiffLib, self).setUp()
767
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
768
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
855
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
856
        self._recurse_matches = _patiencediff_py.recurse_matches_py
769
857
        self._PatienceSequenceMatcher = \
770
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
858
            _patiencediff_py.PatienceSequenceMatcher_py
771
859
 
772
860
    def test_diff_unicode_string(self):
773
861
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
774
862
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
775
863
        sm = self._PatienceSequenceMatcher(None, a, b)
776
864
        mb = sm.get_matching_blocks()
777
 
        self.assertEquals(35, len(mb))
 
865
        self.assertEqual(35, len(mb))
778
866
 
779
867
    def test_unique_lcs(self):
780
868
        unique_lcs = self._unique_lcs
781
 
        self.assertEquals(unique_lcs('', ''), [])
782
 
        self.assertEquals(unique_lcs('', 'a'), [])
783
 
        self.assertEquals(unique_lcs('a', ''), [])
784
 
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
785
 
        self.assertEquals(unique_lcs('a', 'b'), [])
786
 
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
787
 
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
788
 
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
789
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
 
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),
790
878
                                                         (3,3), (4,4)])
791
 
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
 
879
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2,1)])
792
880
 
793
881
    def test_recurse_matches(self):
794
882
        def test_one(a, b, matches):
795
883
            test_matches = []
796
884
            self._recurse_matches(
797
885
                a, b, 0, 0, len(a), len(b), test_matches, 10)
798
 
            self.assertEquals(test_matches, matches)
 
886
            self.assertEqual(test_matches, matches)
799
887
 
800
888
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
801
889
                 [(0, 0), (2, 2), (4, 4)])
807
895
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
808
896
                                          (4, 6), (5, 7), (6, 8)])
809
897
 
810
 
        # recurse_matches doesn't match non-unique 
 
898
        # recurse_matches doesn't match non-unique
811
899
        # lines surrounded by bogus text.
812
900
        # The update has been done in patiencediff.SequenceMatcher instead
813
901
 
906
994
    def test_opcodes(self):
907
995
        def chk_ops(a, b, expected_codes):
908
996
            s = self._PatienceSequenceMatcher(None, a, b)
909
 
            self.assertEquals(expected_codes, s.get_opcodes())
 
997
            self.assertEqual(expected_codes, s.get_opcodes())
910
998
 
911
999
        chk_ops('', '', [])
912
1000
        chk_ops([], [], [])
950
1038
                 ('delete', 1,2, 1,1),
951
1039
                 ('equal',  2,3, 1,2),
952
1040
                ])
953
 
        chk_ops('aBccDe', 'abccde', 
 
1041
        chk_ops('aBccDe', 'abccde',
954
1042
                [('equal',   0,1, 0,1),
955
1043
                 ('replace', 1,5, 1,5),
956
1044
                 ('equal',   5,6, 5,6),
957
1045
                ])
958
 
        chk_ops('aBcDec', 'abcdec', 
 
1046
        chk_ops('aBcDec', 'abcdec',
959
1047
                [('equal',   0,1, 0,1),
960
1048
                 ('replace', 1,2, 1,2),
961
1049
                 ('equal',   2,3, 2,3),
962
1050
                 ('replace', 3,4, 3,4),
963
1051
                 ('equal',   4,6, 4,6),
964
1052
                ])
965
 
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
 
1053
        chk_ops('aBcdEcdFg', 'abcdecdfg',
966
1054
                [('equal',   0,1, 0,1),
967
1055
                 ('replace', 1,8, 1,8),
968
1056
                 ('equal',   8,9, 8,9)
969
1057
                ])
970
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
 
1058
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
971
1059
                [('equal',   0,1, 0,1),
972
1060
                 ('replace', 1,2, 1,2),
973
1061
                 ('equal',   2,4, 2,4),
982
1070
    def test_grouped_opcodes(self):
983
1071
        def chk_ops(a, b, expected_codes, n=3):
984
1072
            s = self._PatienceSequenceMatcher(None, a, b)
985
 
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
 
1073
            self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
986
1074
 
987
1075
        chk_ops('', '', [])
988
1076
        chk_ops([], [], [])
1033
1121
    """
1034
1122
    gnxrf_netf = ['svyr*']
1035
1123
    gnxrf_bcgvbaf = ['ab-erphefr']
1036
 
  
 
1124
 
1037
1125
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1038
1126
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1039
1127
        vs vf_dhvrg():
1047
1135
'''.splitlines(True), '''\
1048
1136
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1049
1137
 
1050
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
 
1138
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
1051
1139
    nqq gurz.
1052
1140
    """
1053
1141
    gnxrf_netf = ['svyr*']
1080
1168
                 'how are you today?\n']
1081
1169
        txt_b = ['hello there\n',
1082
1170
                 'how are you today?\n']
1083
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1171
        unified_diff = patiencediff.unified_diff
1084
1172
        psm = self._PatienceSequenceMatcher
1085
 
        self.assertEquals([ '---  \n',
1086
 
                           '+++  \n',
 
1173
        self.assertEqual(['--- \n',
 
1174
                           '+++ \n',
1087
1175
                           '@@ -1,3 +1,2 @@\n',
1088
1176
                           ' hello there\n',
1089
1177
                           '-world\n',
1094
1182
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1095
1183
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1096
1184
        # This is the result with LongestCommonSubstring matching
1097
 
        self.assertEquals(['---  \n',
1098
 
                           '+++  \n',
 
1185
        self.assertEqual(['--- \n',
 
1186
                           '+++ \n',
1099
1187
                           '@@ -1,6 +1,11 @@\n',
1100
1188
                           ' a\n',
1101
1189
                           ' b\n',
1110
1198
                           ' f\n']
1111
1199
                          , list(unified_diff(txt_a, txt_b)))
1112
1200
        # And the patience diff
1113
 
        self.assertEquals(['---  \n',
1114
 
                           '+++  \n',
 
1201
        self.assertEqual(['--- \n',
 
1202
                           '+++ \n',
1115
1203
                           '@@ -4,6 +4,11 @@\n',
1116
1204
                           ' d\n',
1117
1205
                           ' e\n',
1128
1216
                          , list(unified_diff(txt_a, txt_b,
1129
1217
                                 sequencematcher=psm)))
1130
1218
 
 
1219
    def test_patience_unified_diff_with_dates(self):
 
1220
        txt_a = ['hello there\n',
 
1221
                 'world\n',
 
1222
                 'how are you today?\n']
 
1223
        txt_b = ['hello there\n',
 
1224
                 'how are you today?\n']
 
1225
        unified_diff = patiencediff.unified_diff
 
1226
        psm = self._PatienceSequenceMatcher
 
1227
        self.assertEqual(['--- a\t2008-08-08\n',
 
1228
                           '+++ b\t2008-09-09\n',
 
1229
                           '@@ -1,3 +1,2 @@\n',
 
1230
                           ' hello there\n',
 
1231
                           '-world\n',
 
1232
                           ' how are you today?\n'
 
1233
                          ]
 
1234
                          , list(unified_diff(txt_a, txt_b,
 
1235
                                 fromfile='a', tofile='b',
 
1236
                                 fromfiledate='2008-08-08',
 
1237
                                 tofiledate='2008-09-09',
 
1238
                                 sequencematcher=psm)))
 
1239
 
1131
1240
 
1132
1241
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1133
1242
 
1134
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1243
    _test_needs_features = [features.compiled_patiencediff_feature]
1135
1244
 
1136
1245
    def setUp(self):
1137
1246
        super(TestPatienceDiffLib_c, self).setUp()
1138
 
        import bzrlib._patiencediff_c
1139
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1140
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
 
1247
        from bzrlib import _patiencediff_c
 
1248
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1249
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1141
1250
        self._PatienceSequenceMatcher = \
1142
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1251
            _patiencediff_c.PatienceSequenceMatcher_c
1143
1252
 
1144
1253
    def test_unhashable(self):
1145
1254
        """We should get a proper exception here."""
1155
1264
                                         None, ['valid'], ['valid', []])
1156
1265
 
1157
1266
 
1158
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1267
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1159
1268
 
1160
1269
    def setUp(self):
1161
1270
        super(TestPatienceDiffLibFiles, self).setUp()
1162
1271
        self._PatienceSequenceMatcher = \
1163
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1272
            _patiencediff_py.PatienceSequenceMatcher_py
1164
1273
 
1165
1274
    def test_patience_unified_diff_files(self):
1166
1275
        txt_a = ['hello there\n',
1168
1277
                 'how are you today?\n']
1169
1278
        txt_b = ['hello there\n',
1170
1279
                 'how are you today?\n']
1171
 
        open('a1', 'wb').writelines(txt_a)
1172
 
        open('b1', 'wb').writelines(txt_b)
 
1280
        with open('a1', 'wb') as f: f.writelines(txt_a)
 
1281
        with open('b1', 'wb') as f: f.writelines(txt_b)
1173
1282
 
1174
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1283
        unified_diff_files = patiencediff.unified_diff_files
1175
1284
        psm = self._PatienceSequenceMatcher
1176
 
        self.assertEquals(['--- a1 \n',
1177
 
                           '+++ b1 \n',
 
1285
        self.assertEqual(['--- a1\n',
 
1286
                           '+++ b1\n',
1178
1287
                           '@@ -1,3 +1,2 @@\n',
1179
1288
                           ' hello there\n',
1180
1289
                           '-world\n',
1185
1294
 
1186
1295
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1187
1296
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1188
 
        open('a2', 'wb').writelines(txt_a)
1189
 
        open('b2', 'wb').writelines(txt_b)
 
1297
        with open('a2', 'wb') as f: f.writelines(txt_a)
 
1298
        with open('b2', 'wb') as f: f.writelines(txt_b)
1190
1299
 
1191
1300
        # This is the result with LongestCommonSubstring matching
1192
 
        self.assertEquals(['--- a2 \n',
1193
 
                           '+++ b2 \n',
 
1301
        self.assertEqual(['--- a2\n',
 
1302
                           '+++ b2\n',
1194
1303
                           '@@ -1,6 +1,11 @@\n',
1195
1304
                           ' a\n',
1196
1305
                           ' b\n',
1206
1315
                          , list(unified_diff_files('a2', 'b2')))
1207
1316
 
1208
1317
        # And the patience diff
1209
 
        self.assertEquals(['--- a2 \n',
1210
 
                           '+++ b2 \n',
1211
 
                           '@@ -4,6 +4,11 @@\n',
1212
 
                           ' d\n',
1213
 
                           ' e\n',
1214
 
                           ' f\n',
1215
 
                           '+x\n',
1216
 
                           '+y\n',
1217
 
                           '+d\n',
1218
 
                           '+e\n',
1219
 
                           '+f\n',
1220
 
                           ' g\n',
1221
 
                           ' h\n',
1222
 
                           ' i\n',
1223
 
                          ]
1224
 
                          , list(unified_diff_files('a2', 'b2',
1225
 
                                 sequencematcher=psm)))
 
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)))
1226
1334
 
1227
1335
 
1228
1336
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1229
1337
 
1230
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1338
    _test_needs_features = [features.compiled_patiencediff_feature]
1231
1339
 
1232
1340
    def setUp(self):
1233
1341
        super(TestPatienceDiffLibFiles_c, self).setUp()
1234
 
        import bzrlib._patiencediff_c
 
1342
        from bzrlib import _patiencediff_c
1235
1343
        self._PatienceSequenceMatcher = \
1236
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1237
 
 
1238
 
 
1239
 
class TestUsingCompiledIfAvailable(TestCase):
 
1344
            _patiencediff_c.PatienceSequenceMatcher_c
 
1345
 
 
1346
 
 
1347
class TestUsingCompiledIfAvailable(tests.TestCase):
1240
1348
 
1241
1349
    def test_PatienceSequenceMatcher(self):
1242
 
        if CompiledPatienceDiffFeature.available():
 
1350
        if features.compiled_patiencediff_feature.available():
1243
1351
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1244
1352
            self.assertIs(PatienceSequenceMatcher_c,
1245
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1353
                          patiencediff.PatienceSequenceMatcher)
1246
1354
        else:
1247
1355
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1248
1356
            self.assertIs(PatienceSequenceMatcher_py,
1249
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1357
                          patiencediff.PatienceSequenceMatcher)
1250
1358
 
1251
1359
    def test_unique_lcs(self):
1252
 
        if CompiledPatienceDiffFeature.available():
 
1360
        if features.compiled_patiencediff_feature.available():
1253
1361
            from bzrlib._patiencediff_c import unique_lcs_c
1254
1362
            self.assertIs(unique_lcs_c,
1255
 
                          bzrlib.patiencediff.unique_lcs)
 
1363
                          patiencediff.unique_lcs)
1256
1364
        else:
1257
1365
            from bzrlib._patiencediff_py import unique_lcs_py
1258
1366
            self.assertIs(unique_lcs_py,
1259
 
                          bzrlib.patiencediff.unique_lcs)
 
1367
                          patiencediff.unique_lcs)
1260
1368
 
1261
1369
    def test_recurse_matches(self):
1262
 
        if CompiledPatienceDiffFeature.available():
 
1370
        if features.compiled_patiencediff_feature.available():
1263
1371
            from bzrlib._patiencediff_c import recurse_matches_c
1264
1372
            self.assertIs(recurse_matches_c,
1265
 
                          bzrlib.patiencediff.recurse_matches)
 
1373
                          patiencediff.recurse_matches)
1266
1374
        else:
1267
1375
            from bzrlib._patiencediff_py import recurse_matches_py
1268
1376
            self.assertIs(recurse_matches_py,
1269
 
                          bzrlib.patiencediff.recurse_matches)
1270
 
 
1271
 
 
1272
 
class TestDiffFromTool(TestCaseWithTransport):
 
1377
                          patiencediff.recurse_matches)
 
1378
 
 
1379
 
 
1380
class TestDiffFromTool(tests.TestCaseWithTransport):
1273
1381
 
1274
1382
    def test_from_string(self):
1275
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1383
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1276
1384
        self.addCleanup(diff_obj.finish)
1277
 
        self.assertEqual(['diff', '%(old_path)s', '%(new_path)s'],
 
1385
        self.assertEqual(['diff', '@old_path', '@new_path'],
1278
1386
            diff_obj.command_template)
1279
1387
 
1280
1388
    def test_from_string_u5(self):
1281
 
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1389
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1390
                                                 None, None, None)
1282
1391
        self.addCleanup(diff_obj.finish)
1283
 
        self.assertEqual(['diff', '-u 5', '%(old_path)s', '%(new_path)s'],
 
1392
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1284
1393
                         diff_obj.command_template)
1285
1394
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1286
1395
                         diff_obj._get_command('old-path', 'new-path'))
1287
1396
 
 
1397
    def test_from_string_path_with_backslashes(self):
 
1398
        self.requireFeature(features.backslashdir_feature)
 
1399
        tool = 'C:\\Tools\\Diff.exe'
 
1400
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
 
1401
        self.addCleanup(diff_obj.finish)
 
1402
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
 
1403
                         diff_obj.command_template)
 
1404
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
 
1405
                         diff_obj._get_command('old-path', 'new-path'))
 
1406
 
1288
1407
    def test_execute(self):
1289
1408
        output = StringIO()
1290
 
        diff_obj = DiffFromTool(['python', '-c',
1291
 
                                 'print "%(old_path)s %(new_path)s"'],
1292
 
                                None, None, output)
 
1409
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1410
                                      'print "@old_path @new_path"'],
 
1411
                                     None, None, output)
1293
1412
        self.addCleanup(diff_obj.finish)
1294
1413
        diff_obj._execute('old', 'new')
1295
1414
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1296
1415
 
1297
 
    def test_excute_missing(self):
1298
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1299
 
                                None, None, None)
 
1416
    def test_execute_missing(self):
 
1417
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1418
                                     None, None, None)
1300
1419
        self.addCleanup(diff_obj.finish)
1301
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1302
 
                              'new')
 
1420
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1421
                              'old', 'new')
1303
1422
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1304
1423
                         ' on this machine', str(e))
1305
1424
 
1306
1425
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1307
 
        self.requireFeature(AttribFeature)
 
1426
        self.requireFeature(features.AttribFeature)
1308
1427
        output = StringIO()
1309
1428
        tree = self.make_branch_and_tree('tree')
1310
1429
        self.build_tree_contents([('tree/file', 'content')])
1312
1431
        tree.commit('old tree')
1313
1432
        tree.lock_read()
1314
1433
        self.addCleanup(tree.unlock)
1315
 
        diff_obj = DiffFromTool(['python', '-c',
1316
 
                                 'print "%(old_path)s %(new_path)s"'],
1317
 
                                tree, tree, output)
 
1434
        basis_tree = tree.basis_tree()
 
1435
        basis_tree.lock_read()
 
1436
        self.addCleanup(basis_tree.unlock)
 
1437
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1438
                                      'print "@old_path @new_path"'],
 
1439
                                     basis_tree, tree, output)
1318
1440
        diff_obj._prepare_files('file-id', 'file', 'file')
1319
 
        self.assertReadableByAttrib(diff_obj._root, 'old\\file', r'old\\file')
1320
 
        self.assertReadableByAttrib(diff_obj._root, 'new\\file', r'new\\file')
 
1441
        # The old content should be readonly
 
1442
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
 
1443
                                    r'R.*old\\file$')
 
1444
        # The new content should use the tree object, not a 'new' file anymore
 
1445
        self.assertEndsWith(tree.basedir, 'work/tree')
 
1446
        self.assertReadableByAttrib(tree.basedir, 'file', r'work\\tree\\file$')
1321
1447
 
1322
1448
    def assertReadableByAttrib(self, cwd, relpath, regex):
1323
1449
        proc = subprocess.Popen(['attrib', relpath],
1324
1450
                                stdout=subprocess.PIPE,
1325
1451
                                cwd=cwd)
1326
 
        proc.wait()
1327
 
        result = proc.stdout.read()
1328
 
        self.assertContainsRe(result, regex)
 
1452
        (result, err) = proc.communicate()
 
1453
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
1329
1454
 
1330
1455
    def test_prepare_files(self):
1331
1456
        output = StringIO()
1334
1459
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1335
1460
        tree.add('oldname', 'file-id')
1336
1461
        tree.add('oldname2', 'file2-id')
1337
 
        tree.commit('old tree', timestamp=0)
 
1462
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1463
        tree.commit('old tree', timestamp=315532800)
1338
1464
        tree.rename_one('oldname', 'newname')
1339
1465
        tree.rename_one('oldname2', 'newname2')
1340
1466
        self.build_tree_contents([('tree/newname', 'newcontent')])
1344
1470
        self.addCleanup(old_tree.unlock)
1345
1471
        tree.lock_read()
1346
1472
        self.addCleanup(tree.unlock)
1347
 
        diff_obj = DiffFromTool(['python', '-c',
1348
 
                                 'print "%(old_path)s %(new_path)s"'],
1349
 
                                old_tree, tree, output)
 
1473
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1474
                                      'print "@old_path @new_path"'],
 
1475
                                     old_tree, tree, output)
1350
1476
        self.addCleanup(diff_obj.finish)
1351
1477
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1352
1478
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1353
1479
                                                     'newname')
1354
1480
        self.assertContainsRe(old_path, 'old/oldname$')
1355
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
1356
 
        self.assertContainsRe(new_path, 'new/newname$')
 
1481
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
 
1482
        self.assertContainsRe(new_path, 'tree/newname$')
1357
1483
        self.assertFileEqual('oldcontent', old_path)
1358
1484
        self.assertFileEqual('newcontent', new_path)
1359
1485
        if osutils.host_os_dereferences_symlinks():
1360
1486
            self.assertTrue(os.path.samefile('tree/newname', new_path))
1361
1487
        # make sure we can create files with the same parent directories
1362
1488
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
 
1489
 
 
1490
 
 
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
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
 
1532
 
 
1533
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1534
        """Call get_trees_and_branches_to_diff_locked."""
 
1535
        return diff.get_trees_and_branches_to_diff_locked(
 
1536
            path_list, revision_specs, old_url, new_url, self.addCleanup)
 
1537
 
 
1538
    def test_basic(self):
 
1539
        tree = self.make_branch_and_tree('tree')
 
1540
        (old_tree, new_tree,
 
1541
         old_branch, new_branch,
 
1542
         specific_files, extra_trees) = self.call_gtabtd(
 
1543
             ['tree'], None, None, None)
 
1544
 
 
1545
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1546
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1547
                         old_tree.get_revision_id())
 
1548
        self.assertEqual(tree.basedir, new_tree.basedir)
 
1549
        self.assertEqual(tree.branch.base, old_branch.base)
 
1550
        self.assertEqual(tree.branch.base, new_branch.base)
 
1551
        self.assertIs(None, specific_files)
 
1552
        self.assertIs(None, extra_trees)
 
1553
 
 
1554
    def test_with_rev_specs(self):
 
1555
        tree = self.make_branch_and_tree('tree')
 
1556
        self.build_tree_contents([('tree/file', 'oldcontent')])
 
1557
        tree.add('file', 'file-id')
 
1558
        tree.commit('old tree', timestamp=0, rev_id="old-id")
 
1559
        self.build_tree_contents([('tree/file', 'newcontent')])
 
1560
        tree.commit('new tree', timestamp=0, rev_id="new-id")
 
1561
 
 
1562
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1563
                     revisionspec.RevisionSpec.from_string('2')]
 
1564
        (old_tree, new_tree,
 
1565
         old_branch, new_branch,
 
1566
         specific_files, extra_trees) = self.call_gtabtd(
 
1567
            ['tree'], revisions, None, None)
 
1568
 
 
1569
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1570
        self.assertEqual("old-id", old_tree.get_revision_id())
 
1571
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
 
1572
        self.assertEqual("new-id", new_tree.get_revision_id())
 
1573
        self.assertEqual(tree.branch.base, old_branch.base)
 
1574
        self.assertEqual(tree.branch.base, new_branch.base)
 
1575
        self.assertIs(None, specific_files)
 
1576
        self.assertEqual(tree.basedir, extra_trees[0].basedir)