Files
bamort/backend/pdfrender/weapon_mapper_test.go
T

381 lines
9.6 KiB
Go
Raw Normal View History

2025-12-19 17:28:40 +01:00
package pdfrender
import (
2025-12-20 00:19:20 +01:00
"bamort/database"
2025-12-19 17:28:40 +01:00
"bamort/models"
"testing"
)
// TestMapWeapons_WithEWCalculation tests that weapon EW is correctly calculated
// EW = Waffenfertigkeit.Fertigkeitswert + Character.AngriffBonus + Weapon.Anb
func TestMapWeapons_WithEWCalculation(t *testing.T) {
2025-12-20 00:19:20 +01:00
// Setup test database
database.SetupTestDB()
// Create weapons in gsmaster with skill requirements
testSword := &models.Weapon{
Equipment: models.Equipment{
GameSystem: "midgard",
Name: "Langschwert",
},
SkillRequired: "Schwerter",
Damage: "1W6",
}
_ = testSword.Create()
testBow := &models.Weapon{
Equipment: models.Equipment{
GameSystem: "midgard",
Name: "Langbogen",
},
SkillRequired: "Bogen",
Damage: "1W6",
}
_ = testBow.Create()
2025-12-19 17:28:40 +01:00
// Arrange - Create a character with weapon skills and equipped weapons
char := &models.Char{
BamortBase: models.BamortBase{
ID: 1,
Name: "Test Fighter",
},
// Weapon skills the character has learned
Waffenfertigkeiten: []models.SkWaffenfertigkeit{
{
SkFertigkeit: models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
2025-12-20 00:19:20 +01:00
Name: "Schwerter",
2025-12-19 17:28:40 +01:00
},
},
Fertigkeitswert: 12, // Base skill value
},
},
{
SkFertigkeit: models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Bogen",
},
},
Fertigkeitswert: 10,
},
},
},
// Actual equipped weapons with bonuses
Waffen: []models.EqWaffe{
{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Langschwert",
},
},
2025-12-19 17:29:12 +01:00
Anb: 2, // Attack bonus of weapon
Schb: 1, // Damage bonus of weapon
2025-12-19 17:28:40 +01:00
},
{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
2025-12-20 00:19:20 +01:00
Name: "Langbogen",
2025-12-19 17:28:40 +01:00
},
},
Anb: 0,
Schb: 0,
},
},
// Character attributes that influence combat
Eigenschaften: []models.Eigenschaft{
{Name: "St", Value: 90}, // Strength influences attack bonus
{Name: "Gw", Value: 80}, // Dexterity influences attack bonus
},
}
// Act
vm, err := MapCharacterToViewModel(char)
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Expect 3 weapons: Raufen + Langschwert + Langbogen
if len(vm.Weapons) != 3 {
t.Fatalf("Expected 3 weapons (Raufen + 2 equipped), got %d", len(vm.Weapons))
}
// Check first weapon is Raufen
if vm.Weapons[0].Name != "Raufen" {
t.Errorf("Expected first weapon to be 'Raufen', got '%s'", vm.Weapons[0].Name)
2025-12-19 17:28:40 +01:00
}
// Test Langschwert (index 1)
sword := vm.Weapons[1]
2025-12-19 17:28:40 +01:00
if sword.Name != "Langschwert" {
t.Errorf("Expected weapon name 'Langschwert', got '%s'", sword.Name)
}
2025-12-19 17:29:12 +01:00
2025-12-19 17:28:40 +01:00
// EW should be: skill(12) + char_attack_bonus + weapon_bonus(2)
// Character attack bonus is derived from St/Gw, typically calculated in DerivedValues
// For now, we expect at least: 12 + 2 = 14 (we'll enhance with char bonus later)
if sword.Value < 14 {
t.Errorf("Expected sword EW >= 14 (skill 12 + weapon bonus 2), got %d", sword.Value)
}
// Test Langbogen (index 2)
bow := vm.Weapons[2]
2025-12-20 00:19:20 +01:00
if bow.Name != "Langbogen" {
t.Errorf("Expected weapon name 'Langbogen', got '%s'", bow.Name)
2025-12-19 17:28:40 +01:00
}
2025-12-19 17:29:12 +01:00
2025-12-19 17:28:40 +01:00
if bow.Value < 10 {
t.Errorf("Expected bow EW >= 10 (skill 10 + no weapon bonus), got %d", bow.Value)
}
}
// TestMapWeapons_WithDamageCalculation tests that weapon damage is correctly calculated
2025-12-20 00:19:20 +01:00
// Damage = Base Weapon Damage + Character SchadenBonus + Weapon Schb
2025-12-19 17:28:40 +01:00
func TestMapWeapons_WithDamageCalculation(t *testing.T) {
2025-12-20 00:19:20 +01:00
// Setup test database to load weapon data
database.SetupTestDB()
// Create test weapon in gsmaster if it doesn't exist
testWeapon := &models.Weapon{
Equipment: models.Equipment{
GameSystem: "midgard",
Name: "Langschwert",
},
SkillRequired: "Schwerter",
Damage: "1W6",
}
_ = testWeapon.Create() // Ignore error if already exists
// Arrange - Create a character with weapons that have damage values
char := &models.Char{
BamortBase: models.BamortBase{
ID: 1,
Name: "Test Fighter",
},
// Weapon skills
Waffenfertigkeiten: []models.SkWaffenfertigkeit{
{
SkFertigkeit: models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Schwerter",
},
},
Fertigkeitswert: 12,
},
},
},
// Equipped weapons with damage bonuses
Waffen: []models.EqWaffe{
{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Langschwert",
},
},
Schb: 2, // Weapon's damage bonus
},
},
// Character attributes that influence damage bonus
Eigenschaften: []models.Eigenschaft{
{Name: "St", Value: 95}, // High strength gives SchadenBonus = +1
{Name: "Gw", Value: 80},
},
}
// Act
vm, err := MapCharacterToViewModel(char)
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Expect 2 weapons: Raufen + Langschwert
if len(vm.Weapons) != 2 {
t.Fatalf("Expected 2 weapons (Raufen + Langschwert), got %d", len(vm.Weapons))
2025-12-20 00:19:20 +01:00
}
// Check Langschwert (index 1, after Raufen)
sword := vm.Weapons[1]
2025-12-20 00:19:20 +01:00
// Damage should be in format like "1W6+3" where the bonus combines
// Character's SchadenBonus (from St=95 -> +1) + Weapon's Schb (2) = +3
if sword.Damage == "" {
t.Error("Expected weapon to have damage value, got empty string")
}
// The damage string should be "1W6+3"
// Base damage "1W6" + total bonus (+3)
expectedDamage := "1W6+3"
if sword.Damage != expectedDamage {
t.Errorf("Expected damage '%s', got '%s'", expectedDamage, sword.Damage)
}
t.Logf("✓ Weapon damage correctly calculated: %s (SchadenBonus %d + Weapon Schb 2 = +3)",
sword.Damage, vm.DerivedValues.SchadenBonus)
2025-12-19 17:28:40 +01:00
}
// TestMapWeapons_WithRangedWeaponRanges tests that ranged weapons show their ranges
func TestMapWeapons_WithRangedWeaponRanges(t *testing.T) {
2025-12-20 00:19:20 +01:00
// Setup test database
database.SetupTestDB()
// Delete existing test weapons to ensure clean state
database.DB.Where("name IN (?, ?)", "Langbogen", "Kurzschwert").Delete(&models.Weapon{})
// Create a ranged weapon in gsmaster with range values
testBow := &models.Weapon{
Equipment: models.Equipment{
GameSystem: "midgard",
Name: "Langbogen",
},
SkillRequired: "Bogen",
Damage: "1W6",
RangeNear: 10,
RangeMiddle: 30,
RangeFar: 100,
}
err := testBow.Create()
if err != nil {
t.Fatalf("Failed to create Langbogen: %v", err)
}
// Verify the weapon was created
verifyWeapon := &models.Weapon{}
verifyErr := verifyWeapon.First("Langbogen")
if verifyErr != nil || verifyWeapon.ID == 0 {
t.Fatalf("Failed to create/find Langbogen in database: %v", verifyErr)
}
if verifyWeapon.RangeNear != 10 || verifyWeapon.RangeMiddle != 30 || verifyWeapon.RangeFar != 100 {
t.Fatalf("Langbogen ranges not set correctly: got %d/%d/%d, expected 10/30/100",
verifyWeapon.RangeNear, verifyWeapon.RangeMiddle, verifyWeapon.RangeFar)
}
// Create a melee weapon without ranges
testSword := &models.Weapon{
Equipment: models.Equipment{
GameSystem: "midgard",
Name: "Kurzschwert",
},
SkillRequired: "Schwerter",
Damage: "1W6+1",
RangeNear: 0,
RangeMiddle: 0,
RangeFar: 0,
}
_ = testSword.Create()
// Arrange - Character with both ranged and melee weapons
char := &models.Char{
BamortBase: models.BamortBase{
ID: 1,
Name: "Test Archer",
},
Waffenfertigkeiten: []models.SkWaffenfertigkeit{
{
SkFertigkeit: models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Bogen",
},
},
Fertigkeitswert: 14,
},
},
{
SkFertigkeit: models.SkFertigkeit{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Schwerter",
},
},
Fertigkeitswert: 10,
},
},
},
Waffen: []models.EqWaffe{
{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Langbogen",
},
},
},
{
BamortCharTrait: models.BamortCharTrait{
BamortBase: models.BamortBase{
Name: "Kurzschwert",
},
},
},
},
Eigenschaften: []models.Eigenschaft{
{Name: "St", Value: 75},
{Name: "Gs", Value: 85},
},
}
// Act
vm, err := MapCharacterToViewModel(char)
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Expect 3 weapons: Raufen + Langbogen + Kurzschwert
if len(vm.Weapons) != 3 {
t.Fatalf("Expected 3 weapons (Raufen + 2 equipped), got %d", len(vm.Weapons))
}
// Check first weapon is Raufen
if vm.Weapons[0].Name != "Raufen" {
t.Errorf("Expected first weapon to be 'Raufen', got '%s'", vm.Weapons[0].Name)
2025-12-20 00:19:20 +01:00
}
// Find the bow and sword
2025-12-20 00:19:20 +01:00
var bow *WeaponViewModel
var sword *WeaponViewModel
for i := range vm.Weapons {
if vm.Weapons[i].Name == "Langbogen" {
bow = &vm.Weapons[i]
} else if vm.Weapons[i].Name == "Kurzschwert" {
sword = &vm.Weapons[i]
}
}
// Test ranged weapon
if bow == nil {
t.Fatal("Langbogen not found in weapons")
}
if !bow.IsRanged {
t.Error("Expected Langbogen to be marked as ranged weapon")
}
// Range should be formatted as "10/30/100" (Nah/Mittel/Fern)
expectedRange := "10/30/100"
if bow.Range != expectedRange {
t.Errorf("Expected bow range '%s', got '%s'", expectedRange, bow.Range)
}
t.Logf("✓ Ranged weapon ranges: %s", bow.Range)
// Test melee weapon
if sword == nil {
t.Fatal("Kurzschwert not found in weapons")
}
if sword.IsRanged {
t.Error("Expected Kurzschwert not to be marked as ranged weapon")
}
if sword.Range != "" {
t.Errorf("Expected melee weapon to have empty range, got '%s'", sword.Range)
}
2025-12-19 17:28:40 +01:00
}