140 lines
4.0 KiB
Go
140 lines
4.0 KiB
Go
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(`<ul><li>Color: Red</li><li>Material: Steel</li></ul>`)
|
||
|
|
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 }
|