1 from __future__ import absolute_import, print_function |
1 from __future__ import absolute_import, print_function |
2 import collections |
2 import collections |
3 import struct |
3 import struct |
4 import unittest |
4 import unittest |
5 |
5 |
6 from mercurial import ( |
6 from mercurial import mdiff |
7 mdiff, |
|
8 ) |
|
9 |
7 |
10 class diffreplace( |
8 |
11 collections.namedtuple('diffreplace', 'start end from_ to')): |
9 class diffreplace(collections.namedtuple('diffreplace', 'start end from_ to')): |
12 def __repr__(self): |
10 def __repr__(self): |
13 return 'diffreplace(%r, %r, %r, %r)' % self |
11 return 'diffreplace(%r, %r, %r, %r)' % self |
14 |
12 |
|
13 |
15 class BdiffTests(unittest.TestCase): |
14 class BdiffTests(unittest.TestCase): |
16 |
|
17 def assert_bdiff_applies(self, a, b): |
15 def assert_bdiff_applies(self, a, b): |
18 d = mdiff.textdiff(a, b) |
16 d = mdiff.textdiff(a, b) |
19 c = a |
17 c = a |
20 if d: |
18 if d: |
21 c = mdiff.patches(a, [d]) |
19 c = mdiff.patches(a, [d]) |
22 self.assertEqual( |
20 self.assertEqual( |
23 c, b, ("bad diff+patch result from\n %r to\n " |
21 c, |
24 "%r: \nbdiff: %r\npatched: %r" % (a, b, d, c[:200]))) |
22 b, |
|
23 ( |
|
24 "bad diff+patch result from\n %r to\n " |
|
25 "%r: \nbdiff: %r\npatched: %r" % (a, b, d, c[:200]) |
|
26 ), |
|
27 ) |
25 |
28 |
26 def assert_bdiff(self, a, b): |
29 def assert_bdiff(self, a, b): |
27 self.assert_bdiff_applies(a, b) |
30 self.assert_bdiff_applies(a, b) |
28 self.assert_bdiff_applies(b, a) |
31 self.assert_bdiff_applies(b, a) |
29 |
32 |
56 bin = mdiff.textdiff(a, b) |
59 bin = mdiff.textdiff(a, b) |
57 pos = 0 |
60 pos = 0 |
58 q = 0 |
61 q = 0 |
59 actions = [] |
62 actions = [] |
60 while pos < len(bin): |
63 while pos < len(bin): |
61 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12]) |
64 p1, p2, l = struct.unpack(">lll", bin[pos : pos + 12]) |
62 pos += 12 |
65 pos += 12 |
63 if p1: |
66 if p1: |
64 actions.append(a[q:p1]) |
67 actions.append(a[q:p1]) |
65 actions.append(diffreplace(p1, p2, a[p1:p2], bin[pos:pos + l])) |
68 actions.append(diffreplace(p1, p2, a[p1:p2], bin[pos : pos + l])) |
66 pos += l |
69 pos += l |
67 q = p2 |
70 q = p2 |
68 if q < len(a): |
71 if q < len(a): |
69 actions.append(a[q:]) |
72 actions.append(a[q:]) |
70 return actions |
73 return actions |
71 |
74 |
72 def test_issue1295(self): |
75 def test_issue1295(self): |
73 cases = [ |
76 cases = [ |
74 (b"x\n\nx\n\nx\n\nx\n\nz\n", b"x\n\nx\n\ny\n\nx\n\nx\n\nz\n", |
77 ( |
75 [b'x\n\nx\n\n', |
78 b"x\n\nx\n\nx\n\nx\n\nz\n", |
76 diffreplace(6, 6, b'', b'y\n\n'), |
79 b"x\n\nx\n\ny\n\nx\n\nx\n\nz\n", |
77 b'x\n\nx\n\nz\n']), |
80 [ |
78 (b"x\n\nx\n\nx\n\nx\n\nz\n", b"x\n\nx\n\ny\n\nx\n\ny\n\nx\n\nz\n", |
81 b'x\n\nx\n\n', |
79 [b'x\n\nx\n\n', |
82 diffreplace(6, 6, b'', b'y\n\n'), |
80 diffreplace(6, 6, b'', b'y\n\n'), |
83 b'x\n\nx\n\nz\n', |
81 b'x\n\n', |
84 ], |
82 diffreplace(9, 9, b'', b'y\n\n'), |
85 ), |
83 b'x\n\nz\n']), |
86 ( |
|
87 b"x\n\nx\n\nx\n\nx\n\nz\n", |
|
88 b"x\n\nx\n\ny\n\nx\n\ny\n\nx\n\nz\n", |
|
89 [ |
|
90 b'x\n\nx\n\n', |
|
91 diffreplace(6, 6, b'', b'y\n\n'), |
|
92 b'x\n\n', |
|
93 diffreplace(9, 9, b'', b'y\n\n'), |
|
94 b'x\n\nz\n', |
|
95 ], |
|
96 ), |
84 ] |
97 ] |
85 for old, new, want in cases: |
98 for old, new, want in cases: |
86 self.assertEqual(self.showdiff(old, new), want) |
99 self.assertEqual(self.showdiff(old, new), want) |
87 |
100 |
88 def test_issue1295_varies_on_pure(self): |
101 def test_issue1295_varies_on_pure(self): |
89 # we should pick up abbbc. rather than bc.de as the longest match |
102 # we should pick up abbbc. rather than bc.de as the longest match |
90 got = self.showdiff(b"a\nb\nb\nb\nc\n.\nd\ne\n.\nf\n", |
103 got = self.showdiff( |
91 b"a\nb\nb\na\nb\nb\nb\nc\n.\nb\nc\n.\nd\ne\nf\n") |
104 b"a\nb\nb\nb\nc\n.\nd\ne\n.\nf\n", |
92 want_c = [b'a\nb\nb\n', |
105 b"a\nb\nb\na\nb\nb\nb\nc\n.\nb\nc\n.\nd\ne\nf\n", |
93 diffreplace(6, 6, b'', b'a\nb\nb\nb\nc\n.\n'), |
106 ) |
94 b'b\nc\n.\nd\ne\n', |
107 want_c = [ |
95 diffreplace(16, 18, b'.\n', b''), |
108 b'a\nb\nb\n', |
96 b'f\n'] |
109 diffreplace(6, 6, b'', b'a\nb\nb\nb\nc\n.\n'), |
97 want_pure = [diffreplace(0, 0, b'', b'a\nb\nb\n'), |
110 b'b\nc\n.\nd\ne\n', |
98 b'a\nb\nb\nb\nc\n.\n', |
111 diffreplace(16, 18, b'.\n', b''), |
99 diffreplace(12, 12, b'', b'b\nc\n.\n'), |
112 b'f\n', |
100 b'd\ne\n', |
113 ] |
101 diffreplace(16, 18, b'.\n', b''), b'f\n'] |
114 want_pure = [ |
102 self.assertTrue(got in (want_c, want_pure), |
115 diffreplace(0, 0, b'', b'a\nb\nb\n'), |
103 'got: %r, wanted either %r or %r' % ( |
116 b'a\nb\nb\nb\nc\n.\n', |
104 got, want_c, want_pure)) |
117 diffreplace(12, 12, b'', b'b\nc\n.\n'), |
|
118 b'd\ne\n', |
|
119 diffreplace(16, 18, b'.\n', b''), |
|
120 b'f\n', |
|
121 ] |
|
122 self.assertTrue( |
|
123 got in (want_c, want_pure), |
|
124 'got: %r, wanted either %r or %r' % (got, want_c, want_pure), |
|
125 ) |
105 |
126 |
106 def test_fixws(self): |
127 def test_fixws(self): |
107 cases = [ |
128 cases = [ |
108 (b" \ta\r b\t\n", b"ab\n", 1), |
129 (b" \ta\r b\t\n", b"ab\n", 1), |
109 (b" \ta\r b\t\n", b" a b\n", 0), |
130 (b" \ta\r b\t\n", b" a b\n", 0), |
111 (b"", b"", 0), |
132 (b"", b"", 0), |
112 ] |
133 ] |
113 for a, b, allws in cases: |
134 for a, b, allws in cases: |
114 c = mdiff.fixws(a, allws) |
135 c = mdiff.fixws(a, allws) |
115 self.assertEqual( |
136 self.assertEqual( |
116 c, b, 'fixws(%r) want %r got %r (allws=%r)' % (a, b, c, allws)) |
137 c, b, 'fixws(%r) want %r got %r (allws=%r)' % (a, b, c, allws) |
|
138 ) |
117 |
139 |
118 def test_nice_diff_for_trivial_change(self): |
140 def test_nice_diff_for_trivial_change(self): |
119 self.assertEqual(self.showdiff( |
141 self.assertEqual( |
120 b''.join(b'<%d\n-\n' % i for i in range(5)), |
142 self.showdiff( |
121 b''.join(b'>%d\n-\n' % i for i in range(5))), |
143 b''.join(b'<%d\n-\n' % i for i in range(5)), |
122 [diffreplace(0, 3, b'<0\n', b'>0\n'), |
144 b''.join(b'>%d\n-\n' % i for i in range(5)), |
123 b'-\n', |
145 ), |
124 diffreplace(5, 8, b'<1\n', b'>1\n'), |
146 [ |
125 b'-\n', |
147 diffreplace(0, 3, b'<0\n', b'>0\n'), |
126 diffreplace(10, 13, b'<2\n', b'>2\n'), |
148 b'-\n', |
127 b'-\n', |
149 diffreplace(5, 8, b'<1\n', b'>1\n'), |
128 diffreplace(15, 18, b'<3\n', b'>3\n'), |
150 b'-\n', |
129 b'-\n', |
151 diffreplace(10, 13, b'<2\n', b'>2\n'), |
130 diffreplace(20, 23, b'<4\n', b'>4\n'), |
152 b'-\n', |
131 b'-\n']) |
153 diffreplace(15, 18, b'<3\n', b'>3\n'), |
|
154 b'-\n', |
|
155 diffreplace(20, 23, b'<4\n', b'>4\n'), |
|
156 b'-\n', |
|
157 ], |
|
158 ) |
132 |
159 |
133 def test_prefer_appending(self): |
160 def test_prefer_appending(self): |
134 # 1 line to 3 lines |
161 # 1 line to 3 lines |
135 self.assertEqual(self.showdiff(b'a\n', b'a\n' * 3), |
162 self.assertEqual( |
136 [b'a\n', diffreplace(2, 2, b'', b'a\na\n')]) |
163 self.showdiff(b'a\n', b'a\n' * 3), |
|
164 [b'a\n', diffreplace(2, 2, b'', b'a\na\n')], |
|
165 ) |
137 # 1 line to 5 lines |
166 # 1 line to 5 lines |
138 self.assertEqual(self.showdiff(b'a\n', b'a\n' * 5), |
167 self.assertEqual( |
139 [b'a\n', diffreplace(2, 2, b'', b'a\na\na\na\n')]) |
168 self.showdiff(b'a\n', b'a\n' * 5), |
|
169 [b'a\n', diffreplace(2, 2, b'', b'a\na\na\na\n')], |
|
170 ) |
140 |
171 |
141 def test_prefer_removing_trailing(self): |
172 def test_prefer_removing_trailing(self): |
142 # 3 lines to 1 line |
173 # 3 lines to 1 line |
143 self.assertEqual(self.showdiff(b'a\n' * 3, b'a\n'), |
174 self.assertEqual( |
144 [b'a\n', diffreplace(2, 6, b'a\na\n', b'')]) |
175 self.showdiff(b'a\n' * 3, b'a\n'), |
|
176 [b'a\n', diffreplace(2, 6, b'a\na\n', b'')], |
|
177 ) |
145 # 5 lines to 1 line |
178 # 5 lines to 1 line |
146 self.assertEqual(self.showdiff(b'a\n' * 5, b'a\n'), |
179 self.assertEqual( |
147 [b'a\n', diffreplace(2, 10, b'a\na\na\na\n', b'')]) |
180 self.showdiff(b'a\n' * 5, b'a\n'), |
|
181 [b'a\n', diffreplace(2, 10, b'a\na\na\na\n', b'')], |
|
182 ) |
|
183 |
148 |
184 |
149 if __name__ == '__main__': |
185 if __name__ == '__main__': |
150 import silenttestrunner |
186 import silenttestrunner |
|
187 |
151 silenttestrunner.main(__name__) |
188 silenttestrunner.main(__name__) |