~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
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.
 
12
#
 
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import os
1
18
from cStringIO import StringIO
 
19
import errno
 
20
import subprocess
 
21
from tempfile import TemporaryFile
2
22
 
3
 
from bzrlib.diff import internal_diff
4
 
from bzrlib.errors import BinaryFile
5
 
from bzrlib.patiencediff import (recurse_matches, SequenceMatcher, unique_lcs,
6
 
                                 unified_diff, unified_diff_files)
7
 
from bzrlib.tests import TestCase, TestCaseInTempDir
 
23
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
 
24
from bzrlib.errors import BinaryFile, NoDiff
 
25
import bzrlib.patiencediff
 
26
from bzrlib.tests import (TestCase, TestCaseWithTransport,
 
27
                          TestCaseInTempDir, TestSkipped)
8
28
 
9
29
 
10
30
def udiff_lines(old, new, allow_binary=False):
14
34
    return output.readlines()
15
35
 
16
36
 
 
37
def external_udiff_lines(old, new, use_stringio=False):
 
38
    if use_stringio:
 
39
        # StringIO has no fileno, so it tests a different codepath
 
40
        output = StringIO()
 
41
    else:
 
42
        output = TemporaryFile()
 
43
    try:
 
44
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
45
    except NoDiff:
 
46
        raise TestSkipped('external "diff" not present to test')
 
47
    output.seek(0, 0)
 
48
    lines = output.readlines()
 
49
    output.close()
 
50
    return lines
 
51
 
 
52
 
17
53
class TestDiff(TestCase):
18
54
 
19
55
    def test_add_nl(self):
61
97
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
62
98
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
63
99
 
64
 
 
65
 
class TestCDVDiffLib(TestCase):
 
100
    def test_external_diff(self):
 
101
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
 
102
        self.check_patch(lines)
 
103
        self.assertEqual('\n', lines[-1])
 
104
 
 
105
    def test_external_diff_no_fileno(self):
 
106
        # Make sure that we can handle not having a fileno, even
 
107
        # if the diff is large
 
108
        lines = external_udiff_lines(['boo\n']*10000,
 
109
                                     ['goo\n']*10000,
 
110
                                     use_stringio=True)
 
111
        self.check_patch(lines)
 
112
 
 
113
    def test_external_diff_binary_lang_c(self):
 
114
        orig_lang = os.environ.get('LANG')
 
115
        orig_lc_all = os.environ.get('LC_ALL')
 
116
        try:
 
117
            os.environ['LANG'] = 'C'
 
118
            os.environ['LC_ALL'] = 'C'
 
119
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
120
            # Older versions of diffutils say "Binary files", newer
 
121
            # versions just say "Files".
 
122
            self.assertContainsRe(lines[0],
 
123
                                  '(Binary f|F)iles old and new differ\n')
 
124
            self.assertEquals(lines[1:], ['\n'])
 
125
        finally:
 
126
            for name, value in [('LANG', orig_lang), ('LC_ALL', orig_lc_all)]:
 
127
                if value is None:
 
128
                    del os.environ[name]
 
129
                else:
 
130
                    os.environ[name] = value
 
131
 
 
132
    def test_no_external_diff(self):
 
133
        """Check that NoDiff is raised when diff is not available"""
 
134
        # Use os.environ['PATH'] to make sure no 'diff' command is available
 
135
        orig_path = os.environ['PATH']
 
136
        try:
 
137
            os.environ['PATH'] = ''
 
138
            self.assertRaises(NoDiff, external_diff,
 
139
                              'old', ['boo\n'], 'new', ['goo\n'],
 
140
                              StringIO(), diff_opts=['-u'])
 
141
        finally:
 
142
            os.environ['PATH'] = orig_path
 
143
        
 
144
    def test_internal_diff_default(self):
 
145
        # Default internal diff encoding is utf8
 
146
        output = StringIO()
 
147
        internal_diff(u'old_\xb5', ['old_text\n'],
 
148
                    u'new_\xe5', ['new_text\n'], output)
 
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_utf8(self):
 
161
        output = StringIO()
 
162
        internal_diff(u'old_\xb5', ['old_text\n'],
 
163
                    u'new_\xe5', ['new_text\n'], output,
 
164
                    path_encoding='utf8')
 
