/breezy/unstable

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy/unstable

« back to all changes in this revision

Viewing changes to breezy/tests/test_diff.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-24 01:39:33 UTC
  • mfrom: (3815.3776.6)
  • Revision ID: jelmer@jelmer.uk-20170524013933-ir4y4tqtrsiz2ka2
New upstream snapshot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2014, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2014, 2016, 2017 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
from cStringIO import StringIO
19
18
import subprocess
20
19
import tempfile
21
20
 
22
 
from bzrlib import (
 
21
from .. import (
23
22
    diff,
24
23
    errors,
25
24
    osutils,
31
30
    tests,
32
31
    transform,
33
32
    )
34
 
from bzrlib.tests import (
 
33
from ..sixish import (
 
34
    BytesIO,
 
35
    )
 
36
from ..tests import (
35
37
    features,
36
38
    EncodingAdapter,
37
 
)
38
 
from bzrlib.tests.blackbox.test_diff import subst_dates
39
 
from bzrlib.tests.scenarios import load_tests_apply_scenarios
 
39
    )
 
40
from ..tests.blackbox.test_diff import subst_dates
 
41
from ..tests.scenarios import load_tests_apply_scenarios
40
42
 
41
43
 
42
44
load_tests = load_tests_apply_scenarios
43
45
 
44
46
 
45
47
def udiff_lines(old, new, allow_binary=False):
46
 
    output = StringIO()
 
48
    output = BytesIO()
47
49
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
48
50
    output.seek(0, 0)
49
51
    return output.readlines()
51
53
 
52
54
def external_udiff_lines(old, new, use_stringio=False):
53
55
    if use_stringio:
54
 
        # StringIO has no fileno, so it tests a different codepath
55
 
        output = StringIO()
 
56
        # BytesIO has no fileno, so it tests a different codepath
 
57
        output = BytesIO()
56
58
    else:
57
59
        output = tempfile.TemporaryFile()
58
60
    try:
65
67
    return lines
66
68
 
67
69
 
 
70
class StubO(object):
 
71
    """Simple file-like object that allows writes with any type and records."""
 
72
 
 
73
    def __init__(self):
 
74
        self.write_record = []
 
75
 
 
76
    def write(self, data):
 
77
        self.write_record.append(data)
 
78
 
 
79
    def check_types(self, testcase, expected_type):
 
80
        testcase.assertFalse(
 
81
            any(not isinstance(o, expected_type) for o in self.write_record),
 
82
            "Not all writes of type %s: %r" % (
 
83
                expected_type.__name__, self.write_record))
 
84
 
 
85
 
68
86
class TestDiffOptions(tests.TestCase):
69
87
 
70
88
    def test_unified_added(self):
166
184
        self.overrideEnv('PATH', '')
167
185
        self.assertRaises(errors.NoDiff, diff.external_diff,
168
186
                          'old', ['boo\n'], 'new', ['goo\n'],
169
 
                          StringIO(), diff_opts=['-u'])
 
187
                          BytesIO(), diff_opts=['-u'])
170
188
 
171
189
    def test_internal_diff_default(self):
172
190
        # Default internal diff encoding is utf8
173
 
        output = StringIO()
 
191
        output = BytesIO()
174
192
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
175
193
                           u'new_\xe5', ['new_text\n'], output)
176
194
        lines = output.getvalue().splitlines(True)
185
203
                          , lines)
186
204
 
187
205
    def test_internal_diff_utf8(self):
188
 
        output = StringIO()
 
206
        output = BytesIO()
189
207
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
190
208
                           u'new_\xe5', ['new_text\n'], output,
191
209
                           path_encoding='utf8')
201
219
                          , lines)
202
220
 
203
221
    def test_internal_diff_iso_8859_1(self):
204
 
        output = StringIO()
 
222
        output = BytesIO()
205
223
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
206
224
                           u'new_\xe5', ['new_text\n'], output,
207
225
                           path_encoding='iso-8859-1')
217
235
                          , lines)
218
236
 
219
237
    def test_internal_diff_no_content(self):
220
 
        output = StringIO()
 
238
        output = BytesIO()
221
239
        diff.internal_diff(u'old', [], u'new', [], output)
222
240
        self.assertEqual('', output.getvalue())
223
241
 
224
242
    def test_internal_diff_no_changes(self):
225
 
        output = StringIO()
 
243
        output = BytesIO()
226
244
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
227
245
                           u'new', ['text\n', 'contents\n'],
228
246
                           output)
229
247
        self.assertEqual('', output.getvalue())
