package commandcenter import ( "testing" "time" "github.com/jackc/pgx/v5/pgtype" "github.com/shopspring/decimal" "github.com/missionworkforce/missionmatch/internal/platform/database/dbgen" "github.com/missionworkforce/missionmatch/internal/platform/missionclass" ) func dateVal(s string) pgtype.Date { t, _ := time.Parse("2006-01-02", s) return pgtype.Date{Time: t, Valid: true} } func amt(s string) *decimal.Decimal { d := decimal.RequireFromString(s) return &d } // TestGroupIncumbentMix proves the pure grouping folds the flat (award, role) rows into one entry per // award, preserves the query's pop_end_date ordering, carries the evidence on every role, and renders the // award value at two decimal places. The query already sorts by award id within a pop_end_date, so the // grouping is a single ordered pass. func TestGroupIncumbentMix(t *testing.T) { rows := []dbgen.ListIncumbentRolesByRecompeteRow{ {RecordID: "AWD-1", RecipientName: "Acme Defense", AwardingAgency: "DoD", NaicsCode: "541512", AwardAmount: amt("1000000"), PopEndDate: dateVal("2026-09-30"), LaborCategory: "SIGINT Analyst", RoleCount: 3, Evidence: "SIGINT Analyst x3"}, {RecordID: "AWD-1", RecipientName: "Acme Defense", AwardingAgency: "DoD", NaicsCode: "541512", AwardAmount: amt("1000000"), PopEndDate: dateVal("2026-09-30"), LaborCategory: "Systems Engineer", RoleCount: 2, Evidence: "Systems Engineer x2"}, {RecordID: "AWD-2", RecipientName: "Beta Corp", AwardingAgency: "USAF", NaicsCode: "541330", AwardAmount: nil, PopEndDate: dateVal("2026-12-31"), LaborCategory: "COMSEC Custodian", RoleCount: 1, Evidence: "COMSEC Custodian"}, } got := groupIncumbentMix(rows) if len(got) != 2 { t.Fatalf("expected 2 grouped awards, got %d", len(got)) } if got[0].RecordID != "AWD-1" || got[1].RecordID != "AWD-2" { t.Fatalf("award order not preserved: %q then %q", got[0].RecordID, got[1].RecordID) } if len(got[0].Roles) != 2 { t.Fatalf("AWD-1 should carry 2 roles, got %d", len(got[0].Roles)) } if got[0].Roles[0].LaborCategory != "SIGINT Analyst" || got[0].Roles[0].RoleCount != 3 || got[0].Roles[0].Evidence != "SIGINT Analyst x3" { t.Fatalf("AWD-1 first role wrong: %+v", got[0].Roles[0]) } if got[0].AwardValue == nil || *got[0].AwardValue != "1000000.00" { t.Fatalf("AWD-1 value not rendered at two decimals: %v", got[0].AwardValue) } if got[0].PopEndDate != "2026-09-30" { t.Fatalf("AWD-1 pop_end_date wrong: %q", got[0].PopEndDate) } if got[1].AwardValue != nil { t.Fatalf("AWD-2 has a null award amount, value should stay nil, got %v", *got[1].AwardValue) } if len(got[1].Roles) != 1 || got[1].Roles[0].Evidence != "COMSEC Custodian" { t.Fatalf("AWD-2 role wrong: %+v", got[1].Roles) } } // TestGroupIncumbentMixEmpty proves the grouping returns a non nil empty slice so the JSON renders []. func TestGroupIncumbentMixEmpty(t *testing.T) { got := groupIncumbentMix(nil) if got == nil { t.Fatal("groupIncumbentMix(nil) returned nil, want an empty non nil slice") } if len(got) != 0 { t.Fatalf("expected 0 awards, got %d", len(got)) } } // TestValidMissionCode pins the panel mission filter to the shared controlled vocabulary so an unknown // code is rejected rather than silently running an empty filter, and every real code is accepted. func TestValidMissionCode(t *testing.T) { for _, c := range missionclass.Codes { if !validMissionCode(c) { t.Fatalf("controlled code %q rejected by validMissionCode", c) } } for _, bad := range []string{"", "NOPE", "sigint", "SIGINT ", "EWX"} { if validMissionCode(bad) { t.Fatalf("invalid code %q accepted by validMissionCode", bad) } } }