~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

Late bind to PatienceSequenceMatcher to allow plugin to override.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
import os
18
17
from cStringIO import StringIO
19
 
import errno
20
 
from tempfile import TemporaryFile
21
18
 
22
 
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
23
 
from bzrlib.errors import BinaryFile, NoDiff
 
19
from bzrlib.diff import internal_diff
 
20
from bzrlib.errors import BinaryFile
24
21
import bzrlib.patiencediff
25
 
from bzrlib.tests import (TestCase, TestCaseWithTransport,
26
 
                          TestCaseInTempDir, TestSkipped)
 
22
from bzrlib.tests import TestCase, TestCaseInTempDir
27
23
 
28
24
 
29
25
def udiff_lines(old, new, allow_binary=False):
33
29
    return output.readlines()
34
30
 
35
31
 
36
 
def external_udiff_lines(old, new, use_stringio=False):
37
 
    if use_stringio:
38
 
        # StringIO has no fileno, so it tests a different codepath
39
 
        output = StringIO()
40
 
    else:
41
 
        output = TemporaryFile()
42
 
    try:
43
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
44
 
    except NoDiff:
45
 
        raise TestSkipped('external "diff" not present to test')
46
 
    output.seek(0, 0)
47
 
    lines = output.readlines()
48
 
    output.close()
49
 
    return lines
50
 
 
51
 
 
52
32
class TestDiff(TestCase):
53
33
 
54
34
    def test_add_nl(self):
96
76
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
97
77
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
98
78
 
99
 
    def test_external_diff(self):
100
 
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
101
 
        self.check_patch(lines)
102
 
        self.assertEqual('\n', lines[-1])
103
 
 
104
 
    def test_external_diff_no_fileno(self):
105
 
        # Make sure that we can handle not having a fileno, even
106
 
        # if the diff is large
107
 
        lines = external_udiff_lines(['boo\n']*10000,
108
 
                                     ['goo\n']*10000,
109
 
                                     use_stringio=True)
110
 
        self.check_patch(lines)
111
 
 
112
 
    def test_external_diff_binary(self):
113
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
114
 
        self.assertEqual(['Binary files old and new differ\n', '\n'], lines)
115
 
 
116
 
    def test_no_external_diff(self):
117
 
        """Check that NoDiff is raised when diff is not available"""
118
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
119
 
        orig_path = os.environ['PATH']
120
 
        try:
121
 
            os.environ['PATH'] = ''
122
 
            self.assertRaises(NoDiff, external_diff,
123
 
                              'old', ['boo\n'], 'new', ['goo\n'],
124
 
                              StringIO(), diff_opts=['-u'])
125
 
        finally:
126
 
            os.environ['PATH'] = orig_path
127
 
        
128
 
    def test_internal_diff_default(self):
129
 
        # Default internal diff encoding is utf8
130
 
        output = StringIO()
131
 
        internal_diff(u'old_\xb5', ['old_text\n'],
132
 
                    u'new_\xe5', ['new_text\n'], output)
133
 
        lines = output.getvalue().splitlines(True)
134
 
        self.check_patch(lines)
135
 
        self.assertEquals(['--- old_\xc2\xb5\n',
136
 
                           '+++ new_\xc3\xa5\n',
137
 
                           '@@ -1,1 +1,1 @@\n',
138
 
                           '-old_text\n',
139
 
                           '+new_text\n',
140
 
                           '\n',
141
 
                          ]
142
 
                          , lines)
143
 
 
144
 
    def test_internal_diff_utf8(self):
145
 
        output = StringIO()
146
 
        internal_diff(u'old_\xb5', ['old_text\n'],
147
 
                    u'new_\xe5', ['new_text\n'], output,
148
 
                    path_encoding='utf8')
149
 
        lines = output.getvalue().splitlines(True)
150
 
        self.check_patch(lines)
151
 
        self.assertEquals(['--- old_\xc2\xb5\n',
152
 
                           '+++ new_\xc3\xa5\n',
153
 
                           '@@ -1,1 +1,1 @@\n',
154
 
                           '-old_text\n',
155
 
                           '+new_text\n',
156
 
                           '\n',
157
 
                          ]
158
 
                          , lines)
159
 
 
160
 
    def test_internal_diff_iso_8859_1(self):
161
 
        output = StringIO()
162
 
        internal_diff(u'old_\xb5', ['old_text\n'],
163
 
                    u'new_\xe5', ['new_text\n'], output,
164
 
                    path_encoding='iso-8859-1')
165
 
        lines = output.getvalue().splitlines(True)
166
 
        self.check_patch(lines)
167
 
        self.assertEquals(['--- old_\xb5\n',
168
 
                           '+++ new_\xe5\n',
169
 
                           '@@ -1,1 +1,1 @@\n',
170
 
                           '-old_text\n',
171
 
                           '+new_text\n',
172
 
                           '\n',
173
 
                          ]
174
 
                          , lines)
175
 
 
176
 
    def test_internal_diff_returns_bytes(self):
177
 
        import StringIO
178
 
        output = StringIO.StringIO()
179
 
        internal_diff(u'old_\xb5', ['old_text\n'],
180
 
                    u'new_\xe5', ['new_text\n'], output)
181
 
        self.failUnless(isinstance(output.getvalue(), str),
182
 
            'internal_diff should return bytestrings')
183
 
 
184
 
 
185
 
class TestDiffDates(TestCaseWithTransport):
186
 
 
187
 
    def setUp(self):
188
 
        super(TestDiffDates, self).setUp()
189
 
        self.wt = self.make_branch_and_tree('.')
190
 
        self.b = self.wt.branch
