package service import ( "context" "errors" "testing" "wucher/internal/domain/federal_state" ) type federalStateRepoMock struct { createCalled bool updateCalled bool deleteCalled bool getByIDCalled bool listCalled bool lastCreate *federal_state.FederalState lastUpdate *federal_state.FederalState lastDeleteID []byte lastDeleteBy []byte lastGetByID []byte lastListFilter string lastListSort string lastListLimit int lastListOffset int lastListLandID []byte lastLandName string getByIDResult *federal_state.FederalState listResult []federal_state.FederalState listTotal int64 createErr error updateErr error deleteErr error getByIDErr error listErr error } func (m *federalStateRepoMock) Create(_ context.Context, o *federal_state.FederalState) error { m.createCalled = true m.lastCreate = o return m.createErr } func (m *federalStateRepoMock) Update(_ context.Context, o *federal_state.FederalState) error { m.updateCalled = true m.lastUpdate = o return m.updateErr } func (m *federalStateRepoMock) Delete(_ context.Context, id []byte, deletedBy []byte) error { m.deleteCalled = true m.lastDeleteID = id m.lastDeleteBy = deletedBy return m.deleteErr } func (m *federalStateRepoMock) GetByID(_ context.Context, id []byte) (*federal_state.FederalState, error) { m.getByIDCalled = true m.lastGetByID = id return m.getByIDResult, m.getByIDErr } func (m *federalStateRepoMock) List(_ context.Context, filter, sort string, limit, offset int, landID []byte, landName string) ([]federal_state.FederalState, int64, error) { m.listCalled = true m.lastListFilter = filter m.lastListSort = sort m.lastListLimit = limit m.lastListOffset = offset m.lastListLandID = append([]byte(nil), landID...) m.lastLandName = landName return m.listResult, m.listTotal, m.listErr } func TestNewFederalStateService(t *testing.T) { repo := &federalStateRepoMock{} svc := NewFederalStateService(repo) if svc == nil || svc.repo == nil { t.Fatalf("expected service and repo initialized") } } func TestFederalStateServiceCreate(t *testing.T) { repo := &federalStateRepoMock{} svc := NewFederalStateService(repo) row := &federal_state.FederalState{Name: "Name"} if err := svc.Create(context.Background(), row); err != nil { t.Fatalf("unexpected error: %v", err) } if !repo.createCalled || repo.lastCreate != row { t.Fatalf("expected Create forwarded to repo") } repo.createErr = errors.New("create failed") if err := svc.Create(context.Background(), row); err == nil { t.Fatalf("expected error from repo") } } func TestFederalStateServiceUpdate(t *testing.T) { repo := &federalStateRepoMock{} svc := NewFederalStateService(repo) row := &federal_state.FederalState{Name: "Updated"} if err := svc.Update(context.Background(), row); err != nil { t.Fatalf("unexpected error: %v", err) } if !repo.updateCalled || repo.lastUpdate != row { t.Fatalf("expected Update forwarded to repo") } repo.updateErr = errors.New("update failed") if err := svc.Update(context.Background(), row); err == nil { t.Fatalf("expected error from repo") } } func TestFederalStateServiceDelete(t *testing.T) { repo := &federalStateRepoMock{} svc := NewFederalStateService(repo) id := []byte("id") deletedBy := []byte("by") if err := svc.Delete(context.Background(), id, deletedBy); err != nil { t.Fatalf("unexpected error: %v", err) } if !repo.deleteCalled { t.Fatalf("expected Delete forwarded to repo") } if string(repo.lastDeleteID) != string(id) || string(repo.lastDeleteBy) != string(deletedBy) { t.Fatalf("expected delete params forwarded") } repo.deleteErr = errors.New("delete failed") if err := svc.Delete(context.Background(), id, deletedBy); err == nil { t.Fatalf("expected error from repo") } } func TestFederalStateServiceGetByID(t *testing.T) { expected := &federal_state.FederalState{Name: "A"} repo := &federalStateRepoMock{getByIDResult: expected} svc := NewFederalStateService(repo) id := []byte("id") got, err := svc.GetByID(context.Background(), id) if err != nil { t.Fatalf("unexpected error: %v", err) } if got != expected { t.Fatalf("unexpected result") } if !repo.getByIDCalled || string(repo.lastGetByID) != string(id) { t.Fatalf("expected GetByID forwarded") } repo.getByIDErr = errors.New("get failed") if _, err := svc.GetByID(context.Background(), id); err == nil { t.Fatalf("expected error from repo") } } func TestFederalStateServiceList(t *testing.T) { repo := &federalStateRepoMock{ listResult: []federal_state.FederalState{{Name: "A"}}, listTotal: 1, } svc := NewFederalStateService(repo) landID := []byte("land") rows, total, err := svc.List(context.Background(), "find", "sortkey", 10, 20, landID, "Germany") if err != nil { t.Fatalf("unexpected error: %v", err) } if len(rows) != 1 || total != 1 { t.Fatalf("unexpected list result") } if !repo.listCalled { t.Fatalf("expected List forwarded to repo") } if repo.lastListFilter != "find" || repo.lastListSort != "is_active DESC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN 0 ELSE 1 END ASC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN sortkey END ASC, name ASC" || repo.lastListLimit != 10 || repo.lastListOffset != 20 || string(repo.lastListLandID) != string(landID) || repo.lastLandName != "Germany" { t.Fatalf("unexpected list args forwarded") } repo.listErr = errors.New("list failed") if _, _, err := svc.List(context.Background(), "", "unknown", 1, 0, nil, ""); err == nil { t.Fatalf("expected error from repo") } } func TestNormalizeFederalStateSort(t *testing.T) { cases := map[string]string{ "name": "name ASC", "-name": "name DESC", "sortkey": "is_active DESC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN 0 ELSE 1 END ASC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN sortkey END ASC, name ASC", "-sortkey": "is_active DESC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN 0 ELSE 1 END ASC, CASE WHEN is_active = 1 AND sortkey IS NOT NULL AND sortkey >= 0 THEN sortkey END DESC, name ASC", "sort_key": "sortkey ASC", "-sort_key": "sortkey DESC", "is_active": "is_active ASC", "-is_active": "is_active DESC", "created_at": "created_at ASC", "-created_at": "created_at DESC", "updated_at": "updated_at ASC", "-updated_at": "updated_at DESC", "unknown": "", "": "", } for in, want := range cases { if got := normalizeFederalStateSort(in); got != want { t.Fatalf("normalizeFederalStateSort(%q) = %q, want %q", in, got, want) } } }