~bzr-pqm/bzr/bzr.dev

5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2005-2011 Canonical Ltd
1711.2.16 by John Arbash Meinel
test_diff needs a copyright statement
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
12
#
1711.2.16 by John Arbash Meinel
test_diff needs a copyright statement
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1711.2.16 by John Arbash Meinel
test_diff needs a copyright statement
16
1740.2.5 by Aaron Bentley
Merge from bzr.dev
17
import os
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
18
from cStringIO import StringIO
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
19
import subprocess
3287.18.6 by Matt McClure
Snapshot of unfinished work.
20
import sys
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
21
import tempfile
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
22
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
23
from bzrlib import (
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
24
    diff,
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
25
    errors,
26
    osutils,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
27
    patiencediff,
28
    _patiencediff_py,
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
29
    revision as _mod_revision,
30
    revisionspec,
31
    revisiontree,
32
    tests,
33
    transform,
34
    )
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
35
from bzrlib.symbol_versioning import deprecated_in
5074.5.3 by INADA Naoki
merge lp:bzr
36
from bzrlib.tests import features, EncodingAdapter
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
37
from bzrlib.tests.blackbox.test_diff import subst_dates
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
38
from bzrlib.tests import (
39
    features,
40
    )
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
41
42
1558.15.11 by Aaron Bentley
Apply merge review suggestions
43
def udiff_lines(old, new, allow_binary=False):
974.1.6 by Aaron Bentley
Added unit tests
44
    output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
45
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
974.1.6 by Aaron Bentley
Added unit tests
46
    output.seek(0, 0)
47
    return output.readlines()
48
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
49
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
50
def external_udiff_lines(old, new, use_stringio=False):
51
    if use_stringio:
52
        # StringIO has no fileno, so it tests a different codepath
53
        output = StringIO()
54
    else:
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
55
        output = tempfile.TemporaryFile()
1692.8.7 by James Henstridge
changes suggested by John Meinel
56
    try:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
57
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
58
    except errors.NoDiff:
59
        raise tests.TestSkipped('external "diff" not present to test')
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
60
    output.seek(0, 0)
61
    lines = output.readlines()
62
    output.close()
63
    return lines
64
65
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
66
class TestDiff(tests.TestCase):
1185.81.25 by Aaron Bentley
Clean up test_diff
67
1102 by Martin Pool
- merge test refactoring from robertc
68
    def test_add_nl(self):
69
        """diff generates a valid diff for patches that add a newline"""
974.1.6 by Aaron Bentley
Added unit tests
70
        lines = udiff_lines(['boo'], ['boo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
71
        self.check_patch(lines)
72
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
73
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
74
1102 by Martin Pool
- merge test refactoring from robertc
75
    def test_add_nl_2(self):
76
        """diff generates a valid diff for patches that change last line and
77
        add a newline.
78
        """
974.1.6 by Aaron Bentley
Added unit tests
79
        lines = udiff_lines(['boo'], ['goo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
80
        self.check_patch(lines)
81
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
82
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
83
1102 by Martin Pool
- merge test refactoring from robertc
84
    def test_remove_nl(self):
85
        """diff generates a valid diff for patches that change last line and
86
        add a newline.
87
        """
974.1.6 by Aaron Bentley
Added unit tests
88
        lines = udiff_lines(['boo\n'], ['boo'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
89
        self.check_patch(lines)
90
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
91
            ## "expected no-nl, got %r" % lines[5]
92
93
    def check_patch(self, lines):
94
        self.assert_(len(lines) > 1)
95
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
96
        self.assert_(lines[0].startswith ('---'))
97
            ## 'No orig line for patch:\n%s' % "".join(lines)
98
        self.assert_(lines[1].startswith ('+++'))
99
            ## 'No mod line for patch:\n%s' % "".join(lines)
100
        self.assert_(len(lines) > 2)
101
            ## "No hunks for patch:\n%s" % "".join(lines)
102
        self.assert_(lines[2].startswith('@@'))
103
            ## "No hunk header for patch:\n%s" % "".join(lines)
104
        self.assert_('@@' in lines[2][2:])
105
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
106
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
107
    def test_binary_lines(self):
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
108
        empty = []
109
        uni_lines = [1023 * 'a' + '\x00']
110
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
111
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
112
        udiff_lines(uni_lines , empty, allow_binary=True)
113
        udiff_lines(empty, uni_lines, allow_binary=True)
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
114
115
    def test_external_diff(self):
116
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
117
        self.check_patch(lines)
1899.1.6 by John Arbash Meinel
internal_diff always adds a trailing \n, make sure external_diff does too
118
        self.assertEqual('\n', lines[-1])
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
119
120
    def test_external_diff_no_fileno(self):
121
        # Make sure that we can handle not having a fileno, even
122
        # if the diff is large
123
        lines = external_udiff_lines(['boo\n']*10000,
124
                                     ['goo\n']*10000,
125
                                     use_stringio=True)
126
        self.check_patch(lines)
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
127
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
128
    def test_external_diff_binary_lang_c(self):
2321.2.5 by Alexander Belchenko
external diff: no need for special code path for win32 (suggested by John Meinel)
129
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
130
            self.overrideEnv(lang, 'C')
131
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
132
        # Older versions of diffutils say "Binary files", newer
133
        # versions just say "Files".
134
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
135
        self.assertEquals(lines[1:], ['\n'])
1899.1.4 by John Arbash Meinel
Just swallow a return code of 2
136
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
137
    def test_no_external_diff(self):
138
        """Check that NoDiff is raised when diff is not available"""
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
139
        # Make sure no 'diff' command is available
140
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
141
        self.overrideEnv('PATH', '')
142
        self.assertRaises(errors.NoDiff, diff.external_diff,
143
                          'old', ['boo\n'], 'new', ['goo\n'],
144
                          StringIO(), diff_opts=['-u'])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
145
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
146
    def test_internal_diff_default(self):
147
        # Default internal diff encoding is utf8
148
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
149
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
150
                           u'new_\xe5', ['new_text\n'], output)
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
151
        lines = output.getvalue().splitlines(True)
152
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
153
        self.assertEquals(['--- old_\xc2\xb5\n',
154
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
155
                           '@@ -1,1 +1,1 @@\n',
156
                           '-old_text\n',
157
                           '+new_text\n',
158
                           '\n',
159
                          ]
160
                          , lines)
161
162
    def test_internal_diff_utf8(self):
163
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
164
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
165
                           u'new_\xe5', ['new_text\n'], output,
166
                           path_encoding='utf8')
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
167
        lines = output.getvalue().splitlines(True)
168
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
169
        self.assertEquals(['--- old_\xc2\xb5\n',
170
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
171
                           '@@ -1,1 +1,1 @@\n',
172
                           '-old_text\n',
173
                           '+new_text\n',
174
                           '\n',
175
                          ]
176
                          , lines)
177
178
    def test_internal_diff_iso_8859_1(self):
179
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
180
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
181
                           u'new_\xe5', ['new_text\n'], output,
182
                           path_encoding='iso-8859-1')
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
183
        lines = output.getvalue().splitlines(True)
184
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
185
        self.assertEquals(['--- old_\xb5\n',
186
                           '+++ new_\xe5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
187
                           '@@ -1,1 +1,1 @@\n',
188
                           '-old_text\n',
189
                           '+new_text\n',
190
                           '\n',
191
                          ]
192
                          , lines)
193
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
194
    def test_internal_diff_no_content(self):
195
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
196
        diff.internal_diff(u'old', [], u'new', [], output)
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
197
        self.assertEqual('', output.getvalue())
198
199
    def test_internal_diff_no_changes(self):
200
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
201
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
202
                           u'new', ['text\n', 'contents\n'],
203
                           output)
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
204
        self.assertEqual('', output.getvalue())
205
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
206
    def test_internal_diff_returns_bytes(self):
207
        import StringIO
208
        output = StringIO.StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
209
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
210
                            u'new_\xe5', ['new_text\n'], output)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
211
        self.assertIsInstance(output.getvalue(), str,
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
212
            'internal_diff should return bytestrings')
213
6524.5.5 by Paul Nixon
Added tests of configurable context
214
    def test_internal_diff_default_context(self):
215
        output = StringIO()
216
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
217
                           'same_text\n','same_text\n','old_text\n'],
218
                           'new', ['same_text\n','same_text\n','same_text\n',
219
                           'same_text\n','same_text\n','new_text\n'], output)
220
        lines = output.getvalue().splitlines(True)