165
        lines = output.getvalue().splitlines(True)
 
166
        self.check_patch(lines)
 
167
        self.assertEquals(['--- old_\xc2\xb5\n',
 
168
                           '+++ new_\xc3\xa5\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_iso_8859_1(self):
 
177
        output = StringIO()
 
178
        internal_diff(u'old_\xb5', ['old_text\n'],
 
179
                    u'new_\xe5', ['new_text\n'], output,
 
180
                    path_encoding='iso-8859-1')
 
181
        lines = output.getvalue().splitlines(True)
 
182
        self.check_patch(lines)
 
183
        self.assertEquals(['--- old_\xb5\n',
 
184
                           '+++ new_\xe5\n',
 
185
                           '@@ -1,1 +1,1 @@\n',
 
186
                           '-old_text\n',
 
187
                           '+new_text\n',
 
188
                           '\n',
 
189
                          ]
 
190
                          , lines)
 
191
 
 
192
    def test_internal_diff_returns_bytes(self):
 
193
        import StringIO
 
194
        output = StringIO.StringIO()
 
195
        internal_diff(u'old_\xb5', ['old_text\n'],
 
196
                    u'new_\xe5', ['new_text\n'], output)
 
197
        self.failUnless(isinstance(output.getvalue(), str),
 
198
            'internal_diff should return bytestrings')
 
199
 
 
200
 
 
201
class TestDiffFiles(TestCaseInTempDir):
 
202
 
 
203
    def test_external_diff_binary(self):
 
204
        """The output when using external diff should use diff's i18n error"""
 
205
        # Make sure external_diff doesn't fail in the current LANG
 
206
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
207
 
 
208
        cmd = ['diff', '-u', '--binary', 'old', 'new']
 
209
        open('old', 'wb').write('\x00foobar\n')
 
210
        open('new', 'wb').write('foo\x00bar\n')
 
211
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
 
212
                                     stdin=subprocess.PIPE)
 
213
        out, err = pipe.communicate()
 
214
        # Diff returns '2' on Binary files.
 
215
        self.assertEqual(2, pipe.returncode)
 
216
        # We should output whatever diff tells us, plus a trailing newline
 
217
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
 
218
 
 
219
 
 
220
class TestDiffDates(TestCaseWithTransport):
 
221
 
 
222
    def setUp(self):
 
223
        super(TestDiffDates, self).setUp()
 
224
        self.wt = self.make_branch_and_tree('.')
 
225
        self.b = self.wt.branch
 
226
        self.build_tree_contents([
 
227
            ('file1', 'file1 contents at rev 1\n'),
 
228
            ('file2', 'file2 contents at rev 1\n')
 
229
            ])
 
230
        self.wt.add(['file1', 'file2'])
 
231
        self.wt.commit(
 
232
            message='Revision 1',
 
233
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
 
234
            timezone=0,
 
235
            rev_id='rev-1')
 
236
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
 
237
        self.wt.commit(
 
238
            message='Revision 2',
 
239
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
 
240
            timezone=28800,
 
241
            rev_id='rev-2')
 
242
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
 
243
        self.wt.commit(
 
244
            message='Revision 3',
 
245
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
 
246
            timezone=-3600,
 
247
            rev_id='rev-3')
 
248
        self.wt.remove(['file2'])
 
249
        self.wt.commit(
 
250
            message='Revision 4',
 
251
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
 
252
            timezone=0,
 
253
            rev_id='rev-4')
 
254
        self.build_tree_contents([
 
255
            ('file1', 'file1 contents in working tree\n')
 
256
            ])
 
257
        # set the date stamps for files in the working tree to known values
 
258
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
 
259
 
 
260
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
 
261
        output = StringIO()
 
262
        if working_tree is not None:
 
263
            extra_trees = (working_tree,)
 
264
        else:
 
265
            extra_trees = ()
 
266
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
 
267
                        extra_trees=extra_trees, old_label='old/', 
 
268
                        new_label='new/')
 
269
        return output.getvalue()
 
270
 
 
271
    def test_diff_rev_tree_working_tree(self):
 
272
        output = self.get_diff(self.wt.basis_tree(), self.wt)
 
