all tests works...

This commit is contained in:
samantha42
2026-03-21 18:14:23 +01:00
parent c55e7d6774
commit 6c5b4bae67
6 changed files with 239 additions and 150 deletions

View File

@@ -1,12 +1,9 @@
package test
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"Engine/internal/database"
@@ -18,9 +15,11 @@ import (
// ── wire helpers ──────────────────────────────────────────────────────────────
func newBudgetServer(t *testing.T) *httptest.Server {
func newBudgetServer(t *testing.T) (*httptest.Server, int, int) {
t.Helper()
db := testutil.NewTestDB(t)
deptID, glID := testutil.SeedFixtures(t, db)
repo := database.NewBudgetRepo(db)
h := handler.NewBudgetHandler(service.NewBudgetService(repo))
@@ -31,23 +30,25 @@ func newBudgetServer(t *testing.T) *httptest.Server {
srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)
return srv
return srv, deptID, glID
}
func newBudgetHandler(t *testing.T) *handler.BudgetHandler {
func newBudgetHandler(t *testing.T) (*handler.BudgetHandler, int, int) {
t.Helper()
return handler.NewBudgetHandler(service.NewBudgetService(database.NewBudgetRepo(testutil.NewTestDB(t))))
db := testutil.NewTestDB(t)
deptID, glID := testutil.SeedFixtures(t, db)
return handler.NewBudgetHandler(service.NewBudgetService(database.NewBudgetRepo(db))), deptID, glID
}
func validBudget() map[string]any {
func validBudget(deptID, glID int) map[string]any {
return map[string]any{
"fiscal_year": 2024,
"fiscal_period": 1,
"version": "original", // adjust to match your BudgetVersion values
"department_id": 1,
"gl_account_id": 1,
"version": "original",
"department_id": deptID,
"gl_account_id": glID,
"amount": 5000.00,
"currency": "USD",
"currency": "DKK",
"notes": "",
"created_by": "test",
}
@@ -56,9 +57,8 @@ func validBudget() map[string]any {
// ── Create ────────────────────────────────────────────────────────────────────
func TestCreateBudget_OK(t *testing.T) {
h := newBudgetHandler(t)
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", validBudget())
h, deptID, glID := newBudgetHandler(t)
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", validBudget(deptID, glID))
testutil.AssertStatus(t, w, http.StatusCreated)
var got model.Budget
@@ -72,31 +72,22 @@ func TestCreateBudget_OK(t *testing.T) {
}
func TestCreateBudget_InvalidJSON(t *testing.T) {
h := newBudgetHandler(t)
h, _, _ := newBudgetHandler(t)
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", nil)
testutil.AssertStatus(t, w, http.StatusBadRequest)
}
func TestCreateBudget_MissingPeriod(t *testing.T) {
h := newBudgetHandler(t)
body := validBudget()
h, deptID, glID := newBudgetHandler(t)
body := validBudget(deptID, glID)
delete(body, "fiscal_period")
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", body)
testutil.AssertStatus(t, w, http.StatusBadRequest)
}
func TestCreateBudget_ZeroAmount(t *testing.T) {
h := newBudgetHandler(t)
body := validBudget()
body["amount"] = 0
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", body)
// Whether 0 is rejected or accepted depends on your business rule — adjust to match
t.Logf("zero amount response: %d — verify against your handler", w.Code)
}
func TestCreateBudget_NegativeAmount(t *testing.T) {
h := newBudgetHandler(t)
body := validBudget()
h, deptID, glID := newBudgetHandler(t)
body := validBudget(deptID, glID)
body["amount"] = -100
w := testutil.Do(t, http.HandlerFunc(h.Create), http.MethodPost, "/", body)
testutil.AssertStatus(t, w, http.StatusBadRequest)
@@ -105,14 +96,13 @@ func TestCreateBudget_NegativeAmount(t *testing.T) {
// ── Update ────────────────────────────────────────────────────────────────────
func TestUpdateBudget_OK(t *testing.T) {
srv := newBudgetServer(t)
srv, deptID, glID := newBudgetServer(t)
client := srv.Client()
// Create a budget to update
resp, err := client.Post(
srv.URL+"/api/v1/budget/create",
"application/json",
mustJSON(t, validBudget()),
mustJSON(t, validBudget(deptID, glID)),
)
if err != nil {
t.Fatal(err)
@@ -181,55 +171,43 @@ func TestUpdateBudget_OK(t *testing.T) {
}
}
func TestUpdateBudget_NotFound(t *testing.T) {
srv := newBudgetServer(t)
func TestUpdateBudget_BadRequest(t *testing.T) {
srv, _, _ := newBudgetServer(t)
req, _ := http.NewRequest(http.MethodPut, srv.URL+"/api/v1/budgets/9999",
mustJSON(t, validBudget()))
req.Header.Set("Content-Type", "application/json")
// bad request...
wantNotes := "updated in test"
updateReq := model.UpdateBudgetRequest{
Notes: &wantNotes,
ChangedBy: "idk",
}
req, err := http.NewRequest(
http.MethodPut,
srv.URL+"/api/v1/budget/update",
mustJSON(t, updateReq),
)
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("update non-existent: got %d, want 404 or 204", resp.StatusCode)
}
}
func TestUpdateBudget_InvalidJSON(t *testing.T) {
srv := newBudgetServer(t)
// Create one first so the ID exists
resp, _ := srv.Client().Post(srv.URL+"/api/v1/budgets", "application/json",
mustJSON(t, validBudget()))
var created model.Budget
json.NewDecoder(resp.Body).Decode(&created)
resp.Body.Close()
req, _ := http.NewRequest(http.MethodPut,
fmt.Sprintf("%s/api/v1/budgets/%d", srv.URL, created.ID),
bytes.NewBufferString("not-json"))
req.Header.Set("Content-Type", "application/json")
resp2, err := srv.Client().Do(req)
if err != nil {
t.Fatal(err)
}
resp2.Body.Close()
if resp2.StatusCode != http.StatusBadRequest {
t.Errorf("invalid JSON update: got %d, want 400", resp2.StatusCode)
if resp.StatusCode != http.StatusBadRequest && resp.StatusCode != http.StatusNoContent {
t.Errorf("update non-existent: got %d, want 400 or 204", resp.StatusCode)
}
}
// ── Delete ────────────────────────────────────────────────────────────────────
func TestDeleteBudget_OK(t *testing.T) {
srv := newBudgetServer(t)
srv, deptID, glID := newBudgetServer(t)
client := srv.Client()
resp, err := client.Post(srv.URL+"/api/v1/budgets", "application/json",
mustJSON(t, validBudget()))
resp, err := client.Post(
srv.URL+"/api/v1/budget/create",
"application/json",
mustJSON(t, validBudget(deptID, glID)),
)
if err != nil {
t.Fatal(err)
}
@@ -237,8 +215,20 @@ func TestDeleteBudget_OK(t *testing.T) {
json.NewDecoder(resp.Body).Decode(&created)
resp.Body.Close()
req, _ := http.NewRequest(http.MethodDelete,
srv.URL+"/api/v1/budgets/"+strconv.Itoa(created.ID), nil)
if created.ID == 0 {
t.Fatal("expected non-zero ID from create")
}
req, err := http.NewRequest(
http.MethodDelete,
srv.URL+"/api/v1/budget/delete",
mustJSON(t, model.DeleteBudgetRequest{ID: created.ID}),
)
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
resp2, err := client.Do(req)
if err != nil {
t.Fatal(err)
@@ -249,11 +239,16 @@ func TestDeleteBudget_OK(t *testing.T) {
t.Errorf("delete: got %d, want 200 or 204", resp2.StatusCode)
}
}
func TestDeleteBudget_NotFound(t *testing.T) {
srv := newBudgetServer(t)
srv, _, _ := newBudgetServer(t)
req, _ := http.NewRequest(
http.MethodDelete,
srv.URL+"/api/v1/budget/delete",
mustJSON(t, model.DeleteBudgetRequest{ID: 9999}),
)
req.Header.Set("Content-Type", "application/json")
req, _ := http.NewRequest(http.MethodDelete, srv.URL+"/api/v1/budgets/9999", nil)
resp, err := srv.Client().Do(req)
if err != nil {
t.Fatal(err)
@@ -266,23 +261,47 @@ func TestDeleteBudget_NotFound(t *testing.T) {
}
func TestDeleteBudget_DoubleDelete(t *testing.T) {
srv := newBudgetServer(t)
srv, deptID, glID := newBudgetServer(t)
client := srv.Client()
resp, _ := client.Post(srv.URL+"/api/v1/budgets", "application/json",
mustJSON(t, validBudget()))
resp, err := client.Post(
srv.URL+"/api/v1/budget/create",
"application/json",
mustJSON(t, validBudget(deptID, glID)),
)
if err != nil {
t.Fatal(err)
}
var created model.Budget
json.NewDecoder(resp.Body).Decode(&created)
resp.Body.Close()
url := srv.URL + "/api/v1/budgets/" + strconv.Itoa(created.ID)
if created.ID == 0 {
t.Fatal("expected non-zero ID from create")
}
req1, _ := http.NewRequest(http.MethodDelete, url, nil)
deleteBody := model.DeleteBudgetRequest{ID: created.ID}
req1, _ := http.NewRequest(
http.MethodDelete,
srv.URL+"/api/v1/budget/delete",
mustJSON(t, deleteBody),
)
req1.Header.Set("Content-Type", "application/json")
resp1, _ := client.Do(req1)
resp1.Body.Close()
// Second delete — should not panic, should return 404 or 204
req2, _ := http.NewRequest(http.MethodDelete, url, nil)
req2, err := http.NewRequest(
http.MethodDelete,
srv.URL+"/api/v1/budget/delete",
mustJSON(t, deleteBody),
)
if err != nil {
t.Fatal(err)
}
req2.Header.Set("Content-Type", "application/json")
resp2, err := client.Do(req2)
if err != nil {
t.Fatal(err)