package matching import ( "context" "testing" "github.com/shopspring/decimal" "github.com/missionworkforce/missionmatch/internal/modules/matching/engine" ) func acronymFixture() *AcronymResolver { return NewAcronymResolverFromMap(map[string]string{ "JWICS": "Joint Worldwide Intelligence Communications System", "SIGINT": "Signals Intelligence", "RMF": "Risk Management Framework", "TS/SCI": "Top Secret SCI", }) } func TestAcronymResolverMatchesAcronymToExpansion(t *testing.T) { a := acronymFixture() req := engine.RequiredSkill{Name: "Joint Worldwide Intelligence Communications System"} cands := []engine.CandidateSkill{{SkillID: "s1", Name: "JWICS"}} m, ok := a.Match(context.Background(), req, cands, decimal.RequireFromString("0.62")) if !ok || !m.Matched { t.Fatal("JWICS must match its expansion") } if m.Exact { t.Fatal("an acronym equivalence is not a verbatim exact match") } if m.CandidateName != "JWICS" || m.CandidateSkillID != "s1" { t.Fatalf("wrong candidate side: %+v", m) } if m.Similarity.String() != "1" { t.Fatalf("acronym equivalence is similarity 1, got %s", m.Similarity) } } func TestAcronymResolverMatchesBothDirectionsAndInsidePhrases(t *testing.T) { a := acronymFixture() cases := []struct { required, candidate string }{ {"SIGINT", "Signals Intelligence"}, {"Signals Intelligence", "SIGINT"}, {"RMF compliance", "Risk Management Framework compliance"}, {"TS/SCI", "top secret sci"}, } for _, tc := range cases { m, ok := a.Match(context.Background(), engine.RequiredSkill{Name: tc.required}, []engine.CandidateSkill{{Name: tc.candidate}}, decimal.RequireFromString("0.62")) if !ok || !m.Matched { t.Fatalf("%q should match %q", tc.required, tc.candidate) } } } func TestAcronymResolverNeverInventsAMatch(t *testing.T) { a := acronymFixture() cases := []struct { required, candidate string }{ {"SIGINT", "HUMINT"}, {"SIGINT", "Signals Processing"}, {"Java", "JavaScript"}, {"", "SIGINT"}, } for _, tc := range cases { if _, ok := a.Match(context.Background(), engine.RequiredSkill{Name: tc.required}, []engine.CandidateSkill{{Name: tc.candidate}}, decimal.RequireFromString("0.62")); ok { t.Fatalf("%q must NOT match %q", tc.required, tc.candidate) } } } func TestChainedResolverConsultsAcronymsBeforeSemantic(t *testing.T) { // A chain with no curated resolver and no semantic matcher: only the acronym layer can hit. c := NewChainedResolver(nil, nil).WithAcronyms(acronymFixture()) m, ok := c.Match(context.Background(), engine.RequiredSkill{Name: "JWICS"}, []engine.CandidateSkill{{Name: "Joint Worldwide Intelligence Communications System"}}, decimal.RequireFromString("0.62")) if !ok || !m.Matched { t.Fatal("the chain must surface the acronym hit when semantic is absent") } }