cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.60.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/reporter/comments_test.go

771lines · modecode

1package reporter
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "log/slog"
8 "testing"
9
10 "github.com/neilotoole/slogt"
11 "github.com/stretchr/testify/require"
12
13 "github.com/cloudflare/pint/internal/checks"
14 "github.com/cloudflare/pint/internal/discovery"
15 "github.com/cloudflare/pint/internal/parser"
16)
17
18var (
19 errSummary = errors.New("Summary() error")
20 errList = errors.New("List() error")
21 errCanCreate = errors.New("CanCreate() error")
22 errCreate = errors.New("Create() error")
23 errDelete = errors.New("Delete() error")
24)
25
26type testCommenter struct {
27 destinations func(context.Context) ([]any, error)
28 summary func(context.Context, any, Summary, []error) error
29 list func(context.Context, any) ([]ExistingCommentV2, error)
30 create func(context.Context, any, PendingCommentV2) error
31 delete func(context.Context, any, ExistingCommentV2) error
32 canCreate func(int) (bool, error)
33 isEqual func(ExistingCommentV2, PendingCommentV2) bool
34}
35
36func (tc testCommenter) Describe() string {
37 return "testCommenter"
38}
39
40func (tc testCommenter) Destinations(ctx context.Context) ([]any, error) {
41 return tc.destinations(ctx)
42}
43
44func (tc testCommenter) Summary(ctx context.Context, dst any, s Summary, errs []error) error {
45 return tc.summary(ctx, dst, s, errs)
46}
47
48func (tc testCommenter) List(ctx context.Context, dst any) ([]ExistingCommentV2, error) {
49 return tc.list(ctx, dst)
50}
51
52func (tc testCommenter) Create(ctx context.Context, dst any, comment PendingCommentV2) error {
53 return tc.create(ctx, dst, comment)
54}
55
56func (tc testCommenter) Delete(ctx context.Context, dst any, comment ExistingCommentV2) error {
57 return tc.delete(ctx, dst, comment)
58}
59
60func (tc testCommenter) CanCreate(n int) (bool, error) {
61 return tc.canCreate(n)
62}
63
64func (tc testCommenter) IsEqual(e ExistingCommentV2, p PendingCommentV2) bool {
65 return tc.isEqual(e, p)
66}
67
68func TestCommenter(t *testing.T) {
69 p := parser.NewParser()
70 mockRules, _ := p.Parse([]byte(`
71- record: target is down
72 expr: up == 0
73- record: sum errors
74 expr: sum(errors) by (job)
75`))
76
77 fooReport := Report{
78 Path: discovery.Path{
79 SymlinkTarget: "foo.txt",
80 Name: "foo.txt",
81 },
82 ModifiedLines: []int{2},
83 Rule: mockRules[0],
84 Problem: checks.Problem{
85 Reporter: "foo",
86 Text: "foo error",
87 Details: "foo details",
88 Lines: parser.LineRange{First: 1, Last: 3},
89 Severity: checks.Fatal,
90 Anchor: checks.AnchorAfter,
91 },
92 }
93 fooComment := ExistingCommentV2{
94 path: "foo.txt",
95 line: 2,
96 text: `:stop_sign: **Fatal** reported by [pint](https://cloudflare.github.io/pint/) **foo** check.
97
98------
99
100foo error
101
102foo details
103
104------
105
106:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/foo.html).
107`,
108 meta: nil,
109 }
110
111 barReport := Report{
112 Path: discovery.Path{
113 SymlinkTarget: "bar.txt",
114 Name: "bar.txt",
115 },
116 ModifiedLines: []int{1},
117 Rule: mockRules[0],
118 Problem: checks.Problem{
119 Reporter: "bar",
120 Text: "bar warning",
121 Details: "",
122 Lines: parser.LineRange{First: 1, Last: 1},
123 Severity: checks.Warning,
124 Anchor: checks.AnchorBefore,
125 },
126 }
127 barComment := ExistingCommentV2{
128 path: "bar.txt",
129 line: 1,
130 text: `:warning: **Warning** reported by [pint](https://cloudflare.github.io/pint/) **bar** check.
131
132------
133
134bar warning
135
136------
137
138:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/bar.html).
139`,
140 meta: nil,
141 }
142
143 type testCaseT struct {
144 commenter Commenter
145 checkErr func(t *testing.T, err error)
146 description string
147 reports []Report
148 }
149
150 testCases := []testCaseT{
151 {
152 description: "no-op when there are no destinations",
153 reports: []Report{},
154 commenter: testCommenter{
155 destinations: func(_ context.Context) ([]any, error) {
156 return []any{}, nil
157 },
158 },
159 checkErr: func(t *testing.T, err error) {
160 require.NoError(t, err)
161 },
162 },
163 {
164 description: "stops if List() fails",
165 reports: []Report{},
166 commenter: testCommenter{
167 destinations: func(_ context.Context) ([]any, error) {
168 return []any{1}, nil
169 },
170 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
171 if len(errs) != 0 {
172 return fmt.Errorf("Expected empty errs, got %v", errs)
173 }
174 return nil
175 },
176 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
177 return nil, errList
178 },
179 },
180 checkErr: func(t *testing.T, err error) {
181 require.ErrorIs(t, err, errList)
182 },
183 },
184 {
185 description: "no-op when all comments already exist",
186 reports: []Report{fooReport, barReport},
187 commenter: testCommenter{
188 destinations: func(_ context.Context) ([]any, error) {
189 return []any{1}, nil
190 },
191 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
192 if len(errs) != 0 {
193 return fmt.Errorf("Expected empty errs, got %v", errs)
194 }
195 return nil
196 },
197 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
198 return []ExistingCommentV2{fooComment, barComment}, nil
199 },
200 create: func(_ context.Context, _ any, p PendingCommentV2) error {
201 return fmt.Errorf("shouldn't try to create %s:%d", p.path, p.line)
202 },
203 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
204 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
205 },
206 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
207 return e.path == p.path && e.line == p.line && e.text == p.text
208 },
209 canCreate: func(_ int) (bool, error) {
210 return true, nil
211 },
212 },
213 checkErr: func(t *testing.T, err error) {
214 require.NoError(t, err)
215 },
216 },
217 {
218 description: "creates missing comments",
219 reports: []Report{fooReport, barReport},
220 commenter: testCommenter{
221 destinations: func(_ context.Context) ([]any, error) {
222 return []any{1}, nil
223 },
224 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
225 if len(errs) != 0 {
226 return fmt.Errorf("Expected empty errs, got %v", errs)
227 }
228 return nil
229 },
230 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
231 return []ExistingCommentV2{fooComment}, nil
232 },
233 create: func(_ context.Context, _ any, p PendingCommentV2) error {
234 if p.path == barComment.path && p.line == barComment.line && p.text == barComment.text {
235 return nil
236 }
237 return fmt.Errorf("shouldn't try to create %s:%d", p.path, p.line)
238 },
239 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
240 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
241 },
242 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
243 return e.path == p.path && e.line == p.line && e.text == p.text
244 },
245 canCreate: func(_ int) (bool, error) {
246 return true, nil
247 },
248 },
249 checkErr: func(t *testing.T, err error) {
250 require.NoError(t, err)
251 },
252 },
253 {
254 description: "skips creating comments when CanCreate() is false",
255 reports: []Report{barReport, fooReport},
256 commenter: testCommenter{
257 destinations: func(_ context.Context) ([]any, error) {
258 return []any{1}, nil
259 },
260 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
261 if len(errs) != 0 {
262 return fmt.Errorf("Expected empty errs, got %v", errs)
263 }
264 return nil
265 },
266 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
267 return nil, nil
268 },
269 create: func(_ context.Context, _ any, p PendingCommentV2) error {
270 if p.path == barComment.path && p.line == barComment.line && p.text == barComment.text {
271 return nil
272 }
273 return fmt.Errorf("shouldn't try to create %s:%d", p.path, p.line)
274 },
275 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
276 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
277 },
278 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
279 return e.path == p.path && e.line == p.line && e.text == p.text
280 },
281 canCreate: func(n int) (bool, error) {
282 return n == 0, nil
283 },
284 },
285 checkErr: func(t *testing.T, err error) {
286 require.NoError(t, err)
287 },
288 },
289 {
290 description: "CanCreate() fails",
291 reports: []Report{barReport, fooReport},
292 commenter: testCommenter{
293 destinations: func(_ context.Context) ([]any, error) {
294 return []any{1}, nil
295 },
296 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
297 if len(errs) != 2 {
298 return fmt.Errorf("Expected errCanCreate in errs, got %v", errs)
299 }
300 if !errors.Is(errs[0], errCanCreate) {
301 return fmt.Errorf("Expected errCanCreate in errs, got %w", errs[0])
302 }
303 if !errors.Is(errs[1], errCanCreate) {
304 return fmt.Errorf("Expected errCanCreate in errs, got %w", errs[1])
305 }
306 return nil
307 },
308 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
309 return nil, nil
310 },
311 create: func(_ context.Context, _ any, p PendingCommentV2) error {
312 if p.path == barComment.path && p.line == barComment.line && p.text == barComment.text {
313 return nil
314 }
315 return fmt.Errorf("shouldn't try to create %s:%d", p.path, p.line)
316 },
317 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
318 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
319 },
320 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
321 return e.path == p.path && e.line == p.line && e.text == p.text
322 },
323 canCreate: func(_ int) (bool, error) {
324 return false, errCanCreate
325 },
326 },
327 checkErr: func(t *testing.T, err error) {
328 require.NoError(t, err)
329 },
330 },
331 {
332 description: "Create() fails",
333 reports: []Report{barReport, fooReport},
334 commenter: testCommenter{
335 destinations: func(_ context.Context) ([]any, error) {
336 return []any{1}, nil
337 },
338 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
339 if len(errs) != 0 {
340 return fmt.Errorf("Expected empty errs, got %v", errs)
341 }
342 return nil
343 },
344 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
345 return nil, nil
346 },
347 create: func(_ context.Context, _ any, p PendingCommentV2) error {
348 if p.path == barComment.path && p.line == barComment.line && p.text == barComment.text {
349 return nil
350 }
351 return errCreate
352 },
353 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
354 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
355 },
356 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
357 return e.path == p.path && e.line == p.line && e.text == p.text
358 },
359 canCreate: func(_ int) (bool, error) {
360 return true, nil
361 },
362 },
363 checkErr: func(t *testing.T, err error) {
364 require.ErrorIs(t, err, errCreate)
365 },
366 },
367 {
368 description: "Create() works",
369 reports: []Report{barReport, fooReport},
370 commenter: testCommenter{
371 destinations: func(_ context.Context) ([]any, error) {
372 return []any{1}, nil
373 },
374 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
375 if len(errs) != 0 {
376 return fmt.Errorf("Expected empty errs, got %v", errs)
377 }
378 return nil
379 },
380 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
381 return nil, nil
382 },
383 create: func(_ context.Context, _ any, p PendingCommentV2) error {
384 if p.path == barComment.path && p.line == barComment.line && p.text == barComment.text {
385 return nil
386 }
387 if p.path == fooComment.path && p.line == fooComment.line && p.text == fooComment.text {
388 return nil
389 }
390 return fmt.Errorf("unexpected comment at %s:%d: %s", p.path, p.line, p.text)
391 },
392 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
393 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
394 },
395 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
396 return e.path == p.path && e.line == p.line && e.text == p.text
397 },
398 canCreate: func(_ int) (bool, error) {
399 return true, nil
400 },
401 },
402 checkErr: func(t *testing.T, err error) {
403 require.NoError(t, err)
404 },
405 },
406 {
407 description: "Create() merges details",
408 reports: []Report{
409 {
410 Path: discovery.Path{
411 SymlinkTarget: "bar.txt",
412 Name: "foo.txt",
413 },
414 ModifiedLines: []int{2, 3, 4, 5},
415 Rule: mockRules[0],
416 Problem: checks.Problem{
417 Reporter: "foo",
418 Text: "foo error 1",
419 Details: "foo details",
420 Lines: parser.LineRange{First: 1, Last: 3},
421 Severity: checks.Bug,
422 Anchor: checks.AnchorAfter,
423 },
424 },
425 {
426 Path: discovery.Path{
427 SymlinkTarget: "bar.txt",
428 Name: "foo.txt",
429 },
430 ModifiedLines: []int{2, 3, 4, 5},
431 Rule: mockRules[0],
432 Problem: checks.Problem{
433 Reporter: "foo",
434 Text: "foo error 2",
435 Details: "foo details",
436 Lines: parser.LineRange{First: 1, Last: 3},
437 Severity: checks.Bug,
438 Anchor: checks.AnchorAfter,
439 },
440 },
441 },
442 commenter: testCommenter{
443 destinations: func(_ context.Context) ([]any, error) {
444 return []any{1}, nil
445 },
446 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
447 if len(errs) != 0 {
448 return fmt.Errorf("Expected empty errs, got %v", errs)
449 }
450 return nil
451 },
452 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
453 return nil, nil
454 },
455 create: func(_ context.Context, _ any, p PendingCommentV2) error {
456 if p.path != "bar.txt" {
457 return fmt.Errorf("wrong path: %s", p.path)
458 }
459 if p.line != 3 {
460 return fmt.Errorf("wrong line: %d", p.line)
461 }
462 if p.text != `:stop_sign: **Bug** reported by [pint](https://cloudflare.github.io/pint/) **foo** check.
463
464------
465
466foo error 1
467
468:leftwards_arrow_with_hook: This problem was detected on a symlinked file `+"`foo.txt`"+`.
469
470------
471
472foo error 2
473
474:leftwards_arrow_with_hook: This problem was detected on a symlinked file `+"`foo.txt`"+`.
475
476------
477
478foo details
479
480------
481
482:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/foo.html).
483` {
484 return fmt.Errorf("wrong text: %s", p.text)
485 }
486 return nil
487 },
488 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
489 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
490 },
491 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
492 return e.path == p.path && e.line == p.line && e.text == p.text
493 },
494 canCreate: func(_ int) (bool, error) {
495 return true, nil
496 },
497 },
498 checkErr: func(t *testing.T, err error) {
499 require.NoError(t, err)
500 },
501 },
502 {
503 description: "Create() reports symlink",
504 reports: []Report{
505 {
506 Path: discovery.Path{
507 SymlinkTarget: "bar.txt",
508 Name: "foo.txt",
509 },
510 ModifiedLines: []int{2, 3, 4, 5},
511 Rule: mockRules[0],
512 Problem: checks.Problem{
513 Reporter: "foo",
514 Text: "foo error",
515 Details: "foo details",
516 Lines: parser.LineRange{First: 1, Last: 3},
517 Severity: checks.Bug,
518 Anchor: checks.AnchorAfter,
519 },
520 },
521 },
522 commenter: testCommenter{
523 destinations: func(_ context.Context) ([]any, error) {
524 return []any{1}, nil
525 },
526 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
527 if len(errs) != 0 {
528 return fmt.Errorf("Expected empty errs, got %v", errs)
529 }
530 return nil
531 },
532 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
533 return nil, nil
534 },
535 create: func(_ context.Context, _ any, p PendingCommentV2) error {
536 if p.path != "bar.txt" {
537 return fmt.Errorf("wrong path: %s", p.path)
538 }
539 if p.line != 3 {
540 return fmt.Errorf("wrong line: %d", p.line)
541 }
542 if p.text != `:stop_sign: **Bug** reported by [pint](https://cloudflare.github.io/pint/) **foo** check.
543
544------
545
546foo error
547
548foo details
549
550:leftwards_arrow_with_hook: This problem was detected on a symlinked file `+"`foo.txt`"+`.
551
552------
553
554:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/foo.html).
555` {
556 return fmt.Errorf("wrong text: %s", p.text)
557 }
558 return nil
559 },
560 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
561 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
562 },
563 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
564 return e.path == p.path && e.line == p.line && e.text == p.text
565 },
566 canCreate: func(_ int) (bool, error) {
567 return true, nil
568 },
569 },
570 checkErr: func(t *testing.T, err error) {
571 require.NoError(t, err)
572 },
573 },
574 {
575 description: "Create() doesn't merge details with different line range",
576 reports: []Report{
577 {
578 Path: discovery.Path{
579 SymlinkTarget: "foo.txt",
580 Name: "foo.txt",
581 },
582 ModifiedLines: []int{2, 3, 4, 5},
583 Rule: mockRules[0],
584 Problem: checks.Problem{
585 Reporter: "foo",
586 Text: "foo error 1",
587 Details: "foo details",
588 Lines: parser.LineRange{First: 1, Last: 3},
589 Severity: checks.Bug,
590 Anchor: checks.AnchorAfter,
591 },
592 },
593 {
594 Path: discovery.Path{
595 SymlinkTarget: "foo.txt",
596 Name: "foo.txt",
597 },
598 ModifiedLines: []int{2, 3, 4, 5},
599 Rule: mockRules[0],
600 Problem: checks.Problem{
601 Reporter: "foo",
602 Text: "foo error 2",
603 Details: "foo details",
604 Lines: parser.LineRange{First: 2, Last: 2},
605 Severity: checks.Bug,
606 Anchor: checks.AnchorAfter,
607 },
608 },
609 },
610 commenter: testCommenter{
611 destinations: func(_ context.Context) ([]any, error) {
612 return []any{1}, nil
613 },
614 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
615 if len(errs) != 0 {
616 return fmt.Errorf("Expected empty errs, got %v", errs)
617 }
618 return nil
619 },
620 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
621 return nil, nil
622 },
623 create: func(_ context.Context, _ any, p PendingCommentV2) error {
624 if p.path != "foo.txt" {
625 return fmt.Errorf("wrong path: %s", p.path)
626 }
627 if p.line != 2 && p.line != 3 {
628 return fmt.Errorf("wrong line: %d", p.line)
629 }
630 if p.line == 3 && p.text != `:stop_sign: **Bug** reported by [pint](https://cloudflare.github.io/pint/) **foo** check.
631
632------
633
634foo error 1
635
636foo details
637
638------
639
640:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/foo.html).
641` {
642 return fmt.Errorf("wrong text on first report: %s", p.text)
643 }
644 if p.line == 2 && p.text != `:stop_sign: **Bug** reported by [pint](https://cloudflare.github.io/pint/) **foo** check.
645
646------
647
648foo error 2
649
650foo details
651
652------
653
654:information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/foo.html).
655` {
656 return fmt.Errorf("wrong text on second report: %s", p.text)
657 }
658 return nil
659 },
660 delete: func(_ context.Context, _ any, e ExistingCommentV2) error {
661 return fmt.Errorf("shouldn't try to delete %s:%d", e.path, e.line)
662 },
663 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
664 return e.path == p.path && e.line == p.line && e.text == p.text
665 },
666 canCreate: func(_ int) (bool, error) {
667 return true, nil
668 },
669 },
670 checkErr: func(t *testing.T, err error) {
671 require.NoError(t, err)
672 },
673 },
674 {
675 description: "Delete() fails",
676 reports: []Report{barReport},
677 commenter: testCommenter{
678 destinations: func(_ context.Context) ([]any, error) {
679 return []any{1}, nil
680 },
681 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
682 if len(errs) != 1 {
683 return fmt.Errorf("Expected errDelete in errs, got %v", errs)
684 }
685 if !errors.Is(errs[0], errDelete) {
686 return fmt.Errorf("Expected errDelete in errs, got %w", errs[0])
687 }
688 return nil
689 },
690 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
691 return []ExistingCommentV2{fooComment}, nil
692 },
693 create: func(_ context.Context, _ any, _ PendingCommentV2) error {
694 return nil
695 },
696 delete: func(_ context.Context, _ any, _ ExistingCommentV2) error {
697 return errDelete
698 },
699 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
700 return e.path == p.path && e.line == p.line && e.text == p.text
701 },
702 canCreate: func(_ int) (bool, error) {
703 return true, nil
704 },
705 },
706 checkErr: func(t *testing.T, err error) {
707 require.NoError(t, err)
708 },
709 },
710 {
711 description: "Delete() works",
712 reports: []Report{barReport},
713 commenter: testCommenter{
714 destinations: func(_ context.Context) ([]any, error) {
715 return []any{1}, nil
716 },
717 summary: func(_ context.Context, _ any, _ Summary, errs []error) error {
718 if len(errs) != 0 {
719 return fmt.Errorf("Expected empty errs, got %v", errs)
720 }
721 return nil
722 },
723 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
724 return []ExistingCommentV2{fooComment}, nil
725 },
726 create: func(_ context.Context, _ any, _ PendingCommentV2) error {
727 return nil
728 },
729 delete: func(_ context.Context, _ any, _ ExistingCommentV2) error {
730 return nil
731 },
732 isEqual: func(e ExistingCommentV2, p PendingCommentV2) bool {
733 return e.path == p.path && e.line == p.line && e.text == p.text
734 },
735 canCreate: func(_ int) (bool, error) {
736 return true, nil
737 },
738 },
739 checkErr: func(t *testing.T, err error) {
740 require.NoError(t, err)
741 },
742 },
743 {
744 description: "Summary() fails",
745 reports: []Report{},
746 commenter: testCommenter{
747 destinations: func(_ context.Context) ([]any, error) {
748 return []any{1}, nil
749 },
750 summary: func(_ context.Context, _ any, _ Summary, _ []error) error {
751 return errSummary
752 },
753 list: func(_ context.Context, _ any) ([]ExistingCommentV2, error) {
754 return nil, nil
755 },
756 },
757 checkErr: func(t *testing.T, err error) {
758 require.ErrorIs(t, err, errSummary)
759 },
760 },
761 }
762
763 for _, tc := range testCases {
764 t.Run(tc.description, func(t *testing.T) {
765 slog.SetDefault(slogt.New(t))
766
767 summary := NewSummary(tc.reports)
768 tc.checkErr(t, Submit(context.Background(), summary, tc.commenter))
769 })
770 }
771}
772