package db import ( "testing" ) func TestPaginationNormalize(t *testing.T) { tests := []struct { in PaginationParams wantPage int wantSize int }{ {PaginationParams{0, 0}, 1, 20}, {PaginationParams{-1, -5}, 1, 20}, {PaginationParams{1, 200}, 1, 20}, {PaginationParams{3, 10}, 3, 10}, } for _, tt := range tests { tt.in.Normalize() if tt.in.Page != tt.wantPage || tt.in.Size != tt.wantSize { t.Errorf("Normalize(%+v) = page=%d size=%d, want page=%d size=%d", tt.in, tt.in.Page, tt.in.Size, tt.wantPage, tt.wantSize) } } } func TestPaginationOffset(t *testing.T) { p := PaginationParams{Page: 3, Size: 10} if p.Offset() != 20 { t.Fatalf("Offset() = %d, want 20", p.Offset()) } } func TestPaginate(t *testing.T) { d := setupTestDB(t) for i := 0; i < 25; i++ { d.Create(&EmailRecord{Email: "test" + string(rune('A'+i)) + "@x.com", Status: "used"}) } var records []EmailRecord result, err := Paginate(d.Model(&EmailRecord{}), PaginationParams{Page: 2, Size: 10}, &records) if err != nil { t.Fatalf("Paginate: %v", err) } if result.Total != 25 { t.Fatalf("Total = %d, want 25", result.Total) } if result.Page != 2 || result.Size != 10 { t.Fatalf("Page=%d Size=%d, want 2/10", result.Page, result.Size) } if len(records) != 10 { t.Fatalf("got %d records, want 10", len(records)) } } func TestGetCardStats(t *testing.T) { d := setupTestDB(t) d.Create(&Card{NumberHash: "h1", Status: "available", MaxBinds: 1}) d.Create(&Card{NumberHash: "h2", Status: "active", MaxBinds: 1}) d.Create(&Card{NumberHash: "h3", Status: "exhausted", MaxBinds: 1}) d.Create(&Card{NumberHash: "h4", Status: "rejected", MaxBinds: 1}) d.Create(&Card{NumberHash: "h5", Status: "disabled", MaxBinds: 1}) s := GetCardStats(d) if s.Total != 5 { t.Fatalf("Total = %d, want 5", s.Total) } if s.Available != 1 || s.Active != 1 || s.Exhausted != 1 || s.Rejected != 1 || s.Disabled != 1 { t.Fatalf("stats mismatch: %+v", s) } } func TestGetCardCodeStats(t *testing.T) { d := setupTestDB(t) d.Create(&CardCode{Code: "c1", Status: "unused"}) d.Create(&CardCode{Code: "c2", Status: "unused"}) d.Create(&CardCode{Code: "c3", Status: "redeemed"}) d.Create(&CardCode{Code: "c4", Status: "failed"}) s := GetCardCodeStats(d) if s.Total != 4 || s.Unused != 2 || s.Redeemed != 1 || s.Failed != 1 { t.Fatalf("stats mismatch: %+v", s) } } func TestGetEmailRecordStats(t *testing.T) { d := setupTestDB(t) d.Create(&EmailRecord{Email: "a@x.com", Status: "used"}) d.Create(&EmailRecord{Email: "b@x.com", Status: "used_member"}) d.Create(&EmailRecord{Email: "c@x.com", Status: "used_failed"}) d.Create(&EmailRecord{Email: "d@x.com", Status: "in_use"}) s := GetEmailRecordStats(d) if s.Total != 4 || s.Used != 1 || s.UsedMember != 1 || s.UsedFailed != 1 { t.Fatalf("stats mismatch: %+v", s) } } func TestGetDashboardStats(t *testing.T) { d := setupTestDB(t) d.Create(&Account{Email: "p1@x.com", Plan: "plus", Status: "active"}) d.Create(&Account{Email: "p2@x.com", Plan: "plus", Status: "active"}) d.Create(&Account{Email: "t1@x.com", Plan: "team_owner", Status: "active"}) d.Create(&Account{Email: "m1@x.com", Plan: "team_member", Status: "active"}) d.Create(&TaskLog{TaskID: "t1", Status: "success", Email: "p1@x.com"}) d.Create(&TaskLog{TaskID: "t1", Status: "success", Email: "p2@x.com"}) d.Create(&TaskLog{TaskID: "t1", Status: "failed", Email: "f@x.com"}) stats, err := GetDashboardStats(d) if err != nil { t.Fatalf("GetDashboardStats: %v", err) } if stats.TotalAccounts != 4 { t.Fatalf("TotalAccounts = %d, want 4", stats.TotalAccounts) } if stats.PlusCount != 2 { t.Fatalf("PlusCount = %d, want 2", stats.PlusCount) } if stats.TeamCount != 2 { t.Fatalf("TeamCount = %d, want 2", stats.TeamCount) } // success rate: 2/3 * 100 = 66.66... if stats.SuccessRate < 66 || stats.SuccessRate > 67 { t.Fatalf("SuccessRate = %.2f, want ~66.67", stats.SuccessRate) } }