package service import ( "context" "errors" "testing" otherperson "wucher/internal/domain/other_person" "wucher/internal/shared/pkg/uuidv7" ) type fakeOtherPersonRepo struct { byID map[string]*otherperson.OtherPerson identity map[string]*otherperson.OtherPerson // key: name|phone|email created *otherperson.OtherPerson updated *otherperson.OtherPerson deletedID []byte forceError error } func newFakeOtherPersonRepo() *fakeOtherPersonRepo { return &fakeOtherPersonRepo{ byID: map[string]*otherperson.OtherPerson{}, identity: map[string]*otherperson.OtherPerson{}, } } func identityKey(name, phone, email string) string { return name + "|" + phone + "|" + email } func (r *fakeOtherPersonRepo) Upsert(context.Context, *otherperson.OtherPerson) error { return nil } func (r *fakeOtherPersonRepo) Create(_ context.Context, p *otherperson.OtherPerson) error { if r.forceError != nil { return r.forceError } if len(p.ID) == 0 { p.ID = uuidv7.MustBytes() } r.created = p cp := *p r.byID[string(p.ID)] = &cp r.identity[identityKey(p.Name, p.MobilePhone, p.Email)] = &cp return nil } func (r *fakeOtherPersonRepo) Update(_ context.Context, p *otherperson.OtherPerson) error { if r.forceError != nil { return r.forceError } r.updated = p cp := *p r.byID[string(p.ID)] = &cp return nil } func (r *fakeOtherPersonRepo) Delete(_ context.Context, id, _ []byte) error { if r.forceError != nil { return r.forceError } r.deletedID = id delete(r.byID, string(id)) return nil } func (r *fakeOtherPersonRepo) GetByID(_ context.Context, id []byte) (*otherperson.OtherPerson, error) { return r.byID[string(id)], nil } func (r *fakeOtherPersonRepo) FindByIdentity(_ context.Context, name, phone, email string) (*otherperson.OtherPerson, error) { return r.identity[identityKey(name, phone, email)], nil } func (r *fakeOtherPersonRepo) Search(context.Context, string, int, int) ([]otherperson.OtherPerson, int64, error) { return nil, 0, nil } func TestOtherPersonServiceCreate(t *testing.T) { repo := newFakeOtherPersonRepo() svc := NewOtherPersonService(repo) ctx := context.Background() // Name required. if err := svc.Create(ctx, &otherperson.OtherPerson{Name: " "}); !errors.Is(err, otherperson.ErrNameRequired) { t.Fatalf("expected ErrNameRequired, got %v", err) } // Happy path. p := &otherperson.OtherPerson{Name: "Guest", MobilePhone: "1", Email: "g@x.io"} if err := svc.Create(ctx, p); err != nil { t.Fatalf("create: %v", err) } if len(p.ID) == 0 || repo.created == nil { t.Fatalf("expected create persisted") } // Duplicate identity rejected. dup := &otherperson.OtherPerson{Name: "Guest", MobilePhone: "1", Email: "g@x.io"} if err := svc.Create(ctx, dup); !errors.Is(err, otherperson.ErrDuplicate) { t.Fatalf("expected ErrDuplicate, got %v", err) } } func TestOtherPersonServiceUpdate(t *testing.T) { repo := newFakeOtherPersonRepo() svc := NewOtherPersonService(repo) ctx := context.Background() // Seed two rows. a := &otherperson.OtherPerson{Name: "Alpha", MobilePhone: "1", Email: "a@x.io"} b := &otherperson.OtherPerson{Name: "Beta", MobilePhone: "2", Email: "b@x.io"} _ = svc.Create(ctx, a) _ = svc.Create(ctx, b) // Updating a missing id -> not found. missing := &otherperson.OtherPerson{ID: uuidv7.MustBytes(), Name: "X"} if err := svc.Update(ctx, missing); !errors.Is(err, otherperson.ErrNotFound) { t.Fatalf("expected ErrNotFound, got %v", err) } // Updating A to B's identity -> duplicate. clash := &otherperson.OtherPerson{ID: a.ID, Name: "Beta", MobilePhone: "2", Email: "b@x.io"} if err := svc.Update(ctx, clash); !errors.Is(err, otherperson.ErrDuplicate) { t.Fatalf("expected ErrDuplicate, got %v", err) } // Updating A to a fresh identity -> ok. ok := &otherperson.OtherPerson{ID: a.ID, Name: "Alpha2", MobilePhone: "1", Email: "a@x.io"} if err := svc.Update(ctx, ok); err != nil { t.Fatalf("expected update ok, got %v", err) } if repo.updated == nil || repo.updated.Name != "Alpha2" { t.Fatalf("update not forwarded") } } func TestOtherPersonServiceDeleteNotFound(t *testing.T) { repo := newFakeOtherPersonRepo() svc := NewOtherPersonService(repo) if err := svc.Delete(context.Background(), uuidv7.MustBytes(), nil); !errors.Is(err, otherperson.ErrNotFound) { t.Fatalf("expected ErrNotFound, got %v", err) } }