diff options
Diffstat (limited to '')
| -rw-r--r-- | cmd/pr-analyzer/analyzer_test.go | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/cmd/pr-analyzer/analyzer_test.go b/cmd/pr-analyzer/analyzer_test.go new file mode 100644 index 0000000..d2c3041 --- /dev/null +++ b/cmd/pr-analyzer/analyzer_test.go @@ -0,0 +1,233 @@ +package main + +import ( + "testing" + "time" + + "go.fcuny.net/x/internal/github" +) + +func TestAnalyzePRs(t *testing.T) { + startDate := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + endDate := time.Date(2024, 1, 31, 0, 0, 0, 0, time.UTC) + a := NewAnalyzer(startDate, endDate) + + tests := []struct { + name string + prs []github.PullRequest + reviews map[int][]github.Review + comments map[int][]github.ReviewComment + want []ReviewerMetrics + }{ + { + name: "single PR with immediate approval", + prs: []github.PullRequest{ + { + Number: 1, + CreatedAt: time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC), + User: github.User{ + Login: "author1", + }, + }, + }, + reviews: map[int][]github.Review{ + 1: { + { + ID: 1, + User: github.User{Login: "reviewer1"}, + State: "APPROVED", + SubmittedAt: time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), + }, + }, + }, + comments: map[int][]github.ReviewComment{}, + want: []ReviewerMetrics{ + { + Username: "reviewer1", + PRsReviewed: 1, + AverageReviewSpeed: 0.5, // 30 minutes + AverageComments: 0, + ImmediateApprovals: 100.0, // 100% immediate approvals + }, + }, + }, + { + name: "PR with comments and changes requested", + prs: []github.PullRequest{ + { + Number: 2, + CreatedAt: time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC), + User: github.User{ + Login: "author2", + }, + }, + }, + reviews: map[int][]github.Review{ + 2: { + { + ID: 2, + User: github.User{Login: "reviewer2"}, + State: "CHANGES_REQUESTED", + SubmittedAt: time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC), + }, + }, + }, + comments: map[int][]github.ReviewComment{ + 2: { + { + ID: 3, + ReviewID: 2, + User: github.User{Login: "reviewer2"}, + CreatedAt: time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC), + Path: "file1.go", + Line: 10, + }, + { + ID: 4, + ReviewID: 2, + User: github.User{Login: "reviewer2"}, + CreatedAt: time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC), + Path: "file2.go", + Line: 20, + }, + }, + }, + want: []ReviewerMetrics{ + { + Username: "reviewer2", + PRsReviewed: 1, + AverageReviewSpeed: 1.0, // 1 hour + AverageComments: 2.0, + ImmediateApprovals: 0.0, // 0% immediate approvals + }, + }, + }, + { + name: "multiple PRs with same reviewer", + prs: []github.PullRequest{ + { + Number: 3, + CreatedAt: time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC), + User: github.User{ + Login: "author3", + }, + }, + { + Number: 4, + CreatedAt: time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC), + User: github.User{ + Login: "author4", + }, + }, + }, + reviews: map[int][]github.Review{ + 3: { + { + ID: 5, + User: github.User{Login: "reviewer3"}, + State: "APPROVED", + SubmittedAt: time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), + }, + }, + 4: { + { + ID: 6, + User: github.User{Login: "reviewer3"}, + State: "APPROVED", + SubmittedAt: time.Date(2024, 1, 15, 11, 30, 0, 0, time.UTC), + }, + }, + }, + comments: map[int][]github.ReviewComment{}, + want: []ReviewerMetrics{ + { + Username: "reviewer3", + PRsReviewed: 2, + AverageReviewSpeed: 0.5, // 30 minutes average + AverageComments: 0, + ImmediateApprovals: 100.0, // 100% immediate approvals + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + prData := make([]PRData, len(tt.prs)) + for i, pr := range tt.prs { + reviews := tt.reviews[pr.Number] + comments := tt.comments[pr.Number] + + commentsByReview := make(map[int64][]CommentData) + for _, comment := range comments { + commentsByReview[comment.ReviewID] = append( + commentsByReview[comment.ReviewID], + CommentData{ + Reviewer: comment.User.Login, + CreatedAt: comment.CreatedAt, + Path: comment.Path, + Line: comment.Line, + }, + ) + } + + reviewData := make([]ReviewData, len(reviews)) + for j, review := range reviews { + reviewData[j] = ReviewData{ + Reviewer: review.User.Login, + State: review.State, + SubmittedAt: review.SubmittedAt, + Comments: commentsByReview[review.ID], + } + } + + prData[i] = PRData{ + Number: pr.Number, + CreatedAt: pr.CreatedAt, + Reviews: reviewData, + } + } + + got, err := a.AnalyzePRs(prData) + if err != nil { + t.Errorf("AnalyzePRs() error = %v", err) + return + } + + if len(got) != len(tt.want) { + t.Errorf("AnalyzePRs() returned %d metrics, want %d", len(got), len(tt.want)) + return + } + + for i, m := range got { + if m.Username != tt.want[i].Username { + t.Errorf("Username = %v, want %v", m.Username, tt.want[i].Username) + } + if m.PRsReviewed != tt.want[i].PRsReviewed { + t.Errorf("PRsReviewed = %v, want %v", m.PRsReviewed, tt.want[i].PRsReviewed) + } + if m.AverageReviewSpeed != tt.want[i].AverageReviewSpeed { + t.Errorf( + "AverageReviewSpeed = %v, want %v", + m.AverageReviewSpeed, + tt.want[i].AverageReviewSpeed, + ) + } + if m.AverageComments != tt.want[i].AverageComments { + t.Errorf( + "AverageComments = %v, want %v", + m.AverageComments, + tt.want[i].AverageComments, + ) + } + if m.ImmediateApprovals != tt.want[i].ImmediateApprovals { + t.Errorf( + "ImmediateApprovals = %v, want %v", + m.ImmediateApprovals, + tt.want[i].ImmediateApprovals, + ) + } + } + }) + } +} |
