Files
bamort/backend/bmrt/character/skills_creation_test.go
T
Bardioc26 042a1d4773 Learncost frontend (#42)
* introduced central package  registry by package init function
* dynamic registration of routes, model, migrations and initializers.
* setting a docker compose project name to prevent shutdown of other containers with the same (composer)name
* ai documentation
* app template
* 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.
* adopting agent instructions for a more consistent coding style
* added desired module layout and debugging information
* Fix All Failing tests All failing tests are fixed now that makes the refactoring more easy since all tests must pass
* restored routes for maintenance
* added common translations
* added new tests for API Endpoint
* Merge branch 'separate_business_logic'
* added lern and skill improvement cost editing
* Set Docker image tag when building to prevent rebuild when nothing has changed
* add and remove PP for Weaponskill fixed
* add and remove PP for same named skills fixed
* add new task
2026-05-01 18:15:31 +02:00

321 lines
9.1 KiB
Go

package character
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"bamort/database"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
// TestGetAllSkillsWithLearningCosts tests the helper function directly
func TestGetAllSkillsWithLearningCosts(t *testing.T) {
// Setup test database
database.SetupTestDB(true, true)
defer database.ResetTestDB()
tests := []struct {
name string
characterClass string
expectError bool
expectSkills bool
}{
{
name: "ValidCharacterClassAs",
characterClass: "As",
expectError: false,
expectSkills: true,
},
{
name: "ValidCharacterClassMagier",
characterClass: "Magier",
expectError: false,
expectSkills: true,
},
{
name: "EmptyCharacterClass",
characterClass: "",
expectError: false,
expectSkills: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
skillsByCategory, err := GetAllSkillsWithLearningCosts(tt.characterClass)
if tt.expectError {
assert.Error(t, err)
return
}
assert.NoError(t, err, "GetAllSkillsWithLearningCosts should not return error")
if tt.expectSkills {
assert.Greater(t, len(skillsByCategory), 0, "Should return at least some skill categories")
// Verify structure of returned data
for categoryName, skills := range skillsByCategory {
assert.NotEmpty(t, categoryName, "Category name should not be empty")
skillsArray := skills
assert.Greater(t, len(skillsArray), 0, "Category should have at least one skill")
// Check first skill structure
if len(skillsArray) > 0 {
skill := skillsArray[0]
assert.Contains(t, skill, "name", "Skill should have name")
assert.Contains(t, skill, "learnCost", "Skill should have learnCost")
name, nameOk := skill["name"].(string)
assert.True(t, nameOk, "Skill name should be string")
assert.NotEmpty(t, name, "Skill name should not be empty")
learnCost, costOk := skill["learnCost"].(int)
assert.True(t, costOk, "Learn cost should be int")
assert.Greater(t, learnCost, 0, "Learn cost should be positive")
assert.LessOrEqual(t, learnCost, 500, "Learn cost should be reasonable")
}
}
t.Logf("Character class %s: Found %d skill categories", tt.characterClass, len(skillsByCategory))
// Log some sample skills for verification
count := 0
for categoryName, skills := range skillsByCategory {
skillsArray := skills
for _, skill := range skillsArray {
skillMap := skill
t.Logf(" %s -> %s: %v LP", categoryName, skillMap["name"], skillMap["learnCost"])
count++
if count >= 5 { // Only log first 5 skills
break
}
}
if count >= 5 {
break
}
}
}
})
}
}
// TestGetAvailableSkillsForCreationHandler tests the HTTP handler directly
func TestHandlerGetAvailableSkillsForCreation(t *testing.T) {
// Setup test database
database.SetupTestDB(true, true)
defer database.ResetTestDB()
tests := []struct {
name string
requestBody interface{}
expectStatus int
expectError bool
validateFunc func(t *testing.T, response map[string]interface{})
}{
{
name: "ValidMagierRequest",
requestBody: gin.H{
"characterClass": "Magier",
},
expectStatus: http.StatusOK,
expectError: false,
validateFunc: func(t *testing.T, response map[string]interface{}) {
assert.Contains(t, response, "skills_by_category")
skillsByCategory := response["skills_by_category"].(map[string]interface{})
assert.Greater(t, len(skillsByCategory), 0, "Should have skill categories")
},
},
{
name: "ValidAsRequest",
requestBody: gin.H{
"characterClass": "As",
},
expectStatus: http.StatusOK,
expectError: false,
validateFunc: func(t *testing.T, response map[string]interface{}) {
assert.Contains(t, response, "skills_by_category")
skillsByCategory := response["skills_by_category"].(map[string]interface{})
assert.Greater(t, len(skillsByCategory), 0, "Should have skill categories")
// Verify that skills have reasonable learning costs
hasReasonableCosts := false
for _, skills := range skillsByCategory {
if skillsList, ok := skills.([]interface{}); ok {
for _, skill := range skillsList {
if skillMap, ok := skill.(map[string]interface{}); ok {
if learnCost, exists := skillMap["leCost"]; exists {
if cost, ok := learnCost.(float64); ok {
assert.Greater(t, cost, 0.0, "Learn cost should be positive")
assert.LessOrEqual(t, cost, 500.0, "Learn cost should be reasonable")
hasReasonableCosts = true
}
}
}
}
}
}
assert.True(t, hasReasonableCosts, "Should find skills with reasonable costs")
},
},
{
name: "EmptyCharacterClass",
requestBody: gin.H{
"characterClass": "",
},
expectStatus: http.StatusBadRequest,
expectError: true,
validateFunc: func(t *testing.T, response map[string]interface{}) {
assert.Contains(t, response, "error")
},
},
{
name: "MissingCharacterClass",
requestBody: gin.H{
"someOtherField": "value",
},
expectStatus: http.StatusBadRequest,
expectError: true,
validateFunc: func(t *testing.T, response map[string]interface{}) {
assert.Contains(t, response, "error")
},
},
{
name: "InvalidJSON",
requestBody: "invalid json string",
expectStatus: http.StatusBadRequest,
expectError: true,
validateFunc: func(t *testing.T, response map[string]interface{}) {
assert.Contains(t, response, "error")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Prepare request body
var requestBody []byte
var err error
if str, ok := tt.requestBody.(string); ok {
requestBody = []byte(str)
} else {
requestBody, err = json.Marshal(tt.requestBody)
assert.NoError(t, err)
}
// Create HTTP request
req, err := http.NewRequest("POST", "/api/characters/available-skills-creation", bytes.NewBuffer(requestBody))
assert.NoError(t, err)
req.Header.Set("Content-Type", "application/json")
// Create response recorder
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
// Call the handler
GetAvailableSkillsForCreation(c)
// Verify response status
assert.Equal(t, tt.expectStatus, w.Code, "HTTP status should match expected")
// Parse response body
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err, "Response should be valid JSON")
// Run custom validation if provided
if tt.validateFunc != nil {
tt.validateFunc(t, response)
}
// Log response for debugging
if !tt.expectError {
t.Logf("Response for %s: %v", tt.name, response)
}
})
}
}
// BenchmarkGetAllSkillsWithLearningCosts benchmarks the skills loading function
func BenchmarkGetAllSkillsWithLearningCosts(b *testing.B) {
// Setup test database
database.SetupTestDB(true, true)
defer database.ResetTestDB()
characterClass := "Magier"
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := GetAllSkillsWithLearningCosts(characterClass)
if err != nil {
b.Fatalf("GetAllSkillsWithLearningCosts failed: %v", err)
}
}
}
// TestSkillsCreationEndpointIntegration tests the full integration
func TestSkillsCreationEndpointIntegration(t *testing.T) {
// Setup test database
database.SetupTestDB(true, true)
defer database.ResetTestDB()
// Test different character classes
characterClasses := []string{"As", "Magier", "Krieger", "Spitzbube"}
for _, class := range characterClasses {
t.Run("CharacterClass_"+class, func(t *testing.T) {
// Create request
requestData := gin.H{
"characterClass": class,
}
requestBody, err := json.Marshal(requestData)
assert.NoError(t, err)
// Create HTTP request
req, err := http.NewRequest("POST", "/api/characters/available-skills-creation", bytes.NewBuffer(requestBody))
assert.NoError(t, err)
req.Header.Set("Content-Type", "application/json")
// Create response recorder
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
// Call the handler
GetAvailableSkillsForCreation(c)
// Verify response
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
// Verify structure
assert.Contains(t, response, "skills_by_category")
skillsByCategory := response["skills_by_category"].(map[string]interface{})
assert.Greater(t, len(skillsByCategory), 0, "Should have at least one skill category")
// Count total skills available
totalSkills := 0
for categoryName, skills := range skillsByCategory {
if skillsList, ok := skills.([]interface{}); ok {
totalSkills += len(skillsList)
t.Logf("Category %s has %d skills", categoryName, len(skillsList))
}
}
assert.Greater(t, totalSkills, 0, "Should have at least some skills available")
t.Logf("Character class %s: %d total skills in %d categories", class, totalSkills, len(skillsByCategory))
})
}
}