cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.65.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/reporter/bitbucket_comments_test.go

632lines · modecode

1package reporter
2
3import (
4 "fmt"
5 "log/slog"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/google/go-cmp/cmp"
11 "github.com/neilotoole/slogt"
12
13 "github.com/cloudflare/pint/internal/checks"
14 "github.com/cloudflare/pint/internal/discovery"
15 "github.com/cloudflare/pint/internal/parser"
16)
17
18func TestBitBucketMakeComments(t *testing.T) {
19 type testCaseT struct {
20 changes *bitBucketPRChanges
21 description string
22 comments []BitBucketPendingComment
23 summary Summary
24 maxComments int
25 }
26
27 commentBody := func(icon, severity, reporter, text string) string {
28 return fmt.Sprintf(
29 ":%s: **%s** reported by [pint](https://cloudflare.github.io/pint/) **%s** check.\n\n------\n\n%s\n\n------\n\n:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/%s.html).\n",
30 icon, severity, reporter, text, reporter,
31 )
32 }
33
34 testCases := []testCaseT{
35 {
36 description: "empty summary",
37 maxComments: 50,
38 comments: []BitBucketPendingComment{},
39 },
40 {
41 description: "report not included in changes",
42 maxComments: 50,
43 summary: Summary{reports: []Report{
44 {
45 Path: discovery.Path{
46 SymlinkTarget: "rule.yaml",
47 Name: "rule.yaml",
48 },
49 ModifiedLines: []int{2, 3},
50 Problem: checks.Problem{
51 Severity: checks.Bug,
52 },
53 },
54 }},
55 changes: &bitBucketPRChanges{},
56 comments: []BitBucketPendingComment{},
57 },
58 {
59 description: "reports included in changes",
60 maxComments: 50,
61 summary: Summary{reports: []Report{
62 {
63 Path: discovery.Path{
64 SymlinkTarget: "rule.yaml",
65 Name: "rule.yaml",
66 },
67 ModifiedLines: []int{2, 3},
68 Problem: checks.Problem{
69 Severity: checks.Bug,
70 Lines: parser.LineRange{
71 First: 2,
72 Last: 2,
73 },
74 Text: "first error",
75 Details: "first details",
76 Reporter: "r1",
77 },
78 },
79 {
80 Path: discovery.Path{
81 SymlinkTarget: "rule.yaml",
82 Name: "rule.yaml",
83 },
84 ModifiedLines: []int{2, 3},
85 Problem: checks.Problem{
86 Severity: checks.Warning,
87 Lines: parser.LineRange{
88 First: 3,
89 Last: 3,
90 },
91 Text: "second error",
92 Details: "second details",
93 Reporter: "r1",
94 },
95 },
96 {
97 Path: discovery.Path{
98 SymlinkTarget: "rule.yaml",
99 Name: "rule.yaml",
100 },
101 ModifiedLines: []int{2, 3},
102 Problem: checks.Problem{
103 Severity: checks.Bug,
104 Lines: parser.LineRange{
105 First: 2,
106 Last: 2,
107 },
108 Text: "third error",
109 Details: "third details",
110 Reporter: "r2",
111 },
112 },
113 {
114 Path: discovery.Path{
115 SymlinkTarget: "rule.yaml",
116 Name: "symlink.yaml",
117 },
118 ModifiedLines: []int{2, 3},
119 Problem: checks.Problem{
120 Severity: checks.Bug,
121 Lines: parser.LineRange{
122 First: 2,
123 Last: 2,
124 },
125 Text: "fourth error",
126 Details: "fourth details",
127 Reporter: "r2",
128 },
129 },
130 {
131 Path: discovery.Path{
132 SymlinkTarget: "second.yaml",
133 Name: "second.yaml",
134 },
135 ModifiedLines: []int{1, 2, 3},
136 Problem: checks.Problem{
137 Anchor: checks.AnchorBefore,
138 Severity: checks.Bug,
139 Lines: parser.LineRange{
140 First: 2,
141 Last: 2,
142 },
143 Text: "fifth error",
144 Details: "fifth details",
145 Reporter: "r2",
146 },
147 },
148 {
149 Path: discovery.Path{
150 SymlinkTarget: "second.yaml",
151 Name: "second.yaml",
152 },
153 ModifiedLines: []int{1, 2, 3},
154 Problem: checks.Problem{
155 Severity: checks.Bug,
156 Lines: parser.LineRange{
157 First: 2,
158 Last: 2,
159 },
160 Text: "sixth error",
161 Details: "sixth details",
162 Reporter: "r2",
163 },
164 },
165 }},
166 changes: &bitBucketPRChanges{
167 pathModifiedLines: map[string][]int{
168 "rule.yaml": {2, 3},
169 "second.yaml": {1, 2, 3},
170 },
171 pathLineMapping: map[string]map[int]int{
172 "rule.yaml": {2: 2, 3: 3},
173 "second.yaml": {1: 5, 2: 6, 3: 7},
174 },
175 },
176 comments: []BitBucketPendingComment{
177 {
178 Text: commentBody("stop_sign", "Bug", "r1", "first error\n\nfirst details"),
179 Severity: "BLOCKER",
180 Anchor: BitBucketPendingCommentAnchor{
181 Path: "rule.yaml",
182 Line: 2,
183 LineType: "ADDED",
184 FileType: "TO",
185 DiffType: "EFFECTIVE",
186 },
187 },
188 {
189 Text: commentBody("warning", "Warning", "r1", "second error\n\nsecond details"),
190 Severity: "NORMAL",
191 Anchor: BitBucketPendingCommentAnchor{
192 Path: "rule.yaml",
193 Line: 3,
194 LineType: "ADDED",
195 FileType: "TO",
196 DiffType: "EFFECTIVE",
197 },
198 },
199 {
200 Text: commentBody("stop_sign", "Bug", "r2", "third error\n\nthird details\n\n------\n\nfourth error\n\nfourth details\n\n:leftwards_arrow_with_hook: This problem was detected on a symlinked file `symlink.yaml`."),
201 Severity: "BLOCKER",
202 Anchor: BitBucketPendingCommentAnchor{
203 Path: "rule.yaml",
204 Line: 2,
205 LineType: "ADDED",
206 FileType: "TO",
207 DiffType: "EFFECTIVE",
208 },
209 },
210 {
211 Text: commentBody("stop_sign", "Bug", "r2", "fifth error\n\nfifth details"),
212 Severity: "BLOCKER",
213 Anchor: BitBucketPendingCommentAnchor{
214 Path: "second.yaml",
215 Line: 2,
216 LineType: "REMOVED",
217 FileType: "FROM",
218 DiffType: "EFFECTIVE",
219 },
220 },
221 {
222 Text: commentBody("stop_sign", "Bug", "r2", "sixth error\n\nsixth details"),
223 Severity: "BLOCKER",
224 Anchor: BitBucketPendingCommentAnchor{
225 Path: "second.yaml",
226 Line: 2,
227 LineType: "ADDED",
228 FileType: "TO",
229 DiffType: "EFFECTIVE",
230 },
231 },
232 },
233 },
234 {
235 description: "dedup reporter",
236 maxComments: 50,
237 summary: Summary{reports: []Report{
238 {
239 Path: discovery.Path{
240 SymlinkTarget: "rule.yaml",
241 Name: "rule.yaml",
242 },
243 ModifiedLines: []int{2, 3},
244 Problem: checks.Problem{
245 Severity: checks.Bug,
246 Lines: parser.LineRange{
247 First: 2,
248 Last: 2,
249 },
250 Text: "first error",
251 Details: "first details",
252 Reporter: "r1",
253 },
254 },
255 {
256 Path: discovery.Path{
257 SymlinkTarget: "rule.yaml",
258 Name: "rule.yaml",
259 },
260 ModifiedLines: []int{2, 3},
261 Problem: checks.Problem{
262 Severity: checks.Bug,
263 Lines: parser.LineRange{
264 First: 2,
265 Last: 2,
266 },
267 Text: "second error",
268 Details: "second details",
269 Reporter: "r1",
270 },
271 },
272 }},
273 changes: &bitBucketPRChanges{
274 pathModifiedLines: map[string][]int{
275 "rule.yaml": {2, 3},
276 },
277 pathLineMapping: map[string]map[int]int{
278 "rule.yaml": {2: 2, 3: 3},
279 },
280 },
281 comments: []BitBucketPendingComment{
282 {
283 Text: commentBody("stop_sign", "Bug", "r1", "first error\n\nfirst details\n\n------\n\nsecond error\n\nsecond details"),
284 Severity: "BLOCKER",
285 Anchor: BitBucketPendingCommentAnchor{
286 Path: "rule.yaml",
287 Line: 2,
288 LineType: "ADDED",
289 FileType: "TO",
290 DiffType: "EFFECTIVE",
291 },
292 },
293 },
294 },
295 {
296 description: "dedup identical reports",
297 maxComments: 50,
298 summary: Summary{reports: []Report{
299 {
300 Path: discovery.Path{
301 SymlinkTarget: "rule.yaml",
302 Name: "rule.yaml",
303 },
304 ModifiedLines: []int{2, 3},
305 Problem: checks.Problem{
306 Severity: checks.Bug,
307 Lines: parser.LineRange{
308 First: 2,
309 Last: 2,
310 },
311 Text: "my error",
312 Details: "my details",
313 Reporter: "r1",
314 },
315 },
316 {
317 Path: discovery.Path{
318 SymlinkTarget: "rule.yaml",
319 Name: "rule.yaml",
320 },
321 ModifiedLines: []int{2, 3},
322 Problem: checks.Problem{
323 Severity: checks.Bug,
324 Lines: parser.LineRange{
325 First: 2,
326 Last: 2,
327 },
328 Text: "my error",
329 Details: "my details",
330 Reporter: "r1",
331 },
332 },
333 }},
334 changes: &bitBucketPRChanges{
335 pathModifiedLines: map[string][]int{
336 "rule.yaml": {2, 3},
337 },
338 pathLineMapping: map[string]map[int]int{
339 "rule.yaml": {2: 2, 3: 3},
340 },
341 },
342 comments: []BitBucketPendingComment{
343 {
344 Text: commentBody("stop_sign", "Bug", "r1", "my error\n\nmy details"),
345 Severity: "BLOCKER",
346 Anchor: BitBucketPendingCommentAnchor{
347 Path: "rule.yaml",
348 Line: 2,
349 LineType: "ADDED",
350 FileType: "TO",
351 DiffType: "EFFECTIVE",
352 },
353 },
354 },
355 },
356 {
357 description: "dedup details",
358 maxComments: 50,
359 summary: Summary{reports: []Report{
360 {
361 Path: discovery.Path{
362 SymlinkTarget: "rule.yaml",
363 Name: "rule.yaml",
364 },
365 ModifiedLines: []int{2, 3},
366 Problem: checks.Problem{
367 Severity: checks.Bug,
368 Lines: parser.LineRange{
369 First: 2,
370 Last: 2,
371 },
372 Text: "first error",
373 Details: "shared details",
374 Reporter: "r1",
375 },
376 },
377 {
378 Path: discovery.Path{
379 SymlinkTarget: "rule.yaml",
380 Name: "rule.yaml",
381 },
382 ModifiedLines: []int{2, 3},
383 Problem: checks.Problem{
384 Severity: checks.Bug,
385 Lines: parser.LineRange{
386 First: 2,
387 Last: 2,
388 },
389 Text: "second error",
390 Details: "shared details",
391 Reporter: "r1",
392 },
393 },
394 }},
395 changes: &bitBucketPRChanges{
396 pathModifiedLines: map[string][]int{
397 "rule.yaml": {2, 3},
398 },
399 pathLineMapping: map[string]map[int]int{
400 "rule.yaml": {2: 2, 3: 3},
401 },
402 },
403 comments: []BitBucketPendingComment{
404 {
405 Text: commentBody("stop_sign", "Bug", "r1", "first error\n\n------\n\nsecond error\n\n------\n\nshared details"),
406 Severity: "BLOCKER",
407 Anchor: BitBucketPendingCommentAnchor{
408 Path: "rule.yaml",
409 Line: 2,
410 LineType: "ADDED",
411 FileType: "TO",
412 DiffType: "EFFECTIVE",
413 },
414 },
415 },
416 },
417 {
418 description: "maxComments 2",
419 maxComments: 2,
420 summary: Summary{reports: []Report{
421 {
422 Path: discovery.Path{
423 SymlinkTarget: "rule.yaml",
424 Name: "rule.yaml",
425 },
426 ModifiedLines: []int{2, 3},
427 Problem: checks.Problem{
428 Severity: checks.Bug,
429 Lines: parser.LineRange{
430 First: 2,
431 Last: 2,
432 },
433 Text: "first error",
434 Details: "first details",
435 Reporter: "r1",
436 },
437 },
438 {
439 Path: discovery.Path{
440 SymlinkTarget: "rule.yaml",
441 Name: "rule.yaml",
442 },
443 ModifiedLines: []int{2, 3},
444 Problem: checks.Problem{
445 Severity: checks.Warning,
446 Lines: parser.LineRange{
447 First: 3,
448 Last: 3,
449 },
450 Text: "second error",
451 Details: "second details",
452 Reporter: "r1",
453 },
454 },
455 {
456 Path: discovery.Path{
457 SymlinkTarget: "rule.yaml",
458 Name: "rule.yaml",
459 },
460 ModifiedLines: []int{2, 3},
461 Problem: checks.Problem{
462 Severity: checks.Bug,
463 Lines: parser.LineRange{
464 First: 2,
465 Last: 2,
466 },
467 Text: "third error",
468 Details: "third details",
469 Reporter: "r2",
470 },
471 },
472 {
473 Path: discovery.Path{
474 SymlinkTarget: "rule.yaml",
475 Name: "symlink.yaml",
476 },
477 ModifiedLines: []int{2, 3},
478 Problem: checks.Problem{
479 Severity: checks.Bug,
480 Lines: parser.LineRange{
481 First: 2,
482 Last: 2,
483 },
484 Text: "fourth error",
485 Details: "fourth details",
486 Reporter: "r2",
487 },
488 },
489 {
490 Path: discovery.Path{
491 SymlinkTarget: "second.yaml",
492 Name: "second.yaml",
493 },
494 ModifiedLines: []int{1, 2, 3},
495 Problem: checks.Problem{
496 Anchor: checks.AnchorBefore,
497 Severity: checks.Bug,
498 Lines: parser.LineRange{
499 First: 2,
500 Last: 2,
501 },
502 Text: "fifth error",
503 Details: "fifth details",
504 Reporter: "r2",
505 },
506 },
507 {
508 Path: discovery.Path{
509 SymlinkTarget: "second.yaml",
510 Name: "second.yaml",
511 },
512 ModifiedLines: []int{1, 2, 3},
513 Problem: checks.Problem{
514 Severity: checks.Bug,
515 Lines: parser.LineRange{
516 First: 2,
517 Last: 2,
518 },
519 Text: "sixth error",
520 Details: "sixth details",
521 Reporter: "r2",
522 },
523 },
524 }},
525 changes: &bitBucketPRChanges{
526 pathModifiedLines: map[string][]int{
527 "rule.yaml": {2, 3},
528 "second.yaml": {1, 2, 3},
529 },
530 pathLineMapping: map[string]map[int]int{
531 "rule.yaml": {2: 2, 3: 3},
532 "second.yaml": {1: 5, 2: 6, 3: 7},
533 },
534 },
535 comments: []BitBucketPendingComment{
536 {
537 Text: commentBody("stop_sign", "Bug", "r1", "first error\n\nfirst details"),
538 Severity: "BLOCKER",
539 Anchor: BitBucketPendingCommentAnchor{
540 Path: "rule.yaml",
541 Line: 2,
542 LineType: "ADDED",
543 FileType: "TO",
544 DiffType: "EFFECTIVE",
545 },
546 },
547 {
548 Text: commentBody("warning", "Warning", "r1", "second error\n\nsecond details"),
549 Severity: "NORMAL",
550 Anchor: BitBucketPendingCommentAnchor{
551 Path: "rule.yaml",
552 Line: 3,
553 LineType: "ADDED",
554 FileType: "TO",
555 DiffType: "EFFECTIVE",
556 },
557 },
558 {
559 Text: "This pint run would create 5 comment(s), which is more than 2 limit configured for pint.\n3 comments were skipped and won't be visibile on this PR.",
560 Severity: "NORMAL",
561 Anchor: BitBucketPendingCommentAnchor{
562 DiffType: "EFFECTIVE",
563 },
564 },
565 },
566 },
567 {
568 description: "truncate long comments",
569 maxComments: 2,
570 summary: Summary{reports: []Report{
571 {
572 Path: discovery.Path{
573 SymlinkTarget: "rule.yaml",
574 Name: "rule.yaml",
575 },
576 ModifiedLines: []int{2, 3},
577 Problem: checks.Problem{
578 Severity: checks.Bug,
579 Lines: parser.LineRange{
580 First: 2,
581 Last: 2,
582 },
583 Text: strings.Repeat("X", maxCommentLength+1),
584 Reporter: "r1",
585 },
586 },
587 }},
588 changes: &bitBucketPRChanges{
589 pathModifiedLines: map[string][]int{
590 "rule.yaml": {2, 3},
591 },
592 pathLineMapping: map[string]map[int]int{
593 "rule.yaml": {2: 2, 3: 3},
594 },
595 },
596 comments: []BitBucketPendingComment{
597 {
598 Text: ":stop_sign: **Bug** reported by [pint](https://cloudflare.github.io/pint/) **r1** check.\n\n------\n\n" + strings.Repeat("X", maxCommentLength-98-4) + " ...",
599 Severity: "BLOCKER",
600 Anchor: BitBucketPendingCommentAnchor{
601 Path: "rule.yaml",
602 Line: 2,
603 LineType: "ADDED",
604 FileType: "TO",
605 DiffType: "EFFECTIVE",
606 },
607 },
608 },
609 },
610 }
611
612 for _, tc := range testCases {
613 t.Run(tc.description, func(t *testing.T) {
614 slog.SetDefault(slogt.New(t))
615 r := NewBitBucketReporter(
616 "v0.0.0",
617 "http://bitbucket.example.com",
618 time.Second,
619 "token",
620 "proj",
621 "repo",
622 tc.maxComments,
623 nil,
624 )
625 comments := r.api.limitComments(r.api.makeComments(tc.summary, tc.changes))
626 if diff := cmp.Diff(tc.comments, comments); diff != "" {
627 t.Errorf("api.makeComments() returned wrong output (-want +got):\n%s", diff)
628 return
629 }
630 })
631 }
632}
633