//go:build integration package product_catalog_test import ( "context" "testing" "github.com/food-ai/backend/internal/domain/product" "github.com/food-ai/backend/internal/infra/locale" "github.com/food-ai/backend/internal/testutil" ) func TestProductRepository_Upsert_Insert(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() cat := "produce" unit := "g" cal := 52.0 catalogProduct := &product.Product{ CanonicalName: "apple", Category: &cat, DefaultUnit: &unit, CaloriesPer100g: &cal, } got, upsertError := repo.Upsert(ctx, catalogProduct) if upsertError != nil { t.Fatalf("upsert: %v", upsertError) } if got.ID == "" { t.Error("expected non-empty ID") } if got.CanonicalName != "apple" { t.Errorf("canonical_name: want apple, got %s", got.CanonicalName) } if *got.CaloriesPer100g != 52.0 { t.Errorf("calories: want 52.0, got %v", got.CaloriesPer100g) } } func TestProductRepository_Upsert_ConflictUpdates(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() cat := "produce" unit := "g" first := &product.Product{ CanonicalName: "banana", Category: &cat, DefaultUnit: &unit, } got1, firstUpsertError := repo.Upsert(ctx, first) if firstUpsertError != nil { t.Fatalf("first upsert: %v", firstUpsertError) } cal := 89.0 second := &product.Product{ CanonicalName: "banana", Category: &cat, DefaultUnit: &unit, CaloriesPer100g: &cal, } got2, secondUpsertError := repo.Upsert(ctx, second) if secondUpsertError != nil { t.Fatalf("second upsert: %v", secondUpsertError) } if got1.ID != got2.ID { t.Errorf("ID changed on conflict update: %s != %s", got1.ID, got2.ID) } if got2.CanonicalName != "banana" { t.Errorf("canonical_name not updated: got %s", got2.CanonicalName) } if got2.CaloriesPer100g == nil || *got2.CaloriesPer100g != 89.0 { t.Errorf("calories not updated: got %v", got2.CaloriesPer100g) } } func TestProductRepository_GetByID_Found(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() cat := "dairy" unit := "g" saved, upsertError := repo.Upsert(ctx, &product.Product{ CanonicalName: "cheese", Category: &cat, DefaultUnit: &unit, }) if upsertError != nil { t.Fatalf("upsert: %v", upsertError) } got, getError := repo.GetByID(ctx, saved.ID) if getError != nil { t.Fatalf("get: %v", getError) } if got == nil { t.Fatal("expected non-nil result") } if got.CanonicalName != "cheese" { t.Errorf("want cheese, got %s", got.CanonicalName) } } func TestProductRepository_GetByID_NotFound(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() got, getError := repo.GetByID(ctx, "00000000-0000-0000-0000-000000000000") if getError != nil { t.Fatalf("unexpected error: %v", getError) } if got != nil { t.Error("expected nil result for missing ID") } } func TestProductRepository_UpsertAliases(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() cat := "produce" unit := "g" saved, upsertError := repo.Upsert(ctx, &product.Product{ CanonicalName: "apple_test_aliases", Category: &cat, DefaultUnit: &unit, }) if upsertError != nil { t.Fatalf("upsert: %v", upsertError) } aliases := []string{"apple", "apples", "red apple"} if aliasError := repo.UpsertAliases(ctx, saved.ID, "en", aliases); aliasError != nil { t.Fatalf("upsert aliases: %v", aliasError) } if aliasError := repo.UpsertAliases(ctx, saved.ID, "en", aliases); aliasError != nil { t.Fatalf("second upsert aliases: %v", aliasError) } englishContext := locale.WithLang(ctx, "en") got, getError := repo.GetByID(englishContext, saved.ID) if getError != nil { t.Fatalf("get by id: %v", getError) } if string(got.Aliases) == "[]" || string(got.Aliases) == "null" { t.Errorf("expected non-empty aliases, got %s", got.Aliases) } } func TestProductRepository_UpsertCategoryTranslation(t *testing.T) { pool := testutil.SetupTestDB(t) repo := product.NewRepository(pool) ctx := context.Background() cat := "dairy" unit := "g" saved, upsertError := repo.Upsert(ctx, &product.Product{ CanonicalName: "milk_test_category", Category: &cat, DefaultUnit: &unit, }) if upsertError != nil { t.Fatalf("upsert: %v", upsertError) } russianContext := locale.WithLang(ctx, "ru") got, getError := repo.GetByID(russianContext, saved.ID) if getError != nil { t.Fatalf("get by id: %v", getError) } if got.CategoryName == nil || *got.CategoryName == "" { t.Error("expected non-empty CategoryName for 'dairy' in Russian") } if translationError := repo.UpsertCategoryTranslation(ctx, "dairy", "de", "Milchprodukte"); translationError != nil { t.Fatalf("upsert category translation: %v", translationError) } germanContext := locale.WithLang(ctx, "de") gotGerman, getGermanError := repo.GetByID(germanContext, saved.ID) if getGermanError != nil { t.Fatalf("get by id (de): %v", getGermanError) } if gotGerman.CategoryName == nil || *gotGerman.CategoryName != "Milchprodukte" { t.Errorf("expected CategoryName='Milchprodukte', got %v", gotGerman.CategoryName) } }