221
        self.check_patch(lines)
222
        self.assertEquals(['--- old\n',
223
                           '+++ new\n',
224
                           '@@ -3,4 +3,4 @@\n',
225
                           ' same_text\n',
226
                           ' same_text\n',
227
                           ' same_text\n',
228
                           '-old_text\n',
229
                           '+new_text\n',
230
                           '\n',
231
                          ]
232
                          , lines)
233
234
    def test_internal_diff_no_context(self):
235
        output = StringIO()
236
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
237
                           'same_text\n','same_text\n','old_text\n'],
238
                           'new', ['same_text\n','same_text\n','same_text\n',
239
                           'same_text\n','same_text\n','new_text\n'], output,
240
                           context_lines=0)
241
        lines = output.getvalue().splitlines(True)
242
        self.check_patch(lines)
243
        self.assertEquals(['--- old\n',
244
                           '+++ new\n',
245
                           '@@ -6,1 +6,1 @@\n',
246
                           '-old_text\n',
247
                           '+new_text\n',
248
                           '\n',
249
                          ]
250
                          , lines)
251
252
    def test_internal_diff_more_context(self):
253
        output = StringIO()
254
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
255
                           'same_text\n','same_text\n','old_text\n'],
256
                           'new', ['same_text\n','same_text\n','same_text\n',
257
                           'same_text\n','same_text\n','new_text\n'], output,
258
                           context_lines=4)
259
        lines = output.getvalue().splitlines(True)
260
        self.check_patch(lines)
261
        self.assertEquals(['--- old\n',
262
                           '+++ new\n',
263
                           '@@ -2,5 +2,5 @@\n',
264
                           ' same_text\n',
265
                           ' same_text\n',
266
                           ' same_text\n',
267
                           ' same_text\n',
268
                           '-old_text\n',
269
                           '+new_text\n',
270
                           '\n',
271
                          ]
272
                          , lines)
273
274
275
276
1185.81.25 by Aaron Bentley
Clean up test_diff
277
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
278
class TestDiffFiles(tests.TestCaseInTempDir):
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
279
280
    def test_external_diff_binary(self):
281
        """The output when using external diff should use diff's i18n error"""
282
        # Make sure external_diff doesn't fail in the current LANG
283
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
284
2240.1.1 by Alexander Belchenko
test_external_diff_binary: run external diff with --binary flag
285
        cmd = ['diff', '-u', '--binary', 'old', 'new']
6437.20.3 by Wouter van Heyst
mechanically replace file().write() pattern with a with-keyword version
286
        with open('old', 'wb') as f: f.write('\x00foobar\n')
287
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
288
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
289
                                     stdin=subprocess.PIPE)
290
        out, err = pipe.communicate()
291
        # Diff returns '2' on Binary files.
292
        self.assertEqual(2, pipe.returncode)
293
        # We should output whatever diff tells us, plus a trailing newline
294
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
295
296
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
297
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
298
    output = StringIO()
299
    if working_tree is not None:
300
        extra_trees = (working_tree,)
301
    else:
302
        extra_trees = ()
303
    diff.show_diff_trees(tree1, tree2, output,
304
        specific_files=specific_files,
305
        extra_trees=extra_trees, old_label='old/',
306
        new_label='new/')
307
    return output.getvalue()
308
309
310
class TestDiffDates(tests.TestCaseWithTransport):
1740.2.5 by Aaron Bentley
Merge from bzr.dev
311
312
    def setUp(self):
313
        super(TestDiffDates, self).setUp()
314
        self.wt = self.make_branch_and_tree('.')
315
        self.b = self.wt.branch
316
        self.build_tree_contents([
317
            ('file1', 'file1 contents at rev 1\n'),
318
            ('file2', 'file2 contents at rev 1\n')
319
            ])
320
        self.wt.add(['file1', 'file2'])
321
        self.wt.commit(
322
            message='Revision 1',
323
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
324
            timezone=0,
325
            rev_id='rev-1')
326
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
327
        self.wt.commit(
328
            message='Revision 2',
329
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
330
            timezone=28800,
331
            rev_id='rev-2')
332
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
333
        self.wt.commit(
334
            message='Revision 3',
335
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
336
            timezone=-3600,
337
            rev_id='rev-3')
338
        self.wt.remove(['file2'])
339
        self.wt.commit(
340
            message='Revision 4',
341
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
342
            timezone=0,
343
            rev_id='rev-4')
344
        self.build_tree_contents([
345
            ('file1', 'file1 contents in working tree\n')
346
            ])
347
        # set the date stamps for files in the working tree to known values
348
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
349
350
    def test_diff_rev_tree_working_tree(self):
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
351
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
352
        # note that the date for old/file1 is from rev 2 rather than from
353
        # the basis revision (rev 4)
354
        self.assertEqualDiff(output, '''\
355
=== modified file 'file1'
356
--- old/file1\t2006-04-02 00:00:00 +0000
357
+++ new/file1\t2006-04-05 00:00:00 +0000
358
@@ -1,1 +1,1 @@
359
-file1 contents at rev 2
360
+file1 contents in working tree
361
362
''')
363
364
    def test_diff_rev_tree_rev_tree(self):
365
        tree1 = self.b.repository.revision_tree('rev-2')
366
        tree2 = self.b.repository.revision_tree('rev-3')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
367
        output = get_diff_as_string(tree1, tree2)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
368
        self.assertEqualDiff(output, '''\
369
=== modified file 'file2'
370
--- old/file2\t2006-04-01 00:00:00 +0000
371
+++ new/file2\t2006-04-03 00:00:00 +0000
372
@@ -1,1 +1,1 @@
373
-file2 contents at rev 1
374
+file2 contents at rev 3
375
376
''')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
377
1740.2.5 by Aaron Bentley
Merge from bzr.dev
378
    def test_diff_add_files(self):
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
379
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
380
        tree2 = self.b.repository.revision_tree('rev-1')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
381
        output = get_diff_as_string(tree1, tree2)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
382
        # the files have the epoch time stamp for the tree in which
383
        # they don't exist.
384
        self.assertEqualDiff(output, '''\
385
=== added file 'file1'
386
--- old/file1\t1970-01-01 00:00:00 +0000
387
+++ new/file1\t2006-04-01 00:00:00 +0000
388
@@ -0,0 +1,1 @@
389
+file1 contents at rev 1
390
391
=== added file 'file2'
392
--- old/file2\t1970-01-01 00:00:00 +0000
393
+++ new/file2\t2006-04-01 00:00:00 +0000
394
@@ -0,0 +1,1 @@
395
+file2 contents at rev 1
396
397
''')
398
399
    def test_diff_remove_files(self):
400
        tree1 = self.b.repository.revision_tree('rev-3')
401
        tree2 = self.b.repository.revision_tree('rev-4')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
402
        output = get_diff_as_string(tree1, tree2)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
403
        # the file has the epoch time stamp for the tree in which
404
        # it doesn't exist.
405
        self.assertEqualDiff(output, '''\
406
=== removed file 'file2'
407
--- old/file2\t2006-04-03 00:00:00 +0000
408
+++ new/file2\t1970-01-01 00:00:00 +0000
409
@@ -1,1 +0,0 @@
410
-file2 contents at rev 3
411
412
''')
413
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
414
    def test_show_diff_specified(self):
1551.7.22 by Aaron Bentley
Changes from review
415
        """A working tree filename can be used to identify a file"""
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
416
        self.wt.rename_one('file1', 'file1b')
417
        old_tree = self.b.repository.revision_tree('rev-1')
418
        new_tree = self.b.repository.revision_tree('rev-4')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
419
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
1551.7.22 by Aaron Bentley
Changes from review
420
                            working_tree=self.wt)
421
        self.assertContainsRe(out, 'file1\t')
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
422
1551.7.22 by Aaron Bentley
Changes from review
423
    def test_recursive_diff(self):
424
        """Children of directories are matched"""
425
        os.mkdir('dir1')
426
        os.mkdir('dir2')
427
        self.wt.add(['dir1', 'dir2'])
428
        self.wt.rename_one('file1', 'dir1/file1')
429
        old_tree = self.b.repository.revision_tree('rev-1')
430
        new_tree = self.b.repository.revision_tree('rev-4')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
431
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
1551.7.22 by Aaron Bentley
Changes from review
432
                            working_tree=self.wt)
433
        self.assertContainsRe(out, 'file1\t')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
