New test TestCalculateSpellLearnCostNewSystem in chain of learning system
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(¤tSource).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
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user