cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.62.2

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/reporter/bitbucket_comments_test.go

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