9.2 KB370 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import {splitLines} from '../diff';
9import {guessIsSubmodule, parseParsedDiff, parsePatch} from '../patch/parse';
10
11describe('patch/parse', () => {
12 it('should parse basic modified patch', () => {
13 const patch = `
14diff --git sapling/eden/scm/a sapling/eden/scm/a
15--- sapling/eden/scm/a
16+++ sapling/eden/scm/a
17@@ -1,1 +1,2 @@
18 1
19+2
20`;
21 const expected = [
22 {
23 hunks: [
24 {
25 linedelimiters: ['\n', '\n'],
26 lines: [' 1', '+2'],
27 newLines: 2,
28 newStart: 1,
29 oldLines: 1,
30 oldStart: 1,
31 },
32 ],
33 newFileName: 'sapling/eden/scm/a',
34 oldFileName: 'sapling/eden/scm/a',
35 type: 'Modified',
36 },
37 ];
38 expect(parsePatch(patch)).toEqual(expected);
39 });
40
41 it('should parse rename', () => {
42 const patch = `
43diff --git sapling/eden/scm/a sapling/eden/scm/b
44rename from sapling/eden/scm/a
45rename to sapling/eden/scm/b
46`;
47 const expected = [
48 {
49 hunks: [],
50 newFileName: 'sapling/eden/scm/b',
51 oldFileName: 'sapling/eden/scm/a',
52 type: 'Renamed',
53 },
54 ];
55 expect(parsePatch(patch)).toEqual(expected);
56 });
57
58 it('should parse rename and modify', () => {
59 const patch = `
60diff --git sapling/eden/addons/LICENSE sapling/eden/addons/LICENSE.bak
61rename from sapling/eden/addons/LICENSE
62rename to sapling/eden/addons/LICENSE.bak
63--- sapling/eden/addons/LICENSE
64+++ sapling/eden/addons/LICENSE.bak
65@@ -2,6 +2,7 @@
66
67 Copyright (c) Meta Platforms, Inc. and its affiliates.
68
69+
70`;
71 const expected = [
72 {
73 hunks: [
74 {
75 linedelimiters: ['\n', '\n', '\n', '\n'],
76 lines: ['', ' Copyright (c) Meta Platforms, Inc. and its affiliates.', '', '+'],
77 newLines: 7,
78 newStart: 2,
79 oldLines: 6,
80 oldStart: 2,
81 },
82 ],
83 newFileName: 'sapling/eden/addons/LICENSE.bak',
84 oldFileName: 'sapling/eden/addons/LICENSE',
85 type: 'Renamed',
86 },
87 ];
88 expect(parsePatch(patch)).toEqual(expected);
89 });
90
91 it('should parse new file', () => {
92 const patch = `
93diff --git sapling/eden/scm/c sapling/eden/scm/c
94new file mode 100644
95--- /dev/null
96+++ sapling/eden/scm/c
97@@ -0,0 +1,1 @@
98+1
99`;
100 const expected = [
101 {
102 hunks: [
103 {
104 linedelimiters: ['\n'],
105 lines: ['+1'],
106 newLines: 1,
107 newStart: 1,
108 oldLines: 0,
109 oldStart: 1,
110 },
111 ],
112 newFileName: 'sapling/eden/scm/c',
113 newMode: '100644',
114 oldFileName: 'sapling/eden/scm/c',
115 type: 'Added',
116 },
117 ];
118 expect(parsePatch(patch)).toEqual(expected);
119 });
120
121 it('should parse new empty file', () => {
122 const patch = `
123diff --git sapling/eden/addons/d sapling/eden/addons/d
124new file mode 100644
125`;
126 const expected = [
127 {
128 hunks: [],
129 newFileName: 'sapling/eden/addons/d',
130 newMode: '100644',
131 oldFileName: 'sapling/eden/addons/d',
132 type: 'Added',
133 },
134 ];
135 expect(parsePatch(patch)).toEqual(expected);
136 });
137
138 it('should parse deleted file', () => {
139 const patch = `
140diff --git sapling/eden/scm/a sapling/eden/scm/a
141deleted file mode 100644
142--- sapling/eden/scm/a
143+++ /dev/null
144@@ -1,1 +0,0 @@
145-1
146`;
147 const expected = [
148 {
149 hunks: [
150 {
151 linedelimiters: ['\n'],
152 lines: ['-1'],
153 newLines: 0,
154 newStart: 1,
155 oldLines: 1,
156 oldStart: 1,
157 },
158 ],
159 newFileName: 'sapling/eden/scm/a',
160 newMode: '100644',
161 oldFileName: 'sapling/eden/scm/a',
162 type: 'Removed',
163 },
164 ];
165 expect(parsePatch(patch)).toEqual(expected);
166 });
167
168 it('should parse copied file', () => {
169 const patch = `
170diff --git sapling/eden/scm/a sapling/eden/scm/b
171copy from sapling/eden/scm/a
172copy to sapling/eden/scm/b
173`;
174 const expected = [
175 {
176 hunks: [],
177 newFileName: 'sapling/eden/scm/b',
178 oldFileName: 'sapling/eden/scm/a',
179 type: 'Copied',
180 },
181 ];
182 expect(parsePatch(patch)).toEqual(expected);
183 });
184
185 it('should parse multiple files', () => {
186 const patch = `
187diff --git sapling/eden/scm/a sapling/eden/scm/a
188--- sapling/eden/scm/a
189+++ sapling/eden/scm/a
190@@ -1,1 +1,2 @@
191 1
192+2
193diff --git sapling/eden/scm/a sapling/eden/scm/b
194copy from sapling/eden/scm/a
195copy to sapling/eden/scm/b
196diff --git sapling/eden/scm/c sapling/eden/scm/d
197copy from sapling/eden/scm/c
198copy to sapling/eden/scm/d
199`;
200 const expected = [
201 {
202 hunks: [
203 {
204 linedelimiters: ['\n', '\n'],
205 lines: [' 1', '+2'],
206 newLines: 2,
207 newStart: 1,
208 oldLines: 1,
209 oldStart: 1,
210 },
211 ],
212 newFileName: 'sapling/eden/scm/a',
213 oldFileName: 'sapling/eden/scm/a',
214 type: 'Modified',
215 },
216 {
217 hunks: [],
218 newFileName: 'sapling/eden/scm/b',
219 oldFileName: 'sapling/eden/scm/a',
220 type: 'Copied',
221 },
222 {
223 hunks: [],
224 newFileName: 'sapling/eden/scm/d',
225 oldFileName: 'sapling/eden/scm/c',
226 type: 'Copied',
227 },
228 ];
229 expect(parsePatch(patch)).toEqual(expected);
230 });
231
232 it('should parse file mode change', () => {
233 const patch = `
234diff --git sapling/eden/scm/a sapling/eden/scm/a
235old mode 100644
236new mode 100755
237`;
238 const expected = [
239 {
240 hunks: [],
241 newFileName: 'sapling/eden/scm/a',
242 newMode: '100755',
243 oldFileName: 'sapling/eden/scm/a',
244 oldMode: '100644',
245 type: 'Modified',
246 },
247 ];
248 expect(parsePatch(patch)).toEqual(expected);
249 });
250
251 it('should fail for invalid file mode format', () => {
252 const patch = `
253diff --git sapling/eden/scm/a sapling/eden/scm/a
254old mode XXX
255new mode 100755
256`;
257 expect(() => parsePatch(patch)).toThrow("invalid format 'old mode XXX'");
258 });
259});
260
261describe('guessSubmodule', () => {
262 it('modified submodules', () => {
263 const patch = `
264diff --git a/external/brotli b/external/brotli
265--- a/external/brotli
266+++ b/external/brotli
267@@ -1,1 +1,1 @@
268-Subproject commit 892110204ccf44fcd493ae415c9a69c470c2a9cf
269+Subproject commit 57de5cc4288565a9c3a7af978ef15f0abf0ada1b
270diff --git a/external/rust/cxx b/external/rust/cxx
271--- a/external/rust/cxx
272+++ b/external/rust/cxx
273@@ -1,1 +1,1 @@
274-Subproject commit 862a23082a087566776280a5b1539d3b62701bcb
275+Subproject commit 1869e93e54fa9d9425bd88bdb25073af9ed7e782
276`;
277 const parsed = parsePatch(patch);
278 expect(parsed.length).toEqual(2);
279 expect(guessIsSubmodule(parsed[0])).toEqual(true);
280 expect(guessIsSubmodule(parsed[1])).toEqual(true);
281 });
282
283 it('added submodule', () => {
284 const patch = `
285diff --git a/path/to/submodule b/path/to/submodule
286new file mode 160000
287--- /dev/null
288+++ b/path/to/submodule
289@@ -0,0 +1,1 @@
290+Subproject commit 7ef4220022059b9b1e1d8ec4eea6f7abd011894f
291`;
292 const parsed = parsePatch(patch);
293 expect(parsed.length).toEqual(1);
294 expect(guessIsSubmodule(parsed[0])).toEqual(true);
295 });
296
297 it('invalid file modification', () => {
298 const patch = `
299diff --git sapling/eden/scm/a sapling/eden/scm/a
300--- sapling/eden/scm/a
301+++ sapling/eden/scm/a
302@@ -1,1 +1,2 @@
303 Subproject commit abcdef01234556789ABCDEF
304+Subproject commit abcdef01234556789ABCDEF
305`;
306 const parsed = parsePatch(patch);
307 expect(parsed.length).toEqual(1);
308 expect(guessIsSubmodule(parsed[0])).toEqual(false);
309 });
310
311 it('invalid hash value', () => {
312 const patch = `
313diff --git a/external/rust/cxx b/external/rust/cxx
314--- a/external/rust/cxx
315+++ b/external/rust/cxx
316@@ -1,1 +1,1 @@
317-Subproject commit ghijklmnGHIJKLMN
318+Subproject commit ghijklmnGHIJKLMN
319`;
320 const parsed = parsePatch(patch);
321 expect(parsed.length).toEqual(1);
322 expect(guessIsSubmodule(parsed[0])).toEqual(false);
323 });
324});
325
326describe('createParsedDiffWithLines', () => {
327 it('return no hunks for empty lines', () => {
328 expect(parseParsedDiff([], [], 1)).toMatchObject({hunks: []});
329 });
330
331 it('returns no hunks when comparing same lines', () => {
332 const lines = splitLines('a\nb\nc\nd\ne\n');
333 expect(parseParsedDiff(lines, lines, 1)).toMatchObject({hunks: []});
334 });
335
336 it('return all "-" for old code and "=" for new code for totally different contents', () => {
337 const aLines = splitLines('x\ny\n');
338 const bLines = splitLines('a\nb\nc\n');
339 expect(parseParsedDiff(aLines, bLines, 1)).toMatchObject({
340 hunks: [
341 {
342 oldStart: 1,
343 oldLines: 2,
344 newStart: 1,
345 newLines: 3,
346 lines: ['-x\n', '-y\n', '+a\n', '+b\n', '+c\n'],
347 linedelimiters: ['\n', '\n', '\n', '\n', '\n'],
348 },
349 ],
350 });
351 });
352
353 it('return for when a line was changed in the middle', () => {
354 const aLines = splitLines('a\nb\nc\nd\ne\n');
355 const bLines = splitLines('a\nb\nc\nd1\nd2\ne\n');
356 expect(parseParsedDiff(aLines, bLines, 1)).toMatchObject({
357 hunks: [
358 {
359 oldStart: 4,
360 oldLines: 1,
361 newStart: 4,
362 newLines: 2,
363 lines: ['-d\n', '+d1\n', '+d2\n'],
364 linedelimiters: ['\n', '\n', '\n'],
365 },
366 ],
367 });
368 });
369});
370