package domain import ( "testing" "time" "github.com/google/uuid" ) func TestNewResult(t *testing.T) { id := uuid.New() competitionID := uuid.New() userID := uuid.New() submissionID := uuid.New() now := time.Now() rank := 1 result := NewResult( id, competitionID, userID, 95.5, &rank, ResultStatusCompleted, &submissionID, map[string]interface{}{"notes": "test"}, now, now, ) if result.ID != id { t.Errorf("Expected ID %v, got %v", id, result.ID) } if result.CompetitionID != competitionID { t.Errorf("Expected CompetitionID %v, got %v", competitionID, result.CompetitionID) } if result.UserID != userID { t.Errorf("Expected UserID %v, got %v", userID, result.UserID) } if result.Score != 95.5 { t.Errorf("Expected Score 95.5, got %v", result.Score) } if result.Rank == nil || *result.Rank != 1 { t.Errorf("Expected Rank 1, got %v", result.Rank) } if result.Status != ResultStatusCompleted { t.Errorf("Expected Status %v, got %v", ResultStatusCompleted, result.Status) } if result.SubmissionID == nil || *result.SubmissionID != submissionID { t.Errorf("Expected SubmissionID %v, got %v", submissionID, result.SubmissionID) } if len(result.Metadata) != 1 { t.Errorf("Expected Metadata with 1 item, got %d", len(result.Metadata)) } } func TestResultStatusConstants(t *testing.T) { tests := []struct { status ResultStatus expected string }{ {ResultStatusUnspecified, "UNSPECIFIED"}, {ResultStatusPending, "PENDING"}, {ResultStatusProcessing, "PROCESSING"}, {ResultStatusCompleted, "COMPLETED"}, {ResultStatusFailed, "FAILED"}, } for _, tt := range tests { t.Run(string(tt.status), func(t *testing.T) { if string(tt.status) != tt.expected { t.Errorf("Expected %s, got %s", tt.expected, tt.status) } }) } } func TestResultWithNilValues(t *testing.T) { id := uuid.New() competitionID := uuid.New() userID := uuid.New() now := time.Now() result := NewResult( id, competitionID, userID, 0.0, nil, ResultStatusPending, nil, nil, now, now, ) if result.Rank != nil { t.Errorf("Expected Rank to be nil, got %v", result.Rank) } if result.SubmissionID != nil { t.Errorf("Expected SubmissionID to be nil, got %v", result.SubmissionID) } if result.Metadata != nil { t.Errorf("Expected Metadata to be nil, got %v", result.Metadata) } } func TestResultMetadata(t *testing.T) { id := uuid.New() competitionID := uuid.New() userID := uuid.New() now := time.Now() metadata := map[string]interface{}{ "attempt": 3, "time_spent": 3600, "notes": "First submission", "tags": []string{"urgent", "review"}, } result := NewResult( id, competitionID, userID, 95.5, nil, ResultStatusCompleted, nil, metadata, now, now, ) if len(result.Metadata) != 4 { t.Errorf("Expected 4 metadata items, got %d", len(result.Metadata)) } if result.Metadata["attempt"] != 3 { t.Errorf("Expected attempt=3, got %v", result.Metadata["attempt"]) } if result.Metadata["notes"] != "First submission" { t.Errorf("Expected notes='First submission', got %v", result.Metadata["notes"]) } } func TestResultScoreRange(t *testing.T) { tests := []struct { name string score float64 valid bool }{ {"Zero score", 0.0, true}, {"Positive score", 95.5, true}, {"Max score", 100.0, true}, {"High score", 1000.0, true}, {"Negative score", -10.0, true}, // Negative might be valid in some contexts {"Decimal precision", 95.123456, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &Result{ ID: uuid.New(), CompetitionID: uuid.New(), UserID: uuid.New(), Score: tt.score, Status: ResultStatusCompleted, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if result.Score != tt.score { t.Errorf("Expected score %v, got %v", tt.score, result.Score) } }) } } func TestResultRankValidation(t *testing.T) { tests := []struct { name string rank *int }{ {"First place", intPtr(1)}, {"Middle rank", intPtr(50)}, {"Last place", intPtr(1000)}, {"No rank", nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &Result{ ID: uuid.New(), CompetitionID: uuid.New(), UserID: uuid.New(), Score: 95.5, Rank: tt.rank, Status: ResultStatusCompleted, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if tt.rank != nil && result.Rank != nil && *result.Rank != *tt.rank { t.Errorf("Expected rank %d, got %d", *tt.rank, *result.Rank) } if tt.rank == nil && result.Rank != nil { t.Errorf("Expected rank to be nil, got %d", *result.Rank) } }) } } func TestResultStatusTransitions(t *testing.T) { result := &Result{ ID: uuid.New(), CompetitionID: uuid.New(), UserID: uuid.New(), Score: 0.0, Status: ResultStatusPending, CreatedAt: time.Now(), UpdatedAt: time.Now(), } result.Status = ResultStatusProcessing if result.Status != ResultStatusProcessing { t.Errorf("Expected status %v, got %v", ResultStatusProcessing, result.Status) } result.Status = ResultStatusCompleted result.Score = 95.5 if result.Status != ResultStatusCompleted { t.Errorf("Expected status %v, got %v", ResultStatusCompleted, result.Status) } result.Status = ResultStatusFailed if result.Status != ResultStatusFailed { t.Errorf("Expected status %v, got %v", ResultStatusFailed, result.Status) } } func TestResultTimestamps(t *testing.T) { now := time.Now() result := &Result{ ID: uuid.New(), CompetitionID: uuid.New(), UserID: uuid.New(), Score: 95.5, Status: ResultStatusCompleted, CreatedAt: now, UpdatedAt: now, } if !result.CreatedAt.Equal(now) { t.Errorf("Expected CreatedAt %v, got %v", now, result.CreatedAt) } if !result.UpdatedAt.Equal(now) { t.Errorf("Expected UpdatedAt %v, got %v", now, result.UpdatedAt) } if result.UpdatedAt.Before(result.CreatedAt) { t.Errorf("UpdatedAt should not be before CreatedAt") } } func TestResultWithSubmission(t *testing.T) { submissionID := uuid.New() result := &Result{ ID: uuid.New(), CompetitionID: uuid.New(), UserID: uuid.New(), Score: 95.5, Status: ResultStatusCompleted, SubmissionID: &submissionID, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if result.SubmissionID == nil { t.Error("Expected SubmissionID to be set") } if *result.SubmissionID != submissionID { t.Errorf("Expected SubmissionID %v, got %v", submissionID, *result.SubmissionID) } } func TestResultComparison(t *testing.T) { competitionID := uuid.New() now := time.Now() result1 := &Result{ ID: uuid.New(), CompetitionID: competitionID, UserID: uuid.New(), Score: 100.0, Rank: intPtr(1), Status: ResultStatusCompleted, CreatedAt: now, UpdatedAt: now, } result2 := &Result{ ID: uuid.New(), CompetitionID: competitionID, UserID: uuid.New(), Score: 95.0, Rank: intPtr(2), Status: ResultStatusCompleted, CreatedAt: now.Add(1 * time.Second), UpdatedAt: now.Add(1 * time.Second), } if result1.Score <= result2.Score { t.Errorf("result1 should have higher score than result2") } if *result1.Rank >= *result2.Rank { t.Errorf("result1 should have lower (better) rank than result2") } if result1.CreatedAt.After(result2.CreatedAt) { t.Errorf("result1 should be created before result2") } } // Helper function func intPtr(i int) *int { return &i }