package app import ( "testing" "gitea.maximumdirect.net/eric/narratio/internal/config" ) func TestArtifactSelectionFlagNormalize(t *testing.T) { tests := []struct { name string inputs []string want []string wantErr string }{ { name: "single value", inputs: []string{"session_recap"}, want: []string{"session_recap"}, }, { name: "repeatable and comma separated values are deduped and sorted", inputs: []string{"session_recap,player_handout", "session_recap"}, want: []string{"player_handout", "session_recap"}, }, { name: "empty token fails", inputs: []string{"session_recap,"}, wantErr: "artifact names must be non-empty", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var flag artifactSelectionFlag for _, in := range tt.inputs { if err := flag.Set(in); err != nil { t.Fatalf("Set(%q) error = %v", in, err) } } got, err := flag.Normalize() if tt.wantErr != "" { if err == nil { t.Fatalf("Normalize() error = nil, want %q", tt.wantErr) } if err.Error() != tt.wantErr { t.Fatalf("Normalize() error = %q, want %q", err.Error(), tt.wantErr) } return } if err != nil { t.Fatalf("Normalize() error = %v", err) } if len(got) != len(tt.want) { t.Fatalf("Normalize() len = %d, want %d; got=%v", len(got), len(tt.want), got) } for i := range got { if got[i] != tt.want[i] { t.Fatalf("Normalize()[%d] = %q, want %q", i, got[i], tt.want[i]) } } }) } } func TestValidateSelectedArtifacts(t *testing.T) { tests := []struct { name string cfg *config.Config selected []string wantErr string }{ { name: "empty selection is accepted", cfg: &config.Config{}, selected: nil, }, { name: "scriptorium required when selected artifacts present", cfg: &config.Config{Pipeline: &config.PipelineConfig{}}, selected: []string{"session_recap"}, wantErr: "--artifacts requires pipeline.scriptorium.artifacts to be configured", }, { name: "unknown selected artifact fails", cfg: &config.Config{ Pipeline: &config.PipelineConfig{ Scriptorium: &config.ScriptoriumConfig{ Artifacts: map[string]config.ScriptoriumArtifactConfig{ "session_recap": {Enabled: true, PromptID: "dnd.session_recap", OutputPath: "artifacts/session_recap.md"}, }, }, }, }, selected: []string{"player_handout"}, wantErr: `--artifacts includes unknown artifact "player_handout"`, }, { name: "known selected artifacts are accepted", cfg: &config.Config{ Pipeline: &config.PipelineConfig{ Scriptorium: &config.ScriptoriumConfig{ Artifacts: map[string]config.ScriptoriumArtifactConfig{ "session_recap": {Enabled: true, PromptID: "dnd.session_recap", OutputPath: "artifacts/session_recap.md"}, "player_handout": {Enabled: true, PromptID: "dnd.player_handout", OutputPath: "artifacts/player_handout.md"}, }, }, }, }, selected: []string{"player_handout", "session_recap"}, }, { name: "selected disabled artifact must be executable", cfg: &config.Config{ Pipeline: &config.PipelineConfig{ Scriptorium: &config.ScriptoriumConfig{ Artifacts: map[string]config.ScriptoriumArtifactConfig{ "player_handout": {Enabled: false, OutputPath: "artifacts/player_handout.md"}, }, }, }, }, selected: []string{"player_handout"}, wantErr: "pipeline.scriptorium.artifacts.player_handout.prompt_id is required when selected", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validateSelectedArtifacts(tt.cfg, tt.selected) if tt.wantErr != "" { if err == nil { t.Fatalf("error = nil, want %q", tt.wantErr) } if err.Error() != tt.wantErr { t.Fatalf("error = %q, want %q", err.Error(), tt.wantErr) } return } if err != nil { t.Fatalf("error = %v, want nil", err) } }) } }