2026-01-02 10:21:29 +01:00
|
|
|
package maintenance
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bamort/database"
|
|
|
|
|
"bamort/models"
|
|
|
|
|
"os"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func setupTestEnvironment(t *testing.T) {
|
|
|
|
|
original := os.Getenv("ENVIRONMENT")
|
|
|
|
|
os.Setenv("ENVIRONMENT", "test")
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
if original != "" {
|
|
|
|
|
os.Setenv("ENVIRONMENT", original)
|
|
|
|
|
} else {
|
|
|
|
|
os.Unsetenv("ENVIRONMENT")
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMigrateSkillCategoriesToRelations(t *testing.T) {
|
|
|
|
|
setupTestEnvironment(t)
|
|
|
|
|
|
|
|
|
|
// Reset and setup fresh test database to avoid interference from other tests
|
|
|
|
|
database.ResetTestDB()
|
|
|
|
|
database.SetupTestDB()
|
|
|
|
|
testDB := database.DB
|
|
|
|
|
|
|
|
|
|
// Ensure database is valid
|
|
|
|
|
if testDB == nil {
|
|
|
|
|
t.Fatal("Database connection is nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a test source - use unique code to avoid conflicts
|
|
|
|
|
source := models.Source{
|
2026-01-29 09:14:33 +01:00
|
|
|
Code: "TSTMIG1",
|
|
|
|
|
Name: "Test Migration Source",
|
|
|
|
|
GameSystemId: 1,
|
|
|
|
|
IsActive: true,
|
2026-01-02 10:21:29 +01:00
|
|
|
}
|
|
|
|
|
if err := testDB.Create(&source).Error; err != nil {
|
|
|
|
|
t.Fatalf("Failed to create test source: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create test skills with old-style category/difficulty - use unique names to avoid conflicts
|
|
|
|
|
testSkills := []models.Skill{
|
|
|
|
|
{
|
|
|
|
|
Name: "TestMigSkill_Schwimmen",
|
|
|
|
|
Category: "Körper",
|
|
|
|
|
Difficulty: "leicht",
|
2026-01-29 09:49:36 +01:00
|
|
|
GameSystemId: 1,
|
2026-01-02 10:21:29 +01:00
|
|
|
Initialwert: 12,
|
|
|
|
|
Improvable: true,
|
|
|
|
|
Bonuseigenschaft: "Gw",
|
|
|
|
|
SourceID: source.ID,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "TestMigSkill_Klettern",
|
|
|
|
|
Category: "Körper",
|
|
|
|
|
Difficulty: "normal",
|
2026-01-29 09:49:36 +01:00
|
|
|
GameSystemId: 1,
|
2026-01-02 10:21:29 +01:00
|
|
|
Initialwert: 10,
|
|
|
|
|
Improvable: true,
|
|
|
|
|
Bonuseigenschaft: "Gw",
|
|
|
|
|
SourceID: source.ID,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "TestMigSkill_LesenSchreiben",
|
|
|
|
|
Category: "Wissen",
|
|
|
|
|
Difficulty: "schwer",
|
2026-01-29 09:49:36 +01:00
|
|
|
GameSystemId: 1,
|
2026-01-02 10:21:29 +01:00
|
|
|
Initialwert: 0,
|
|
|
|
|
Improvable: true,
|
|
|
|
|
Bonuseigenschaft: "In",
|
|
|
|
|
SourceID: source.ID,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := range testSkills {
|
|
|
|
|
if err := testDB.Create(&testSkills[i]).Error; err != nil {
|
|
|
|
|
t.Fatalf("Failed to create test skill: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run migration
|
|
|
|
|
if err := MigrateSkillCategoriesToRelations(testDB); err != nil {
|
|
|
|
|
t.Fatalf("Migration failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify migration results
|
|
|
|
|
for _, skill := range testSkills {
|
|
|
|
|
var scds []models.SkillCategoryDifficulty
|
|
|
|
|
err := testDB.Preload("SkillCategory").Preload("SkillDifficulty").
|
|
|
|
|
Where("skill_id = ?", skill.ID).Find(&scds).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("Failed to find migrated data for skill %s: %v", skill.Name, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(scds) == 0 {
|
|
|
|
|
t.Errorf("No SkillCategoryDifficulty created for skill %s", skill.Name)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scd := scds[0]
|
|
|
|
|
if scd.SkillCategory.Name != skill.Category {
|
|
|
|
|
t.Errorf("Category mismatch for %s: expected %s, got %s",
|
|
|
|
|
skill.Name, skill.Category, scd.SkillCategory.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if scd.SkillDifficulty.Name != skill.Difficulty {
|
|
|
|
|
t.Errorf("Difficulty mismatch for %s: expected %s, got %s",
|
|
|
|
|
skill.Name, skill.Difficulty, scd.SkillDifficulty.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test idempotency - running migration again should not create duplicates
|
|
|
|
|
if err := MigrateSkillCategoriesToRelations(testDB); err != nil {
|
|
|
|
|
t.Fatalf("Second migration failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, skill := range testSkills {
|
|
|
|
|
var count int64
|
|
|
|
|
testDB.Model(&models.SkillCategoryDifficulty{}).Where("skill_id = ?", skill.ID).Count(&count)
|
|
|
|
|
if count != 1 {
|
|
|
|
|
t.Errorf("Idempotency check failed for %s: expected 1 record, got %d", skill.Name, count)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestGetDefaultLearnCost(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
difficulty string
|
|
|
|
|
expected int
|
|
|
|
|
}{
|
|
|
|
|
{"leicht", 5},
|
|
|
|
|
{"easy", 5},
|
|
|
|
|
{"normal", 10},
|
|
|
|
|
{"standard", 10},
|
|
|
|
|
{"schwer", 20},
|
|
|
|
|
{"hard", 20},
|
|
|
|
|
{"sehr schwer", 30},
|
|
|
|
|
{"very hard", 30},
|
|
|
|
|
{"unknown", 10}, // default
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.difficulty, func(t *testing.T) {
|
|
|
|
|
result := getDefaultLearnCost(tt.difficulty)
|
|
|
|
|
if result != tt.expected {
|
|
|
|
|
t.Errorf("getDefaultLearnCost(%s) = %d, expected %d",
|
|
|
|
|
tt.difficulty, result, tt.expected)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMigrateSkillCategoryDifficulty_NoCategory(t *testing.T) {
|
|
|
|
|
setupTestEnvironment(t)
|
|
|
|
|
|
|
|
|
|
// Reset and setup fresh test database to avoid interference from other tests
|
|
|
|
|
database.ResetTestDB()
|
|
|
|
|
database.SetupTestDB()
|
|
|
|
|
testDB := database.DB
|
|
|
|
|
|
|
|
|
|
// Ensure database is valid
|
|
|
|
|
if testDB == nil {
|
|
|
|
|
t.Fatal("Database connection is nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use existing source or create one with a unique code
|
|
|
|
|
var source models.Source
|
|
|
|
|
err := testDB.Where("code = ?", "KOD").First(&source).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
// Create a test source if KOD doesn't exist
|
|
|
|
|
source = models.Source{
|
|
|
|
|
Code: "TSTMIG2",
|
|
|
|
|
Name: "Test Migration Source 2",
|
2026-01-29 09:14:33 +01:00
|
|
|
GameSystemId: 1,
|
2026-01-02 10:21:29 +01:00
|
|
|
IsActive: true,
|
|
|
|
|
}
|
|
|
|
|
if err := testDB.Create(&source).Error; err != nil {
|
|
|
|
|
t.Fatalf("Failed to create test source: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create skill without category (should use default) - use unique name
|
|
|
|
|
skill := models.Skill{
|
|
|
|
|
Name: "TestMigSkill_NoCategory",
|
|
|
|
|
Category: "", // Empty category
|
|
|
|
|
Difficulty: "", // Empty difficulty
|
2026-01-29 09:49:36 +01:00
|
|
|
GameSystemId: 1,
|
2026-01-02 10:21:29 +01:00
|
|
|
Initialwert: 10,
|
|
|
|
|
SourceID: source.ID,
|
|
|
|
|
}
|
|
|
|
|
if err := testDB.Create(&skill).Error; err != nil {
|
|
|
|
|
t.Fatalf("Failed to create test skill: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Migrate
|
|
|
|
|
if err := migrateSkillCategoryDifficulty(testDB, &skill); err != nil {
|
|
|
|
|
t.Fatalf("Migration failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify defaults were used
|
|
|
|
|
var scd models.SkillCategoryDifficulty
|
|
|
|
|
err = testDB.Preload("SkillCategory").Preload("SkillDifficulty").
|
|
|
|
|
Where("skill_id = ?", skill.ID).First(&scd).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Failed to find migrated data: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if scd.SkillCategory.Name != "Alltag" {
|
|
|
|
|
t.Errorf("Expected default category 'Alltag', got %s", scd.SkillCategory.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if scd.SkillDifficulty.Name != "normal" {
|
|
|
|
|
t.Errorf("Expected default difficulty 'normal', got %s", scd.SkillDifficulty.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|