230
248
 
231
249
    def test_internal_diff_returns_bytes(self):
232
 
        import StringIO
233
 
        output = StringIO.StringIO()
 
250
        output = StubO()
234
251
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
235
252
                            u'new_\xe5', ['new_text\n'], output)
236
 
        self.assertIsInstance(output.getvalue(), str,
237
 
            'internal_diff should return bytestrings')
 
253
        output.check_types(self, bytes)
238
254
 
239
255
    def test_internal_diff_default_context(self):
240
 
        output = StringIO()
 
256
        output = BytesIO()
241
257
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
242
258
                           'same_text\n','same_text\n','old_text\n'],
243
259
                           'new', ['same_text\n','same_text\n','same_text\n',
257
273
                          , lines)
258
274
 
259
275
    def test_internal_diff_no_context(self):
260
 
        output = StringIO()
 
276
        output = BytesIO()
261
277
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
262
278
                           'same_text\n','same_text\n','old_text\n'],
263
279
                           'new', ['same_text\n','same_text\n','same_text\n',
275
291
                          , lines)
276
292
 
277
293
    def test_internal_diff_more_context(self):
278
 
        output = StringIO()
 
294
        output = BytesIO()
279
295
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
280
296
                           'same_text\n','same_text\n','old_text\n'],
281
297
                           'new', ['same_text\n','same_text\n','same_text\n',
313
329
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
314
330
                                     stdin=subprocess.PIPE)
315
331
        out, err = pipe.communicate()
316
 
        # Diff returns '2' on Binary files.
317
 
        self.assertEqual(2, pipe.returncode)
318
332
        # We should output whatever diff tells us, plus a trailing newline
319
333
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
320
334
 
321
335
 
322
336
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
323
 
    output = StringIO()
 
337
    output = BytesIO()
324
338
    if working_tree is not None:
325
339
        extra_trees = (working_tree,)
326
340
    else:
586
600
        # See https://bugs.launchpad.net/bugs/110092.
587
601
        self.requireFeature(features.UnicodeFilenameFeature)
588
602
 
589
 
        # This bug isn't triggered with cStringIO.
590
 
        from StringIO import StringIO
591
603
        tree = self.make_branch_and_tree('tree')
592
604
        alpha, omega = u'\u03b1', u'\u03c9'
593
605
        alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
597
609
              ('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
598
610
        tree.add([alpha], ['file-id'])
599
611
        tree.add([omega], ['file-id-2'])
600
 
        diff_content = StringIO()
 
612
        diff_content = StubO()
601
613
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
602
 
        d = diff_content.getvalue()
 
614
        diff_content.check_types(self, bytes)
 
615
        d = b''.join(diff_content.write_record)
603
616
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
604
617
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
605
618
                              % (alpha_utf8, alpha_utf8))
656
669
            ])
657
670
        tree.add([test_txt, u1234, directory])
658
671
 
659
 
        sio = StringIO()
 
672
        sio = BytesIO()
660
673
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
661
674
            path_encoding='cp1251')
662
675
 
701
714
        self.new_tree = self.make_branch_and_tree('new-tree')
702
715
        self.new_tree.lock_write()
703
716
        self.addCleanup(self.new_tree.unlock)
704
 
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
717
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
705
718
 
706
719
    def test_diff_text(self):
707
720
        self.build_tree_contents([('old-tree/olddir/',),
712
725
                                  ('new-tree/newdir/newfile', 'new\n')])
713
726
        self.new_tree.add('newdir')
714
727
        self.new_tree.add('newdir/newfile', 'file-id')
715
 
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
 
728
        differ = diff.DiffText(self.old_tree, self.new_tree, BytesIO())
716
729
        differ.diff_text('file-id', None, 'old label', 'new label')
717
730
        self.assertEqual(
718
731
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
747
760
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
748
761
 
749
762
    def test_diff_symlink(self):
750
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
763
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
751
764
        differ.diff_symlink('old target', None)
752
765
        self.assertEqual("=== target was 'old target'\n",
753
766
                         differ.to_file.getvalue())
754
767
 
755
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
768
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
756
769
        differ.diff_symlink(None, 'new target')
757
770
        self.assertEqual("=== target is 'new target'\n",
758
771
                         differ.to_file.getvalue())
759
772
 
760
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
773
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, BytesIO())
761
774
        differ.diff_symlink('old target', 'new target')
762
775
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
763
776
                         differ.to_file.getvalue())
817
830
        diff.DiffTree.diff_factories=old_diff_factories[:]
