2026-08-13 02:22:24 +00:00
|
|
|
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)
|
|
|
|
|
}
|
2026-08-13 07:54:25 +00:00
|
|
|
for _, p := range append(append([]domain.DemandMapPhrase{}, first.PainPhrases...), append(first.ScenarioPhrases, first.SolutionSignals...)...) {
|
|
|
|
|
if !domain.IsThreadsSearchable(p.Text) {
|
|
|
|
|
t.Fatalf("baseline phrase %q is not searchable", p.Text)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-13 02:22:24 +00:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|