Create tests for ALL API entpoints in ALL packages

Based on current data. Ensure that all API endpoints used in frontend are tested. These tests are crucial for the next refactoring tasks.
This commit is contained in:
2026-04-11 23:37:40 +02:00
parent 9a429b16a2
commit 2cac1cc41d
8 changed files with 2012 additions and 0 deletions
@@ -0,0 +1,445 @@
package character
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupSessionTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
require.NoError(t, models.MigrateStructure())
gin.SetMode(gin.TestMode)
}
const testUserIDSession = uint(4)
func createTestSession(t *testing.T) string {
t.Helper()
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Request = httptest.NewRequest(http.MethodPost, "/api/characters/create-session", nil)
CreateCharacterSession(c)
require.Equal(t, http.StatusCreated, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
sessionID, ok := resp["session_id"].(string)
require.True(t, ok, "session_id should be a string")
return sessionID
}
func TestCreateCharacterSession(t *testing.T) {
setupSessionTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Request = httptest.NewRequest(http.MethodPost, "/api/characters/create-session", nil)
CreateCharacterSession(c)
assert.Equal(t, http.StatusCreated, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotEmpty(t, resp["session_id"])
assert.NotEmpty(t, resp["expires_at"])
}
func TestCreateCharacterSessionUnauthorized(t *testing.T) {
setupSessionTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
// userID NOT set - simulates missing authentication
c.Request = httptest.NewRequest(http.MethodPost, "/api/characters/create-session", nil)
CreateCharacterSession(c)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestListCharacterSessions(t *testing.T) {
setupSessionTestEnv(t)
// Create a session first
createTestSession(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/create-sessions", nil)
ListCharacterSessions(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp["sessions"])
count, ok := resp["count"].(float64)
assert.True(t, ok)
assert.GreaterOrEqual(t, int(count), 1)
}
func TestGetCharacterSession(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/create-session/"+sessionID, nil)
GetCharacterSession(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp models.CharacterCreationSession
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, sessionID, resp.ID)
}
func TestGetCharacterSessionNotFound(t *testing.T) {
setupSessionTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: "nonexistent_session_id"}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetCharacterSession(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestUpdateCharacterBasicInfo(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
reqBody := map[string]interface{}{
"name": "Torin Eisenstein",
"geschlecht": "male",
"rasse": "Mensch",
"typ": "Kr",
"herkunft": "Norden",
"stand": "Händler",
"glaube": "Gott1",
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterBasicInfo(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(2), resp["current_step"])
}
func TestUpdateCharacterBasicInfoMissingField(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
// Missing required fields
reqBody := map[string]interface{}{
"name": "Incomplete",
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterBasicInfo(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestUpdateCharacterAttributes(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
reqBody := map[string]interface{}{
"st": 50, "gs": 40, "gw": 45,
"ko": 55, "in": 60, "zt": 30, "au": 35,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterAttributes(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(3), resp["current_step"])
}
func TestUpdateCharacterAttributesOutOfRange(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
// Value out of range (max 100)
reqBody := map[string]interface{}{
"st": 150, "gs": 40, "gw": 45,
"ko": 55, "in": 60, "zt": 30, "au": 35,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterAttributes(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestUpdateCharacterDerivedValues(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
reqBody := map[string]interface{}{
"pa": 10,
"wk": 8,
"lp_max": 20,
"ap_max": 100,
"b_max": 10,
"resistenz_koerper": 5,
"resistenz_geist": 5,
"resistenz_bonus_koerper": 0,
"resistenz_bonus_geist": 0,
"abwehr": 5,
"abwehr_bonus": 0,
"ausdauer_bonus": 0,
"angriffs_bonus": 0,
"zaubern": 5,
"zauber_bonus": 0,
"raufen": 5,
"schadens_bonus": 0,
"sg": 3,
"gg": 0,
"gp": 0,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterDerivedValues(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(4), resp["current_step"])
}
func TestUpdateCharacterSkills(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
reqBody := map[string]interface{}{
"skills": []map[string]interface{}{
{"name": "Athletik", "level": 5, "category": "Körper"},
},
"spells": []map[string]interface{}{},
"skill_points": map[string]interface{}{},
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterSkills(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(5), resp["current_step"])
}
func TestDeleteCharacterSession(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodDelete, "/api/characters/create-session/"+sessionID, nil)
DeleteCharacterSession(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, "Session gelöscht", resp["message"])
// Verify session no longer exists
var count int64
database.DB.Model(&models.CharacterCreationSession{}).Where("id = ?", sessionID).Count(&count)
assert.Equal(t, int64(0), count)
}
func TestDeleteCharacterSessionNotFound(t *testing.T) {
setupSessionTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: "nonexistent_session"}}
c.Request = httptest.NewRequest(http.MethodDelete, "/", nil)
DeleteCharacterSession(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestFinalizeCharacterCreationIncomplete(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
// Session is at step 1 (incomplete)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
FinalizeCharacterCreation(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "not complete")
}
func TestFinalizeCharacterCreationViaSteps(t *testing.T) {
setupSessionTestEnv(t)
sessionID := createTestSession(t)
// Progress through all steps
steps := []struct {
handler func(*gin.Context)
body map[string]interface{}
}{
{
UpdateCharacterBasicInfo,
map[string]interface{}{
"name": "Torin Test", "geschlecht": "male",
"rasse": "Mensch", "typ": "Kr",
"herkunft": "Norden", "stand": "Händler",
},
},
{
UpdateCharacterAttributes,
map[string]interface{}{
"st": 50, "gs": 40, "gw": 45,
"ko": 55, "in": 60, "zt": 30, "au": 35,
},
},
{
UpdateCharacterDerivedValues,
map[string]interface{}{
"pa": 10, "wk": 8, "lp_max": 20, "ap_max": 100,
"b_max": 10, "resistenz_koerper": 5, "resistenz_geist": 5,
"resistenz_bonus_koerper": 0, "resistenz_bonus_geist": 0,
"abwehr": 5, "abwehr_bonus": 0, "ausdauer_bonus": 0,
"angriffs_bonus": 0, "zaubern": 5, "zauber_bonus": 0,
"raufen": 5, "schadens_bonus": 0, "sg": 3, "gg": 0, "gp": 0,
},
},
{
UpdateCharacterSkills,
map[string]interface{}{
"skills": []map[string]interface{}{},
"spells": []map[string]interface{}{},
"skill_points": map[string]interface{}{},
},
},
}
for _, step := range steps {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
body, _ := json.Marshal(step.body)
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
step.handler(c)
require.Equal(t, http.StatusOK, w.Code, fmt.Sprintf("Step failed: %s", w.Body.String()))
}
// Now finalize
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", testUserIDSession)
c.Params = gin.Params{{Key: "sessionId", Value: sessionID}}
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
FinalizeCharacterCreation(c)
assert.Equal(t, http.StatusCreated, w.Code, "Finalize response: "+w.Body.String())
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp["character_id"])
}
+236
View File
@@ -0,0 +1,236 @@
package character
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupCRUDTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
err := models.MigrateStructure()
require.NoError(t, err)
gin.SetMode(gin.TestMode)
}
func TestCreateCharacter(t *testing.T) {
setupCRUDTestEnv(t)
char := map[string]interface{}{
"name": "Test Krieger",
"rasse": "Mensch",
"typ": "Kr",
"userID": 4,
}
body, _ := json.Marshal(char)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Request = httptest.NewRequest(http.MethodPost, "/api/characters", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
CreateCharacter(c)
assert.Equal(t, http.StatusCreated, w.Code)
var resp models.Char
err := json.Unmarshal(w.Body.Bytes(), &resp)
assert.NoError(t, err)
assert.Equal(t, "Test Krieger", resp.Name)
}
func TestCreateCharacterInvalidJSON(t *testing.T) {
setupCRUDTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Request = httptest.NewRequest(http.MethodPost, "/api/characters", bytes.NewBufferString("invalid json"))
c.Request.Header.Set("Content-Type", "application/json")
CreateCharacter(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestGetCharacter(t *testing.T) {
setupCRUDTestEnv(t)
// Create a character to retrieve
char := &models.Char{
BamortBase: models.BamortBase{Name: "Fanjo Test"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
GetCharacter(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp models.FeChar
err := json.Unmarshal(w.Body.Bytes(), &resp)
assert.NoError(t, err)
assert.Equal(t, "Fanjo Test", resp.Name)
}
func TestGetCharacterNotFound(t *testing.T) {
setupCRUDTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "99999"}}
GetCharacter(c)
assert.Equal(t, http.StatusInternalServerError, w.Code)
}
func TestUpdateCharacter(t *testing.T) {
setupCRUDTestEnv(t)
// Create a character to update
char := &models.Char{
BamortBase: models.BamortBase{Name: "Original Name"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
updateData := map[string]interface{}{
"name": "Updated Name",
"rasse": "Elb",
"typ": "Kr",
"userID": 4,
}
body, _ := json.Marshal(updateData)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/api/characters/"+fmt.Sprintf("%d", char.ID), bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacter(c)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestUpdateCharacterNotOwner(t *testing.T) {
setupCRUDTestEnv(t)
// Create a character owned by user 4
char := &models.Char{
BamortBase: models.BamortBase{Name: "Other User Char"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
updateData := map[string]interface{}{"name": "Hacked Name"}
body, _ := json.Marshal(updateData)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99)) // Different user
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/api/characters/"+fmt.Sprintf("%d", char.ID), bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacter(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestDeleteCharacter(t *testing.T) {
setupCRUDTestEnv(t)
// Create a character to delete
char := &models.Char{
BamortBase: models.BamortBase{Name: "To Delete"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
DeleteCharacter(c)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "deleted successfully")
// Verify character is actually deleted
var count int64
database.DB.Model(&models.Char{}).Where("id = ?", char.ID).Count(&count)
assert.Equal(t, int64(0), count)
}
func TestDeleteCharacterNotOwner(t *testing.T) {
setupCRUDTestEnv(t)
char := &models.Char{
BamortBase: models.BamortBase{Name: "Protected"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
DeleteCharacter(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestDeleteCharacterNotFound(t *testing.T) {
setupCRUDTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "99999"}}
DeleteCharacter(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
@@ -0,0 +1,270 @@
package character
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupExpWealthTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
err := models.MigrateStructure()
require.NoError(t, err)
gin.SetMode(gin.TestMode)
}
func createTestCharWithEP(t *testing.T, ep int, gold int) *models.Char {
t.Helper()
char := &models.Char{
BamortBase: models.BamortBase{Name: "Test Char EP"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
erfahrung := &models.Erfahrungsschatz{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{},
CharacterID: char.ID,
UserID: 4,
},
EP: ep,
}
require.NoError(t, database.DB.Create(erfahrung).Error)
vermoegen := &models.Vermoegen{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{},
CharacterID: char.ID,
UserID: 4,
},
Goldstuecke: gold,
}
require.NoError(t, database.DB.Create(vermoegen).Error)
return char
}
func TestGetCharacterExperienceAndWealth(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 500, 100)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
GetCharacterExperienceAndWealth(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(500), resp["experience_points"])
assert.NotNil(t, resp["wealth"])
}
func TestGetCharacterExperienceAndWealthNotFound(t *testing.T) {
setupExpWealthTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "99999"}}
GetCharacterExperienceAndWealth(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestUpdateCharacterExperience(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 300, 0)
reqBody := map[string]interface{}{
"experience_points": 400,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/api/characters/"+fmt.Sprintf("%d", char.ID)+"/experience", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterExperience(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(400), resp["experience_points"])
}
func TestUpdateCharacterExperienceNotOwner(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 300, 0)
reqBody := map[string]interface{}{"experience_points": 100}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterExperience(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestUpdateCharacterExperienceInvalidBody(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 300, 0)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBufferString("bad json"))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterExperience(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestUpdateCharacterWealth(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 0, 50)
gold := 200
silver := 30
reqBody := map[string]interface{}{
"goldstücke": gold,
"silberstücke": silver,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterWealth(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, "Wealth updated successfully", resp["message"])
}
func TestUpdateCharacterWealthNotOwner(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 0, 50)
gold := 999
reqBody := map[string]interface{}{"goldstücke": gold}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterWealth(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestGetCharacterAuditLog(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 100, 0)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/"+fmt.Sprintf("%d", char.ID)+"/audit-log", nil)
GetCharacterAuditLog(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, float64(char.ID), resp["character_id"])
assert.NotNil(t, resp["entries"])
}
func TestGetCharacterAuditLogInvalidID(t *testing.T) {
setupExpWealthTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "notanumber"}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetCharacterAuditLog(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestGetAuditLogStats(t *testing.T) {
setupExpWealthTestEnv(t)
char := createTestCharWithEP(t, 100, 0)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/"+fmt.Sprintf("%d", char.ID)+"/audit-log/stats", nil)
GetAuditLogStats(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
stats, ok := resp["stats"].(map[string]interface{})
require.True(t, ok, "Response should contain 'stats' key")
assert.NotNil(t, stats["total_changes"])
assert.NotNil(t, stats["by_field"])
assert.NotNil(t, stats["by_reason"])
}
@@ -0,0 +1,256 @@
package character
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupPPTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
require.NoError(t, models.MigrateStructure())
gin.SetMode(gin.TestMode)
}
func createCharWithSkillPP(t *testing.T, skillName string, ppAmount int) *models.Char {
t.Helper()
char := &models.Char{
BamortBase: models.BamortBase{Name: "PP Test Char"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
skill := &models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{Name: skillName},
CharacterID: char.ID,
UserID: 4,
},
Fertigkeitswert: 5,
Pp: ppAmount,
Improvable: true,
}
require.NoError(t, database.DB.Create(skill).Error)
return char
}
func TestGetPracticePoints(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 3)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetPracticePoints(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp []PracticePointResponse
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
require.Len(t, resp, 1)
assert.Equal(t, "Athletik", resp[0].SkillName)
assert.Equal(t, 3, resp[0].Amount)
}
func TestGetPracticePointsEmpty(t *testing.T) {
setupPPTestEnv(t)
// A character with zero PP skills
char := createCharWithSkillPP(t, "Athletik", 0)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetPracticePoints(c)
assert.Equal(t, http.StatusOK, w.Code)
// Should return null or empty
body := w.Body.String()
assert.True(t, body == "null" || body == "[]", "Empty PP list should return null or empty array, got: "+body)
}
func TestGetPracticePointsCharNotFound(t *testing.T) {
setupPPTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "99999"}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetPracticePoints(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestUpdatePracticePoints(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 1)
updates := []PracticePointResponse{
{SkillName: "Athletik", Amount: 5},
}
body, _ := json.Marshal(updates)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdatePracticePoints(c)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestUpdatePracticePointsNotOwner(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 1)
updates := []PracticePointResponse{{SkillName: "Athletik", Amount: 5}}
body, _ := json.Marshal(updates)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdatePracticePoints(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestAddPracticePoint(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 0)
reqBody := map[string]interface{}{
"skill_name": "Athletik",
"amount": 1,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
AddPracticePoint(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp PracticePointActionResponse
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.True(t, resp.Success)
assert.Equal(t, "Athletik", resp.TargetSkill)
}
func TestAddPracticePointSkillNotFound(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 0)
reqBody := map[string]interface{}{
"skill_name": "Zauberei",
"amount": 1,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
AddPracticePoint(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestUsePracticePoint(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 3)
reqBody := map[string]interface{}{
"skill_name": "Athletik",
"amount": 1,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UsePracticePoint(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp PracticePointActionResponse
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.True(t, resp.Success)
}
func TestUsePracticePointInsufficientPP(t *testing.T) {
setupPPTestEnv(t)
char := createCharWithSkillPP(t, "Athletik", 0)
reqBody := map[string]interface{}{
"skill_name": "Athletik",
"amount": 5,
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UsePracticePoint(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
@@ -0,0 +1,179 @@
package character
import (
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupRefDataTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
require.NoError(t, models.MigrateStructure())
gin.SetMode(gin.TestMode)
}
func TestGetRaces(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/races", nil)
GetRaces(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
races, ok := resp["races"]
assert.True(t, ok, "Response should contain 'races' key")
assert.NotEmpty(t, races)
}
func TestGetCharacterClasses(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/classes", nil)
GetCharacterClasses(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp)
}
func TestGetOrigins(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/origins", nil)
GetOrigins(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp)
}
func TestGetSkillCategoriesHandlerStatic(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodGet, "/api/characters/skill-categories", nil)
GetSkillCategoriesHandlerStatic(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
categories, ok := resp["skill_categories"]
assert.True(t, ok, "Response should contain 'skill_categories' key")
catMap, ok := categories.(map[string]interface{})
assert.True(t, ok)
assert.Contains(t, catMap, "Alltag")
}
func TestGetRewardTypesStaticImprove(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Params = gin.Params{{Key: "id", Value: "1"}}
req := httptest.NewRequest(http.MethodGet, "/api/characters/reward-types?learning_type=improve&skill_name=Athletik&skill_type=skill", nil)
c.Request = req
GetRewardTypesStatic(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp["reward_types"])
assert.Equal(t, "improve", resp["learning_type"])
}
func TestGetRewardTypesStaticLearn(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Params = gin.Params{{Key: "id", Value: "1"}}
req := httptest.NewRequest(http.MethodGet, "/api/characters/reward-types?learning_type=learn&skill_name=Athletik", nil)
c.Request = req
GetRewardTypesStatic(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
rewardTypes, ok := resp["reward_types"].([]interface{})
assert.True(t, ok)
assert.GreaterOrEqual(t, len(rewardTypes), 1)
}
func TestGetRewardTypesStaticSpell(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Params = gin.Params{{Key: "id", Value: "1"}}
req := httptest.NewRequest(http.MethodGet, "/api/characters/reward-types?learning_type=spell", nil)
c.Request = req
GetRewardTypesStatic(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, "spell", resp["learning_type"])
}
func TestGetSpellDetailsNotFound(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
req := httptest.NewRequest(http.MethodGet, "/api/characters/spell-details?name=NonExistentSpellXYZ", nil)
c.Request = req
GetSpellDetails(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestGetSpellDetailsMissingName(t *testing.T) {
setupRefDataTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
req := httptest.NewRequest(http.MethodGet, "/api/characters/spell-details", nil)
c.Request = req
GetSpellDetails(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
+197
View File
@@ -0,0 +1,197 @@
package character
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupSharesTestEnv(t *testing.T) {
t.Helper()
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
t.Cleanup(func() {
if original != "" {
os.Setenv("ENVIRONMENT", original)
} else {
os.Unsetenv("ENVIRONMENT")
}
})
database.SetupTestDB(true, true)
t.Cleanup(database.ResetTestDB)
require.NoError(t, models.MigrateStructure())
gin.SetMode(gin.TestMode)
}
func createTestCharForShares(t *testing.T) *models.Char {
t.Helper()
char := &models.Char{
BamortBase: models.BamortBase{Name: "Share Test Char"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
return char
}
func TestGetCharacterSharesEmpty(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetCharacterShares(c)
assert.Equal(t, http.StatusOK, w.Code)
body := w.Body.String()
assert.True(t, body == "null" || body == "[]", "Empty shares should return null or []")
}
func TestGetCharacterSharesNotOwner(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetCharacterShares(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestGetCharacterSharesNotFound(t *testing.T) {
setupSharesTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: "99999"}}
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
GetCharacterShares(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestUpdateCharacterShares(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
// Share with user 1 (different from owner user 4)
reqBody := map[string]interface{}{
"user_ids": []uint{1},
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterShares(c)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "updated successfully")
// Verify the share was created
var count int64
database.DB.Model(&models.CharShare{}).Where("character_id = ? AND user_id = ?", char.ID, 1).Count(&count)
assert.Equal(t, int64(1), count)
}
func TestUpdateCharacterSharesClearAll(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
// First add a share
share := &models.CharShare{
CharacterID: char.ID,
UserID: 1,
Permission: "read",
}
require.NoError(t, database.DB.Create(share).Error)
// Now clear all shares
reqBody := map[string]interface{}{
"user_ids": []uint{},
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterShares(c)
assert.Equal(t, http.StatusOK, w.Code)
// Verify all shares removed
var count int64
database.DB.Model(&models.CharShare{}).Where("character_id = ?", char.ID).Count(&count)
assert.Equal(t, int64(0), count)
}
func TestUpdateCharacterSharesNotOwner(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
reqBody := map[string]interface{}{"user_ids": []uint{1}}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterShares(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestUpdateCharacterSharesInvalidBody(t *testing.T) {
setupSharesTestEnv(t)
char := createTestCharForShares(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBufferString("invalid json"))
c.Request.Header.Set("Content-Type", "application/json")
UpdateCharacterShares(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
+273
View File
@@ -0,0 +1,273 @@
package equipment
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"bamort/database"
"bamort/models"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupWaffeTestEnv(t *testing.T) {
t.Helper()
database.SetupTestDB(true)
t.Cleanup(database.ResetTestDB)
gin.SetMode(gin.TestMode)
}
func newWaffe(characterID, userID uint, name string) models.EqWaffe {
return models.EqWaffe{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{Name: name},
CharacterID: characterID,
UserID: userID,
},
Beschreibung: "Test Waffe",
Gewicht: 1.5,
Wert: 80.0,
Anb: 5,
Abwb: 3,
}
}
func createTestCharForWaffe(t *testing.T) *models.Char {
t.Helper()
require.NoError(t, models.MigrateStructure())
char := &models.Char{
BamortBase: models.BamortBase{Name: "Waffe Owner"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
return char
}
func TestCreateWaffe(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
waffe := newWaffe(char.ID, 4, "Test Schwert")
body, _ := json.Marshal(waffe)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Request = httptest.NewRequest(http.MethodPost, "/api/weapons", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
CreateWaffe(c)
assert.Equal(t, http.StatusCreated, w.Code)
var resp models.EqWaffe
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, "Test Schwert", resp.Name)
assert.Equal(t, char.ID, resp.CharacterID)
}
func TestCreateWaffeNotOwner(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
waffe := newWaffe(char.ID, 4, "Stolen Sword")
body, _ := json.Marshal(waffe)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99)) // Different user
c.Request = httptest.NewRequest(http.MethodPost, "/api/weapons", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
CreateWaffe(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestCreateWaffeInvalidJSON(t *testing.T) {
setupWaffeTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Request = httptest.NewRequest(http.MethodPost, "/api/weapons", bytes.NewBufferString("bad json"))
c.Request.Header.Set("Content-Type", "application/json")
CreateWaffe(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestListWaffen(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
// Create test waffe
waffe := newWaffe(char.ID, 4, "List Schwert")
require.NoError(t, database.DB.Create(&waffe).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "character_id", Value: fmt.Sprintf("%d", char.ID)}}
c.Request = httptest.NewRequest(http.MethodGet, "/api/weapons/character/"+fmt.Sprintf("%d", char.ID), nil)
ListWaffen(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp []models.EqWaffe
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Len(t, resp, 1)
assert.Equal(t, "List Schwert", resp[0].Name)
}
func TestListWaffenEmpty(t *testing.T) {
setupWaffeTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "character_id", Value: "99999"}}
c.Request = httptest.NewRequest(http.MethodGet, "/api/weapons/character/99999", nil)
ListWaffen(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp []models.EqWaffe
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Empty(t, resp)
}
func TestUpdateWaffe(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
// Create test waffe
waffe := newWaffe(char.ID, 4, "Old Name")
require.NoError(t, database.DB.Create(&waffe).Error)
// Update it
waffe.Name = "New Name"
body, _ := json.Marshal(waffe)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "waffe_id", Value: fmt.Sprintf("%d", waffe.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/api/weapons/"+fmt.Sprintf("%d", waffe.ID), bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateWaffe(c)
assert.Equal(t, http.StatusOK, w.Code)
var resp models.EqWaffe
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(t, "New Name", resp.Name)
}
func TestUpdateWaffeNotOwner(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
waffe := newWaffe(char.ID, 4, "Protected Waffe")
require.NoError(t, database.DB.Create(&waffe).Error)
waffe.Name = "Hacked"
body, _ := json.Marshal(waffe)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "waffe_id", Value: fmt.Sprintf("%d", waffe.ID)}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBuffer(body))
c.Request.Header.Set("Content-Type", "application/json")
UpdateWaffe(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestUpdateWaffeNotFound(t *testing.T) {
setupWaffeTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "waffe_id", Value: "99999"}}
c.Request = httptest.NewRequest(http.MethodPut, "/", bytes.NewBufferString("{}"))
c.Request.Header.Set("Content-Type", "application/json")
UpdateWaffe(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestDeleteWaffe(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
waffe := newWaffe(char.ID, 4, "Delete Me Waffe")
require.NoError(t, database.DB.Create(&waffe).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "waffe_id", Value: fmt.Sprintf("%d", waffe.ID)}}
c.Request = httptest.NewRequest(http.MethodDelete, "/", nil)
DeleteWaffe(c)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "deleted successfully")
// Verify deletion
var count int64
database.DB.Model(&models.EqWaffe{}).Where("id = ?", waffe.ID).Count(&count)
assert.Equal(t, int64(0), count)
}
func TestDeleteWaffeNotOwner(t *testing.T) {
setupWaffeTestEnv(t)
char := createTestCharForWaffe(t)
waffe := newWaffe(char.ID, 4, "Protected Delete Waffe")
require.NoError(t, database.DB.Create(&waffe).Error)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(99))
c.Params = gin.Params{{Key: "waffe_id", Value: fmt.Sprintf("%d", waffe.ID)}}
c.Request = httptest.NewRequest(http.MethodDelete, "/", nil)
DeleteWaffe(c)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestDeleteWaffeNotFound(t *testing.T) {
setupWaffeTestEnv(t)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("userID", uint(4))
c.Params = gin.Params{{Key: "waffe_id", Value: "99999"}}
c.Request = httptest.NewRequest(http.MethodDelete, "/", nil)
DeleteWaffe(c)
assert.Equal(t, http.StatusNotFound, w.Code)
}
+156
View File
@@ -0,0 +1,156 @@
package importer
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"bamort/database"
"bamort/models"
"bamort/router"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupExportTestEnv(t *testing.T) *models.Char {
t.Helper()
database.SetupTestDB(true)
t.Cleanup(database.ResetTestDB)
err := models.MigrateStructure()
require.NoError(t, err)
// Create test character
char := &models.Char{
BamortBase: models.BamortBase{Name: "Export Test Char"},
UserID: 4,
Rasse: "Mensch",
Typ: "Kr",
}
require.NoError(t, database.DB.Create(char).Error)
return char
}
func setupExportRouter() *gin.Engine {
r := gin.Default()
router.SetupGin(r)
protected := router.BaseRouterGrp(r)
RegisterRoutes(protected)
return r
}
func TestExportCharacterVTTHandler(t *testing.T) {
char := setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/vtt/"+uintToStr(char.ID), nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotNil(t, resp)
}
func TestExportCharacterVTTHandlerNotFound(t *testing.T) {
setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/vtt/99999", nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestExportCharacterVTTFileHandler(t *testing.T) {
char := setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/vtt/"+uintToStr(char.ID)+"/file", nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
contentDisposition := w.Header().Get("Content-Disposition")
assert.Contains(t, contentDisposition, "attachment")
}
func TestExportCharacterVTTFileHandlerNotFound(t *testing.T) {
setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/vtt/99999/file", nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestExportCharacterCSVHandler(t *testing.T) {
char := setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/csv/"+uintToStr(char.ID), nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
contentDisposition := w.Header().Get("Content-Disposition")
assert.Contains(t, contentDisposition, "attachment")
}
func TestExportCharacterCSVHandlerNotFound(t *testing.T) {
setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/csv/99999", nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func TestExportSpellsCSVHandler(t *testing.T) {
setupExportTestEnv(t)
r := setupExportRouter()
token := getAuthToken()
req := httptest.NewRequest(http.MethodGet, "/api/importer/export/spells/csv", nil)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
// Should be a file attachment
contentDisposition := w.Header().Get("Content-Disposition")
assert.Contains(t, contentDisposition, "attachment")
}
func uintToStr(id uint) string {
return fmt.Sprintf("%d", id)
}