package missionclass import "testing" // codesOf extracts just the mission codes from a slice of hits, preserving order. func codesOf(hits []Hit) []string { out := make([]string, 0, len(hits)) for _, h := range hits { out = append(out, h.Code) } return out } // equal reports whether two string slices are identical in length, order, and contents. nil and an // empty slice compare equal so a no match (nil) matches the want of nil. func equal(a, b []string) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } func contains(s []string, want string) bool { for _, v := range s { if v == want { return true } } return false } func TestClassifyKeyword(t *testing.T) { cases := []struct { text string want []string // mission codes, in Codes order }{ {"Provide SIGINT collection and COMSEC support", []string{"SIGINT", "COMSEC"}}, {"signals intelligence analysis for the customer", []string{"SIGINT"}}, {"satellite command and control operations", []string{"SAT_C2"}}, {"a cross domain solution accreditation effort", []string{"CDS"}}, {"general administrative support services", nil}, {"", nil}, // bare acronym must not match inside a longer word {"the cdsa framework", nil}, } for _, tc := range cases { got := codesOf(ClassifyKeyword(tc.text)) if !equal(got, tc.want) { t.Fatalf("ClassifyKeyword(%q) = %v, want %v", tc.text, got, tc.want) } } } func TestClassifyAlias(t *testing.T) { idx := NewAliasIndex(map[string]string{ "sigint analyst": "SIGINT", "signals intelligence": "SIGINT", "comsec custodian": "COMSEC", }) got := codesOf(ClassifyAlias("seeking a SIGINT Analyst and a COMSEC Custodian", idx)) want := []string{"SIGINT", "COMSEC"} if !equal(got, want) { t.Fatalf("ClassifyAlias = %v, want %v", got, want) } // Empty text yields no hit. if got := ClassifyAlias("", idx); len(got) != 0 { t.Fatalf("ClassifyAlias of empty text should yield nothing, got %v", got) } // The alias mechanism and evidence phrase are recorded for traceability. hits := ClassifyAlias("hiring a SIGINT Analyst", idx) if len(hits) != 1 || hits[0].Mechanism != MechAlias || hits[0].Evidence != "sigint analyst" { t.Fatalf("alias hit must carry the alias mechanism and matched phrase, got %+v", hits) } } func TestClassifyCodes(t *testing.T) { // The AC PSC prefix (R&D, National Defense) is the one curated mapping: it yields SIGINT and EW. got := codesOf(ClassifyCodes("AC12", "")) if !contains(got, "SIGINT") || !contains(got, "EW") { t.Fatalf("AC PSC prefix must map to SIGINT and EW, got %v", got) } if len(got) != 2 { t.Fatalf("AC PSC prefix must yield exactly the two curated codes, got %v", got) } // The hits carry the psc mechanism and the uppercased code as evidence. for _, h := range ClassifyCodes("ac12", "") { if h.Mechanism != MechPSC || h.Evidence != "AC12" { t.Fatalf("psc hit must carry the psc mechanism and uppercased code, got %+v", h) } } // An unknown PSC and NAICS yields no mission rather than a wrong one. if got := ClassifyCodes("ZZZZ", "999999"); len(got) != 0 { t.Fatalf("unknown PSC and NAICS should yield no mission, got %v", got) } // A deliberately broad NAICS that is intentionally empty yields nothing. if got := ClassifyCodes("", "541330"); len(got) != 0 { t.Fatalf("intentionally broad NAICS 541330 must yield no mission, got %v", got) } } func TestClassifyUnion(t *testing.T) { // "case officer" carries HUMINT in the alias layer but has no keyword form, so the alias mechanism is // the only path to HUMINT and genuinely wins (it is not shadowed by a keyword hit). idx := NewAliasIndex(map[string]string{ "case officer": "HUMINT", }) // A record with a keyword hit (SIGINT), an alias only hit (HUMINT via case officer), and a code hit // (AC prefix => SIGINT, EW). SIGINT is reached by both keyword and code; the union dedupes by code and // the keyword mechanism wins because keyword is unioned first. hits := Classify("SIGINT collection led by a Case Officer", "AC10", "", idx) got := codesOf(hits) want := []string{"SIGINT", "HUMINT", "EW"} if !equal(got, want) { t.Fatalf("Classify union = %v, want %v", got, want) } byCode := map[string]Hit{} for _, h := range hits { byCode[h.Code] = h } if byCode["SIGINT"].Mechanism != MechKeyword { t.Fatalf("SIGINT was reached by keyword and code, keyword must win, got %q", byCode["SIGINT"].Mechanism) } if byCode["HUMINT"].Mechanism != MechAlias { t.Fatalf("HUMINT came only from the alias layer, got %q", byCode["HUMINT"].Mechanism) } if byCode["EW"].Mechanism != MechPSC { t.Fatalf("EW came only from the PSC crosswalk, got %q", byCode["EW"].Mechanism) } }