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, ) } } }) } }