package usecase import ( "context" "errors" "testing" "apps/backend/internal/module/radar/domain" "apps/backend/internal/module/radar/repository" ) type demandMapProducts struct{ product *ProductCatalogProduct } func (s demandMapProducts) GetBrand(context.Context, int64, string) (*ProductBrand, error) { return nil, domain.ErrNotFound } func (s demandMapProducts) GetProduct(_ context.Context, ownerUID int64, id string) (*ProductCatalogProduct, error) { if s.product == nil || s.product.OwnerUID != ownerUID || s.product.ID != id { return nil, domain.ErrNotFound } return s.product, nil } func TestDemandMapBaselineAndOptimisticVersion(t *testing.T) { const owner = int64(42) repo := repository.NewMemory() svc := New(repo) svc.ProductSource = demandMapProducts{product: &ProductCatalogProduct{ ID: "p1", OwnerUID: owner, Label: "舒緩精華", ProductContext: "換季日常修護", PainPoints: []string{"泛紅不適"}, MatchTags: []string{"舒緩保濕"}, ProviderCapabilityTerms: []string{"修護"}, UpdatedAt: 7, }} first, err := svc.GetDemandMap(context.Background(), owner, "p1") if err != nil { t.Fatal(err) } if first.State != "ready" || first.MapVersion != 1 || len(first.DemandInputVersion) != len("demand-")+16 { t.Fatalf("unexpected baseline: %+v", first) } first.PainPhrases[0].Text = "新的痛點" updated, err := svc.UpdateDemandMap(context.Background(), owner, first, 1) if err != nil { t.Fatal(err) } if updated.MapVersion != 2 || updated.PainPhrases[0].Text != "新的痛點" { t.Fatalf("unexpected update: %+v", updated) } if _, err := svc.UpdateDemandMap(context.Background(), owner, first, 1); !errors.Is(err, domain.ErrConflict) { t.Fatalf("stale update must conflict, got %v", err) } } func TestDemandMapBaselineIncomplete(t *testing.T) { repo := repository.NewMemory() svc := New(repo) svc.ProductSource = demandMapProducts{product: &ProductCatalogProduct{ID: "p2", OwnerUID: 42, Label: "服務", PainPoints: []string{"等待太久"}, UpdatedAt: 1}} m, err := svc.GetDemandMap(context.Background(), 42, "p2") if err != nil { t.Fatal(err) } if m.State != "incomplete" { t.Fatalf("expected incomplete baseline, got %q", m.State) } }