273
        # note that the date for old/file1 is from rev 2 rather than from
 
274
        # the basis revision (rev 4)
 
275
        self.assertEqualDiff(output, '''\
 
276
=== modified file 'file1'
 
277
--- old/file1\t2006-04-02 00:00:00 +0000
 
278
+++ new/file1\t2006-04-05 00:00:00 +0000
 
279
@@ -1,1 +1,1 @@
 
280
-file1 contents at rev 2
 
281
+file1 contents in working tree
 
282
 
 
283
''')
 
284
 
 
285
    def test_diff_rev_tree_rev_tree(self):
 
286
        tree1 = self.b.repository.revision_tree('rev-2')
 
287
        tree2 = self.b.repository.revision_tree('rev-3')
 
288
        output = self.get_diff(tree1, tree2)
 
289
        self.assertEqualDiff(output, '''\
 
290
=== modified file 'file2'
 
291
--- old/file2\t2006-04-01 00:00:00 +0000
 
292
+++ new/file2\t2006-04-03 00:00:00 +0000
 
293
@@ -1,1 +1,1 @@
 
294
-file2 contents at rev 1
 
295
+file2 contents at rev 3
 
296
 
 
297
''')
 
298
        
 
299
    def test_diff_add_files(self):
 
300
        tree1 = self.b.repository.revision_tree(None)
 
301
        tree2 = self.b.repository.revision_tree('rev-1')
 
302
        output = self.get_diff(tree1, tree2)
 
303
        # the files have the epoch time stamp for the tree in which
 
304
        # they don't exist.
 
305
        self.assertEqualDiff(output, '''\
 
306
=== added file 'file1'
 
307
--- old/file1\t1970-01-01 00:00:00 +0000
 
308
+++ new/file1\t2006-04-01 00:00:00 +0000
 
309
@@ -0,0 +1,1 @@
 
310
+file1 contents at rev 1
 
311
 
 
312
=== added file 'file2'
 
313
--- old/file2\t1970-01-01 00:00:00 +0000
 
314
+++ new/file2\t2006-04-01 00:00:00 +0000
 
315
@@ -0,0 +1,1 @@
 
316
+file2 contents at rev 1
 
317
 
 
318
''')
 
319
 
 
320
    def test_diff_remove_files(self):
 
321
        tree1 = self.b.repository.revision_tree('rev-3')
 
322
        tree2 = self.b.repository.revision_tree('rev-4')
 
323
        output = self.get_diff(tree1, tree2)
 
324
        # the file has the epoch time stamp for the tree in which
 
325
        # it doesn't exist.
 
326
        self.assertEqualDiff(output, '''\
 
327
=== removed file 'file2'
 
328
--- old/file2\t2006-04-03 00:00:00 +0000
 
329
+++ new/file2\t1970-01-01 00:00:00 +0000
 
330
@@ -1,1 +0,0 @@
 
331
-file2 contents at rev 3
 
332
 
 
333
''')
 
334
 
 
335
    def test_show_diff_specified(self):
 
336
        """A working tree filename can be used to identify a file"""
 
337
        self.wt.rename_one('file1', 'file1b')
 
338
        old_tree = self.b.repository.revision_tree('rev-1')
 
339
        new_tree = self.b.repository.revision_tree('rev-4')
 
340
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
 
341
                            working_tree=self.wt)
 
342
        self.assertContainsRe(out, 'file1\t')
 
343
 
 
344
    def test_recursive_diff(self):
 
345
        """Children of directories are matched"""
 
346
        os.mkdir('dir1')
 
347
        os.mkdir('dir2')
 
348
        self.wt.add(['dir1', 'dir2'])
 
349
        self.wt.rename_one('file1', 'dir1/file1')
 
350
        old_tree = self.b.repository.revision_tree('rev-1')
 
351
        new_tree = self.b.repository.revision_tree('rev-4')
 
352
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
 
353
                            working_tree=self.wt)
 
354
        self.assertContainsRe(out, 'file1\t')
 
355
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
 
356
                            working_tree=self.wt)
 
357
        self.assertNotContainsRe(out, 'file1\t')
 
358
 
 
359
 
 
360
class TestPatienceDiffLib(TestCase):
66
361
 
