~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Patch Queue Manager
  • Date: 2016-02-01 19:13:13 UTC
  • mfrom: (6614.2.2 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20160201191313-wdfvmfff1djde6oq
(vila) Release 2.7.0 (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2014, 2016 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
17
17
import os
18
18
from cStringIO import StringIO
19
19
import subprocess
20
 
import sys
21
20
import tempfile
22
21
 
23
22
from bzrlib import (
32
31
    tests,
33
32
    transform,
34
33
    )
35
 
from bzrlib.symbol_versioning import deprecated_in
36
 
from bzrlib.tests import features, EncodingAdapter
37
 
from bzrlib.tests.blackbox.test_diff import subst_dates
38
34
from bzrlib.tests import (
39
35
    features,
40
 
    )
 
36
    EncodingAdapter,
 
37
)
 
38
from bzrlib.tests.blackbox.test_diff import subst_dates
 
39
from bzrlib.tests.scenarios import load_tests_apply_scenarios
 
40
 
 
41
 
 
42
load_tests = load_tests_apply_scenarios
41
43
 
42
44
 
43
45
def udiff_lines(old, new, allow_binary=False):
63
65
    return lines
64
66
 
65
67
 
 
68
class TestDiffOptions(tests.TestCase):
 
69
 
 
70
    def test_unified_added(self):
 
71
        """Check for default style '-u' only if no other style specified
 
72
        in 'diff-options'.
 
73
        """
 
74
        # Verify that style defaults to unified, id est '-u' appended
 
75
        # to option list, in the absence of an alternative style.
 
76
        self.assertEqual(['-a', '-u'], diff.default_style_unified(['-a']))
 
77
 
 
78
 
 
79
class TestDiffOptionsScenarios(tests.TestCase):
 
80
 
 
81
    scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
 
82
    style = None # Set by load_tests_apply_scenarios from scenarios
 
83
 
 
84
    def test_unified_not_added(self):
 
85
        # Verify that for all valid style options, '-u' is not
 
86
        # appended to option list.
 
87
        ret_opts = diff.default_style_unified(diff_opts=["%s" % (self.style,)])
 
88
        self.assertEqual(["%s" % (self.style,)], ret_opts)
 
89
 
 
90
 
66
91
class TestDiff(tests.TestCase):
67
92
 
68
93
    def test_add_nl(self):
69
94
        """diff generates a valid diff for patches that add a newline"""
70
95
        lines = udiff_lines(['boo'], ['boo\n'])
71
96
        self.check_patch(lines)
72
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
 
97
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
73
98
            ## "expected no-nl, got %r" % lines[4]
74
99
 
75
100
    def test_add_nl_2(self):
78
103
        """
79
104
        lines = udiff_lines(['boo'], ['goo\n'])
80
105
        self.check_patch(lines)
81
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
 
106
        self.assertEqual(lines[4], '\\ No newline at end of file\n')
82
107
            ## "expected no-nl, got %r" % lines[4]
83
108
 
84
109
    def test_remove_nl(self):
87
112
        """
88
113
        lines = udiff_lines(['boo\n'], ['boo'])
89
114
        self.check_patch(lines)
90
 
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
 
115
        self.assertEqual(lines[5], '\\ No newline at end of file\n')
91
116
            ## "expected no-nl, got %r" % lines[5]
92
117
 
93
118
    def check_patch(self, lines):
94
 
        self.assert_(len(lines) > 1)
 
119
        self.assertTrue(len(lines) > 1)
95
120
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
96
 
        self.assert_(lines[0].startswith ('---'))
 
121
        self.assertTrue(lines[0].startswith ('---'))
97
122
            ## 'No orig line for patch:\n%s' % "".join(lines)
98
 
        self.assert_(lines[1].startswith ('+++'))
 
123
        self.assertTrue(lines[1].startswith ('+++'))
99
124
            ## 'No mod line for patch:\n%s' % "".join(lines)
100
 
        self.assert_(len(lines) > 2)
 
125
        self.assertTrue(len(lines) > 2)
101
126
            ## "No hunks for patch:\n%s" % "".join(lines)
102
 
        self.assert_(lines[2].startswith('@@'))
 
127
        self.assertTrue(lines[2].startswith('@@'))
103
128
            ## "No hunk header for patch:\n%s" % "".join(lines)
104
 
        self.assert_('@@' in lines[2][2:])
 
129
        self.assertTrue('@@' in lines[2][2:])
105
130
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
106
131
 
107
132
    def test_binary_lines(self):
132
157
        # Older versions of diffutils say "Binary files", newer
133
158
        # versions just say "Files".
134
159
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
135
 
        self.assertEquals(lines[1:], ['\n'])
 
160
        self.assertEqual(lines[1:], ['\n'])
136
161
 
137
162
    def test_no_external_diff(self):
138
163
        """Check that NoDiff is raised when diff is not available"""
150
175
                           u'new_\xe5', ['new_text\n'], output)
