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