67
362
    def test_unique_lcs(self):
 
363
        unique_lcs = bzrlib.patiencediff.unique_lcs
68
364
        self.assertEquals(unique_lcs('', ''), [])
69
365
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
70
366
        self.assertEquals(unique_lcs('a', 'b'), [])
78
374
    def test_recurse_matches(self):
79
375
        def test_one(a, b, matches):
80
376
            test_matches = []
81
 
            recurse_matches(a, b, len(a), len(b), test_matches, 10)
 
377
            bzrlib.patiencediff.recurse_matches(a, b, 0, 0, len(a), len(b),
 
378
                test_matches, 10)
82
379
            self.assertEquals(test_matches, matches)
83
380
 
84
 
        test_one(['a', None, 'b', None, 'c'], ['a', 'a', 'b', 'c', 'c'],
 
381
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
85
382
                 [(0, 0), (2, 2), (4, 4)])
86
383
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
87
384
                 [(0, 0), (2, 1), (4, 2)])
97
394
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
98
395
 
99
396
    def test_matching_blocks(self):
100
 
        def chk_blocks(a, b, matching):
 
397
        def chk_blocks(a, b, expected_blocks):
101
398
            # difflib always adds a signature of the total
102
399
            # length, with no matching entries at the end
103
 
            s = SequenceMatcher(None, a, b)
 
400
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
104
401
            blocks = s.get_matching_blocks()
105
 
            x = blocks.pop()
106
 
            self.assertEquals(x, (len(a), len(b), 0))
107
 
            self.assertEquals(matching, blocks)
 
402
            self.assertEquals((len(a), len(b), 0), blocks[-1])
 
403
            self.assertEquals(expected_blocks, blocks[:-1])
108
404
 
109
405
        # Some basic matching tests
110
406
        chk_blocks('', '', [])
133
429
                    'how are you today?\n'],
134
430
                [(0, 0, 1), (2, 1, 1)])
135
431
 
136
 
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (2,2,2), (5,5,1)])
137
 
 
138
 
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
139
 
                                              (5,5,2), (8,8,1)])
140
 
 
141
 
        chk_blocks('abbabbXd', 'cabbabxd', [(0,1,5), (7,7,1)])
142
 
        chk_blocks('abbabbbb', 'cabbabbc', [(0,1,6)])
143
 
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [(0,1,6)])
 
432
        # non unique lines surrounded by non-matching lines
 
433
        # won't be found
 
434
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
 
435
 
 
436
        # But they only need to be locally unique
 
437
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
 
438
 
 
439
        # non unique blocks won't be matched
 
440
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
 
441
 
 
442
        # but locally unique ones will
 
443
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
 
444
                                              (5,4,1), (7,5,2), (10,8,1)])
 
445
 
 
446
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
 
447
        chk_blocks('abbabbbb', 'cabbabbc', [])
 
448
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
144
449
 
145
450
    def test_opcodes(self):
146
 
        def chk_ops(a, b, codes):
147
 
            s = SequenceMatcher(None, a, b)
148
 
            self.assertEquals(codes, s.get_opcodes())
 
451
        def chk_ops(a, b, expected_codes):
 
452
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
 
453
            self.assertEquals(expected_codes, s.get_opcodes())
149
454
 
150
455
        chk_ops('', '', [])
151
456
        chk_ops([], [], [])
185
490
                , 'how are you today?\n'],
186
491
                [('equal',  0,1, 0,1),
187
492
                 ('delete', 1,2, 1,1),
188
 
                 ('equal',  2,3, 1,2)
 
493
                 ('equal',  2,3, 1,2),
189
494
                ])
190
495
        chk_ops('aBccDe', 'abccde', 
191
496
                [('equal',   0,1, 0,1),
 
497
                 ('replace', 1,5, 1,5),
 
498
                 ('equal',   5,6, 5,6),
 
499
                ])
 
500
        chk_ops('aBcDec', 'abcdec', 
 
501
                [('equal',   0,1, 0,1),
192
502
                 ('replace', 1,2, 1,2),
193
 
                 ('equal',   2,4, 2,4),
194
 
                 ('replace', 4,5, 4,5),
195
 
                 ('equal',   5,6, 5,6)
 
503
                 ('equal',   2,3, 2,3),
 
504
                 ('replace', 3,4, 3,4),
 
505
                 ('equal',   4,6, 4,6),
196
506
                ])