151
176
        lines = output.getvalue().splitlines(True)
152
177
        self.check_patch(lines)
153
 
        self.assertEquals(['--- old_\xc2\xb5\n',
 
178
        self.assertEqual(['--- old_\xc2\xb5\n',
154
179
                           '+++ new_\xc3\xa5\n',
155
180
                           '@@ -1,1 +1,1 @@\n',
156
181
                           '-old_text\n',
166
191
                           path_encoding='utf8')
167
192
        lines = output.getvalue().splitlines(True)
168
193
        self.check_patch(lines)
169
 
        self.assertEquals(['--- old_\xc2\xb5\n',
 
194
        self.assertEqual(['--- old_\xc2\xb5\n',
170
195
                           '+++ new_\xc3\xa5\n',
171
196
                           '@@ -1,1 +1,1 @@\n',
172
197
                           '-old_text\n',
182
207
                           path_encoding='iso-8859-1')
183
208
        lines = output.getvalue().splitlines(True)
184
209
        self.check_patch(lines)
185
 
        self.assertEquals(['--- old_\xb5\n',
 
210
        self.assertEqual(['--- old_\xb5\n',
186
211
                           '+++ new_\xe5\n',
187
212
                           '@@ -1,1 +1,1 @@\n',
188
213
                           '-old_text\n',
211
236
        self.assertIsInstance(output.getvalue(), str,
212
237
            'internal_diff should return bytestrings')
213
238
 
 
239
    def test_internal_diff_default_context(self):
 
240
        output = StringIO()
 
241
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
 
242
                           'same_text\n','same_text\n','old_text\n'],
 
243
                           'new', ['same_text\n','same_text\n','same_text\n',
 
244
                           'same_text\n','same_text\n','new_text\n'], output)
 
245
        lines = output.getvalue().splitlines(True)
 
246
        self.check_patch(lines)
 
247
        self.assertEqual(['--- old\n',
 
248
                           '+++ new\n',
 
249
                           '@@ -3,4 +3,4 @@\n',
 
250
                           ' same_text\n',
 
251
                           ' same_text\n',
 
252
                           ' same_text\n',
 
253
                           '-old_text\n',
 
254
                           '+new_text\n',
 
255
                           '\n',
 
256
                          ]
 
257
                          , lines)
 
258
 
 
259
    def test_internal_diff_no_context(self):
 
260
        output = StringIO()
 
261
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
 
262
                           'same_text\n','same_text\n','old_text\n'],
 
263
                           'new', ['same_text\n','same_text\n','same_text\n',
 
264
                           'same_text\n','same_text\n','new_text\n'], output,
 
265
                           context_lines=0)
 
266
        lines = output.getvalue().splitlines(True)
 
267
        self.check_patch(lines)
 
268
        self.assertEqual(['--- old\n',
 
269
                           '+++ new\n',
 
270
                           '@@ -6,1 +6,1 @@\n',
 
271
                           '-old_text\n',
 
272
                           '+new_text\n',
 
273
                           '\n',
 
274
                          ]
 
275
                          , lines)
 
276
 
 
277
    def test_internal_diff_more_context(self):
 
278
        output = StringIO()
 
279
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
 
280
                           'same_text\n','same_text\n','old_text\n'],
 
281
                           'new', ['same_text\n','same_text\n','same_text\n',
 
282
                           'same_text\n','same_text\n','new_text\n'], output,
 
283
                           context_lines=4)
 
284
        lines = output.getvalue().splitlines(True)
 
285
        self.check_patch(lines)
 
286
        self.assertEqual(['--- old\n',
 
287
                           '+++ new\n',
 
288
                           '@@ -2,5 +2,5 @@\n',
 
289
                           ' same_text\n',
 
290
                           ' same_text\n',
 
291
                           ' same_text\n',
 
292
                           ' same_text\n',
 
293
                           '-old_text\n',
 
294
                           '+new_text\n',
 
295
                           '\n',
 
296
                          ]
 
297
                          , lines)
 
298
 
 
299
 
 
300
 
 
301
 
214
302
 
215
303
class TestDiffFiles(tests.TestCaseInTempDir):
216
304
 
220
308
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
221
309
 
222
310
        cmd = ['diff', '-u', '--binary', 'old', 'new']
223
 
        open('old', 'wb').write('\x00foobar\n')
224
 
        open('new', 'wb').write('foo\x00bar\n')
 
311
        with open('old', 'wb') as f: f.write('\x00foobar\n')
 
312
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
225
313
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
226
314
                                     stdin=subprocess.PIPE)
227
315
        out, err = pipe.communicate()
776
864
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
777
865
        sm = self._PatienceSequenceMatcher(None, a, b)
778
866
        mb = sm.get_matching_blocks()
779
 
        self.assertEquals(35, len(mb))
 
867
        self.assertEqual(35, len(mb))
780
868
 
781
869
    def test_unique_lcs(self):
782
870
        unique_lcs = self._unique_lcs
783
 
        self.assertEquals(unique_lcs('', ''), [])
784
 
        self.assertEquals(unique_lcs('', 'a'), [])
785
 
        self.assertEquals(unique_lcs('a', ''), [])
786
 
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
787
 
        self.assertEquals(unique_lcs('a', 'b'), [])
788
 
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
789
 
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
790
 
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
791
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
 
871
        self.assertEqual(unique_lcs('', ''), [])
 
872
        self.assertEqual(unique_lcs('', 'a'), [])
 
873
        self.assertEqual(unique_lcs('a', ''), [])
 
874
        self.assertEqual(unique_lcs('a', 'a'), [(0,0)])
 
875
        self.assertEqual(unique_lcs('a', 'b'), [])
 
876
        self.assertEqual(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
 
877
        self.assertEqual(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
 
878
        self.assertEqual(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
 
879
        self.assertEqual(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
792
880
                                                         (3,3), (4,4)])
793
 
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
 
881
        self.assertEqual(unique_lcs('acbac', 'abc'), [(2,1)])
794
882
 
795
883
    def test_recurse_matches(self):
796
884
        def test_one(a, b, matches):
797
885
            test_matches = []
798
886
            self._recurse_matches(
799
887
                a, b, 0, 0, len(a), len(b), test_matches, 10)
800
 
            self.assertEquals(test_matches, matches)
 
888
            self.assertEqual(test_matches, matches)
801
889
 
802
890
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
803
891
                 [(0, 0), (2, 2), (4, 4)])
908
996
    def test_opcodes(self):
909
997
        def chk_ops(a, b, expected_codes):
910
998
            s = self._PatienceSequenceMatcher(None, a, b)
911
 
            self.assertEquals(expected_codes, s.get_opcodes())
 
999
            self.assertEqual(expected_codes, s.get_opcodes())
912
1000
 
913
1001
        chk_ops('', '', [])
914
1002
        chk_ops([], [], [])
984
1072
    def test_grouped_opcodes(self):
985
1073
        def chk_ops(a, b, expected_codes, n=3):
986
1074
            s = self._PatienceSequenceMatcher(None, a, b)
987
 
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
 
1075
            self.assertEqual(expected_codes, list(s.get_grouped_opcodes(n)))
988
1076
 
989
1077
        chk_ops('', '', [])
990
1078
        chk_ops([], [], [])
1084
1172
                 'how are you today?\n']
1085
1173
        unified_diff = patiencediff.unified_diff
1086
1174
        psm = self._PatienceSequenceMatcher
1087
 
        self.assertEquals(['--- \n',
 
1175
        self.assertEqual(['--- \n',
1088
1176
                           '+++ \n',
1089
1177
                           '@@ -1,3 +1,2 @@\n',
1090
1178
                           ' hello there\n',
1096
1184
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1097
1185
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1098
1186
        # This is the result with LongestCommonSubstring matching
1099
 
        self.assertEquals(['--- \n',
 
1187
        self.assertEqual(['--- \n',
1100
1188
                           '+++ \n',
1101
1189
                           '@@ -1,6 +1,11 @@\n',
1102
1190
                           ' a\n',
1112
1200
                           ' f\n']
1113
1201
                          , list(unified_diff(txt_a, txt_b)))
1114
1202
        # And the patience diff
1115
 
        self.assertEquals(['--- \n',
 
1203
        self.assertEqual(['--- \n',
1116
1204
                           '+++ \n',
1117
1205
                           '@@ -4,6 +4,11 @@\n',
1118
1206
                           ' d\n',
1138
1226
                 'how are you today?\n']
1139
1227
        unified_diff = patiencediff.unified_diff
1140
1228
        psm = self._PatienceSequenceMatcher
1141
 
        self.assertEquals(['--- a\t2008-08-08\n',
 
1229
        self.assertEqual(['--- a\t2008-08-08\n',
1142
1230
                           '+++ b\t2008-09-09\n',
1143
1231
                           '@@ -1,3 +1,2 @@\n',
1144
1232
                           ' hello there\n',
1191
1279
                 'how are you today?\n']
1192
1280
        txt_b = ['hello there\n',
1193
1281
                 'how are you today?\n']
1194
 
        open('a1', 'wb').writelines(txt_a)
1195
 
        open('b1', 'wb').writelines(txt_b)
 
1282
        with open('a1', 'wb') as f: f.writelines(txt_a)
 
1283
        with open('b1', 'wb') as f: f.writelines(txt_b)
1196
1284
 
1197
1285
        unified_diff_files = patiencediff.unified_diff_files
1198
1286
        psm = self._PatienceSequenceMatcher
1199
 
        self.assertEquals(['--- a1\n',
 
1287
        self.assertEqual(['--- a1\n',
1200
1288
                           '+++ b1\n',
1201
1289
                           '@@ -1,3 +1,2 @@\n',
1202
1290
                           ' hello there\n',
1208
1296
 
1209
1297
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1210
1298
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1211
 
        open('a2', 'wb').writelines(txt_a)
1212
 
        open('b2', 'wb').writelines(txt_b)
 
1299
        with open('a2', 'wb') as f: f.writelines(txt_a)
 
1300
        with open('b2', 'wb') as f: f.writelines(txt_b)
1213
1301
 
1214
1302
        # This is the result with LongestCommonSubstring matching
1215
 
        self.assertEquals(['--- a2\n',
 
1303
        self.assertEqual(['--- a2\n',
1216
1304
                           '+++ b2\n',
1217
1305
                           '@@ -1,6 +1,11 @@\n',
1218
1306
                           ' a\n',
1229
1317
                          , list(unified_diff_files('a2', 'b2')))
1230
1318
 
1231
1319
        # And the patience diff
1232
 
        self.assertEquals(['--- a2\n',
1233
 
                           '+++ b2\n',
1234
 
                           '@@ -4,6 +4,11 @@\n',
1235
 
                           ' d\n',
1236
 
                           ' e\n',
1237
 
                           ' f\n',
1238
 
                           '+x\n',
1239
 
                           '+y\n',
1240
 
                           '+d\n',
1241
 
                           '+e\n',
1242
 
                           '+f\n',
1243
 
                           ' g\n',
1244
 
                           ' h\n',
1245
 
                           ' i\n',
1246
 
                          ]
1247
 
                          , list(unified_diff_files('a2', 'b2',
1248
 
                                 sequencematcher=psm)))
 
1320
        self.assertEqual(['--- a2\n',
 
1321
                          '+++ b2\n',
 
1322
                          '@@ -4,6 +4,11 @@\n',
 
1323
                          ' d\n',
 
1324
                          ' e\n',
 
1325
                          ' f\n',
 
1326
                          '+x\n',
 
1327
                          '+y\n',
 
1328
                          '+d\n',
 
1329
                          '+e\n',
 
1330
                          '+f\n',
 
1331
                          ' g\n',
 
1332
                          ' h\n',
 
1333
                          ' i\n'],
 
1334
                         list(unified_diff_files('a2', 'b2',
 
1335
                                                 sequencematcher=psm)))
1249
1336
 
1250
1337
 
1251
1338
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1328
1415
        diff_obj._execute('old', 'new')
1329
1416
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1330
1417
 
1331
 
    def test_excute_missing(self):
 
1418
    def test_execute_missing(self):
1332
1419
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1333
1420
                                     None, None, None)
1334
1421
        self.addCleanup(diff_obj.finish)
1408
1495
    def test_encodable_filename(self):
1409
1496
        # Just checks file path for external diff tool.
1410
1497
        # We cannot change CPython's internal encoding used by os.exec*.
1411
 
        import sys
1412
1498
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1413
1499
                                    None, None, None)
1414
1500
        for _, scenario in EncodingAdapter.encoding_scenarios:
1415
1501
            encoding = scenario['encoding']
1416
 
            dirname  = scenario['info']['directory']
 
1502
            dirname = scenario['info']['directory']
1417
1503
            filename = scenario['info']['filename']
1418
1504
 
1419
1505
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1420
1506
            relpath = dirname + u'/' + filename
1421
1507
            fullpath = diffobj._safe_filename('safe', relpath)
1422
 
            self.assertEqual(
1423
 
                    fullpath,
1424
 
                    fullpath.encode(encoding).decode(encoding)
1425
 
                    )
1426
 
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
 
1508
            self.assertEqual(fullpath,
 
1509
                             fullpath.encode(encoding).decode(encoding))
 
1510
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1427
1511
 
1428
1512
    def test_unencodable_filename(self):
1429
 
        import sys
1430
1513
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1431
1514
                                    None, None, None)
1432
1515
        for _, scenario in EncodingAdapter.encoding_scenarios:
1433
1516
            encoding = scenario['encoding']
1434
 
            dirname  = scenario['info']['directory']
 
1517
            dirname = scenario['info']['directory']
1435
1518
            filename = scenario['info']['filename']
1436
1519
 
1437
1520
            if encoding == 'iso-8859-1':
1442
1525
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1443
1526
            relpath = dirname + u'/' + filename
1444
1527
            fullpath = diffobj._safe_filename('safe', relpath)
1445
 
            self.assertEqual(
1446
 
                    fullpath,
1447
 
                    fullpath.encode(encoding).decode(encoding)
1448
 
                    )
1449
 
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
 
1528
            self.assertEqual(fullpath,
 
1529
                             fullpath.encode(encoding).decode(encoding))
 
1530
            self.assertTrue(fullpath.startswith(diffobj._root + '/safe'))
1450
1531
 
1451
1532
 
1452
1533
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):