package missionclass import "testing" // TestClassifyLaborGolden pins ClassifyLabor to the exact labor category set the old inline laborKeywords // logic in matching/intel.go produced for representative profile headlines. The matcher is a lowercased // substring match over the same word list, so candidate intelligence output stays byte identical after // the helper moved here. Results are returned in stable sorted order. func TestClassifyLaborGolden(t *testing.T) { cases := []struct { text string want []string }{ // An ISSO headline. {"Information System Security Officer with ISSM duties", []string{"ISSO"}}, // A cyber headline that hits both the engineer and the SOC analyst words, plus intelligence via sigint. {"Senior Security Engineer and SOC Analyst, SIGINT background", []string{"Cyber Engineer", "Intelligence Analyst"}}, // A program manager who is also a PMP. {"Program Manager, PMP certified capture manager", []string{"Program Manager"}}, // A data scientist who does machine learning. {"Data Scientist focused on machine learning pipelines", []string{"Data Scientist"}}, // A cloud and solutions architect. {"Cloud Architect and Solutions Architect for AWS", []string{"Cloud Architect"}}, // An all source intelligence analyst. {"All Source Intelligence Analyst, GEOINT and intel analyst tradecraft", []string{"Intelligence Analyst"}}, // A plain administrative headline matches nothing. {"General administrative support coordinator", nil}, // Empty text matches nothing. {"", nil}, } for _, tc := range cases { got := ClassifyLabor(tc.text) if len(got) != len(tc.want) { t.Fatalf("ClassifyLabor(%q) = %v, want %v", tc.text, got, tc.want) } for i := range got { if got[i] != tc.want[i] { t.Fatalf("ClassifyLabor(%q) = %v, want %v", tc.text, got, tc.want) } } } } // TestClassifyLaborCounts pins ClassifyLaborCounts to its deterministic occurrence count and first matched // phrase evidence. Count is the literal sum of strings.Count over every matched keyword phrase, so a // repeated mention counts again and a category named through two phrases counts both. Order follows the // stable laborKeywords order. The labor mix is mined from genuine text matches only, never fabricated. func TestClassifyLaborCounts(t *testing.T) { cases := []struct { name string text string want []LaborHit }{ { // Two ISSO mentions: "isso" matches twice. The first matched phrase in the word list is "isso". name: "repeated isso counts twice", text: "We need an ISSO and a second ISSO for night shift", want: []LaborHit{{LCAT: "ISSO", Count: 2, Evidence: "isso"}}, }, { // A description naming three engineers and two cyber roles. "cyber engineer" hits once, and the // Intelligence Analyst category is hit by sigint once. name: "engineer and intel mix", text: "3 Cyber Engineer staff and 2 SIGINT analysts on the SIGINT desk", want: []LaborHit{ {LCAT: "Cyber Engineer", Count: 1, Evidence: "cyber engineer"}, {LCAT: "Intelligence Analyst", Count: 2, Evidence: "sigint"}, }, }, { // A plain administrative headline matches nothing. name: "no match", text: "general administrative support services", want: nil, }, { name: "empty", text: "", want: nil, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := ClassifyLaborCounts(tc.text) if len(got) != len(tc.want) { t.Fatalf("ClassifyLaborCounts(%q) = %v, want %v", tc.text, got, tc.want) } for i := range got { if got[i] != tc.want[i] { t.Fatalf("ClassifyLaborCounts(%q)[%d] = %+v, want %+v", tc.text, i, got[i], tc.want[i]) } } }) } }