New test TestCalculateSpellLearnCostNewSystem in chain of learning system

This commit is contained in:
2026-01-30 15:17:33 +01:00
parent 95a65afcbd
commit 7ef9b2f17a
8 changed files with 504 additions and 172 deletions
+24 -8
View File
@@ -69,13 +69,26 @@ type MultiLevelCostResponse struct {
// GetLernCostNewSystem verwendet das neue Datenbank-Lernkosten-System
// und produziert die gleichen Ergebnisse wie GetLernCost.
//
// Unterschiede zum alten System:
// - Verwendet Models aus models/model_learning_costs.go statt der hardkodierten learningCostsData
// - Daten werden aus der Datenbank gelesen (learning_* Tabellen)
// - Unterstützt die gleichen Belohnungen und Parameter wie das alte System
// - API ist vollständig kompatibel mit GetLernCost
// Wie es funktionert:
// - Für "learn" Aktion: Nur eine Berechnung, da Lernkosten einmalig sind
// - Für "improve" Aktion: Berechne für jedes Level von current+1 bis 18
// - Berücksichtigt Praxispunkte (PP) und Gold-für-EP Konvertierung
// - Wendet Belohnungen an (kostenloses Lernen, halbe EP, etc.)
// - Gibt eine Liste von Kosten pro Level zurück
// Schritt für Schritt:
// 1. Hole Charakter und Klassenabkürzung
// 2. Normalisiere Fertigkeits-/Zaubername
// 3. Initialisiere einzusetzende/verbleibende PP und Gold
// 4. Je nach Aktion:
// 4.1 "learn": Hole Lerninformationen und berechne Kosten
// 4.1.1 "spell": Hole Zauber-Lerninformationen und berechne Kosten
// 4.1.2 "skill": Hole Fertigkeits-Lerninformationen und berechne Kosten
// 4.2 "improve": Für jedes Level, hole Verbesserungsinformationen und berechne Kosten
// (nur Fertigkeiten, keine Zauber)
//
// Das neue System muss zuerst mit gsmaster.InitializeLearningCostsSystem() initialisiert werden.
// 5. Wende Belohnungen an
// 6. Wende PP und Gold-für-EP an
// 7. Sammle Ergebnisse und sende als JSON-Antwort
func GetLernCostNewSystem(c *gin.Context) {
// Request-Parameter abrufen
var request gsmaster.LernCostRequest
@@ -84,6 +97,7 @@ func GetLernCostNewSystem(c *gin.Context) {
return
}
// 1. Hole Charakter
charID := fmt.Sprintf("%d", request.CharId)
var character models.Char
if err := character.FirstID(charID); err != nil {
@@ -99,7 +113,7 @@ func GetLernCostNewSystem(c *gin.Context) {
characterClass = character.Typ
}
// Normalize skill/spell name (trim whitespace, proper case)
//2. Normalize skill/spell name (trim whitespace, proper case)
skillName := strings.TrimSpace(request.Name)
var response []gsmaster.SkillCostResultNew
@@ -108,7 +122,9 @@ func GetLernCostNewSystem(c *gin.Context) {
// Für "learn" Aktion: nur eine Berechnung, da Lernkosten einmalig sind
if request.Action == "learn" {
// 4.1 "learn": Hole Lerninformationen und berechne Kosten
if request.Type == "spell" {
// 4.1.1 "spell": Hole Zauber-Lerninformationen und berechne Kosten
// Spell learning logic
spellInfo, err := models.GetSpellLearningInfoNewSystem(skillName, characterClass)
if err != nil {
@@ -133,7 +149,7 @@ func GetLernCostNewSystem(c *gin.Context) {
response = append(response, levelResult)
} else {
// Skill learning logic
// 4.1.2 "skill": Hole Fertigkeits-Lerninformationen und berechne Kosten
skillInfo, err := models.GetSkillCategoryAndDifficultyNewSystem(skillName, characterClass)
if err != nil {
respondWithError(c, http.StatusBadRequest, fmt.Sprintf("Fertigkeit '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v", skillName, characterClass, err))
+149
View File
@@ -219,3 +219,152 @@ func TestGetLernCostEndpointNewSystem(t *testing.T) {
})
}
func TestCalculateSpellLearnCostNewSystem(t *testing.T) {
rewardHalve := "halveep"
tests := []struct {
name string
request gsmaster.LernCostRequest
spellInfo models.SpellLearningInfo
remainingPP int
remainingGold int
wantLE int
wantEP int
wantGold int
wantPPUsed int
wantGoldUsed int
wantRemainingPP int
wantRemainingGold int
}{
{
name: "applies PP before cost calculation",
request: gsmaster.LernCostRequest{Reward: nil, CharId: 15},
spellInfo: models.SpellLearningInfo{
SpellID: 47,
SpellName: "Scharfblick",
SpellLevel: 1,
LERequired: 1,
EPPerLE: 60,
SchoolName: "Verändern",
},
remainingPP: 1,
remainingGold: 0,
wantLE: 0,
wantEP: 00,
wantGold: 00,
wantPPUsed: 1,
wantGoldUsed: 0,
wantRemainingPP: 0,
wantRemainingGold: 0,
},
{
name: "halves EP via reward",
request: gsmaster.LernCostRequest{Reward: &rewardHalve, CharId: 22},
spellInfo: models.SpellLearningInfo{
SpellID: 1,
SpellName: "Angst",
SpellLevel: 2,
LERequired: 1,
EPPerLE: 60,
SchoolName: "Beherrschen",
},
remainingPP: 0,
remainingGold: 0,
wantLE: 1,
wantEP: 30, // 3 LE * 40 EP/LE -> 120, reward halves to 60
wantGold: 100,
wantPPUsed: 0,
wantGoldUsed: 0,
wantRemainingPP: 0,
wantRemainingGold: 0,
},
{
name: "Zaubersprung Hx uses gold up to available but below cap",
request: gsmaster.LernCostRequest{Reward: nil, CharId: 18},
spellInfo: models.SpellLearningInfo{
SpellID: 68,
SpellName: "Zaubersprung",
SpellLevel: 3,
LERequired: 2,
EPPerLE: 30,
SchoolName: "Beherrschen",
},
remainingPP: 0,
remainingGold: 50, // 5 EP replacement, below EP/2 cap (60)
wantLE: 2,
wantEP: 55,
wantGold: 200,
wantPPUsed: 0,
wantGoldUsed: 50,
wantRemainingPP: 0,
wantRemainingGold: 0,
},
{
name: "Zaubersprung Ma uses gold up to available but below cap",
request: gsmaster.LernCostRequest{Reward: nil, CharId: 22},
spellInfo: models.SpellLearningInfo{
SpellID: 68,
SpellName: "Zaubersprung",
SpellLevel: 3,
LERequired: 2,
EPPerLE: 60,
SchoolName: "Beherrschen",
},
remainingPP: 0,
remainingGold: 50, // 5 EP replacement, below EP/2 cap (60)
wantLE: 2,
wantEP: 115,
wantGold: 200,
wantPPUsed: 0,
wantGoldUsed: 50,
wantRemainingPP: 0,
wantRemainingGold: 0,
},
{
name: "caps gold conversion at half EP",
request: gsmaster.LernCostRequest{CharId: 22},
spellInfo: models.SpellLearningInfo{
SpellID: 68,
SpellName: "Zaubersprung",
SpellLevel: 3,
LERequired: 2,
EPPerLE: 60,
SchoolName: "Beherrschen",
},
remainingPP: 0,
remainingGold: 2000, // would allow 200 EP replacement but cap is EP/2 = 60
wantLE: 2,
wantEP: 60,
wantGold: 200,
wantPPUsed: 0,
wantGoldUsed: 600,
wantRemainingPP: 0,
wantRemainingGold: 1400,
},
}
for _, tc := range tests {
//tc := tc
t.Run(tc.name, func(t *testing.T) {
remainingPP := tc.remainingPP
remainingGold := tc.remainingGold
var result gsmaster.SkillCostResultNew
err := calculateSpellLearnCostNewSystem(&tc.request, &result, &remainingPP, &remainingGold, &tc.spellInfo)
assert.NoError(t, err)
assert.Equal(t, tc.spellInfo.SchoolName, result.Category)
assert.Equal(t, fmt.Sprintf("Stufe %d", tc.spellInfo.SpellLevel), result.Difficulty)
assert.Equal(t, tc.wantLE, result.LE)
assert.Equal(t, tc.wantEP, result.EP)
assert.Equal(t, tc.wantGold, result.GoldCost)
assert.Equal(t, tc.wantPPUsed, result.PPUsed)
assert.Equal(t, tc.wantGoldUsed, result.GoldUsed)
assert.Equal(t, tc.wantRemainingPP, remainingPP)
assert.Equal(t, tc.wantRemainingGold, remainingGold)
})
}
}
+3 -1
View File
@@ -355,15 +355,17 @@ type SkillCategoryOption struct {
LE int `json:"le"`
}
// ToDo: GameSystemId noch einbauen
func GetClassAbbreviationNewSystem(characterClass string) string {
// Try to find by code first (e.g., "Kr" -> "Kr")
var charClass models.CharacterClass
if err := charClass.FirstByName(characterClass); err == nil {
return charClass.Code
}
gs := GetGameSystem(1, "")
// Try to find by name (e.g., "Krieger" -> "Kr")
if err := database.DB.Where("name = ?", characterClass).First(&charClass).Error; err == nil {
if err := database.DB.Where("(game_system=? OR game_system_id=?) AND name = ?", characterClass, gs.ID, characterClass).First(&charClass).Error; err == nil {
return charClass.Code
}
return ""
+46 -109
View File
@@ -1,118 +1,55 @@
package gsmaster
//Diese Tests hier sind SCHROTT denn sie testen statisch erzeugt Strukturen und nicht die Abfrage aus der DB wie erhofft
/*
// Test for exported GetAvailableSkillCategories function
func TestGetAvailableSkillCategories(t *testing.T) {
testCases := []struct {
skillName string
expectedCount int
description string
checkFirst bool
firstCategory string
import (
"testing"
"bamort/database"
"bamort/models"
)
func TestGetClassAbbreviationNewSystem(t *testing.T) {
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
defaultGS := GetGameSystem(1, "")
source := models.Source{Code: "TST", Name: "Test Source", FullName: "Test Source", GameSystem: defaultGS.Name, GameSystemId: defaultGS.ID}
if err := database.DB.Create(&source).Error; err != nil {
t.Fatalf("failed to create source: %v", err)
}
defaultClass := models.CharacterClass{Code: "TC", Name: "Test Class", SourceID: source.ID, GameSystem: defaultGS.Name, GameSystemId: defaultGS.ID}
if err := database.DB.Create(&defaultClass).Error; err != nil {
t.Fatalf("failed to create default game system class: %v", err)
}
altGS := models.GameSystem{Code: "ALT", Name: "Alternate"}
if err := database.DB.Create(&altGS).Error; err != nil {
t.Fatalf("failed to create alternate game system: %v", err)
}
altClass := models.CharacterClass{Code: "AC", Name: "Alternate Class", SourceID: source.ID, GameSystem: altGS.Name, GameSystemId: altGS.ID}
if err := database.DB.Create(&altClass).Error; err != nil {
t.Fatalf("failed to create alternate game system class: %v", err)
}
tests := []struct {
name string
input string
expected string
}{
{"Menschenkenntnis", 2, "Menschenkenntnis should have two categories (Sozial, Unterwelt)", true, "Sozial"},
{"Stichwaffen", 1, "Stichwaffen should have one category", true, "Waffen"},
{"Geländelauf", 1, "Geländelauf should have one category", true, "Körper"},
{"NonExistentSkill", 1, "Unknown skill should have default category", true, "Alltag"},
{name: "returns code for existing class", input: defaultClass.Name, expected: defaultClass.Code},
{name: "returns empty for unknown class", input: "Unknown Class", expected: ""},
{name: "returns empty for class in other game system", input: altClass.Name, expected: ""},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
result := GetAvailableSkillCategories(tc.skillName)
assert.Equal(t, tc.expectedCount, len(result), tc.description)
if tc.checkFirst && len(result) > 0 {
assert.Equal(t, tc.firstCategory, result[0].Category,
fmt.Sprintf("First category for %s should be %s", tc.skillName, tc.firstCategory))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if result := GetClassAbbreviationNewSystem(tt.input); result != tt.expected {
t.Fatalf("GetClassAbbreviationNewSystem(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
// Test for exported GetDefaultCategory function
func TestGetDefaultCategory(t *testing.T) {
testCases := []struct {
skillName string
expectedCategory string
description string
}{
{"Menschenkenntnis", "Sozial", "Should return Sozial for Menschenkenntnis"},
{"Stichwaffen", "Waffen", "Should return Waffen for Stichwaffen"},
{"Geländelauf", "Körper", "Should return Körper for Geländelauf"},
{"Sprache", "Alltag", "Should return Alltag for Sprache"},
{"NonExistentSkill", "Alltag", "Should return default Alltag for unknown skill"},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
result := GetDefaultCategory(tc.skillName)
assert.Equal(t, tc.expectedCategory, result, tc.description)
})
}
}
// Test for exported GetDefaultDifficulty function
func TestGetDefaultDifficulty(t *testing.T) {
testCases := []struct {
skillName string
expectedDifficulty string
description string
}{
{"Menschenkenntnis", "schwer", "Should return schwer for Menschenkenntnis"},
{"Stichwaffen", "leicht", "Should return leicht for Stichwaffen"},
{"Geländelauf", "leicht", "Should return leicht for Geländelauf"},
{"Sprache", "normal", "Should return normal for Sprache"},
{"NonExistentSkill", "normal", "Should return default normal for unknown skill"},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
result := GetDefaultDifficulty(tc.skillName)
assert.Equal(t, tc.expectedDifficulty, result, tc.description)
})
}
}
func TestCalculateDetailedSkillLearningCostForHexer(t *testing.T) {
// Testfall, der direkt mit den exportierten Funktionen arbeitet
t.Run("Lernkosten für Menschenkenntnis als Hexer", func(t *testing.T) {
// Verwendung der exportierten Funktion CalculateDetailedSkillLearningCost
result, err := CalculateDetailedSkillLearningCost("Menschenkenntnis", "Hexer")
assert.NoError(t, err, "CalculateDetailedSkillLearningCost sollte keinen Fehler zurückgeben")
assert.NotNil(t, result, "Ergebnis sollte nicht nil sein")
fmt.Printf("Lernkosten für Menschenkenntnis als Hexer:\n")
fmt.Printf("Lerneinheiten (LE): %d\n", result.LE)
fmt.Printf("Erfahrungspunkte (EP): %d\n", result.Ep)
fmt.Printf("Geldkosten (GS): %d\n", result.Money)
// Test der erwarteten Werte basierend auf aktueller Implementierung
// Menschenkenntnis ist Sozial/schwer: 4 LE
// Hexer EP-Kosten für Sozial: 20 EP/TE
// Money-Kosten: 20 GS/LE
assert.Equal(t, 4, result.LE, "LE-Kosten für Menschenkenntnis (Sozial/schwer) sollten 4 sein")
assert.Equal(t, 80, result.Ep, "EP-Kosten sollten 80 sein (4 LE * 20 EP)")
assert.Equal(t, 80, result.Money, "Geldkosten sollten 80 GS sein (4 LE * 20 GS)")
})
t.Run("Verbesserungskosten für Menschenkenntnis als Hexer", func(t *testing.T) {
// Verwendung der exportierten Funktion CalculateDetailedSkillImprovementCost
currentLevel := 10
result, err := CalculateDetailedSkillImprovementCost("Menschenkenntnis", "Hexer", currentLevel)
assert.NoError(t, err, "CalculateDetailedSkillImprovementCost sollte keinen Fehler zurückgeben")
assert.NotNil(t, result, "Ergebnis sollte nicht nil sein")
fmt.Printf("\nVerbesserungskosten für Menschenkenntnis als Hexer (von %d auf %d):\n", currentLevel, currentLevel+1)
fmt.Printf("Zielstufe: %d\n", result.Stufe) // This appears to be the target level
fmt.Printf("Erfahrungspunkte (EP): %d\n", result.Ep)
fmt.Printf("Geldkosten (GS): %d\n", result.Money)
// Test der erwarteten Werte basierend auf aktueller Implementierung
// Result.Stufe appears to be target level (11), not training units needed
assert.Equal(t, 11, result.Stufe, "Zielstufe sollte 11 sein (von 10 auf 11)")
assert.Equal(t, 80, result.Ep, "EP-Kosten sollten 80 sein")
assert.Equal(t, 80, result.Money, "Geldkosten sollten 80 GS sein")
})
}
*/
@@ -7,6 +7,7 @@ import (
"testing"
)
// setupTestEnvironment ensures ENVIRONMENT is set to test for this package.
func setupTestEnvironment(t *testing.T) {
original := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "test")
+2 -2
View File
@@ -870,8 +870,8 @@ func GetGameSystem(id uint, name string) *GameSystem {
return gs
}
gs.FirstByID(uint(id))
if gs.ID == 0 && name != "" {
gs.Name = name
if gs.ID == 0 {
return nil
}
return gs
}
+41 -14
View File
@@ -18,8 +18,8 @@ type Source struct {
Publisher string `json:"publisher,omitempty"` // z.B. "Pegasus Spiele"
PublishYear int `json:"publish_year,omitempty"` // Erscheinungsjahr
Description string `json:"description,omitempty"` // Beschreibung des Werks
IsCore bool `gorm:"default:false" json:"is_core"` // Ist es ein Grundregelwerk?
IsActive bool `gorm:"default:true" json:"is_active"` // Ist das Werk aktiv/verfügbar?
IsCore bool `json:"is_core"` // Ist es ein Grundregelwerk?
IsActive bool `json:"is_active"` // Ist das Werk aktiv/verfügbar?
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
GameSystemId uint `json:"game_system_id,omitempty"`
}
@@ -364,20 +364,47 @@ func (ss *SpellSchool) Save() error {
}
// CRUD-Methoden
func (s *Source) Create() error {
s.ensureGameSystem()
return database.DB.Create(s).Error
func (object *Source) CreatewGS(gamesystemId uint) error {
gs := GetGameSystem(gamesystemId, "")
if gs == nil {
return fmt.Errorf("invalid game system")
}
object.GameSystemId = gs.ID
return database.DB.Create(object).Error
}
func (s *Source) FirstByCode(code string) error {
gs := GetGameSystem(s.GameSystemId, s.GameSystem)
return database.DB.Where("(game_system = ? OR game_system_id = ?) AND code = ?", gs.Name, gs.ID, code).First(s).Error
func (object *Source) Create() error {
object.ensureGameSystem()
return object.CreatewGS(object.GameSystemId)
}
func (s *Source) FirstByName(name string) error {
gs := GetGameSystem(s.GameSystemId, s.GameSystem)
return database.DB.Where("(game_system = ? OR game_system_id = ?) AND name = ?", gs.Name, gs.ID, name).First(s).Error
func (object *Source) FirstByCodewGS(code string, gameSystemId uint) error {
if code == "" {
return fmt.Errorf("name cannot be empty")
}
gs := GetGameSystem(gameSystemId, "")
if gs == nil {
return fmt.Errorf("invalid game system")
}
return database.DB.Where("(game_system = ? OR game_system_id = ?) AND code = ?", gs.Name, gs.ID, code).First(object).Error
}
func (object *Source) FirstByCode(code string) error {
gs := GetGameSystem(object.GameSystemId, object.GameSystem)
return object.FirstByCodewGS(code, gs.ID)
}
func (object *Source) FirstByNamewGS(name string, gameSystemId uint) error {
if name == "" {
return fmt.Errorf("name cannot be empty")
}
gs := GetGameSystem(gameSystemId, "")
return database.DB.Where("(game_system = ? OR game_system_id = ?) AND name = ?", gs.Name, gs.ID, name).First(object).Error
}
func (object *Source) FirstByName(name string) error {
gs := GetGameSystem(object.GameSystemId, object.GameSystem)
return object.FirstByNamewGS(name, gs.ID)
}
func (cc *CharacterClass) Create() error {
@@ -569,13 +596,13 @@ func GetSpellLearningInfoNewSystem(spellName string, classCode string) (*SpellLe
s.game_system as game_system,
s.game_system_id as game_system_id,
s.stufe as spell_level,
s.learning_category as school_name,
COALESCE(NULLIF(s.category, ''), s.learning_category) as school_name,
cssec.character_class as class_code,
cssec.character_class as class_name,
cssec.ep_per_le,
COALESCE(sllc.le_required, 0) as le_required
FROM gsm_spells s
JOIN learning_class_spell_school_ep_costs cssec ON s.learning_category = cssec.spell_school
JOIN learning_class_spell_school_ep_costs cssec ON COALESCE(NULLIF(s.category, ''), s.learning_category) = cssec.spell_school
LEFT JOIN learning_spell_level_le_costs sllc ON s.stufe = sllc.level AND (sllc.game_system = s.game_system OR sllc.game_system_id = s.game_system_id OR sllc.game_system_id IS NULL)
WHERE s.name = ? AND cssec.character_class = ?
`, spellName, classCode).Scan(&result).Error
+232 -32
View File
@@ -28,9 +28,10 @@ func defaultGameSystem(t *testing.T) *GameSystem {
// Tests for Source struct and methods
// =============================================================================
func TestSource_FirstByCode_Success(t *testing.T) {
setupLearningCostsTestDB(t)
func TestSourceModelFunctions(t *testing.T) {
database.SetupTestDB()
defer database.ResetTestDB()
t.Run("FirstByCode_Success", func(t *testing.T) {
var source Source
err := source.FirstByCode("KOD")
@@ -39,41 +40,86 @@ func TestSource_FirstByCode_Success(t *testing.T) {
assert.Equal(t, "Kodex", source.Name)
assert.True(t, source.IsCore)
assert.True(t, source.IsActive)
}
func TestSource_FirstByCode_NotFound(t *testing.T) {
setupLearningCostsTestDB(t)
assert.Equal(t, uint(1), source.GameSystemId)
})
t.Run("FirstByName_Success", func(t *testing.T) {
var source Source
err := source.FirstByCode("INVALID")
assert.Error(t, err)
}
func TestSource_FirstByName_Success(t *testing.T) {
setupLearningCostsTestDB(t)
var source Source
err := source.FirstByName("Arkanum")
err := source.FirstByName("Kodex")
assert.NoError(t, err)
assert.Equal(t, "ARK", source.Code)
assert.Equal(t, "Arkanum", source.Name)
assert.False(t, source.IsCore)
assert.Equal(t, "KOD", source.Code)
assert.Equal(t, "Kodex", source.Name)
assert.True(t, source.IsCore)
assert.True(t, source.IsActive)
}
func TestSource_FirstByName_NotFound(t *testing.T) {
setupLearningCostsTestDB(t)
assert.Equal(t, uint(1), source.GameSystemId)
})
t.Run("FirstByCodexGS_Success", func(t *testing.T) {
var source Source
err := source.FirstByName("Invalid Source")
err := source.FirstByCodewGS("KOD", 1)
assert.Error(t, err)
assert.NoError(t, err)
assert.Equal(t, "KOD", source.Code)
assert.Equal(t, "Kodex", source.Name)
assert.True(t, source.IsCore)
assert.True(t, source.IsActive)
assert.Equal(t, uint(1), source.GameSystemId)
})
t.Run("FirstByNamexGS_Success", func(t *testing.T) {
var source Source
err := source.FirstByNamewGS("Kodex", 1)
assert.NoError(t, err)
assert.Equal(t, "KOD", source.Code)
assert.Equal(t, "Kodex", source.Name)
assert.True(t, source.IsCore)
assert.True(t, source.IsActive)
assert.Equal(t, uint(1), source.GameSystemId)
})
t.Run("Create_Success", func(t *testing.T) {
cSource := Source{
Code: "XYZ",
Name: "Test Source",
IsCore: false,
IsActive: false,
}
err := cSource.Create()
var source Source
err = source.FirstByNamewGS("Test Source", 1)
assert.NoError(t, err)
assert.Equal(t, "XYZ", source.Code)
assert.Equal(t, "Test Source", source.Name)
assert.False(t, source.IsCore)
assert.False(t, source.IsActive)
assert.Equal(t, uint(1), source.GameSystemId)
cSource = Source{
Code: "KLM",
Name: "KLM Source",
IsCore: true,
IsActive: false,
}
err = cSource.CreatewGS(99999)
assert.Error(t, err, "Games system must be invalid")
err = cSource.CreatewGS(1)
assert.NoError(t, err, "Games system must be valid")
var source2 Source
err = source2.FirstByCodewGS("KLM", 999)
assert.Error(t, err, "Gamesystem should be wrong")
err = source2.FirstByCodewGS("KLM", 1)
assert.Equal(t, "KLM", source2.Code)
assert.Equal(t, "KLM Source", source2.Name)
assert.True(t, source2.IsCore)
assert.False(t, source2.IsActive)
assert.Equal(t, uint(1), source2.GameSystemId)
})
}
func TestSource_Create_SetsGameSystem(t *testing.T) {
setupLearningCostsTestDB(t)
database.SetupTestDB()
defer database.ResetTestDB()
gs := defaultGameSystem(t)
source := Source{
@@ -94,7 +140,8 @@ func TestSource_Create_SetsGameSystem(t *testing.T) {
// =============================================================================
func TestCharacterClass_FirstByCode_Success(t *testing.T) {
setupLearningCostsTestDB(t)
database.SetupTestDB()
defer database.ResetTestDB()
var class CharacterClass
err := class.FirstByCode("Bb")
@@ -406,6 +453,7 @@ func TestGetSkillInfoCategoryAndDifficultyNewSystem_Success(t *testing.T) {
}
}
/*
func TestGetSpellLearningInfoNewSystem_Success(t *testing.T) {
setupLearningCostsTestDB(t)
@@ -419,7 +467,8 @@ func TestGetSpellLearningInfoNewSystem_Success(t *testing.T) {
assert.Greater(t, spellInfo.EPPerLE, 0)
}
}
*/
/*
func TestGetSpellLearningInfoNewSystem_IncludesGameSystem(t *testing.T) {
setupLearningCostsTestDB(t)
@@ -466,7 +515,8 @@ func TestGetSpellLearningInfoNewSystem_IncludesGameSystem(t *testing.T) {
assert.Equal(t, gs.Name, spellInfo.GameSystem)
assert.Equal(t, gs.ID, spellInfo.GameSystemId)
}
*/
/*
func TestGetSpellLearningInfoNewSystem_InvalidSpell(t *testing.T) {
setupLearningCostsTestDB(t)
@@ -474,7 +524,157 @@ func TestGetSpellLearningInfoNewSystem_InvalidSpell(t *testing.T) {
assert.Error(t, err)
}
*/
func TestGetSpellLearningInfoNewSystem(t *testing.T) {
database.SetupTestDB(true)
defer database.ResetTestDB()
gs := GetGameSystem(1, "")
require.NotNil(t, gs)
tests := []struct {
TestName string // Charakter-ID
Name string `json:"name" binding:"omitempty"`
ClassCode string `json:"class_code" binding:"omitempty"`
UsePP int `json:"use_pp,omitempty"` // Anzahl der zu verwendenden Praxispunkte
UseGold int `json:"use_gold,omitempty"` // Anzahl der zu verwendenden Goldstücke
// Belohnungsoptionen
Reward *string `json:"reward" binding:"required,oneof=default noGold halveep halveepnoGold"` // Belohnungsoptionen Lernen als Belohnung
expError bool // Erwartet einen Fehler
LERequired int
SpellLevel int
EPPerLE int
}{
{
TestName: "Schamane Scharfblick, 0,0,-",
Name: "Scharfblick",
ClassCode: "Sc",
LERequired: 1,
SpellLevel: 1,
EPPerLE: 60,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: false,
}, /*{
TestName: "Barde Das Lied der Feier, 0,0,-",
Name: "Das Lied der Feier",
ClassCode: "Ba",
LERequired: 0,
SpellLevel: 2,
EPPerLE: 0,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: false,
},*/{
TestName: "Magier Angst, 0,0,-",
Name: "Angst",
ClassCode: "Ma",
LERequired: 1,
SpellLevel: 2,
EPPerLE: 60,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: false,
}, {
TestName: "Hexer Zaubersprung, 0,0,-",
Name: "Zaubersprung",
ClassCode: "Hx",
LERequired: 2,
SpellLevel: 3,
EPPerLE: 30,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: false,
}, {
TestName: "Magier Zaubersprung, 0,0,-",
Name: "Zaubersprung",
ClassCode: "Ma",
LERequired: 2,
SpellLevel: 3,
EPPerLE: 60,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: false,
}, {
TestName: "Magier NonExistentSpell, 0,0,-",
Name: "NonExistentSpell",
ClassCode: "Ma",
LERequired: 0,
SpellLevel: 2,
EPPerLE: 0,
UsePP: 0,
UseGold: 0,
Reward: nil,
expError: true,
},
}
for _, tt := range tests {
t.Run(tt.TestName, func(t *testing.T) {
info, err := GetSpellLearningInfoNewSystem(tt.Name, tt.ClassCode)
if tt.expError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, info)
assert.Equal(t, tt.Name, info.SpellName)
assert.Equal(t, tt.SpellLevel, info.SpellLevel)
assert.Equal(t, tt.LERequired, info.LERequired)
assert.Equal(t, tt.EPPerLE, info.EPPerLE)
}
})
}
}
/*
func TestGetSpellLearningInfoNewSystem_NotExistingForCurrentGameSystem(t *testing.T) {
database.ResetTestDB()
database.SetupTestDB(true)
defer database.ResetTestDB()
require.NoError(t, MigrateStructure())
altGS := GameSystem{Code: "AGS", Name: "AltSystem"}
require.NoError(t, database.DB.Create(&altGS).Error)
source := Source{Code: "SRC_ALT", Name: "Alt Source", GameSystem: altGS.Name, GameSystemId: altGS.ID}
require.NoError(t, database.DB.Create(&source).Error)
altClass := CharacterClass{Code: "ALC", Name: "Alt Class", SourceID: source.ID, GameSystem: altGS.Name, GameSystemId: altGS.ID}
require.NoError(t, altClass.Create())
altSchool := SpellSchool{Name: "AltSchool", SourceID: source.ID, GameSystem: altGS.Name, GameSystemId: altGS.ID}
require.NoError(t, altSchool.Create())
altCost := ClassSpellSchoolEPCost{CharacterClassID: altClass.ID, SpellSchoolID: altSchool.ID, EPPerLE: 4, CCLass: altClass.Code, SCategory: altSchool.Name}
require.NoError(t, altCost.Create())
altLevel := SpellLevelLECost{Level: 98, LERequired: 1, GameSystem: altGS.Name, GameSystemId: altGS.ID}
if err := altLevel.Create(); err != nil {
require.NoError(t, database.DB.Where("level = ?", altLevel.Level).First(&altLevel).Error)
altLevel.GameSystem = altGS.Name
altLevel.GameSystemId = altGS.ID
require.NoError(t, altLevel.Save())
}
spell := Spell{Name: "Alt Spell", Stufe: altLevel.Level, LearningCategory: altSchool.Name, GameSystem: altGS.Name, GameSystemId: altGS.ID, SourceID: source.ID}
require.NoError(t, spell.Create())
currentSource := Source{Code: "SRC_CUR", Name: "Current Source", GameSystem: "midgard"}
require.NoError(t, database.DB.Create(&currentSource).Error)
currentClass := CharacterClass{Code: "CURC", Name: "Current Class", SourceID: currentSource.ID, GameSystem: "midgard", GameSystemId: 0}
require.NoError(t, currentClass.Create())
_, err := GetSpellLearningInfoNewSystem(spell.Name, currentClass.Code)
assert.Error(t, err)
}
*/
// =============================================================================
// Tests for cost calculation functions
// =============================================================================