1 | const parse = require("../index");
|
2 |
|
3 | describe("diff parser", function () {
|
4 | it("should parse null", () => {
|
5 | expect(parse(null).length).toBe(0);
|
6 | });
|
7 |
|
8 | it("should parse empty string", () => {
|
9 | expect(parse("").length).toBe(0);
|
10 | });
|
11 |
|
12 | it("should parse whitespace", () => {
|
13 | expect(parse(" ").length).toBe(0);
|
14 | });
|
15 |
|
16 | it("should parse simple git-like diff", function () {
|
17 | const diff = `\
|
18 | diff --git a/file b/file
|
19 | index 123..456 789
|
20 | --- a/file
|
21 | +++ b/file
|
22 | @@ -1,2 +1,2 @@
|
23 | - line1
|
24 | + line2\
|
25 | `;
|
26 | const files = parse(diff);
|
27 | expect(files.length).toBe(1);
|
28 | const file = files[0];
|
29 | expect(file.from).toBe("file");
|
30 | expect(file.to).toBe("file");
|
31 | expect(file.deletions).toBe(1);
|
32 | expect(file.additions).toBe(1);
|
33 | expect(file.chunks.length).toBe(1);
|
34 | const chunk = file.chunks[0];
|
35 | expect(chunk.content).toBe("@@ -1,2 +1,2 @@");
|
36 | expect(chunk.changes.length).toBe(2);
|
37 | expect(chunk.changes[0].content).toBe("- line1");
|
38 | expect(chunk.changes[1].content).toBe("+ line2");
|
39 | });
|
40 |
|
41 | it("should parse simple git-like diff with file enclosed by double-quote", function () {
|
42 | const diff = `\
|
43 | diff --git "a/file1" "b/file2"
|
44 | similarity index 100%
|
45 | rename from "file1"
|
46 | rename to "file2"\
|
47 | `;
|
48 | const files = parse(diff);
|
49 | expect(files.length).toBe(1);
|
50 | const file = files[0];
|
51 | expect(file.from).toBe("file1");
|
52 | expect(file.to).toBe("file2");
|
53 | expect(file.chunks.length).toBe(0);
|
54 | });
|
55 |
|
56 | it("should parse file names for changed binaries with spaces in their names", function () {
|
57 | const diff = `\
|
58 | diff --git a/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png b/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png
|
59 | index fc72ba34b..ec373e9a4 100644
|
60 | Binary files a/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png and b/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png differ\
|
61 | `;
|
62 | const files = parse(diff);
|
63 | expect(files.length).toBe(1);
|
64 | const file = files[0];
|
65 | expect(file.from).toBe(
|
66 | "Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png"
|
67 | );
|
68 | expect(file.to).toBe(
|
69 | "Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png"
|
70 | );
|
71 | });
|
72 |
|
73 | it("should parse diff with new file mode line", function () {
|
74 | const diff = `\
|
75 | diff --git a/test b/test
|
76 | new file mode 100644
|
77 | index 0000000..db81be4
|
78 | --- /dev/null
|
79 | +++ b/test
|
80 | @@ -0,0 +1,2 @@
|
81 | +line1
|
82 | +line2\
|
83 | `;
|
84 | const files = parse(diff);
|
85 | expect(files.length).toBe(1);
|
86 | const file = files[0];
|
87 | expect(file.new).toBeTruthy();
|
88 | expect(file.from).toBe("/dev/null");
|
89 | expect(file.to).toBe("test");
|
90 | expect(file.chunks[0].content).toBe("@@ -0,0 +1,2 @@");
|
91 | expect(file.chunks[0].changes.length).toBe(2);
|
92 | expect(file.chunks[0].changes[0].content).toBe("+line1");
|
93 | expect(file.chunks[0].changes[1].content).toBe("+line2");
|
94 | });
|
95 |
|
96 | it("should parse diff with deleted file mode line", function () {
|
97 | const diff = `\
|
98 | diff --git a/test b/test
|
99 | deleted file mode 100644
|
100 | index db81be4..0000000
|
101 | --- b/test
|
102 | +++ /dev/null
|
103 | @@ -1,2 +0,0 @@
|
104 | -line1
|
105 | -line2\
|
106 | `;
|
107 | const files = parse(diff);
|
108 | expect(files.length).toBe(1);
|
109 | const file = files[0];
|
110 | expect(file.deleted).toBeTruthy();
|
111 | expect(file.from).toBe("test");
|
112 | expect(file.to).toBe("/dev/null");
|
113 | expect(file.chunks[0].content).toBe("@@ -1,2 +0,0 @@");
|
114 | expect(file.chunks[0].changes.length).toBe(2);
|
115 | expect(file.chunks[0].changes[0].content).toBe("-line1");
|
116 | expect(file.chunks[0].changes[1].content).toBe("-line2");
|
117 | });
|
118 |
|
119 | it("should parse diff with single line files", function () {
|
120 | const diff = `\
|
121 | diff --git a/file1 b/file1
|
122 | deleted file mode 100644
|
123 | index db81be4..0000000
|
124 | --- b/file1
|
125 | +++ /dev/null
|
126 | @@ -1 +0,0 @@
|
127 | -line1
|
128 | diff --git a/file2 b/file2
|
129 | new file mode 100644
|
130 | index 0000000..db81be4
|
131 | --- /dev/null
|
132 | +++ b/file2
|
133 | @@ -0,0 +1 @@
|
134 | +line1\
|
135 | `;
|
136 | const files = parse(diff);
|
137 | expect(files.length).toBe(2);
|
138 | let file = files[0];
|
139 | expect(file.deleted).toBeTruthy();
|
140 | expect(file.from).toBe("file1");
|
141 | expect(file.to).toBe("/dev/null");
|
142 | expect(file.chunks[0].content).toBe("@@ -1 +0,0 @@");
|
143 | expect(file.chunks[0].changes.length).toBe(1);
|
144 | expect(file.chunks[0].changes[0].content).toBe("-line1");
|
145 | expect(file.chunks[0].changes[0].type).toBe("del");
|
146 | file = files[1];
|
147 | expect(file.new).toBeTruthy();
|
148 | expect(file.from).toBe("/dev/null");
|
149 | expect(file.to).toBe("file2");
|
150 | expect(file.chunks[0].content).toBe("@@ -0,0 +1 @@");
|
151 | expect(file.chunks[0].oldStart).toBe(0);
|
152 | expect(file.chunks[0].oldLines).toBe(0);
|
153 | expect(file.chunks[0].newStart).toBe(1);
|
154 | expect(file.chunks[0].newLines).toBe(1);
|
155 | expect(file.chunks[0].changes.length).toBe(1);
|
156 | expect(file.chunks[0].changes[0].content).toBe("+line1");
|
157 | expect(file.chunks[0].changes[0].type).toBe("add");
|
158 | });
|
159 |
|
160 | it("should parse multiple files in diff", function () {
|
161 | const diff = `\
|
162 | diff --git a/file1 b/file1
|
163 | index 123..456 789
|
164 | --- a/file1
|
165 | +++ b/file1
|
166 | @@ -1,2 +1,2 @@
|
167 | - line1
|
168 | + line2
|
169 | diff --git a/file2 b/file2
|
170 | index 123..456 789
|
171 | --- a/file2
|
172 | +++ b/file2
|
173 | @@ -1,3 +1,3 @@
|
174 | - line1
|
175 | + line2\
|
176 | `;
|
177 | const files = parse(diff);
|
178 | expect(files.length).toBe(2);
|
179 | let file = files[0];
|
180 | expect(file.from).toBe("file1");
|
181 | expect(file.to).toBe("file1");
|
182 | expect(file.chunks[0].content).toBe("@@ -1,2 +1,2 @@");
|
183 | expect(file.chunks[0].changes.length).toBe(2);
|
184 | expect(file.chunks[0].changes[0].content).toBe("- line1");
|
185 | expect(file.chunks[0].changes[1].content).toBe("+ line2");
|
186 | file = files[1];
|
187 | expect(file.from).toBe("file2");
|
188 | expect(file.to).toBe("file2");
|
189 | expect(file.chunks[0].content).toBe("@@ -1,3 +1,3 @@");
|
190 | expect(file.chunks[0].changes.length).toBe(2);
|
191 | expect(file.chunks[0].changes[0].content).toBe("- line1");
|
192 | expect(file.chunks[0].changes[1].content).toBe("+ line2");
|
193 | });
|
194 |
|
195 | it("should parse diff with EOF flag", function () {
|
196 | const diff = `\
|
197 | diff --git a/file1 b/file1
|
198 | index 123..456 789
|
199 | --- a/file1
|
200 | +++ b/file1
|
201 | @@ -1,2 +1,2 @@
|
202 | - line1
|
203 | + line2
|
204 | \\ No newline at end of file\
|
205 | `;
|
206 | const files = parse(diff);
|
207 | expect(files.length).toBe(1);
|
208 | const file = files[0];
|
209 | expect(file.from).toBe("file1");
|
210 | expect(file.to).toBe("file1");
|
211 | const chunk = file.chunks[0];
|
212 | expect(chunk.content).toBe("@@ -1,2 +1,2 @@");
|
213 | expect(chunk.changes.length).toBe(3);
|
214 | expect(chunk.changes[0].content).toBe("- line1");
|
215 | expect(chunk.changes[1].content).toBe("+ line2");
|
216 | expect(chunk.changes[2].type).toBe("add");
|
217 | expect(chunk.changes[2].content).toBe("\\ No newline at end of file");
|
218 | });
|
219 |
|
220 | it("should parse gnu sample diff", function () {
|
221 | const diff = `\
|
222 | --- lao 2002-02-21 23:30:39.942229878 -0800
|
223 | +++ tzu 2002-02-21 23:30:50.442260588 -0800
|
224 | @@ -1,7 +1,6 @@
|
225 | -The Way that can be told of is not the eternal Way;
|
226 | -The name that can be named is not the eternal name.
|
227 | The Nameless is the origin of Heaven and Earth;
|
228 | -The Named is the mother of all things.
|
229 | +The named is the mother of all things.
|
230 | +
|
231 | Therefore let there always be non-being,
|
232 | so we may see their subtlety,
|
233 | And let there always be being,
|
234 | @@ -9,3 +8,6 @@
|
235 | The two are the same,
|
236 | But after they are produced,
|
237 | they have different names.
|
238 | +They both may be called deep and profound.
|
239 | +Deeper and more profound,
|
240 | +The door of all subtleties!\
|
241 | `;
|
242 | const files = parse(diff);
|
243 | expect(files.length).toBe(1);
|
244 | const file = files[0];
|
245 | expect(file.from).toBe("lao");
|
246 | expect(file.to).toBe("tzu");
|
247 | expect(file.chunks.length).toBe(2);
|
248 | const chunk0 = file.chunks[0];
|
249 | expect(chunk0.oldStart).toBe(1);
|
250 | expect(chunk0.oldLines).toBe(7);
|
251 | expect(chunk0.newStart).toBe(1);
|
252 | expect(chunk0.newLines).toBe(6);
|
253 | const chunk1 = file.chunks[1];
|
254 | expect(chunk1.oldStart).toBe(9);
|
255 | expect(chunk1.oldLines).toBe(3);
|
256 | expect(chunk1.newStart).toBe(8);
|
257 | expect(chunk1.newLines).toBe(6);
|
258 | });
|
259 |
|
260 | it("should parse hg diff output", function () {
|
261 | const diff = `\
|
262 | diff -r 514fc757521e lib/parsers.coffee
|
263 | --- a/lib/parsers.coffee Thu Jul 09 00:56:36 2015 +0200
|
264 | +++ b/lib/parsers.coffee Fri Jul 10 16:23:43 2015 +0200
|
265 | @@ -43,6 +43,9 @@
|
266 | files[file] = { added: added, deleted: deleted }
|
267 | files
|
268 |
|
269 | + diff: (out) ->
|
270 | + files = {}
|
271 | +
|
272 | module.exports = Parsers
|
273 |
|
274 | module.exports.version = (out) ->\
|
275 | `;
|
276 | const files = parse(diff);
|
277 | expect(files.length).toBe(1);
|
278 | const file = files[0];
|
279 | expect(file.chunks[0].content).toBe("@@ -43,6 +43,9 @@");
|
280 | expect(file.from).toBe("lib/parsers.coffee");
|
281 | expect(file.to).toBe("lib/parsers.coffee");
|
282 | });
|
283 |
|
284 | it("should parse svn diff output", function () {
|
285 | const diff = `\
|
286 | Index: new.txt
|
287 | ===================================================================
|
288 | --- new.txt (revision 0)
|
289 | +++ new.txt (working copy)
|
290 | @@ -0,0 +1 @@
|
291 | +test
|
292 | Index: text.txt
|
293 | ===================================================================
|
294 | --- text.txt (revision 6)
|
295 | +++ text.txt (working copy)
|
296 | @@ -1,7 +1,5 @@
|
297 | -This part of the
|
298 | -document has stayed the
|
299 | -same from version to
|
300 | -version. It shouldn't
|
301 | +This is an important
|
302 | +notice! It shouldn't
|
303 | be shown if it doesn't
|
304 | change. Otherwise, that
|
305 | would not be helping to\
|
306 | `;
|
307 | const files = parse(diff);
|
308 | expect(files.length).toBe(2);
|
309 | const file = files[0];
|
310 | expect(file.from).toBe("new.txt");
|
311 | expect(file.to).toBe("new.txt");
|
312 | expect(file.chunks[0].changes.length).toBe(1);
|
313 | });
|
314 |
|
315 | it("should parse file names for n new empty file", function () {
|
316 | const diff = `\
|
317 | diff --git a/newFile.txt b/newFile.txt
|
318 | new file mode 100644
|
319 | index 0000000..e6a2e28\
|
320 | `;
|
321 | const files = parse(diff);
|
322 | expect(files.length).toBe(1);
|
323 | const file = files[0];
|
324 | expect(file.from).toBe("/dev/null");
|
325 | expect(file.to).toBe("newFile.txt");
|
326 | });
|
327 |
|
328 | it("should parse file names for a deleted file", function () {
|
329 | const diff = `\
|
330 | diff --git a/deletedFile.txt b/deletedFile.txt
|
331 | deleted file mode 100644
|
332 | index e6a2e28..0000000\
|
333 | `;
|
334 | const files = parse(diff);
|
335 | expect(files.length).toBe(1);
|
336 | const file = files[0];
|
337 | expect(file.from).toBe("deletedFile.txt");
|
338 | expect(file.to).toBe("/dev/null");
|
339 | });
|
340 |
|
341 | it("should parse rename diff with space in path with no changes", function () {
|
342 | const diff = `\
|
343 | diff --git a/My Folder/File b/My Folder/a/File
|
344 | similarity index 100%
|
345 | rename from a/My Folder/File
|
346 | rename to My Folder/a/File\
|
347 | `;
|
348 | const files = parse(diff);
|
349 | expect(files.length).toBe(1);
|
350 | const file = files[0];
|
351 | expect(file.from).toBe("My Folder/File");
|
352 | expect(file.to).toBe("My Folder/a/File");
|
353 | expect(file.chunks.length).toBe(0);
|
354 | });
|
355 |
|
356 | it("should parse rename diff with space in path with changes", function () {
|
357 | const diff = `\
|
358 | diff --git a/My Folder/File b/My Folder/a/File
|
359 | similarity index 100%
|
360 | rename from a/My Folder/File
|
361 | rename to My Folder/a/File
|
362 | @@ -1,2 +1,2 @@
|
363 | - line1
|
364 | + line2\
|
365 | `;
|
366 | const files = parse(diff);
|
367 | expect(files.length).toBe(1);
|
368 | const file = files[0];
|
369 | expect(file.from).toBe("My Folder/File");
|
370 | expect(file.to).toBe("My Folder/a/File");
|
371 | expect(file.chunks.length).toBe(1);
|
372 | const chunk = file.chunks[0];
|
373 | expect(chunk.content).toBe("@@ -1,2 +1,2 @@");
|
374 | expect(chunk.changes.length).toBe(2);
|
375 | expect(chunk.changes[0].content).toBe("- line1");
|
376 | expect(chunk.changes[1].content).toBe("+ line2");
|
377 | });
|
378 |
|
379 | it("should parse diff with single line quote escaped file names", function () {
|
380 | const diff = `
|
381 | diff --git "a/file \\"space\\"" "b/file \\"space\\""
|
382 | index 9daeafb..88bd214 100644
|
383 | --- "a/file \\"space\\""
|
384 | +++ "b/file \\"space\\""
|
385 | @@ -1 +1 @@
|
386 | -test
|
387 | +test\n1234
|
388 | `;
|
389 | const files = parse(diff);
|
390 | expect(files.length).toBe(1);
|
391 | const [file] = files;
|
392 | expect(file.from).toBe(`file \\"space\\"`);
|
393 | expect(file.to).toBe(`file \\"space\\"`);
|
394 | });
|
395 | });
|