2026-08-09 22:47:43 +02:00
|
|
|
package catalog
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestNormalizeGTIN(t *testing.T) {
|
|
|
|
|
if got := NormalizeGTIN(" 400-599-8858394 "); got != "4005998858394" {
|
|
|
|
|
t.Fatalf("got %q", got)
|
|
|
|
|
}
|
|
|
|
|
if got := NormalizeGTIN("SKU-ABC"); got != "SKU-ABC" {
|
|
|
|
|
t.Fatalf("non-digit fallback got %q", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBuildMappedDataFromV1Item(t *testing.T) {
|
|
|
|
|
mapped := BuildMappedDataFromV1Item(V1ProcessItem{
|
|
|
|
|
EAN: "1234567890123",
|
|
|
|
|
Title: "Widget",
|
|
|
|
|
Description: "A widget",
|
|
|
|
|
CategoryUniqueID: "electronics",
|
|
|
|
|
MainImage: "https://cdn.example.com/w.jpg",
|
|
|
|
|
MoreImages: []any{"https://cdn.example.com/w2.jpg"},
|
|
|
|
|
Specifications: []map[string]any{{"key": "color", "value": "red"}},
|
|
|
|
|
})
|
|
|
|
|
if mapped["ean"] != "1234567890123" || mapped["title"] != "Widget" {
|
|
|
|
|
t.Fatalf("mapped=%v", mapped)
|
|
|
|
|
}
|
|
|
|
|
if mapped["category"] != "electronics" {
|
|
|
|
|
t.Fatalf("category=%v", mapped["category"])
|
|
|
|
|
}
|
|
|
|
|
if mapped["image_url"] != "https://cdn.example.com/w.jpg" {
|
|
|
|
|
t.Fatalf("image_url=%v", mapped["image_url"])
|
|
|
|
|
}
|
|
|
|
|
b, _ := json.Marshal(mapped["additional_image_urls"])
|
|
|
|
|
if string(b) != `["https://cdn.example.com/w2.jpg"]` {
|
|
|
|
|
t.Fatalf("more=%s", b)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-16 12:00:28 +02:00
|
|
|
|
|
|
|
|
func TestBuildMappedDataFromV1ItemOmitsEmptyNulls(t *testing.T) {
|
|
|
|
|
mapped := BuildMappedDataFromV1Item(V1ProcessItem{EAN: "123"})
|
|
|
|
|
if _, ok := mapped["title"]; ok {
|
|
|
|
|
t.Fatalf("empty title must be omitted, got %v", mapped)
|
|
|
|
|
}
|
|
|
|
|
if _, ok := mapped["description"]; ok {
|
|
|
|
|
t.Fatalf("empty description must be omitted, got %v", mapped)
|
|
|
|
|
}
|
|
|
|
|
if !v1ItemHasContent(V1ProcessItem{EAN: "1", Title: "x"}) {
|
|
|
|
|
t.Fatal("title should count as content")
|
|
|
|
|
}
|
|
|
|
|
if v1ItemHasContent(V1ProcessItem{EAN: "1"}) {
|
|
|
|
|
t.Fatal("EAN-only must not count as content")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-16 16:57:36 +02:00
|
|
|
|
|
|
|
|
func TestExtractProductImages_promotesMoreimagesWhenMainEmpty(t *testing.T) {
|
|
|
|
|
main, more := ExtractProductImages(map[string]any{
|
|
|
|
|
"main_image": "",
|
|
|
|
|
"moreimages": "https://cdn.example.com/a.jpg,https://cdn.example.com/b.jpg",
|
|
|
|
|
}, nil)
|
|
|
|
|
if main != "https://cdn.example.com/a.jpg" {
|
|
|
|
|
t.Fatalf("main=%q", main)
|
|
|
|
|
}
|
|
|
|
|
if len(more) != 1 || more[0] != "https://cdn.example.com/b.jpg" {
|
|
|
|
|
t.Fatalf("more=%v", more)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestExtractProductImages_imagesStringSliceAndSrcObjects(t *testing.T) {
|
|
|
|
|
main, more := ExtractProductImages(map[string]any{
|
|
|
|
|
"images": []string{
|
|
|
|
|
"https://cdn.example.com/main.jpg",
|
|
|
|
|
"https://cdn.example.com/2.jpg",
|
|
|
|
|
},
|
|
|
|
|
}, nil)
|
|
|
|
|
if main != "https://cdn.example.com/main.jpg" || len(more) != 1 || more[0] != "https://cdn.example.com/2.jpg" {
|
|
|
|
|
t.Fatalf("string slice main=%q more=%v", main, more)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main, more = ExtractProductImages(map[string]any{
|
|
|
|
|
"images": []any{
|
|
|
|
|
map[string]any{"src": "https://cdn.example.com/from-src.jpg"},
|
|
|
|
|
map[string]any{"src": "https://cdn.example.com/from-src-2.jpg"},
|
|
|
|
|
},
|
|
|
|
|
}, nil)
|
|
|
|
|
if main != "https://cdn.example.com/from-src.jpg" || len(more) != 1 || more[0] != "https://cdn.example.com/from-src-2.jpg" {
|
|
|
|
|
t.Fatalf("src objects main=%q more=%v", main, more)
|
|
|
|
|
}
|
|
|
|
|
}
|