191
 
        self.build_tree_contents([
192
 
            ('file1', 'file1 contents at rev 1\n'),
193
 
            ('file2', 'file2 contents at rev 1\n')
194
 
            ])
195
 
        self.wt.add(['file1', 'file2'])
196
 
        self.wt.commit(
197
 
            message='Revision 1',
198
 
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
199
 
            timezone=0,
200
 
            rev_id='rev-1')
201
 
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
202
 
        self.wt.commit(
203
 
            message='Revision 2',
204
 
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
205
 
            timezone=28800,
206
 
            rev_id='rev-2')
207
 
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
208
 
        self.wt.commit(
209
 
            message='Revision 3',
210
 
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
211
 
            timezone=-3600,
212
 
            rev_id='rev-3')
213
 
        self.wt.remove(['file2'])
214
 
        self.wt.commit(
215
 
            message='Revision 4',
216
 
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
217
 
            timezone=0,
218
 
            rev_id='rev-4')
219
 
        self.build_tree_contents([
220
 
            ('file1', 'file1 contents in working tree\n')
221
 
            ])
222
 
        # set the date stamps for files in the working tree to known values
223
 
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
224
 
 
225
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
226
 
        output = StringIO()
227
 
        if working_tree is not None:
228
 
            extra_trees = (working_tree,)
229
 
        else:
230
 
            extra_trees = ()
231
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
232
 
                        extra_trees=extra_trees, old_label='old/', 
233
 
                        new_label='new/')
234
 
        return output.getvalue()
235
 
 
236
 
    def test_diff_rev_tree_working_tree(self):
237
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
238
 
        # note that the date for old/file1 is from rev 2 rather than from
239
 
        # the basis revision (rev 4)
240
 
        self.assertEqualDiff(output, '''\
241
 
=== modified file 'file1'
242
 
--- old/file1\t2006-04-02 00:00:00 +0000
243
 
+++ new/file1\t2006-04-05 00:00:00 +0000
244
 
@@ -1,1 +1,1 @@
245
 
-file1 contents at rev 2
246
 
+file1 contents in working tree
247
 
 
248
 
''')
249
 
 
250
 
    def test_diff_rev_tree_rev_tree(self):
251
 
        tree1 = self.b.repository.revision_tree('rev-2')
252
 
        tree2 = self.b.repository.revision_tree('rev-3')
253
 
        output = self.get_diff(tree1, tree2)
254
 
        self.assertEqualDiff(output, '''\
255
 
=== modified file 'file2'
256
 
--- old/file2\t2006-04-01 00:00:00 +0000
257
 
+++ new/file2\t2006-04-03 00:00:00 +0000
258
 
@@ -1,1 +1,1 @@
259
 
-file2 contents at rev 1
260
 
+file2 contents at rev 3
261
 
 
262
 
''')
263
 
        
264
 
    def test_diff_add_files(self):
265
 
        tree1 = self.b.repository.revision_tree(None)
266
 
        tree2 = self.b.repository.revision_tree('rev-1')
267
 
        output = self.get_diff(tree1, tree2)
268
 
        # the files have the epoch time stamp for the tree in which
269
 
        # they don't exist.
270
 
        self.assertEqualDiff(output, '''\
271
 
=== added file 'file1'
272
 
--- old/file1\t1970-01-01 00:00:00 +0000
273
 
+++ new/file1\t2006-04-01 00:00:00 +0000
274
 
@@ -0,0 +1,1 @@
275
 
+file1 contents at rev 1
276
 
 
277
 
=== added file 'file2'
278
 
--- old/file2\t1970-01-01 00:00:00 +0000
279
 
+++ new/file2\t2006-04-01 00:00:00 +0000
280
 
@@ -0,0 +1,1 @@
281
 
+file2 contents at rev 1
282
 
 
283
 
''')
284
 
 
285
 
    def test_diff_remove_files(self):
286
 
        tree1 = self.b.repository.revision_tree('rev-3')
287
 
        tree2 = self.b.repository.revision_tree('rev-4')
288
 
        output = self.get_diff(tree1, tree2)
289
 
        # the file has the epoch time stamp for the tree in which
290
 
        # it doesn't exist.
291
 
        self.assertEqualDiff(output, '''\
292
 
=== removed file 'file2'
293
 
--- old/file2\t2006-04-03 00:00:00 +0000
294
 
+++ new/file2\t1970-01-01 00:00:00 +0000
295
 
@@ -1,1 +0,0 @@
296
 
-file2 contents at rev 3
297
 
 
298
 
''')
299
 
 
300
 
    def test_show_diff_specified(self):
301
 
        """A working tree filename can be used to identify a file"""
302
 
        self.wt.rename_one('file1', 'file1b')
303
 
        old_tree = self.b.repository.revision_tree('rev-1')
304
 
        new_tree = self.b.repository.revision_tree('rev-4')
305
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
306
 
                            working_tree=self.wt)
307
 
        self.assertContainsRe(out, 'file1\t')
308
 
 
309
 
    def test_recursive_diff(self):
310
 
        """Children of directories are matched"""
311
 
        os.mkdir('dir1')
312
 
        os.mkdir('dir2')
313
 
        self.wt.add(['dir1', 'dir2'])
314
 
        self.wt.rename_one('file1', 'dir1/file1')
315
 
        old_tree = self.b.repository.revision_tree('rev-1')
316
 
        new_tree = self.b.repository.revision_tree('rev-4')
317
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
318
 
                            working_tree=self.wt)
319
 
        self.assertContainsRe(out, 'file1\t')
320
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
321
 
                            working_tree=self.wt)
322
 
        self.assertNotContainsRe(out, 'file1\t')
323
 
 
324
79
 
325
80
class TestPatienceDiffLib(TestCase):
326
81