197
507
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
198
508
                [('equal',   0,1, 0,1),
199
 
                 ('replace', 1,2, 1,2),
200
 
                 ('equal',   2,4, 2,4),
201
 
                 ('replace', 4,5, 4,5),
202
 
                 ('equal',   5,7, 5,7),
203
 
                 ('replace', 7,8, 7,8),
 
509
                 ('replace', 1,8, 1,8),
204
510
                 ('equal',   8,9, 8,9)
205
511
                ])
 
512
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
 
513
                [('equal',   0,1, 0,1),
 
514
                 ('replace', 1,2, 1,2),
 
515
                 ('equal',   2,4, 2,4),
 
516
                 ('delete', 4,5, 4,4),
 
517
                 ('equal',   5,6, 4,5),
 
518
                 ('delete', 6,7, 5,5),
 
519
                 ('equal',   7,9, 5,7),
 
520
                 ('replace', 9,10, 7,8),
 
521
                 ('equal',   10,11, 8,9)
 
522
                ])
206
523
 
207
524
    def test_multiple_ranges(self):
208
525
        # There was an earlier bug where we used a bad set of ranges,
209
526
        # this triggers that specific bug, to make sure it doesn't regress
210
 
        def chk_blocks(a, b, matching):
 
527
        def chk_blocks(a, b, expected_blocks):
211
528
            # difflib always adds a signature of the total
212
529
            # length, with no matching entries at the end
213
 
            s = SequenceMatcher(None, a, b)
 
530
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
214
531
            blocks = s.get_matching_blocks()
215
532
            x = blocks.pop()
216
533
            self.assertEquals(x, (len(a), len(b), 0))
217
 
            self.assertEquals(matching, blocks)
 
534
            self.assertEquals(expected_blocks, blocks)
218
535
 
219
536
        chk_blocks('abcdefghijklmnop'
220
537
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
222
539
 
223
540
        chk_blocks('ABCd efghIjk  L'
224
541
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
225
 
                 , [(0,0,1), (1, 4, 2), (4, 7, 1), (9, 19, 1), (12, 23, 3)])
 
542
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
226
543
 
 
544
        # These are rot13 code snippets.
227
545
        chk_blocks('''\
228
 
    get added when you add a file in the directory.
229
 
    """
230
 
    takes_args = ['file*']
231
 
    takes_options = ['no-recurse']
232
 
    
233
 
    def run(self, file_list, no_recurse=False):
234
 
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
235
 
        if is_quiet():
236
 
            reporter = add_reporter_null
237
 
        else:
238
 
            reporter = add_reporter_print
239
 
        smart_add(file_list, not no_recurse, reporter)
240
 
 
241
 
 
242
 
class cmd_mkdir(Command):
243
 
'''.splitlines(True)
244
 
, '''\
245
 
    get added when you add a file in the directory.
246
 
 
247
 
    --dry-run will show which files would be added, but not actually 
248
 
    add them.
249
 
    """
250
 
    takes_args = ['file*']
251
 
    takes_options = ['no-recurse', 'dry-run']
252
 
 
253
 
    def run(self, file_list, no_recurse=False, dry_run=False):
254
 
        import bzrlib.add
255
 
 
256
 
        if dry_run:
257
 
            if is_quiet():
258
 
                # This is pointless, but I'd rather not raise an error
259
 
                action = bzrlib.add.add_action_null
260
 
            else:
261
 
                action = bzrlib.add.add_action_print
262
 
        elif is_quiet():
263
 
            action = bzrlib.add.add_action_add
264
 
        else:
265
 
            action = bzrlib.add.add_action_add_and_print
266
 
 
267
 
        bzrlib.add.smart_add(file_list, not no_recurse, action)
268
 
 
269
 
 
270
 
class cmd_mkdir(Command):
 
546
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
 
547
    """
 
548
    gnxrf_netf = ['svyr*']
 
549
    gnxrf_bcgvbaf = ['ab-erphefr']
 
550
  
 
551
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
 
552
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
 
553
        vs vf_dhvrg():
 
554
            ercbegre = nqq_ercbegre_ahyy
 
555
        ryfr:
 
556
            ercbegre = nqq_ercbegre_cevag
 
557
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
 
558
 
 
559
 
 
560
pynff pzq_zxqve(Pbzznaq):
 
561
'''.splitlines(True), '''\
 
562
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
 
563
 
 
564
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
 
565
    nqq gurz.
 
566
    """
 
567
    gnxrf_netf = ['svyr*']
 
568
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
 
569
 
 
570
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
 
571
        vzcbeg omeyvo.nqq
 
572
 
 
573
        vs qel_eha:
 
574
            vs vf_dhvrg():
 
575
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
 
576
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
 
577
            ryfr:
 
578
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
 
579
        ryvs vf_dhvrg():
 
580
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
 
581
        ryfr:
 
582
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
 
583
 
 
584
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
 
585
 
 
586
 
 
587
pynff pzq_zxqve(Pbzznaq):
271
588
'''.splitlines(True)
272
589
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
273
590
 
274
 
    def test_cdv_unified_diff(self):
 
591
    def test_patience_unified_diff(self):
275
592
        txt_a = ['hello there\n',
276
593
                 'world\n',
277
594
                 'how are you today?\n']
278
595
        txt_b = ['hello there\n',
279
596
                 'how are you today?\n']
 
597
        unified_diff = bzrlib.patiencediff.unified_diff
 
598
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
280
599
        self.assertEquals([ '---  \n',
281
600
                           '+++  \n',
282
601
                           '@@ -1,3 +1,2 @@\n',
284
603
                           '-world\n',
285
604
                           ' how are you today?\n'
286
605
                          ]
287
 
                          , list(unified_diff(txt_a, txt_b
288
 
                                        , sequencematcher=SequenceMatcher)))
 
606
                          , list(unified_diff(txt_a, txt_b,
 
607
                                 sequencematcher=psm)))
289
608
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
290
609
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
291
610
        # This is the result with LongestCommonSubstring matching
304
623
                           ' e\n',
305
624
                           ' f\n']