434
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
1551.7.22 by Aaron Bentley
Changes from review
435
                            working_tree=self.wt)
436
        self.assertNotContainsRe(out, 'file1\t')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
437
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
438
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
439
class TestShowDiffTrees(tests.TestCaseWithTransport):
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
440
    """Direct tests for show_diff_trees"""
441
442
    def test_modified_file(self):
443
        """Test when a file is modified."""
444
        tree = self.make_branch_and_tree('tree')
445
        self.build_tree_contents([('tree/file', 'contents\n')])
446
        tree.add(['file'], ['file-id'])
447
        tree.commit('one', rev_id='rev-1')
448
449
        self.build_tree_contents([('tree/file', 'new contents\n')])
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
450
        d = get_diff_as_string(tree.basis_tree(), tree)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
451
        self.assertContainsRe(d, "=== modified file 'file'\n")
452
        self.assertContainsRe(d, '--- old/file\t')
453
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
454
        self.assertContainsRe(d, '-contents\n'
455
                                 '\\+new contents\n')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
456
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
457
    def test_modified_file_in_renamed_dir(self):
458
        """Test when a file is modified in a renamed directory."""
459
        tree = self.make_branch_and_tree('tree')
460
        self.build_tree(['tree/dir/'])
461
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
462
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
463
        tree.commit('one', rev_id='rev-1')
464
465
        tree.rename_one('dir', 'other')
466
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
467
        d = get_diff_as_string(tree.basis_tree(), tree)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
468
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
469
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
470
        # XXX: This is technically incorrect, because it used to be at another
471
        # location. What to do?
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
472
        self.assertContainsRe(d, '--- old/dir/file\t')
473
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
474
        self.assertContainsRe(d, '-contents\n'
475
                                 '\\+new contents\n')
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
476
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
477
    def test_renamed_directory(self):
478
        """Test when only a directory is only renamed."""
479
        tree = self.make_branch_and_tree('tree')
480
        self.build_tree(['tree/dir/'])
481
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
482
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
483
        tree.commit('one', rev_id='rev-1')
484
485
        tree.rename_one('dir', 'newdir')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
486
        d = get_diff_as_string(tree.basis_tree(), tree)
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
487
        # Renaming a directory should be a single "you renamed this dir" even
488
        # when there are files inside.
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
489
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
490
491
    def test_renamed_file(self):
492
        """Test when a file is only renamed."""
493
        tree = self.make_branch_and_tree('tree')
494
        self.build_tree_contents([('tree/file', 'contents\n')])
495
        tree.add(['file'], ['file-id'])
496
        tree.commit('one', rev_id='rev-1')
497
498
        tree.rename_one('file', 'newname')
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
499
        d = get_diff_as_string(tree.basis_tree(), tree)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
500
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
501
        # We shouldn't have a --- or +++ line, because there is no content
502
        # change
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
503
        self.assertNotContainsRe(d, '---')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
504
505
    def test_renamed_and_modified_file(self):
506
        """Test when a file is only renamed."""
507
        tree = self.make_branch_and_tree('tree')
508
        self.build_tree_contents([('tree/file', 'contents\n')])
509
        tree.add(['file'], ['file-id'])
510
        tree.commit('one', rev_id='rev-1')
511
512
        tree.rename_one('file', 'newname')
513
        self.build_tree_contents([('tree/newname', 'new contents\n')])
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
514
        d = get_diff_as_string(tree.basis_tree(), tree)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
515
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
516
        self.assertContainsRe(d, '--- old/file\t')
517
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
518
        self.assertContainsRe(d, '-contents\n'
519
                                 '\\+new contents\n')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
520
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
521
522
    def test_internal_diff_exec_property(self):
523
        tree = self.make_branch_and_tree('tree')
524
525
        tt = transform.TreeTransform(tree)
526
        tt.new_file('a', tt.root, 'contents\n', 'a-id', True)
527
        tt.new_file('b', tt.root, 'contents\n', 'b-id', False)
528
        tt.new_file('c', tt.root, 'contents\n', 'c-id', True)
529
        tt.new_file('d', tt.root, 'contents\n', 'd-id', False)
530
        tt.new_file('e', tt.root, 'contents\n', 'control-e-id', True)
531
        tt.new_file('f', tt.root, 'contents\n', 'control-f-id', False)
532
        tt.apply()
533
        tree.commit('one', rev_id='rev-1')
534
535
        tt = transform.TreeTransform(tree)
536
        tt.set_executability(False, tt.trans_id_file_id('a-id'))
537
        tt.set_executability(True, tt.trans_id_file_id('b-id'))
538
        tt.set_executability(False, tt.trans_id_file_id('c-id'))
539
        tt.set_executability(True, tt.trans_id_file_id('d-id'))
540
        tt.apply()
541
        tree.rename_one('c', 'new-c')
542
        tree.rename_one('d', 'new-d')
543
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
544
        d = get_diff_as_string(tree.basis_tree(), tree)
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
545
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
546
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
547
                                  ".*\+x to -x.*\)")
548
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
549
                                  ".*-x to \+x.*\)")
550
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
551
                                  ".*\+x to -x.*\)")
552
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
553
                                  ".*-x to \+x.*\)")
554
        self.assertNotContainsRe(d, r"file 'e'")
555
        self.assertNotContainsRe(d, r"file 'f'")
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
556
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
557
    def test_binary_unicode_filenames(self):
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
558
        """Test that contents of files are *not* encoded in UTF-8 when there
559
        is a binary file in the diff.
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
560
        """
561
        # See https://bugs.launchpad.net/bugs/110092.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
562
        self.requireFeature(features.UnicodeFilenameFeature)
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
563
564
        # This bug isn't triggered with cStringIO.
565
        from StringIO import StringIO
566
        tree = self.make_branch_and_tree('tree')
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
567
        alpha, omega = u'\u03b1', u'\u03c9'
568
        alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
