package processing import ( "context" "encoding/json" "strings" "testing" ) func TestNormalizeMapped_aliasesAndZeroDims(t *testing.T) { got := NormalizeMapped(map[string]any{ "EAN": "999", "netWidth": 0, "name": "X", }, nil) if got["gtin"] != "999" { t.Fatalf("gtin=%v", got["gtin"]) } if _, ok := got["width"]; ok { t.Fatalf("zero width should be dropped: %v", got) } } func TestParseSpecifications_htmlAndCSV(t *testing.T) { attrs := ParseSpecifications(``) if attrs["color"] != "Red" { t.Fatalf("html attrs=%v", attrs) } attrs2 := ParseSpecifications("Size: L\nWeight: 2 kg") if attrs2["size"] != "L" { t.Fatalf("csv attrs=%v", attrs2) } } func TestFillMissingFields_brandAndDims(t *testing.T) { m := FillMissingFields(map[string]any{ "name": "Nike Air 30x20x10 cm", }, map[string]any{}) if m["brand"] != "Nike" { t.Fatalf("brand=%v", m["brand"]) } if m["width"] == nil || m["height"] == nil { t.Fatalf("dims missing: %v", m) } } func TestRunSteps_skipsAIWithoutCompleter(t *testing.T) { e := &Engine{} out, err := e.RunSteps(context.TODO(), "co", ProductInput{ Mapped: map[string]any{"name": "Widget"}, }, "full", nil, StepPolicy{AllowAI: true, AllowEPREL: true}) if err != nil { t.Fatal(err) } found := false for _, n := range out.Notes { if len(n) > 0 { found = true } } if !found { t.Fatalf("expected skip notes, got %v", out.Notes) } } func TestRunSteps_skipsAIWithoutEntitlement(t *testing.T) { calls := 0 e := &Engine{ Completer: stubCompleter{fn: func(system, user string) (Completion, error) { calls++ return Completion{Text: `{"name":"N","description":"D"}`, TotalTokens: 1}, nil }}, } out, err := e.RunSteps(context.TODO(), "co", ProductInput{ Mapped: map[string]any{"name": "Widget"}, }, "full", nil, StepPolicy{AllowAI: false, AllowEPREL: false}) if err != nil { t.Fatal(err) } if calls != 0 { t.Fatalf("AI should not run without entitlement, calls=%d", calls) } joined := strings.Join(out.Notes, ";") if !strings.Contains(joined, "can_use_ai") && !strings.Contains(joined, "Free plan") { t.Fatalf("expected free-plan skip note, got %v", out.Notes) } } func TestRunSteps_injectsBrandPromptIntoAI(t *testing.T) { var gotSystem string e := &Engine{Completer: captureCompleter{fn: func(system, _ string) (Completion, error) { gotSystem = system b, _ := json.Marshal(map[string]string{"name": "N", "description": "D"}) return Completion{Text: string(b), TotalTokens: 1, Model: "test"}, nil }}} out, err := e.RunSteps(context.TODO(), "co", ProductInput{ Mapped: map[string]any{"name": "Widget"}, BrandPrompt: "Brand:\n- tone: bold", }, "enhance_only", nil, StepPolicy{AllowAI: true, AllowEPREL: true}) if err != nil { t.Fatal(err) } if out.ProcessedName != "N" { t.Fatalf("name=%q", out.ProcessedName) } if !strings.Contains(gotSystem, "Brand:") || !strings.Contains(gotSystem, "bold") { t.Fatalf("system prompt missing brand: %q", gotSystem) } } func TestRunSteps_InjectsLanguageIntoAI(t *testing.T) { var gotSystem string e := &Engine{Completer: captureCompleter{fn: func(system, _ string) (Completion, error) { gotSystem = system b, _ := json.Marshal(map[string]string{"name": "N", "description": "D"}) return Completion{Text: string(b), TotalTokens: 1, Model: "test"}, nil }}} out, err := e.RunSteps(context.TODO(), "co", ProductInput{ Mapped: map[string]any{"name": "Widget"}, Language: "fr", }, "enhance_only", nil, StepPolicy{AllowAI: true, AllowEPREL: true}) if err != nil { t.Fatal(err) } if out.ProcessedName != "N" { t.Fatalf("name=%q", out.ProcessedName) } if !strings.Contains(gotSystem, "French") { t.Fatalf("system prompt missing language: %q", gotSystem) } } type captureCompleter struct { fn func(system, user string) (Completion, error) } func (c captureCompleter) Complete(_ context.Context, system, user string) (Completion, error) { return c.fn(system, user) } func (c captureCompleter) Enabled() bool { return true }