306
625
                          , list(unified_diff(txt_a, txt_b)))
307
 
        # And the cdv diff
 
626
        # And the patience diff
308
627
        self.assertEquals(['---  \n',
309
628
                           '+++  \n',
310
629
                           '@@ -4,6 +4,11 @@\n',
321
640
                           ' i\n',
322
641
                          ]
323
642
                          , list(unified_diff(txt_a, txt_b,
324
 
                                 sequencematcher=SequenceMatcher)))
325
 
 
326
 
 
327
 
class TestCDVDiffLibFiles(TestCaseInTempDir):
328
 
 
329
 
    def test_cdv_unified_diff_files(self):
 
643
                                 sequencematcher=psm)))
 
644
 
 
645
 
 
646
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
647
 
 
648
    def test_patience_unified_diff_files(self):
330
649
        txt_a = ['hello there\n',
331
650
                 'world\n',
332
651
                 'how are you today?\n']
335
654
        open('a1', 'wb').writelines(txt_a)
336
655
        open('b1', 'wb').writelines(txt_b)
337
656
 
 
657
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
658
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
338
659
        self.assertEquals(['--- a1 \n',
339
660
                           '+++ b1 \n',
340
661
                           '@@ -1,3 +1,2 @@\n',
343
664
                           ' how are you today?\n',
344
665
                          ]
345
666
                          , list(unified_diff_files('a1', 'b1',
346
 
                                 sequencematcher=SequenceMatcher)))
 
667
                                 sequencematcher=psm)))
347
668
 
348
669
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
349
670
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
367
688
                           ' f\n']
368
689
                          , list(unified_diff_files('a2', 'b2')))
369
690
 
370
 
        # And the cdv diff
 
691
        # And the patience diff
371
692
        self.assertEquals(['--- a2 \n',
372
693
                           '+++ b2 \n',
373
694
                           '@@ -4,6 +4,11 @@\n',
384
705
                           ' i\n',
385
706
                          ]
386
707
                          , list(unified_diff_files('a2', 'b2',
387
 
                                 sequencematcher=SequenceMatcher)))
 
708
                                 sequencematcher=psm)))