569
        self.build_tree_contents(
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
570
            [('tree/' + alpha, chr(0)),
571
             ('tree/' + omega,
572
              ('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
573
        tree.add([alpha], ['file-id'])
574
        tree.add([omega], ['file-id-2'])
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
575
        diff_content = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
576
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
577
        d = diff_content.getvalue()
578
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
579
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
580
                              % (alpha_utf8, alpha_utf8))
581
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
582
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
583
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
584
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
585
    def test_unicode_filename(self):
586
        """Test when the filename are unicode."""
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
587
        self.requireFeature(features.UnicodeFilenameFeature)
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
588
589
        alpha, omega = u'\u03b1', u'\u03c9'
590
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
591
592
        tree = self.make_branch_and_tree('tree')
593
        self.build_tree_contents([('tree/ren_'+alpha, 'contents\n')])
594
        tree.add(['ren_'+alpha], ['file-id-2'])
595
        self.build_tree_contents([('tree/del_'+alpha, 'contents\n')])
596
        tree.add(['del_'+alpha], ['file-id-3'])
597
        self.build_tree_contents([('tree/mod_'+alpha, 'contents\n')])
598
        tree.add(['mod_'+alpha], ['file-id-4'])
599
600
        tree.commit('one', rev_id='rev-1')
601
602
        tree.rename_one('ren_'+alpha, 'ren_'+omega)
603
        tree.remove('del_'+alpha)
604
        self.build_tree_contents([('tree/add_'+alpha, 'contents\n')])
605
        tree.add(['add_'+alpha], ['file-id'])
606
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
607
5784.3.1 by Martin Pool
Remove unnecessary TestShowDiffTreesHelper and just use a function
608
        d = get_diff_as_string(tree.basis_tree(), tree)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
609
        self.assertContainsRe(d,
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
610
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
611
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
612
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
613
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
614
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
615
    def test_unicode_filename_path_encoding(self):
616
        """Test for bug #382699: unicode filenames on Windows should be shown
617
        in user encoding.
618
        """
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
619
        self.requireFeature(features.UnicodeFilenameFeature)
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
620
        # The word 'test' in Russian
621
        _russian_test = u'\u0422\u0435\u0441\u0442'
622
        directory = _russian_test + u'/'
623
        test_txt = _russian_test + u'.txt'
624
        u1234 = u'\u1234.txt'
625
626
        tree = self.make_branch_and_tree('.')
627
        self.build_tree_contents([
628
            (test_txt, 'foo\n'),
629
            (u1234, 'foo\n'),
630
            (directory, None),
631
            ])
632
        tree.add([test_txt, u1234, directory])
633
634
        sio = StringIO()
5258.1.1 by Alexander Belchenko
merge diff header work from my 2.1 branch
635
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
636
            path_encoding='cp1251')
637
638
        output = subst_dates(sio.getvalue())
639
        shouldbe = ('''\
640
=== added directory '%(directory)s'
641
=== added file '%(test_txt)s'
642
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
643
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
644
@@ -0,0 +1,1 @@
645
+foo
646
647
=== added file '?.txt'
648
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
649
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
650
@@ -0,0 +1,1 @@
651
+foo
652
653
''' % {'directory': _russian_test.encode('cp1251'),
654
       'test_txt': test_txt.encode('cp1251'),
655
      })
656
        self.assertEqualDiff(output, shouldbe)
657
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
658
659
class DiffWasIs(diff.DiffPath):
3009.2.15 by Aaron Bentley
Test differ registration
660
661
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
662
        self.to_file.write('was: ')
663
        self.to_file.write(self.old_tree.get_file(file_id).read())
664
        self.to_file.write('is: ')
665
        self.to_file.write(self.new_tree.get_file(file_id).read())
666
        pass
667
668
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
669
class TestDiffTree(tests.TestCaseWithTransport):
3009.2.9 by Aaron Bentley
Add tests for Differ
670
671
    def setUp(self):
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
672
        super(TestDiffTree, self).setUp()
3009.2.9 by Aaron Bentley
Add tests for Differ
673
        self.old_tree = self.make_branch_and_tree('old-tree')
674
        self.old_tree.lock_write()
675
        self.addCleanup(self.old_tree.unlock)
676
        self.new_tree = self.make_branch_and_tree('new-tree')
677
        self.new_tree.lock_write()
678
        self.addCleanup(self.new_tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
679
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
3009.2.9 by Aaron Bentley
Add tests for Differ
680
681
    def test_diff_text(self):
682
        self.build_tree_contents([('old-tree/olddir/',),
683
                                  ('old-tree/olddir/oldfile', 'old\n')])
684
        self.old_tree.add('olddir')
685
        self.old_tree.add('olddir/oldfile', 'file-id')
686
        self.build_tree_contents([('new-tree/newdir/',),
687
                                  ('new-tree/newdir/newfile', 'new\n')])
688
        self.new_tree.add('newdir')
689
        self.new_tree.add('newdir/newfile', 'file-id')
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
690
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
691
        differ.diff_text('file-id', None, 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
692
        self.assertEqual(
693
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
694
            differ.to_file.getvalue())
695
        differ.to_file.seek(0)
696
        differ.diff_text(None, 'file-id', 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
697
        self.assertEqual(
698
            '--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
699
            differ.to_file.getvalue())
700
        differ.to_file.seek(0)
701
        differ.diff_text('file-id', 'file-id', 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
702
        self.assertEqual(
703
            '--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
704
            differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
705
3087.1.1 by Aaron Bentley
Diff handles missing files correctly, with no tracebacks
706
    def test_diff_deletion(self):
707
        self.build_tree_contents([('old-tree/file', 'contents'),
708
                                  ('new-tree/file', 'contents')])
709
        self.old_tree.add('file', 'file-id')
710
        self.new_tree.add('file', 'file-id')
711
        os.unlink('new-tree/file')
712
        self.differ.show_diff(None)
713
        self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
714
715
    def test_diff_creation(self):
716
        self.build_tree_contents([('old-tree/file', 'contents'),
717
                                  ('new-tree/file', 'contents')])
718
        self.old_tree.add('file', 'file-id')
719
        self.new_tree.add('file', 'file-id')
720
        os.unlink('old-tree/file')
721
        self.differ.show_diff(None)
722
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
723
3009.2.9 by Aaron Bentley
Add tests for Differ
724
    def test_diff_symlink(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
725
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
726
        differ.diff_symlink('old target', None)
3009.2.9 by Aaron Bentley
Add tests for Differ
727
        self.assertEqual("=== target was 'old target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
728
                         differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
729
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
730
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
731
        differ.diff_symlink(None, 'new target')
3009.2.9 by Aaron Bentley
Add tests for Differ
732
        self.assertEqual("=== target is 'new target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
733
                         differ.to_file.getvalue())
734
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
735
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
736
        differ.diff_symlink('old target', 'new target')
3009.2.9 by Aaron Bentley
Add tests for Differ
737
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
738
                         differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
739
740
    def test_diff(self):
741
        self.build_tree_contents([('old-tree/olddir/',),
742
                                  ('old-tree/olddir/oldfile', 'old\n')])
743
        self.old_tree.add('olddir')
744
        self.old_tree.add('olddir/oldfile', 'file-id')
745
        self.build_tree_contents([('new-tree/newdir/',),
746
                                  ('new-tree/newdir/newfile', 'new\n')])
747
        self.new_tree.add('newdir')
748
        self.new_tree.add('newdir/newfile', 'file-id')
3009.2.12 by Aaron Bentley
Associate labels with text diffing only
749
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
3009.2.9 by Aaron Bentley
Add tests for Differ
750
        self.assertContainsRe(
751
            self.differ.to_file.getvalue(),
752
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
753
             ' \@\@\n-old\n\+new\n\n')
754
755
    def test_diff_kind_change(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
756
        self.requireFeature(features.SymlinkFeature)
3009.2.9 by Aaron Bentley
Add tests for Differ
757
        self.build_tree_contents([('old-tree/olddir/',),
758
                                  ('old-tree/olddir/oldfile', 'old\n')])
759
        self.old_tree.add('olddir')
760
        self.old_tree.add('olddir/oldfile', 'file-id')
761
        self.build_tree(['new-tree/newdir/'])
762
        os.symlink('new', 'new-tree/newdir/newfile')
763
        self.new_tree.add('newdir')
764
        self.new_tree.add('newdir/newfile', 'file-id')
3009.2.12 by Aaron Bentley
Associate labels with text diffing only
765
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
3009.2.9 by Aaron Bentley
Add tests for Differ
766
        self.assertContainsRe(
767
            self.differ.to_file.getvalue(),
768
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
769
             ' \@\@\n-old\n\n')
770
        self.assertContainsRe(self.differ.to_file.getvalue(),
4216.3.1 by Robert Collins
Fix Tree.get_symlink_target to decode from the disk encoding to get a unicode encoded string.
771
                              "=== target is u'new'\n")
3009.2.9 by Aaron Bentley
Add tests for Differ
772
3009.2.19 by Aaron Bentley
Implement directory diffing
773
    def test_diff_directory(self):
774
        self.build_tree(['new-tree/new-dir/'])
775
        self.new_tree.add('new-dir', 'new-dir-id')
776
        self.differ.diff('new-dir-id', None, 'new-dir')
777
        self.assertEqual(self.differ.to_file.getvalue(), '')
778
3009.2.16 by Aaron Bentley
Test support for extra differs
779
    def create_old_new(self):
780
        self.build_tree_contents([('old-tree/olddir/',),
781
                                  ('old-tree/olddir/oldfile', 'old\n')])
782
        self.old_tree.add('olddir')
783
        self.old_tree.add('olddir/oldfile', 'file-id')
784
        self.build_tree_contents([('new-tree/newdir/',),
785
                                  ('new-tree/newdir/newfile', 'new\n')])
786
        self.new_tree.add('newdir')
787
        self.new_tree.add('newdir/newfile', 'file-id')
788
3009.2.27 by Aaron Bentley
Use extra_factories instead of extra_diffs
789
    def test_register_diff(self):
3009.2.16 by Aaron Bentley
Test support for extra differs
790
        self.create_old_new()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
791
        old_diff_factories = diff.DiffTree.diff_factories
792
        diff.DiffTree.diff_factories=old_diff_factories[:]
793
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
3009.2.16 by Aaron Bentley
Test support for extra differs
794
        try:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
795
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
3009.2.16 by Aaron Bentley
Test support for extra differs
796
        finally:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
797
            diff.DiffTree.diff_factories = old_diff_factories
3009.2.16 by Aaron Bentley
Test support for extra differs
798
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
799
        self.assertNotContainsRe(
800
            differ.to_file.getvalue(),
801
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
802
             ' \@\@\n-old\n\+new\n\n')
803
        self.assertContainsRe(differ.to_file.getvalue(),
804
                              'was: old\nis: new\n')
805
3009.2.27 by Aaron Bentley
Use extra_factories instead of extra_diffs
806
    def test_extra_factories(self):
3009.2.16 by Aaron Bentley
Test support for extra differs
807
        self.create_old_new()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
808
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
809
                               extra_factories=[DiffWasIs.from_diff_tree])
3009.2.16 by Aaron Bentley
Test support for extra differs
810
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
811
        self.assertNotContainsRe(
812
            differ.to_file.getvalue(),
813
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
814
             ' \@\@\n-old\n\+new\n\n')
815
        self.assertContainsRe(differ.to_file.getvalue(),
816
                              'was: old\nis: new\n')
817
3123.4.1 by Aaron Bentley
Diff sorts files in alphabetical order
818
    def test_alphabetical_order(self):
819
        self.build_tree(['new-tree/a-file'])
820
        self.new_tree.add('a-file')
821
        self.build_tree(['old-tree/b-file'])
822
        self.old_tree.add('b-file')
823
        self.differ.show_diff(None)
824
        self.assertContainsRe(self.differ.to_file.getvalue(),
825
            '.*a-file(.|\n)*b-file')
826
3009.2.9 by Aaron Bentley
Add tests for Differ
827
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
828
class TestPatienceDiffLib(tests.TestCase):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
829
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
830
    def setUp(self):
831
        super(TestPatienceDiffLib, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
832
        self._unique_lcs = _patiencediff_py.unique_lcs_py
833
        self._recurse_matches = _patiencediff_py.recurse_matches_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
834
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
835
            _patiencediff_py.PatienceSequenceMatcher_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
836
3628.1.3 by Lukáš Lalinský
Add a test
837
    def test_diff_unicode_string(self):
838
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
839
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
840
        sm = self._PatienceSequenceMatcher(None, a, b)
841
        mb = sm.get_matching_blocks()
842
        self.assertEquals(35, len(mb))
843
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
844
    def test_unique_lcs(self):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
845
        unique_lcs = self._unique_lcs
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
846
        self.assertEquals(unique_lcs('', ''), [])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
847
        self.assertEquals(unique_lcs('', 'a'), [])
848
        self.assertEquals(unique_lcs('a', ''), [])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
849
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
850
        self.assertEquals(unique_lcs('a', 'b'), [])
851
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
852
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
853
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
854
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
855
                                                         (3,3), (4,4)])
856
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
857
858
    def test_recurse_matches(self):
859
        def test_one(a, b, matches):
860
            test_matches = []
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
861
            self._recurse_matches(
862
                a, b, 0, 0, len(a), len(b), test_matches, 10)
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
863
            self.assertEquals(test_matches, matches)
864
1711.2.17 by John Arbash Meinel
Small cleanups to patience_diff code.
865
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
866
                 [(0, 0), (2, 2), (4, 4)])
867
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
868
                 [(0, 0), (2, 1), (4, 2)])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
869
        # Even though 'bc' is not unique globally, and is surrounded by
870
        # non-matching lines, we should still match, because they are locally
871
        # unique
872
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
873
                                          (4, 6), (5, 7), (6, 8)])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
874
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
875
        # recurse_matches doesn't match non-unique
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
876
        # lines surrounded by bogus text.
1185.81.24 by Aaron Bentley
Reoganize patience-related code
877
        # The update has been done in patiencediff.SequenceMatcher instead
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
878
879
        # This is what it could be
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
880
        #test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
881
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
882
        # This is what it currently gives:
883
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
884
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
885
    def assertDiffBlocks(self, a, b, expected_blocks):
886
        """Check that the sequence matcher returns the correct blocks.
887
888
        :param a: A sequence to match
889
        :param b: Another sequence to match
890
        :param expected_blocks: The expected output, not including the final
891
            matching block (len(a), len(b), 0)
892
        """
893
        matcher = self._PatienceSequenceMatcher(None, a, b)
894
        blocks = matcher.get_matching_blocks()
895
        last = blocks.pop()
896
        self.assertEqual((len(a), len(b), 0), last)
897
        self.assertEqual(expected_blocks, blocks)
898
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
899
    def test_matching_blocks(self):
1185.81.2 by John Arbash Meinel
A couple small tests.
900
        # Some basic matching tests
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
901
        self.assertDiffBlocks('', '', [])
902
        self.assertDiffBlocks([], [], [])
903
        self.assertDiffBlocks('abc', '', [])
904
        self.assertDiffBlocks('', 'abc', [])
905
        self.assertDiffBlocks('abcd', 'abcd', [(0, 0, 4)])
906
        self.assertDiffBlocks('abcd', 'abce', [(0, 0, 3)])
907
        self.assertDiffBlocks('eabc', 'abce', [(1, 0, 3)])
908
        self.assertDiffBlocks('eabce', 'abce', [(1, 0, 4)])
909
        self.assertDiffBlocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
910
        self.assertDiffBlocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
911
        self.assertDiffBlocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
912
        # This may check too much, but it checks to see that
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
913
        # a copied block stays attached to the previous section,
914
        # not the later one.
915
        # difflib would tend to grab the trailing longest match
916
        # which would make the diff not look right
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
917
        self.assertDiffBlocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
918
                              [(0, 0, 6), (6, 11, 10)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
919
1185.81.2 by John Arbash Meinel
A couple small tests.
920
        # make sure it supports passing in lists
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
921
        self.assertDiffBlocks(
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
922
                   ['hello there\n',
923
                    'world\n',
924
                    'how are you today?\n'],
925
                   ['hello there\n',
926
                    'how are you today?\n'],
1185.81.2 by John Arbash Meinel
A couple small tests.
927
                [(0, 0, 1), (2, 1, 1)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
928
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
929
        # non unique lines surrounded by non-matching lines
930
        # won't be found
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
931
        self.assertDiffBlocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
932
933
        # But they only need to be locally unique
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
934
        self.assertDiffBlocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
935
936
        # non unique blocks won't be matched
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
937
        self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
938
939
        # but locally unique ones will
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
940
        self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
941
                                              (5,4,1), (7,5,2), (10,8,1)])
942
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
943
        self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7,7,1)])
944
        self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
945
        self.assertDiffBlocks('bbbbbbbb', 'cbbbbbbc', [])
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
946
3074.2.1 by John Arbash Meinel
Change the C PatienceDiff implementation to support arbitrary objects.
947
    def test_matching_blocks_tuples(self):
948
        # Some basic matching tests
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
949
        self.assertDiffBlocks([], [], [])
950
        self.assertDiffBlocks([('a',), ('b',), ('c,')], [], [])
951
        self.assertDiffBlocks([], [('a',), ('b',), ('c,')], [])
952
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
953
                              [('a',), ('b',), ('c,')],
954
                              [(0, 0, 3)])
955
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
956
                              [('a',), ('b',), ('d,')],
957
                              [(0, 0, 2)])
958
        self.assertDiffBlocks([('d',), ('b',), ('c,')],
959
                              [('a',), ('b',), ('c,')],
960
                              [(1, 1, 2)])
961
        self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
962
                              [('a',), ('b',), ('c,')],
963
                              [(1, 0, 3)])