818
831
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
819
832
        try:
820
 
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
833
            differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO())
821
834
        finally:
822
835
            diff.DiffTree.diff_factories = old_diff_factories
823
836
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
830
843
 
831
844
    def test_extra_factories(self):
832
845
        self.create_old_new()
833
 
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
846
        differ = diff.DiffTree(self.old_tree, self.new_tree, BytesIO(),
834
847
                               extra_factories=[DiffWasIs.from_diff_tree])
835
848
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
836
849
        self.assertNotContainsRe(
1246
1259
 
1247
1260
    def setUp(self):
1248
1261
        super(TestPatienceDiffLib_c, self).setUp()
1249
 
        from bzrlib import _patiencediff_c
 
1262
        from breezy import _patiencediff_c
1250
1263
        self._unique_lcs = _patiencediff_c.unique_lcs_c
1251
1264
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1252
1265
        self._PatienceSequenceMatcher = \
1341
1354
 
1342
1355
    def setUp(self):
1343
1356
        super(TestPatienceDiffLibFiles_c, self).setUp()
1344
 
        from bzrlib import _patiencediff_c
 
1357
        from breezy import _patiencediff_c
1345
1358
        self._PatienceSequenceMatcher = \
1346
1359
            _patiencediff_c.PatienceSequenceMatcher_c
1347
1360
 
1350
1363
 
1351
1364
    def test_PatienceSequenceMatcher(self):
1352
1365
        if features.compiled_patiencediff_feature.available():
1353
 
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
 
1366
            from breezy._patiencediff_c import PatienceSequenceMatcher_c
1354
1367
            self.assertIs(PatienceSequenceMatcher_c,
1355
1368
                          patiencediff.PatienceSequenceMatcher)
1356
1369
        else:
1357
 
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
 
1370
            from breezy._patiencediff_py import PatienceSequenceMatcher_py
1358
1371
            self.assertIs(PatienceSequenceMatcher_py,
1359
1372
                          patiencediff.PatienceSequenceMatcher)
1360
1373
 
1361
1374
    def test_unique_lcs(self):
1362
1375
        if features.compiled_patiencediff_feature.available():
1363
 
            from bzrlib._patiencediff_c import unique_lcs_c
 
1376
            from breezy._patiencediff_c import unique_lcs_c
1364
1377
            self.assertIs(unique_lcs_c,
1365
1378
                          patiencediff.unique_lcs)
1366
1379
        else:
1367
 
            from bzrlib._patiencediff_py import unique_lcs_py
 
1380
            from breezy._patiencediff_py import unique_lcs_py
1368
1381
            self.assertIs(unique_lcs_py,
1369
1382
                          patiencediff.unique_lcs)
1370
1383
 
1371
1384
    def test_recurse_matches(self):
1372
1385
        if features.compiled_patiencediff_feature.available():
1373
 
            from bzrlib._patiencediff_c import recurse_matches_c
 
1386
            from breezy._patiencediff_c import recurse_matches_c
1374
1387
            self.assertIs(recurse_matches_c,
1375
1388
                          patiencediff.recurse_matches)
1376
1389
        else:
1377
 
            from bzrlib._patiencediff_py import recurse_matches_py
 
1390
            from breezy._patiencediff_py import recurse_matches_py
1378
1391
            self.assertIs(recurse_matches_py,
1379
1392
                          patiencediff.recurse_matches)
1380
1393
 
1407
1420
                         diff_obj._get_command('old-path', 'new-path'))
1408
1421
 
1409
1422
    def test_execute(self):
1410
 
        output = StringIO()
 
1423
        output = BytesIO()
1411
1424
        diff_obj = diff.DiffFromTool(['python', '-c',
1412
1425
                                      'print "@old_path @new_path"'],
1413
1426
                                     None, None, output)
1426
1439
 
1427
1440
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1428
1441
        self.requireFeature(features.AttribFeature)
1429
 
        output = StringIO()
 
1442
        output = BytesIO()
1430
1443
        tree = self.make_branch_and_tree('tree')
1431
1444
        self.build_tree_contents([('tree/file', 'content')])
1432
1445
        tree.add('file', 'file-id')
1455
1468
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
1456
1469
 
1457
1470
    def test_prepare_files(self):
1458
 
        output = StringIO()
 
1471
        output = BytesIO()
1459
1472
        tree = self.make_branch_and_tree('tree')
1460
1473
        self.build_tree_contents([('tree/oldname', 'oldcontent')])
1461
1474
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])