2025-08-06 23:05:59 +02:00
|
|
|
package character
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"bamort/database"
|
2026-05-01 18:15:31 +02:00
|
|
|
"bamort/bmrt/gsmaster"
|
|
|
|
|
"bamort/bmrt/models"
|
2025-08-06 23:05:59 +02:00
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestGetAvailableSpellsNewSystem(t *testing.T) {
|
|
|
|
|
// Setup test database with real data
|
|
|
|
|
database.SetupTestDB(true, true)
|
|
|
|
|
defer database.ResetTestDB()
|
|
|
|
|
|
|
|
|
|
// Setup Gin in test mode
|
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
|
|
|
|
|
|
t.Run("Get available spells for character ID 20", func(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
// Test Request wie im Frontend
|
|
|
|
|
request := gsmaster.LernCostRequest{
|
|
|
|
|
CharId: 18,
|
|
|
|
|
Type: "spell",
|
|
|
|
|
Action: "learn",
|
|
|
|
|
UsePP: 0,
|
|
|
|
|
UseGold: 0,
|
|
|
|
|
Reward: stringPtr("default"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert request to JSON
|
|
|
|
|
requestJSON, err := json.Marshal(request)
|
|
|
|
|
assert.NoError(t, err, "Should marshal request")
|
|
|
|
|
|
|
|
|
|
// Create HTTP request
|
|
|
|
|
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(requestJSON))
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
// Create response recorder
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
// Create Gin context
|
|
|
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
|
c.Request = req
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Test: Get available spells for character ID 20\n")
|
|
|
|
|
fmt.Printf("Request: %s\n", string(requestJSON))
|
|
|
|
|
|
|
|
|
|
// Call the handler function
|
|
|
|
|
GetAvailableSpellsNewSystem(c)
|
|
|
|
|
|
|
|
|
|
// Print the response for debugging
|
|
|
|
|
fmt.Printf("Response Status: %d\n", w.Code)
|
|
|
|
|
fmt.Printf("Response Body: %s\n", w.Body.String())
|
|
|
|
|
|
|
|
|
|
// Assert response status
|
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code, "Status code should be 200 OK")
|
|
|
|
|
|
|
|
|
|
// Parse response
|
|
|
|
|
var response map[string]interface{}
|
|
|
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
|
|
|
assert.NoError(t, err, "Response should be valid JSON")
|
|
|
|
|
|
|
|
|
|
// Check response structure
|
|
|
|
|
assert.Contains(t, response, "spells_by_school", "Response should contain spells_by_school field")
|
|
|
|
|
|
|
|
|
|
// Check if spells_by_school is an object
|
|
|
|
|
spellsBySchool, ok := response["spells_by_school"].(map[string]interface{})
|
|
|
|
|
assert.True(t, ok, "spells_by_school should be an object")
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Found %d spell schools\n", len(spellsBySchool))
|
|
|
|
|
|
|
|
|
|
// Check each school
|
|
|
|
|
totalSpells := 0
|
|
|
|
|
for schoolName, schoolSpells := range spellsBySchool {
|
|
|
|
|
fmt.Printf("School: %s\n", schoolName)
|
|
|
|
|
|
|
|
|
|
spells, ok := schoolSpells.([]interface{})
|
|
|
|
|
assert.True(t, ok, fmt.Sprintf("School %s should contain an array of spells", schoolName))
|
|
|
|
|
|
|
|
|
|
totalSpells += len(spells)
|
|
|
|
|
fmt.Printf(" Spells in school: %d\n", len(spells))
|
|
|
|
|
|
|
|
|
|
// Check structure of first spell in school if exists
|
|
|
|
|
if len(spells) > 0 {
|
|
|
|
|
firstSpell, ok := spells[0].(map[string]interface{})
|
|
|
|
|
assert.True(t, ok, "First spell should be an object")
|
|
|
|
|
|
|
|
|
|
// Check required fields
|
|
|
|
|
assert.Contains(t, firstSpell, "name", "Spell should have name field")
|
|
|
|
|
assert.Contains(t, firstSpell, "level", "Spell should have level field")
|
|
|
|
|
assert.Contains(t, firstSpell, "epCost", "Spell should have epCost field")
|
|
|
|
|
assert.Contains(t, firstSpell, "goldCost", "Spell should have goldCost field")
|
|
|
|
|
|
|
|
|
|
spellName, ok := firstSpell["name"].(string)
|
|
|
|
|
assert.True(t, ok, "Spell name should be a string")
|
|
|
|
|
assert.NotEmpty(t, spellName, "Spell name should not be empty")
|
|
|
|
|
|
|
|
|
|
level, ok := firstSpell["level"].(float64)
|
|
|
|
|
assert.True(t, ok, "Spell level should be a number")
|
|
|
|
|
assert.GreaterOrEqual(t, level, float64(0), "Spell level should be at least 0")
|
|
|
|
|
|
|
|
|
|
epCost, ok := firstSpell["epCost"].(float64)
|
|
|
|
|
assert.True(t, ok, "EP cost should be a number")
|
|
|
|
|
assert.GreaterOrEqual(t, epCost, float64(0), "EP cost should be non-negative")
|
|
|
|
|
|
|
|
|
|
goldCost, ok := firstSpell["goldCost"].(float64)
|
|
|
|
|
assert.True(t, ok, "Gold cost should be a number")
|
|
|
|
|
assert.GreaterOrEqual(t, goldCost, float64(0), "Gold cost should be non-negative")
|
|
|
|
|
|
|
|
|
|
fmt.Printf(" Example spell: %s (Level %v, EP: %v, Gold: %v)\n",
|
|
|
|
|
spellName, level, epCost, goldCost)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Total spells found: %d\n", totalSpells)
|
|
|
|
|
assert.Greater(t, totalSpells, 0, "Should have at least some spells available")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Test with different reward types", func(t *testing.T) {
|
|
|
|
|
// Verwende existierenden Charakter
|
|
|
|
|
rewardTypes := []string{"default", "noGold", "halveep", "halveepnoGold"}
|
|
|
|
|
|
|
|
|
|
for _, rewardType := range rewardTypes {
|
|
|
|
|
t.Run(fmt.Sprintf("RewardType_%s", rewardType), func(t *testing.T) {
|
|
|
|
|
request := gsmaster.LernCostRequest{
|
|
|
|
|
CharId: 18,
|
|
|
|
|
Type: "spell",
|
|
|
|
|
Action: "learn",
|
|
|
|
|
UsePP: 0,
|
|
|
|
|
UseGold: 0,
|
|
|
|
|
Reward: stringPtr(rewardType),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestJSON, err := json.Marshal(request)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(requestJSON))
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
|
c.Request = req
|
|
|
|
|
|
|
|
|
|
GetAvailableSpellsNewSystem(c)
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Testing reward type: %s - Status: %d\n", rewardType, w.Code)
|
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code, fmt.Sprintf("Should work with reward type %s", rewardType))
|
|
|
|
|
|
|
|
|
|
var response map[string]interface{}
|
|
|
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
|
|
|
assert.NoError(t, err, "Response should be valid JSON")
|
|
|
|
|
assert.Contains(t, response, "spells_by_school", "Should contain spells_by_school")
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Test with invalid character ID", func(t *testing.T) {
|
|
|
|
|
request := gsmaster.LernCostRequest{
|
|
|
|
|
CharId: 99999, // Non-existent character
|
|
|
|
|
Type: "spell",
|
|
|
|
|
Action: "learn",
|
|
|
|
|
UsePP: 0,
|
|
|
|
|
UseGold: 0,
|
|
|
|
|
Reward: stringPtr("default"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestJSON, err := json.Marshal(request)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(requestJSON))
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
|
c.Request = req
|
|
|
|
|
|
|
|
|
|
GetAvailableSpellsNewSystem(c)
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Testing invalid character ID - Status: %d\n", w.Code)
|
|
|
|
|
// Der Handler verwendet nicht den "id" Parameter aus der URL, sondern CharId aus dem Request Body
|
|
|
|
|
// Daher wird kein 404 zurückgegeben, sondern ein leeres Ergebnis oder Fehler
|
|
|
|
|
assert.True(t, w.Code == http.StatusNotFound || w.Code == http.StatusOK,
|
|
|
|
|
"Should return 404 or 200 for non-existent character")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Test with invalid request format", func(t *testing.T) {
|
|
|
|
|
invalidJSON := []byte(`{"invalid": "request"}`)
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(invalidJSON))
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
|
c.Request = req
|
|
|
|
|
|
|
|
|
|
GetAvailableSpellsNewSystem(c)
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Testing invalid request format - Status: %d\n", w.Code)
|
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 for invalid request")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Test excluding already learned spells", func(t *testing.T) {
|
|
|
|
|
// Füge dem Charakter einen Zauber hinzu
|
|
|
|
|
learnedSpell := models.SkZauber{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Feuerball",
|
|
|
|
|
},
|
|
|
|
|
CharacterID: 20,
|
|
|
|
|
},
|
|
|
|
|
Beschreibung: "Ein mächtiger Feuerball",
|
|
|
|
|
Bonus: 5,
|
|
|
|
|
Quelle: "Test",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := database.DB.Create(&learnedSpell).Error
|
|
|
|
|
assert.NoError(t, err, "Should create learned spell")
|
|
|
|
|
|
|
|
|
|
request := gsmaster.LernCostRequest{
|
|
|
|
|
CharId: 18,
|
|
|
|
|
Type: "spell",
|
|
|
|
|
Action: "learn",
|
|
|
|
|
UsePP: 0,
|
|
|
|
|
UseGold: 0,
|
|
|
|
|
Reward: stringPtr("default"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestJSON, err := json.Marshal(request)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(requestJSON))
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
|
c.Request = req
|
|
|
|
|
|
|
|
|
|
GetAvailableSpellsNewSystem(c)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK")
|
|
|
|
|
|
|
|
|
|
var response map[string]interface{}
|
|
|
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
spellsBySchool := response["spells_by_school"].(map[string]interface{})
|
|
|
|
|
|
|
|
|
|
// Prüfe, dass "Feuerball" nicht in der Liste ist
|
|
|
|
|
foundFeuerball := false
|
|
|
|
|
for _, schoolSpells := range spellsBySchool {
|
|
|
|
|
spells := schoolSpells.([]interface{})
|
|
|
|
|
for _, spell := range spells {
|
|
|
|
|
spellObj := spell.(map[string]interface{})
|
|
|
|
|
if spellObj["name"].(string) == "Feuerball" {
|
|
|
|
|
foundFeuerball = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.False(t, foundFeuerball, "Already learned spell 'Feuerball' should not be in available spells")
|
|
|
|
|
fmt.Printf("Correctly excluded already learned spell 'Feuerball'\n")
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper function to create string pointer
|
|
|
|
|
func stringPtr(s string) *string {
|
|
|
|
|
return &s
|
|
|
|
|
}
|