964
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
965
                              [('a', 'b'), ('c', 'X'), ('e', 'f')],
966
                              [(0, 0, 1), (2, 2, 1)])
967
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
968
                              [('a', 'b'), ('c', 'dX'), ('e', 'f')],
969
                              [(0, 0, 1), (2, 2, 1)])
3074.2.1 by John Arbash Meinel
Change the C PatienceDiff implementation to support arbitrary objects.
970
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
971
    def test_opcodes(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
972
        def chk_ops(a, b, expected_codes):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
973
            s = self._PatienceSequenceMatcher(None, a, b)
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
974
            self.assertEquals(expected_codes, s.get_opcodes())
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
975
976
        chk_ops('', '', [])
977
        chk_ops([], [], [])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
978
        chk_ops('abc', '', [('delete', 0,3, 0,0)])
979
        chk_ops('', 'abc', [('insert', 0,0, 0,3)])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
980
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
981
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
982
                                 ('replace', 3,4, 3,4)
983
                                ])
984
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
985
                                 ('equal',  1,4, 0,3),
986
                                 ('insert', 4,4, 3,4)
987
                                ])
988
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
989
                                  ('equal',  1,5, 0,4)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
990
                                 ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
991
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
992
                                   ('replace', 2,3, 2,3),
993
                                   ('equal',   3,5, 3,5)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
994
                                  ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
995
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
996
                                     ('replace', 2,3, 2,5),
997
                                     ('equal',   3,5, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
998
                                    ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
999
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
1000
                                    ('insert', 2,2, 2,5),
1001
                                    ('equal',  2,4, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
1002
                                   ])
