fork of go-gitdiff with jj support
1package gitdiff
2
3import (
4 "testing"
5 "time"
6)
7
8func TestParsePatchIdentity(t *testing.T) {
9 tests := map[string]struct {
10 Input string
11 Output PatchIdentity
12 Err interface{}
13 }{
14 "simple": {
15 Input: "Morton Haypenny <mhaypenny@example.com>",
16 Output: PatchIdentity{
17 Name: "Morton Haypenny",
18 Email: "mhaypenny@example.com",
19 },
20 },
21 "extraWhitespace": {
22 Input: " Morton Haypenny <mhaypenny@example.com > ",
23 Output: PatchIdentity{
24 Name: "Morton Haypenny",
25 Email: "mhaypenny@example.com",
26 },
27 },
28 "trailingCharacters": {
29 Input: "Morton Haypenny <mhaypenny@example.com> unrelated garbage",
30 Output: PatchIdentity{
31 Name: "Morton Haypenny",
32 Email: "mhaypenny@example.com",
33 },
34 },
35 "missingName": {
36 Input: "<mhaypenny@example.com>",
37 Err: "invalid identity",
38 },
39 "missingEmail": {
40 Input: "Morton Haypenny",
41 Err: "invalid identity",
42 },
43 "unclosedEmail": {
44 Input: "Morton Haypenny <mhaypenny@example.com",
45 Err: "unclosed email",
46 },
47 }
48
49 for name, test := range tests {
50 t.Run(name, func(t *testing.T) {
51 id, err := ParsePatchIdentity(test.Input)
52 if test.Err != nil {
53 assertError(t, test.Err, err, "parsing identity")
54 return
55 }
56 if err != nil {
57 t.Fatalf("unexpected error parsing identity: %v", err)
58 }
59
60 if test.Output != id {
61 t.Errorf("incorrect identity: expected %#v, actual %#v", test.Output, id)
62 }
63 })
64 }
65}
66
67func TestParsePatchDate(t *testing.T) {
68 expected := time.Date(2020, 4, 9, 8, 7, 6, 0, time.UTC)
69
70 tests := map[string]struct {
71 Input string
72 Output time.Time
73 Err interface{}
74 }{
75 "default": {
76 Input: "Thu Apr 9 01:07:06 2020 -0700",
77 Output: expected,
78 },
79 "defaultLocal": {
80 Input: "Thu Apr 9 01:07:06 2020",
81 Output: time.Date(2020, 4, 9, 1, 7, 6, 0, time.Local),
82 },
83 "iso": {
84 Input: "2020-04-09 01:07:06 -0700",
85 Output: expected,
86 },
87 "isoStrict": {
88 Input: "2020-04-09T01:07:06-07:00",
89 Output: expected,
90 },
91 "rfc": {
92 Input: "Thu, 9 Apr 2020 01:07:06 -0700",
93 Output: expected,
94 },
95 "short": {
96 Input: "2020-04-09",
97 Output: time.Date(2020, 4, 9, 0, 0, 0, 0, time.Local),
98 },
99 "raw": {
100 Input: "1586419626 -0700",
101 Output: expected,
102 },
103 "unix": {
104 Input: "1586419626",
105 Output: expected,
106 },
107 "unknownFormat": {
108 Input: "4/9/2020 01:07:06 PDT",
109 Err: "unknown date format",
110 },
111 "empty": {
112 Input: "",
113 },
114 }
115
116 for name, test := range tests {
117 t.Run(name, func(t *testing.T) {
118 d, err := ParsePatchDate(test.Input)
119 if test.Err != nil {
120 assertError(t, test.Err, err, "parsing date")
121 return
122 }
123 if err != nil {
124 t.Fatalf("unexpected error parsing date: %v", err)
125 }
126 if !test.Output.Equal(d) {
127 t.Errorf("incorrect parsed date: expected %v, actual %v", test.Output, d)
128 }
129 })
130 }
131}
132
133func TestParsePatchHeader(t *testing.T) {
134 expectedSHA := "61f5cd90bed4d204ee3feb3aa41ee91d4734855b"
135 expectedIdentity := &PatchIdentity{
136 Name: "Morton Haypenny",
137 Email: "mhaypenny@example.com",
138 }
139 expectedDate := time.Date(2020, 04, 11, 15, 21, 23, 0, time.FixedZone("PDT", -7*60*60))
140 expectedTitle := "A sample commit to test header parsing"
141 expectedBody := "The medium format shows the body, which\nmay wrap on to multiple lines.\n\nAnother body line."
142 expectedBodyAppendix := "CC: Joe Smith <joe.smith@company.com>"
143
144 tests := map[string]struct {
145 Input string
146 Header PatchHeader
147 Err interface{}
148 }{
149 "prettyShort": {
150 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
151Author: Morton Haypenny <mhaypenny@example.com>
152
153 A sample commit to test header parsing
154`,
155 Header: PatchHeader{
156 SHA: expectedSHA,
157 Author: expectedIdentity,
158 Title: expectedTitle,
159 },
160 },
161 "prettyMedium": {
162 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
163Author: Morton Haypenny <mhaypenny@example.com>
164Date: Sat Apr 11 15:21:23 2020 -0700
165
166 A sample commit to test header parsing
167
168 The medium format shows the body, which
169 may wrap on to multiple lines.
170
171 Another body line.
172`,
173 Header: PatchHeader{
174 SHA: expectedSHA,
175 Author: expectedIdentity,
176 AuthorDate: expectedDate,
177 Title: expectedTitle,
178 Body: expectedBody,
179 },
180 },
181 "prettyFull": {
182 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
183Author: Morton Haypenny <mhaypenny@example.com>
184Commit: Morton Haypenny <mhaypenny@example.com>
185
186 A sample commit to test header parsing
187
188 The medium format shows the body, which
189 may wrap on to multiple lines.
190
191 Another body line.
192`,
193 Header: PatchHeader{
194 SHA: expectedSHA,
195 Author: expectedIdentity,
196 Committer: expectedIdentity,
197 Title: expectedTitle,
198 Body: expectedBody,
199 },
200 },
201 "prettyFuller": {
202 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
203Author: Morton Haypenny <mhaypenny@example.com>
204AuthorDate: Sat Apr 11 15:21:23 2020 -0700
205Commit: Morton Haypenny <mhaypenny@example.com>
206CommitDate: Sat Apr 11 15:21:23 2020 -0700
207
208 A sample commit to test header parsing
209
210 The medium format shows the body, which
211 may wrap on to multiple lines.
212
213 Another body line.
214`,
215 Header: PatchHeader{
216 SHA: expectedSHA,
217 Author: expectedIdentity,
218 AuthorDate: expectedDate,
219 Committer: expectedIdentity,
220 CommitterDate: expectedDate,
221 Title: expectedTitle,
222 Body: expectedBody,
223 },
224 },
225 "prettyAppendix": {
226 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
227Author: Morton Haypenny <mhaypenny@example.com>
228AuthorDate: Sat Apr 11 15:21:23 2020 -0700
229Commit: Morton Haypenny <mhaypenny@example.com>
230CommitDate: Sat Apr 11 15:21:23 2020 -0700
231
232 A sample commit to test header parsing
233
234 The medium format shows the body, which
235 may wrap on to multiple lines.
236
237 Another body line.
238 ---
239 CC: Joe Smith <joe.smith@company.com>
240`,
241 Header: PatchHeader{
242 SHA: expectedSHA,
243 Author: expectedIdentity,
244 AuthorDate: expectedDate,
245 Committer: expectedIdentity,
246 CommitterDate: expectedDate,
247 Title: expectedTitle,
248 Body: expectedBody + "\n---\n" + expectedBodyAppendix,
249 },
250 },
251 "mailbox": {
252 Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
253From: Morton Haypenny <mhaypenny@example.com>
254Date: Sat, 11 Apr 2020 15:21:23 -0700
255Subject: [PATCH] A sample commit to test header parsing
256
257The medium format shows the body, which
258may wrap on to multiple lines.
259
260Another body line.
261`,
262 Header: PatchHeader{
263 SHA: expectedSHA,
264 Author: expectedIdentity,
265 AuthorDate: expectedDate,
266 Title: expectedTitle,
267 Body: expectedBody,
268 },
269 },
270 "mailboxAppendix": {
271 Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
272From: Morton Haypenny <mhaypenny@example.com>
273Date: Sat, 11 Apr 2020 15:21:23 -0700
274Subject: [PATCH] A sample commit to test header parsing
275
276The medium format shows the body, which
277may wrap on to multiple lines.
278
279Another body line.
280---
281CC: Joe Smith <joe.smith@company.com>
282`,
283 Header: PatchHeader{
284 SHA: expectedSHA,
285 Author: expectedIdentity,
286 AuthorDate: expectedDate,
287 Title: expectedTitle,
288 Body: expectedBody,
289 BodyAppendix: expectedBodyAppendix,
290 },
291 },
292 "unwrapTitle": {
293 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
294Author: Morton Haypenny <mhaypenny@example.com>
295Date: Sat Apr 11 15:21:23 2020 -0700
296
297 A sample commit to test header parsing with a long
298 title that is wrapped.
299`,
300 Header: PatchHeader{
301 SHA: expectedSHA,
302 Author: expectedIdentity,
303 AuthorDate: expectedDate,
304 Title: expectedTitle + " with a long title that is wrapped.",
305 },
306 },
307 "normalizeBodySpace": {
308 Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
309Author: Morton Haypenny <mhaypenny@example.com>
310Date: Sat Apr 11 15:21:23 2020 -0700
311
312 A sample commit to test header parsing
313
314
315 The medium format shows the body, which
316 may wrap on to multiple lines.
317
318
319 Another body line.
320
321
322`,
323 Header: PatchHeader{
324 SHA: expectedSHA,
325 Author: expectedIdentity,
326 AuthorDate: expectedDate,
327 Title: expectedTitle,
328 Body: expectedBody,
329 },
330 },
331 "ignoreLeadingBlankLines": {
332 Input: `
333
334` + " " + `
335commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
336Author: Morton Haypenny <mhaypenny@example.com>
337
338 A sample commit to test header parsing
339`,
340 Header: PatchHeader{
341 SHA: expectedSHA,
342 Author: expectedIdentity,
343 Title: expectedTitle,
344 },
345 },
346 }
347
348 for name, test := range tests {
349 t.Run(name, func(t *testing.T) {
350 h, err := ParsePatchHeader(test.Input)
351 if test.Err != nil {
352 assertError(t, test.Err, err, "parsing patch header")
353 return
354 }
355 if err != nil {
356 t.Fatalf("unexpected error parsing patch header: %v", err)
357 }
358 if h == nil {
359 t.Fatalf("expected non-nil header, but got nil")
360 }
361
362 exp := test.Header
363 act := *h
364
365 if exp.SHA != act.SHA {
366 t.Errorf("incorrect parsed SHA: expected %q, actual %q", exp.SHA, act.SHA)
367 }
368
369 assertPatchIdentity(t, "author", exp.Author, act.Author)
370 if !exp.AuthorDate.Equal(act.AuthorDate) {
371 t.Errorf("incorrect parsed author date: expected %v, but got %v", exp.AuthorDate, act.AuthorDate)
372 }
373
374 assertPatchIdentity(t, "committer", exp.Committer, act.Committer)
375 if !exp.CommitterDate.Equal(act.CommitterDate) {
376 t.Errorf("incorrect parsed committer date: expected %v, but got %v", exp.CommitterDate, act.CommitterDate)
377 }
378
379 if exp.Title != act.Title {
380 t.Errorf("incorrect parsed title:\n expected: %q\n actual: %q", exp.Title, act.Title)
381 }
382 if exp.Body != act.Body {
383 t.Errorf("incorrect parsed body:\n expected: %q\n actual: %q", exp.Body, act.Body)
384 }
385 if exp.BodyAppendix != act.BodyAppendix {
386 t.Errorf("incorrect parsed body appendix:\n expected: %q\n actual: %q",
387 exp.BodyAppendix, act.BodyAppendix)
388 }
389 })
390 }
391}
392
393func assertPatchIdentity(t *testing.T, kind string, exp, act *PatchIdentity) {
394 switch {
395 case exp == nil && act == nil:
396 case exp == nil && act != nil:
397 t.Errorf("incorrect parsed %s: expected nil, but got %+v", kind, act)
398 case exp != nil && act == nil:
399 t.Errorf("incorrect parsed %s: expected %+v, but got nil", kind, exp)
400 case exp.Name != act.Name || exp.Email != act.Email:
401 t.Errorf("incorrect parsed %s, expected %+v, bot got %+v", kind, exp, act)
402 }
403}
404
405func TestCleanupSubject(t *testing.T) {
406 exp := "A sample commit to test header parsing"
407 tests := map[string]string{
408 "plain": "",
409 "patch": "[PATCH] ",
410 "patchv5": "[PATCH v5] ",
411 "patchrfc": "[PATCH RFC] ",
412 "patchnospace": "[PATCH]",
413 "space": " ",
414 "re": "re: ",
415 "Re": "Re: ",
416 "RE": "rE: ",
417 "rere": "re: re: ",
418 }
419
420 for name, prefix := range tests {
421 gotprefix, gottitle := parseSubject(prefix + exp)
422 if gottitle != exp {
423 t.Errorf("%s: Incorrect parsing of prefix %s: got title %s, wanted %s",
424 name, prefix, gottitle, exp)
425 }
426 if gotprefix != prefix {
427 t.Errorf("%s: Incorrect parsing of prefix %s: got prefix %s",
428 name, prefix, gotprefix)
429 }
430 }
431
432 moretests := map[string]struct {
433 in, eprefix, etitle string
434 }{
435 "Reimplement": {"Reimplement something", "", "Reimplement something"},
436 "patch-reimplement": {"[PATCH v5] Reimplement something", "[PATCH v5] ", "Reimplement something"},
437 "Openbracket": {"[Just to annoy people", "", "[Just to annoy people"},
438 }
439
440 for name, test := range moretests {
441 prefix, title := parseSubject(test.in)
442 if title != test.etitle {
443 t.Errorf("%s: Incorrect parsing of %s: got title %s, wanted %s",
444 name, test.in, title, test.etitle)
445 }
446 if prefix != test.eprefix {
447 t.Errorf("%s: Incorrect parsing of %s: got prefix %s, wanted %s",
448 name, test.in, title, test.etitle)
449 }
450 }
451}