diff --git a/internal/test/refrence_test.go b/internal/test/refrence_test.go deleted file mode 100644 index c88ba77..0000000 --- a/internal/test/refrence_test.go +++ /dev/null @@ -1,334 +0,0 @@ -package test - -import ( - "bytes" - "encoding/json" - "net/http" - "net/http/httptest" - "strconv" - "testing" - - "Engine/internal/database" - "Engine/internal/handler" - "Engine/internal/model" - "Engine/tests/internal/testutil" -) - -// ── wire helpers ────────────────────────────────────────────────────────────── - -func newReferenceHandler(t *testing.T) *handler.ReferenceHandler { - t.Helper() - return handler.NewReferenceHandler(database.NewReferenceRepo(testutil.NewTestDB(t))) -} - -// newReferenceServer spins up a real httptest.Server with the production -// mux routes. Use this for delete/path-param tests that need {id} routing. -func newReferenceServer(t *testing.T) *httptest.Server { - t.Helper() - h := newReferenceHandler(t) - - mux := http.NewServeMux() - mux.HandleFunc("POST /api/v1/departments", h.CreateDepartment) - mux.HandleFunc("GET /api/v1/departments", h.ListDepartments) - mux.HandleFunc("DELETE /api/v1/departments/{id}", h.DeleteDepartment) - mux.HandleFunc("POST /api/v1/gl-accounts", h.CreateGLAccount) - mux.HandleFunc("GET /api/v1/gl-accounts", h.ListGLAccounts) - mux.HandleFunc("DELETE /api/v1/gl-accounts/{id}", h.DeleteGLAccount) - - srv := httptest.NewServer(mux) - t.Cleanup(srv.Close) - return srv -} - -// ── Department: Create ──────────────────────────────────────────────────────── - -func TestCreateDepartment_OK(t *testing.T) { - h := newReferenceHandler(t) - - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", - map[string]any{"code": "ENG", "name": "Engineering", "active": true}) - - testutil.AssertStatus(t, w, http.StatusCreated) - - var got database.Department - testutil.DecodeJSON(t, w, &got) - if got.Code != "ENG" { - t.Errorf("code: got %q, want %q", got.Code, "ENG") - } - if got.ID == 0 { - t.Error("expected non-zero ID in response") - } - if !got.Active { - t.Error("expected active=true") - } -} - -func TestCreateDepartment_DefaultsActiveTrue(t *testing.T) { - h := newReferenceHandler(t) - - // active field omitted — handler must default it to true - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", - map[string]any{"code": "MKT", "name": "Marketing"}) - - testutil.AssertStatus(t, w, http.StatusCreated) - - var got database.Department - testutil.DecodeJSON(t, w, &got) - if !got.Active { - t.Error("expected active to default to true when omitted") - } -} - -func TestCreateDepartment_MissingCode(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", - map[string]any{"name": "Engineering"}) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateDepartment_MissingName(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", - map[string]any{"code": "ENG"}) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateDepartment_WhitespaceOnly(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", - map[string]any{"code": " ", "name": " "}) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateDepartment_InvalidJSON(t *testing.T) { - h := newReferenceHandler(t) - // nil body → empty body → JSON decode fails → 400 - w := testutil.Do(t, http.HandlerFunc(h.CreateDepartment), http.MethodPost, "/", nil) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateDepartment_Upsert(t *testing.T) { - h := newReferenceHandler(t) - fn := http.HandlerFunc(h.CreateDepartment) - - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "FIN", "name": "Finance"}) - - w := testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "FIN", "name": "Finance Updated"}) - testutil.AssertStatus(t, w, http.StatusCreated) - - var got database.Department - testutil.DecodeJSON(t, w, &got) - if got.Name != "Finance Updated" { - t.Errorf("upsert name: got %q, want %q", got.Name, "Finance Updated") - } -} - -// ── Department: List ────────────────────────────────────────────────────────── - -func TestListDepartments_Empty(t *testing.T) { - h := newReferenceHandler(t) - - w := testutil.Do(t, http.HandlerFunc(h.ListDepartments), http.MethodGet, "/", nil) - testutil.AssertStatus(t, w, http.StatusOK) - - var got []database.Department - testutil.DecodeJSON(t, w, &got) - if len(got) != 0 { - t.Errorf("expected empty list, got %d", len(got)) - } -} - -func TestListDepartments_ReturnAll(t *testing.T) { - h := newReferenceHandler(t) - fn := http.HandlerFunc(h.CreateDepartment) - - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "HR", "name": "Human Resources"}) - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "IT", "name": "Information Technology"}) - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "OPS", "name": "Operations"}) - - w := testutil.Do(t, http.HandlerFunc(h.ListDepartments), http.MethodGet, "/", nil) - testutil.AssertStatus(t, w, http.StatusOK) - - var got []database.Department - testutil.DecodeJSON(t, w, &got) - if len(got) != 3 { - t.Errorf("expected 3 departments, got %d", len(got)) - } -} - -// ── Department: Delete ──────────────────────────────────────────────────────── - -func TestDeleteDepartment_OK(t *testing.T) { - srv := newReferenceServer(t) - client := srv.Client() - - resp, err := client.Post(srv.URL+"/api/v1/departments", "application/json", - mustJSON(t, map[string]any{"code": "OPS", "name": "Operations"})) - if err != nil { - t.Fatal(err) - } - var created database.Department - json.NewDecoder(resp.Body).Decode(&created) - resp.Body.Close() - - req, _ := http.NewRequest(http.MethodDelete, srv.URL+"/api/v1/departments/"+strconv.Itoa(created.ID), nil) - resp2, err := client.Do(req) - if err != nil { - t.Fatal(err) - } - resp2.Body.Close() - - if resp2.StatusCode != http.StatusNoContent && resp2.StatusCode != http.StatusOK { - t.Errorf("delete: got %d, want 200 or 204", resp2.StatusCode) - } -} - -func TestDeleteDepartment_NotFound(t *testing.T) { - srv := newReferenceServer(t) - - req, _ := http.NewRequest(http.MethodDelete, srv.URL+"/api/v1/departments/9999", nil) - resp, err := srv.Client().Do(req) - if err != nil { - t.Fatal(err) - } - resp.Body.Close() - - // Accept 404 or 204 — adjust to match your handler's behaviour - if resp.StatusCode != http.StatusNotFound && resp.StatusCode != http.StatusNoContent { - t.Errorf("delete non-existent: got %d, want 404 or 204", resp.StatusCode) - } -} - -// ── GL Account: Create ──────────────────────────────────────────────────────── - -func TestCreateGLAccount_OK(t *testing.T) { - h := newReferenceHandler(t) - - w := testutil.Do(t, http.HandlerFunc(h.CreateGLAccount), http.MethodPost, "/", - map[string]any{"code": "5001", "name": "Travel Expenses", "type": "expense"}) - - testutil.AssertStatus(t, w, http.StatusCreated) - - var got database.GLAccount - testutil.DecodeJSON(t, w, &got) - if got.Code != "5001" { - t.Errorf("code: got %q, want %q", got.Code, "5001") - } - if got.ID == 0 { - t.Error("expected non-zero ID") - } -} - -func TestCreateGLAccount_MissingCode(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.CreateGLAccount), http.MethodPost, "/", - map[string]any{"name": "Travel Expenses"}) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateGLAccount_MissingName(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.CreateGLAccount), http.MethodPost, "/", - map[string]any{"code": "5001"}) - testutil.AssertStatus(t, w, http.StatusBadRequest) -} - -func TestCreateGLAccount_Upsert(t *testing.T) { - h := newReferenceHandler(t) - fn := http.HandlerFunc(h.CreateGLAccount) - - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "4001", "name": "Revenue"}) - - w := testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "4001", "name": "Revenue Updated"}) - testutil.AssertStatus(t, w, http.StatusCreated) - - var got model.GLAccount - testutil.DecodeJSON(t, w, &got) - if got.Name != "Revenue Updated" { - t.Errorf("upsert name: got %q, want %q", got.Name, "Revenue Updated") - } -} - -// ── GL Account: List ────────────────────────────────────────────────────────── - -func TestListGLAccounts_Empty(t *testing.T) { - h := newReferenceHandler(t) - w := testutil.Do(t, http.HandlerFunc(h.ListGLAccounts), http.MethodGet, "/", nil) - testutil.AssertStatus(t, w, http.StatusOK) - - var got []database.GLAccount - testutil.DecodeJSON(t, w, &got) - if len(got) != 0 { - t.Errorf("expected empty list, got %d", len(got)) - } -} - -func TestListGLAccounts_ReturnAll(t *testing.T) { - h := newReferenceHandler(t) - fn := http.HandlerFunc(h.CreateGLAccount) - - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "4001", "name": "Revenue"}) - testutil.Do(t, fn, http.MethodPost, "/", map[string]any{"code": "5001", "name": "COGS"}) - - w := testutil.Do(t, http.HandlerFunc(h.ListGLAccounts), http.MethodGet, "/", nil) - testutil.AssertStatus(t, w, http.StatusOK) - - var got []database.GLAccount - testutil.DecodeJSON(t, w, &got) - if len(got) != 2 { - t.Errorf("expected 2 GL accounts, got %d", len(got)) - } -} - -// ── GL Account: Delete ──────────────────────────────────────────────────────── - -func TestDeleteGLAccount_OK(t *testing.T) { - srv := newReferenceServer(t) - client := srv.Client() - - resp, err := client.Post(srv.URL+"/api/v1/gl-accounts", "application/json", - mustJSON(t, map[string]any{"code": "6001", "name": "Rent"})) - if err != nil { - t.Fatal(err) - } - var created database.GLAccount - json.NewDecoder(resp.Body).Decode(&created) - resp.Body.Close() - - req, _ := http.NewRequest(http.MethodDelete, srv.URL+"/api/v1/gl-accounts/"+strconv.Itoa(created.ID), nil) - resp2, err := client.Do(req) - if err != nil { - t.Fatal(err) - } - resp2.Body.Close() - - if resp2.StatusCode != http.StatusNoContent && resp2.StatusCode != http.StatusOK { - t.Errorf("delete: got %d, want 200 or 204", resp2.StatusCode) - } -} - -func TestDeleteGLAccount_NotFound(t *testing.T) { - srv := newReferenceServer(t) - - req, _ := http.NewRequest(http.MethodDelete, srv.URL+"/api/v1/gl-accounts/9999", nil) - resp, err := srv.Client().Do(req) - if err != nil { - t.Fatal(err) - } - resp.Body.Close() - - if resp.StatusCode != http.StatusNotFound && resp.StatusCode != http.StatusNoContent { - t.Errorf("delete non-existent: got %d, want 404 or 204", resp.StatusCode) - } -} - -// ── local helpers ───────────────────────────────────────────────────────────── - -func mustJSON(t *testing.T, v any) *bytes.Reader { - t.Helper() - b, err := json.Marshal(v) - if err != nil { - t.Fatal(err) - } - return bytes.NewReader(b) -}