package ai import ( "strings" "testing" ) func TestPersonaSystemPromptNonEmptyDistinct(t *testing.T) { modes := []string{PersonaAggressive, PersonaSilent, PersonaPassive, PersonaPersuasive, PersonaBalanced} seen := make(map[string]string, len(modes)) for _, mode := range modes { prompt := PersonaSystemPrompt(mode) if strings.TrimSpace(prompt) == "" { t.Fatalf("persona %q returned empty prompt", mode) } if !strings.Contains(prompt, "AetherForge fleet controller") { t.Fatalf("persona %q missing base system prompt", mode) } if prev, ok := seen[prompt]; ok { t.Fatalf("personas %q and %q produced identical prompts", prev, mode) } seen[prompt] = mode } } func TestPersonaSystemPromptModeSpecificGuidance(t *testing.T) { cases := []struct { mode string needle string }{ {PersonaAggressive, "spread_now and discover_and_join"}, {PersonaSilent, "Never spread_now unless stuck"}, {PersonaPassive, "Default to noop"}, {PersonaPersuasive, "discover_and_join before restart_mining"}, {PersonaBalanced, "Balance spread vs mine"}, } for _, tc := range cases { prompt := PersonaSystemPrompt(tc.mode) if !strings.Contains(prompt, tc.needle) { t.Fatalf("persona %q missing %q in:\n%s", tc.mode, tc.needle, prompt) } } } func TestNormalizePersona(t *testing.T) { if got := NormalizePersona(" AGGRESSIVE "); got != PersonaAggressive { t.Fatalf("got %q", got) } if got := NormalizePersona("unknown"); got != PersonaBalanced { t.Fatalf("unknown should map to balanced, got %q", got) } } func TestPersonaSpreadTierOrderDistinct(t *testing.T) { modes := []string{PersonaAggressive, PersonaSilent, PersonaPassive, PersonaPersuasive, PersonaBalanced} seen := make(map[string]string, len(modes)) for _, mode := range modes { order := PersonaSpreadTierOrder(mode) if len(order) != len(defaultSpreadTiers) { t.Fatalf("persona %q tier count = %d want %d", mode, len(order), len(defaultSpreadTiers)) } key := strings.Join(order, ",") if prev, ok := seen[key]; ok && mode != PersonaBalanced { t.Fatalf("personas %q and %q share spread order", prev, mode) } seen[key] = mode } if PersonaSpreadTierOrder(PersonaPersuasive)[1] != "dns_txt" { t.Fatalf("persuasive should front dns_txt, got %v", PersonaSpreadTierOrder(PersonaPersuasive)) } if PersonaSpreadTierOrder(PersonaAggressive)[2] != "smb" { t.Fatalf("aggressive should front smb early, got %v", PersonaSpreadTierOrder(PersonaAggressive)) } } func TestPersonaSpreadTemperamentShape(t *testing.T) { temp := PersonaSpreadTemperament(PersonaSilent) if len(temp.TierOrder) == 0 || len(temp.Reasoning) == 0 || temp.Confidence <= 0 { t.Fatalf("invalid spread temperament: %+v", temp) } if !strings.Contains(temp.Reasoning[0].Fact, PersonaSilent) { t.Fatalf("reasoning should cite persona: %+v", temp.Reasoning[0]) } } func TestCourtJudgeOverlayDistinct(t *testing.T) { modes := []string{PersonaAggressive, PersonaSilent, PersonaPassive, PersonaPersuasive, PersonaBalanced} prev := "" for _, mode := range modes { overlay := CourtJudgeOverlay(mode) if strings.TrimSpace(overlay) == "" { t.Fatalf("empty overlay for %q", mode) } if overlay == prev && prev != "" { t.Fatalf("duplicate court overlay for %q", mode) } prev = overlay } }