1003
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1004
                [('equal',  0,6,  0,6),
1005
                 ('insert', 6,6,  6,11),
1006
                 ('equal',  6,16, 11,21)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
1007
                ])
1008
        chk_ops(
1009
                [ 'hello there\n'
1010
                , 'world\n'
1011
                , 'how are you today?\n'],
1012
                [ 'hello there\n'
1013
                , 'how are you today?\n'],
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1014
                [('equal',  0,1, 0,1),
1015
                 ('delete', 1,2, 1,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1016
                 ('equal',  2,3, 1,2),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
1017
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1018
        chk_ops('aBccDe', 'abccde',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1019
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1020
                 ('replace', 1,5, 1,5),
1021
                 ('equal',   5,6, 5,6),
1022
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1023
        chk_ops('aBcDec', 'abcdec',
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1024
                [('equal',   0,1, 0,1),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1025
                 ('replace', 1,2, 1,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1026
                 ('equal',   2,3, 2,3),
1027
                 ('replace', 3,4, 3,4),
1028
                 ('equal',   4,6, 4,6),
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
1029
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1030
        chk_ops('aBcdEcdFg', 'abcdecdfg',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1031
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1032
                 ('replace', 1,8, 1,8),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1033
                 ('equal',   8,9, 8,9)
1185.81.10 by John Arbash Meinel
Added some more test cases.
1034
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1035
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1036
                [('equal',   0,1, 0,1),
1037
                 ('replace', 1,2, 1,2),
1038
                 ('equal',   2,4, 2,4),
1039
                 ('delete', 4,5, 4,4),
1040
                 ('equal',   5,6, 4,5),
1041
                 ('delete', 6,7, 5,5),
1042
                 ('equal',   7,9, 5,7),
1043
                 ('replace', 9,10, 7,8),
1044
                 ('equal',   10,11, 8,9)
1045
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
1046
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1047
    def test_grouped_opcodes(self):
1048
        def chk_ops(a, b, expected_codes, n=3):
1049
            s = self._PatienceSequenceMatcher(None, a, b)
1050
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
1051
1052
        chk_ops('', '', [])
1053
        chk_ops([], [], [])
1054
        chk_ops('abc', '', [[('delete', 0,3, 0,0)]])
1055
        chk_ops('', 'abc', [[('insert', 0,0, 0,3)]])
1056
        chk_ops('abcd', 'abcd', [])
1057
        chk_ops('abcd', 'abce', [[('equal',   0,3, 0,3),
1058
                                  ('replace', 3,4, 3,4)
1059
                                 ]])
1060
        chk_ops('eabc', 'abce', [[('delete', 0,1, 0,0),
1061
                                 ('equal',  1,4, 0,3),
1062
                                 ('insert', 4,4, 3,4)
1063
                                ]])
1064
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1065
                [[('equal',  3,6, 3,6),
1066
                  ('insert', 6,6, 6,11),
1067
                  ('equal',  6,9, 11,14)
1068
                  ]])
1069
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1070
                [[('equal',  2,6, 2,6),
1071
                  ('insert', 6,6, 6,11),
1072
                  ('equal',  6,10, 11,15)
1073
                  ]], 4)
1074
        chk_ops('Xabcdef', 'abcdef',
1075
                [[('delete', 0,1, 0,0),
1076
                  ('equal',  1,4, 0,3)
1077
                  ]])
1078
        chk_ops('abcdef', 'abcdefX',
1079
                [[('equal',  3,6, 3,6),
1080
                  ('insert', 6,6, 6,7)
1081
                  ]])
1082
1083
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
1084
    def test_multiple_ranges(self):
1085
        # There was an earlier bug where we used a bad set of ranges,
1086
        # this triggers that specific bug, to make sure it doesn't regress
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1087
        self.assertDiffBlocks('abcdefghijklmnop',
1088
                              'abcXghiYZQRSTUVWXYZijklmnop',
1089
                              [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
1090
1091
        self.assertDiffBlocks('ABCd efghIjk  L',
1092
                              'AxyzBCn mo pqrstuvwI1 2  L',
1093
                              [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
1094
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1095
        # These are rot13 code snippets.
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1096
        self.assertDiffBlocks('''\
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1097
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1098
    """
1099
    gnxrf_netf = ['svyr*']
1100
    gnxrf_bcgvbaf = ['ab-erphefr']
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1101
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1102
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1103
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1104
        vs vf_dhvrg():
1105
            ercbegre = nqq_ercbegre_ahyy
1106
        ryfr:
1107
            ercbegre = nqq_ercbegre_cevag
1108
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
1109
1110
1111
pynff pzq_zxqve(Pbzznaq):
1112
'''.splitlines(True), '''\
1113
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1114
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1115
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1116
    nqq gurz.
1117
    """
1118
    gnxrf_netf = ['svyr*']
1119
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
1120
1121
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
1122
        vzcbeg omeyvo.nqq
1123
1124
        vs qel_eha:
1125
            vs vf_dhvrg():
1126
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
1127
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
1128
            ryfr:
1129
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
1130
        ryvs vf_dhvrg():
1131
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
1132
        ryfr:
1133
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
1134
1135
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
1136
1137
1138
pynff pzq_zxqve(Pbzznaq):
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
1139
'''.splitlines(True)
1140
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1141
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1142
    def test_patience_unified_diff(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1143
        txt_a = ['hello there\n',
1144
                 'world\n',
1145
                 'how are you today?\n']
1146
        txt_b = ['hello there\n',
1147
                 'how are you today?\n']
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1148
        unified_diff = patiencediff.unified_diff
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1149
        psm = self._PatienceSequenceMatcher
3922.1.3 by John Arbash Meinel
fix some odd spacing.
1150
        self.assertEquals(['--- \n',
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1151
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1152
                           '@@ -1,3 +1,2 @@\n',
1153
                           ' hello there\n',
1154
                           '-world\n',
1155
                           ' how are you today?\n'
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1156
                          ]
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
1157
                          , list(unified_diff(txt_a, txt_b,
1158
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1159
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1160
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1161
        # This is the result with LongestCommonSubstring matching
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1162
        self.assertEquals(['--- \n',
1163
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1164
                           '@@ -1,6 +1,11 @@\n',
1165
                           ' a\n',
1166
                           ' b\n',
1167
                           ' c\n',
1168
                           '+d\n',
1169
                           '+e\n',
1170
                           '+f\n',
1171
                           '+x\n',
1172
                           '+y\n',
1173
                           ' d\n',
1174
                           ' e\n',
1175
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1176
                          , list(unified_diff(txt_a, txt_b)))
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1177
        # And the patience diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1178
        self.assertEquals(['--- \n',
1179
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1180
                           '@@ -4,6 +4,11 @@\n',
1181
                           ' d\n',
1182
                           ' e\n',
1183
                           ' f\n',
1184
                           '+x\n',
1185
                           '+y\n',
1186
                           '+d\n',
1187
                           '+e\n',
1188
                           '+f\n',
1189
                           ' g\n',
1190
                           ' h\n',
1191
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1192
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1193
                          , list(unified_diff(txt_a, txt_b,
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
1194
                                 sequencematcher=psm)))
1185.81.25 by Aaron Bentley
Clean up test_diff
1195
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1196
    def test_patience_unified_diff_with_dates(self):
1197
        txt_a = ['hello there\n',
1198
                 'world\n',
1199
                 'how are you today?\n']
1200
        txt_b = ['hello there\n',
1201
                 'how are you today?\n']
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1202
        unified_diff = patiencediff.unified_diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1203
        psm = self._PatienceSequenceMatcher
3922.1.4 by John Arbash Meinel
It turns out that internal_diff worked around the trailing whitespace problem
1204
        self.assertEquals(['--- a\t2008-08-08\n',
1205
                           '+++ b\t2008-09-09\n',
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1206
                           '@@ -1,3 +1,2 @@\n',
1207
                           ' hello there\n',
1208
                           '-world\n',
1209
                           ' how are you today?\n'
1210
                          ]
1211
                          , list(unified_diff(txt_a, txt_b,
1212
                                 fromfile='a', tofile='b',
1213
                                 fromfiledate='2008-08-08',
1214
                                 tofiledate='2008-09-09',
1215
                                 sequencematcher=psm)))
1216
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1217
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1218
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1219
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1220
    _test_needs_features = [features.compiled_patiencediff_feature]
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1221
1222
    def setUp(self):
1223
        super(TestPatienceDiffLib_c, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1224
        from bzrlib import _patiencediff_c
1225
        self._unique_lcs = _patiencediff_c.unique_lcs_c
1226
        self._recurse_matches = _patiencediff_c.recurse_matches_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1227
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1228
            _patiencediff_c.PatienceSequenceMatcher_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1229
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1230
    def test_unhashable(self):
1231
        """We should get a proper exception here."""
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1232
        # We need to be able to hash items in the sequence, lists are
1233
        # unhashable, and thus cannot be diffed
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1234
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1235
                                         None, [[]], [])
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1236
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1237
                                         None, ['valid', []], [])
1238
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1239
                                         None, ['valid'], [[]])
1240
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1241
                                         None, ['valid'], ['valid', []])
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1242
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1243
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1244
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1245
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1246
    def setUp(self):
1247
        super(TestPatienceDiffLibFiles, self).setUp()
1248
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1249
            _patiencediff_py.PatienceSequenceMatcher_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1250
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1251
    def test_patience_unified_diff_files(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1252
        txt_a = ['hello there\n',
1253
                 'world\n',
1254
                 'how are you today?\n']
1255
        txt_b = ['hello there\n',
1256
                 'how are you today?\n']
6437.20.3 by Wouter van Heyst
mechanically replace file().write() pattern with a with-keyword version
1257
        with open('a1', 'wb') as f: f.writelines(txt_a)
1258
        with open('b1', 'wb') as f: f.writelines(txt_b)
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1259
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1260
        unified_diff_files = patiencediff.unified_diff_files
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1261
        psm = self._PatienceSequenceMatcher
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1262
        self.assertEquals(['--- a1\n',
1263
                           '+++ b1\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1264
                           '@@ -1,3 +1,2 @@\n',
1265
                           ' hello there\n',
1266
                           '-world\n',
1267
                           ' how are you today?\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1268
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1269
                          , list(unified_diff_files('a1', 'b1',
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
1270
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1271
1272
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1273
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
6437.20.3 by Wouter van Heyst
mechanically replace file().write() pattern with a with-keyword version
1274
        with open('a2', 'wb') as f: f.writelines(txt_a)
1275
        with open('b2', 'wb') as f: f.writelines(txt_b)
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1276
1277
        # This is the result with LongestCommonSubstring matching
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1278
        self.assertEquals(['--- a2\n',
1279
                           '+++ b2\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1280
                           '@@ -1,6 +1,11 @@\n',
1281
                           ' a\n',
1282
                           ' b\n',
1283
                           ' c\n',
1284
                           '+d\n',
1285
                           '+e\n',
1286
                           '+f\n',
1287
                           '+x\n',
1288
                           '+y\n',
1289
                           ' d\n',
1290
                           ' e\n',
1291
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1292
                          , list(unified_diff_files('a2', 'b2')))
1293
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1294
        # And the patience diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1295
        self.assertEquals(['--- a2\n',
1296
                           '+++ b2\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1297
                           '@@ -4,6 +4,11 @@\n',
1298
                           ' d\n',
1299
                           ' e\n',
1300
                           ' f\n',
1301
                           '+x\n',
1302
                           '+y\n',
1303
                           '+d\n',
1304
                           '+e\n',
1305
                           '+f\n',
1306
                           ' g\n',
1307
                           ' h\n',
1308
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1309
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1310
                          , list(unified_diff_files('a2', 'b2',
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
1311
                                 sequencematcher=psm)))
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1312
1313
1314
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1315
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1316
    _test_needs_features = [features.compiled_patiencediff_feature]
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1317
1318
    def setUp(self):
1319
        super(TestPatienceDiffLibFiles_c, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1320
        from bzrlib import _patiencediff_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1321
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1322
            _patiencediff_c.PatienceSequenceMatcher_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1323
1324
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1325
class TestUsingCompiledIfAvailable(tests.TestCase):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1326
1327
    def test_PatienceSequenceMatcher(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1328
        if features.compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1329
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1330
            self.assertIs(PatienceSequenceMatcher_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1331
                          patiencediff.PatienceSequenceMatcher)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1332
        else:
1333
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1334
            self.assertIs(PatienceSequenceMatcher_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1335
                          patiencediff.PatienceSequenceMatcher)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1336
1337
    def test_unique_lcs(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1338
        if features.compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1339
            from bzrlib._patiencediff_c import unique_lcs_c
1340
            self.assertIs(unique_lcs_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1341
                          patiencediff.unique_lcs)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1342
        else:
1343
            from bzrlib._patiencediff_py import unique_lcs_py
1344
            self.assertIs(unique_lcs_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1345
                          patiencediff.unique_lcs)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1346
1347
    def test_recurse_matches(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1348
        if features.compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1349
            from bzrlib._patiencediff_c import recurse_matches_c
1350
            self.assertIs(recurse_matches_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1351
                          patiencediff.recurse_matches)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1352
        else:
1353
            from bzrlib._patiencediff_py import recurse_matches_py
1354
            self.assertIs(recurse_matches_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1355
                          patiencediff.recurse_matches)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1356
1357
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1358
class TestDiffFromTool(tests.TestCaseWithTransport):
3123.6.2 by Aaron Bentley
Implement diff --using natively
1359
1360
    def test_from_string(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1361
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1362
        self.addCleanup(diff_obj.finish)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
1363
        self.assertEqual(['diff', '@old_path', '@new_path'],
3123.6.2 by Aaron Bentley
Implement diff --using natively
1364
            diff_obj.command_template)
3199.1.6 by Vincent Ladeuil
Fiz last leaking tmp dir.
1365
1366
    def test_from_string_u5(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1367
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1368
                                                 None, None, None)
3199.1.6 by Vincent Ladeuil
Fiz last leaking tmp dir.
1369
        self.addCleanup(diff_obj.finish)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
1370
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
3123.6.2 by Aaron Bentley
Implement diff --using natively
1371
                         diff_obj.command_template)
1372
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1373
                         diff_obj._get_command('old-path', 'new-path'))
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1374
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1375
    def test_from_string_path_with_backslashes(self):
5241.2.2 by Robert Collins
Missed one test.
1376
        self.requireFeature(features.backslashdir_feature)
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1377
        tool = 'C:\\Tools\\Diff.exe'
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1378
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1379
        self.addCleanup(diff_obj.finish)
1380
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1381
                         diff_obj.command_template)
1382
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
1383
                         diff_obj._get_command('old-path', 'new-path'))
3123.6.2 by Aaron Bentley
Implement diff --using natively
1384
1385
    def test_execute(self):
1386
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1387
        diff_obj = diff.DiffFromTool(['python', '-c',
1388
                                      'print "@old_path @new_path"'],
1389
                                     None, None, output)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1390
        self.addCleanup(diff_obj.finish)
1391
        diff_obj._execute('old', 'new')
3146.4.2 by Aaron Bentley
Avoid assuming unix newline on output
1392
        self.assertEqual(output.getvalue().rstrip(), 'old new')
3123.6.2 by Aaron Bentley
Implement diff --using natively
1393
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1394
    def test_excute_missing(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1395
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1396
                                     None, None, None)
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1397
        self.addCleanup(diff_obj.finish)
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1398
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
1399
                              'old', 'new')
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1400
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1401
                         ' on this machine', str(e))
1402
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1403
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1404
        self.requireFeature(features.AttribFeature)
3287.18.10 by Matt McClure
Uses TestSkipped for test_execute_windows_tool on non-Windows platforms.
1405
        output = StringIO()
1406
        tree = self.make_branch_and_tree('tree')
1407
        self.build_tree_contents([('tree/file', 'content')])
1408
        tree.add('file', 'file-id')
3287.18.11 by Matt McClure
Removed unnecessary timestamp parameter.
1409
        tree.commit('old tree')
3287.18.10 by Matt McClure
Uses TestSkipped for test_execute_windows_tool on non-Windows platforms.
1410
        tree.lock_read()
1411
        self.addCleanup(tree.unlock)
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1412
        basis_tree = tree.basis_tree()
1413
        basis_tree.lock_read()
1414
        self.addCleanup(basis_tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1415
        diff_obj = diff.DiffFromTool(['python', '-c',
1416
                                      'print "@old_path @new_path"'],
1417
                                     basis_tree, tree, output)
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1418
        diff_obj._prepare_files('file-id', 'file', 'file')
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1419
        # The old content should be readonly
1420
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1421
                                    r'R.*old\\file$')
1422
        # The new content should use the tree object, not a 'new' file anymore
1423
        self.assertEndsWith(tree.basedir, 'work/tree')
1424
        self.assertReadableByAttrib(tree.basedir, 'file', r'work\\tree\\file$')
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1425
1426
    def assertReadableByAttrib(self, cwd, relpath, regex):
1427
        proc = subprocess.Popen(['attrib', relpath],
1428
                                stdout=subprocess.PIPE,
1429
                                cwd=cwd)
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1430
        (result, err) = proc.communicate()
1431
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
3287.18.9 by Matt McClure
Adds a test asserting that a Windows tool that understands forward slashes
1432
3123.6.2 by Aaron Bentley
Implement diff --using natively
1433
    def test_prepare_files(self):
1434
        output = StringIO()
1435
        tree = self.make_branch_and_tree('tree')
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1436
        self.build_tree_contents([('tree/oldname', 'oldcontent')])
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1437
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1438
        tree.add('oldname', 'file-id')
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1439
        tree.add('oldname2', 'file2-id')
5151.3.1 by Martin
Fix os.utime test failures, three on FAT filesystems and one with readonly files
1440
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
1441
        tree.commit('old tree', timestamp=315532800)
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1442
        tree.rename_one('oldname', 'newname')
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1443
        tree.rename_one('oldname2', 'newname2')
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1444
        self.build_tree_contents([('tree/newname', 'newcontent')])
3287.19.1 by Matt McClure
Fixes https://bugs.launchpad.net/bzr/+bug/212289. I submitted this patch.
1445
        self.build_tree_contents([('tree/newname2', 'newcontent2')])
3123.6.2 by Aaron Bentley
Implement diff --using natively
1446
        old_tree = tree.basis_tree()
1447
        old_tree.lock_read()
1448
        self.addCleanup(old_tree.unlock)
3123.6.4 by Aaron Bentley
Set mtime (and atime) on files for --using
1449
        tree.lock_read()
1450
        self.addCleanup(tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1451
        diff_obj = diff.DiffFromTool(['python', '-c',
1452
                                      'print "@old_path @new_path"'],
1453
                                     old_tree, tree, output)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1454
        self.addCleanup(diff_obj.finish)
1455
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1456
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1457
                                                     'newname')
1458
        self.assertContainsRe(old_path, 'old/oldname$')
5151.3.1 by Martin
Fix os.utime test failures, three on FAT filesystems and one with readonly files
1459
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
4845.2.1 by Gary van der Merwe
When launching an external diff app, don't write temporary files for a working tree.
1460
        self.assertContainsRe(new_path, 'tree/newname$')
3123.6.2 by Aaron Bentley
Implement diff --using natively
1461
        self.assertFileEqual('oldcontent', old_path)
1462
        self.assertFileEqual('newcontent', new_path)
3287.18.14 by Matt McClure
Extracted a host_os_dereferences_symlinks method.
1463
        if osutils.host_os_dereferences_symlinks():
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1464
            self.assertTrue(os.path.samefile('tree/newname', new_path))
3123.6.2 by Aaron Bentley
Implement diff --using natively
1465
        # make sure we can create files with the same parent directories
3287.18.25 by Matt McClure
Uses the correct file_id as the argument to _prepare_files.
1466
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1467
1468
5074.5.4 by INADA Naoki
fix easy bug.
1469
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
5074.5.2 by INADA Naoki
Add test for encoded filenames
1470
1471
    def test_encodable_filename(self):
5074.5.9 by INADA Naoki
Make additional comments to clarify
1472
        # Just checks file path for external diff tool.
1473
        # We cannot change CPython's internal encoding used by os.exec*.
5074.5.2 by INADA Naoki
Add test for encoded filenames
1474
        import sys
5074.5.9 by INADA Naoki
Make additional comments to clarify
1475
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1476
                                    None, None, None)
5074.5.2 by INADA Naoki
Add test for encoded filenames
1477
        for _, scenario in EncodingAdapter.encoding_scenarios:
1478
            encoding = scenario['encoding']
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1479
            dirname  = scenario['info']['directory']
5074.5.2 by INADA Naoki
Add test for encoded filenames
1480
            filename = scenario['info']['filename']
5074.5.6 by INADA Naoki
Change directry name for each check.
1481
5074.5.8 by INADA Naoki
Use tempfile when filepath in tree is not be able to encode with fsencoding.
1482
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1483
            relpath = dirname + u'/' + filename
1484
            fullpath = diffobj._safe_filename('safe', relpath)
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1485
            self.assertEqual(
1486
                    fullpath,
1487
                    fullpath.encode(encoding).decode(encoding)
1488
                    )
1489
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
5074.5.2 by INADA Naoki
Add test for encoded filenames
1490
1491
    def test_unencodable_filename(self):
1492
        import sys
5074.5.9 by INADA Naoki
Make additional comments to clarify
1493
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1494
                                    None, None, None)
5074.5.2 by INADA Naoki
Add test for encoded filenames
1495
        for _, scenario in EncodingAdapter.encoding_scenarios:
1496
            encoding = scenario['encoding']
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1497
            dirname  = scenario['info']['directory']
5074.5.2 by INADA Naoki
Add test for encoded filenames
1498
            filename = scenario['info']['filename']
1499
1500
            if encoding == 'iso-8859-1':
1501
                encoding = 'iso-8859-2'
1502
            else:
1503
                encoding = 'iso-8859-1'
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1504
5074.5.8 by INADA Naoki
Use tempfile when filepath in tree is not be able to encode with fsencoding.
1505
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1506
            relpath = dirname + u'/' + filename
1507
            fullpath = diffobj._safe_filename('safe', relpath)
5074.5.7 by INADA Naoki
Test for filename encoding can't test subprocess execution because
1508
            self.assertEqual(
1509
                    fullpath,
1510
                    fullpath.encode(encoding).decode(encoding)
1511
                    )
1512
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
5074.5.2 by INADA Naoki
Add test for encoded filenames
1513
1514
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1515
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1516
1517
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
6027.1.4 by Vincent Ladeuil
Remove ``diff.get_trees_and_branches_to_diff`` deprecated in 2.2.0 and the corrsponding tests.
1518
        """Call get_trees_and_branches_to_diff_locked."""
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1519
        return diff.get_trees_and_branches_to_diff_locked(
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1520
            path_list, revision_specs, old_url, new_url, self.addCleanup)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1521
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1522
    def test_basic(self):
1523
        tree = self.make_branch_and_tree('tree')
1524
        (old_tree, new_tree,
1525
         old_branch, new_branch,
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1526
         specific_files, extra_trees) = self.call_gtabtd(
1527
             ['tree'], None, None, None)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1528
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1529
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1530
        self.assertEqual(_mod_revision.NULL_REVISION,
1531
                         old_tree.get_revision_id())
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1532
        self.assertEqual(tree.basedir, new_tree.basedir)
1533
        self.assertEqual(tree.branch.base, old_branch.base)
1534
        self.assertEqual(tree.branch.base, new_branch.base)
1535
        self.assertIs(None, specific_files)
1536
        self.assertIs(None, extra_trees)
1537
1538
    def test_with_rev_specs(self):
1539
        tree = self.make_branch_and_tree('tree')
1540
        self.build_tree_contents([('tree/file', 'oldcontent')])
1541
        tree.add('file', 'file-id')
1542
        tree.commit('old tree', timestamp=0, rev_id="old-id")
1543
        self.build_tree_contents([('tree/file', 'newcontent')])
1544
        tree.commit('new tree', timestamp=0, rev_id="new-id")
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1545
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1546
        revisions = [revisionspec.RevisionSpec.from_string('1'),
1547
                     revisionspec.RevisionSpec.from_string('2')]
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1548
        (old_tree, new_tree,
1549
         old_branch, new_branch,
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1550
         specific_files, extra_trees) = self.call_gtabtd(
1551
            ['tree'], revisions, None, None)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1552
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1553
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1554
        self.assertEqual("old-id", old_tree.get_revision_id())
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1555
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1556
        self.assertEqual("new-id", new_tree.get_revision_id())
1557
        self.assertEqual(tree.branch.base, old_branch.base)
1558
        self.assertEqual(tree.branch.base, new_branch.base)
1559
        self.assertIs(None, specific_files)
4705.1.4 by Gary van der Merwe
Add newline to end of test_diff.py
1560
        self.assertEqual(tree.basedir, extra_trees[0].basedir)