package importer import ( "bamort/database" "bamort/models" "bytes" "encoding/json" "io" "mime/multipart" "net/http" "net/http/httptest" "os" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func defaultGameSystem(t *testing.T) *models.GameSystem { gs := models.GetGameSystem(0, "midgard") require.NotNil(t, gs) require.NotZero(t, gs.ID) return gs } func NoT_estImportCsv2Spell(t *testing.T) { // Clear source cache to ensure clean test state ClearSourceCache() // Setup test database database.SetupTestDB(true, false) // Use in-memory SQLite, no test data loading defer database.ResetTestDB() models.MigrateStructure() /* // Create test source data testSources := []models.Source{ {Code: "ARK", Name: "Arkanum", GameSystemId: 1}, {Code: "MYS", Name: "Mysterium", GameSystemId: 1}, {Code: "KOD", Name: "Kodex", GameSystemId: 1}, } for _, source := range testSources { source.Create() } */ t.Run("Import Zauber-Arkanum.csv", func(t *testing.T) { // Test if file exists csvPath := "/data/dev/bamort/backend/doc/Zauber-Arkanum.csv" if _, err := os.Stat(csvPath); os.IsNotExist(err) { t.Skipf("CSV file %s not found, skipping test", csvPath) return } // Test import err := ImportCsv2Spell(csvPath) assert.NoError(t, err, "Import should succeed") // Verify some spells were imported var count int64 database.DB.Model(&models.Spell{}).Count(&count) assert.Greater(t, count, int64(0), "Should have imported some spells") // Test specific spell with more detailed debugging var spell models.Spell err = spell.First("Angst") if err != nil { // Let's check what spells actually exist var allSpells []models.Spell database.DB.Limit(10).Find(&allSpells) t.Logf("Found %d spells in database, first 10:", count) for i, s := range allSpells { t.Logf("Spell %d: %s (Category: %s, Level: %d)", i+1, s.Name, s.Category, s.Stufe) } } assert.NoError(t, err, "Should find 'Angst' spell") assert.Equal(t, "Beherrschen", spell.Category, "Spell category should match") assert.Equal(t, 2, spell.Stufe, "Spell level should be 2") // Test that source_id was set correctly (ARK should have been looked up) if spell.SourceID != 0 { var source models.Source err = database.DB.First(&source, spell.SourceID).Error assert.NoError(t, err, "Should find source by ID") assert.Equal(t, "ARK", source.Code, "Source code should be ARK") } }) t.Run("Import Zauber-Mysterium.csv", func(t *testing.T) { // Test if file exists csvPath := "/data/dev/bamort/backend/doc/Zauber-Mysterium.csv" if _, err := os.Stat(csvPath); os.IsNotExist(err) { t.Skipf("CSV file %s not found, skipping test", csvPath) return } // Get current spell count var countBefore int64 database.DB.Model(&models.Spell{}).Count(&countBefore) // Test import err := ImportCsv2Spell(csvPath) assert.NoError(t, err, "Import should succeed") // Verify more spells were imported var countAfter int64 database.DB.Model(&models.Spell{}).Count(&countAfter) assert.Greater(t, countAfter, countBefore, "Should have imported additional spells") }) t.Run("Test update existing spell", func(t *testing.T) { // Create a test spell first testSpell := models.Spell{ GameSystemId: 1, Name: "Test Zauber", Beschreibung: "Original description", Stufe: 1, } err := testSpell.Create() assert.NoError(t, err, "Should create test spell") // Create temporary CSV with updated data csvContent := `name,Beschreibung,stufe Test Zauber,Updated description,2` tmpFile, err := os.CreateTemp("", "test_spell_*.csv") assert.NoError(t, err, "Should create temp file") defer os.Remove(tmpFile.Name()) _, err = tmpFile.WriteString(csvContent) assert.NoError(t, err, "Should write to temp file") tmpFile.Close() // Import the updated data err = ImportCsv2Spell(tmpFile.Name()) assert.NoError(t, err, "Import should succeed") // Verify the spell was updated var updatedSpell models.Spell err = updatedSpell.First("Test Zauber") assert.NoError(t, err, "Should find updated spell") assert.Equal(t, "Updated description", updatedSpell.Beschreibung, "Description should be updated") assert.Equal(t, 2, updatedSpell.Stufe, "Level should be updated") }) t.Run("Test source lookup function", func(t *testing.T) { gs := defaultGameSystem(t) // Clear cache to ensure fresh lookups ClearSourceCache() // Test successful lookup of existing source sourceID, err := lookupSourceID("ARK") assert.NoError(t, err, "Should find ARK source") assert.Greater(t, sourceID, uint(0), "Source ID should be greater than 0") // Test auto-creation of non-existent source newSourceID, err := lookupSourceID("NEWCODE") assert.NoError(t, err, "Should auto-create NEWCODE source") assert.Greater(t, newSourceID, uint(0), "New source ID should be greater than 0") // Verify the source was actually created in the database var newSource models.Source err = database.DB.First(&newSource, newSourceID).Error assert.NoError(t, err, "Should find newly created source") assert.Equal(t, "NEWCODE", newSource.Code, "Source code should match") assert.Equal(t, "NEWCODE", newSource.Name, "Source name should default to code") assert.Equal(t, gs.ID, newSource.GameSystemId, "Game system ID should match default") assert.True(t, newSource.IsActive, "New source should be active") // Test that the second lookup uses cache (should return same ID) cachedSourceID, err := lookupSourceID("NEWCODE") assert.NoError(t, err, "Should find cached source") assert.Equal(t, newSourceID, cachedSourceID, "Cached lookup should return same ID") // Test empty source code _, err = lookupSourceID("") assert.Error(t, err, "Should return error for empty source code") }) t.Run("Test auto-creation of sources during CSV import", func(t *testing.T) { // Clear cache and check initial source count ClearSourceCache() var initialSourceCount int64 database.DB.Model(&models.Source{}).Count(&initialSourceCount) // Create temporary CSV with a new source code csvContent := `name,quelle,stufe,category Test Spell,TESTSRC,1,Beherrschen` tmpFile, err := os.CreateTemp("", "test_auto_source_*.csv") assert.NoError(t, err, "Should create temp file") defer os.Remove(tmpFile.Name()) _, err = tmpFile.WriteString(csvContent) assert.NoError(t, err, "Should write to temp file") tmpFile.Close() // Import the CSV err = ImportCsv2Spell(tmpFile.Name()) assert.NoError(t, err, "Import should succeed") // Verify new source was created var finalSourceCount int64 database.DB.Model(&models.Source{}).Count(&finalSourceCount) assert.Greater(t, finalSourceCount, initialSourceCount, "Should have created new source") // Verify the spell was imported with correct source var importedSpell models.Spell err = importedSpell.First("Test Spell") assert.NoError(t, err, "Should find imported spell") assert.Equal(t, "TESTSRC", importedSpell.Quelle, "Spell quelle should match") assert.Greater(t, importedSpell.SourceID, uint(0), "Spell should have source ID") // Verify the source details var createdSource models.Source err = database.DB.First(&createdSource, importedSpell.SourceID).Error assert.NoError(t, err, "Should find created source") assert.Equal(t, "TESTSRC", createdSource.Code, "Source code should match") }) } func NoT_estImportSpellCSVHandler(t *testing.T) { // Setup test database database.SetupTestDB(true, false) defer database.ResetTestDB() models.MigrateStructure() // Create test source testSource := models.Source{Code: "ARK", Name: "Arkanum", GameSystemId: 1} testSource.Create() // Setup Gin in test mode gin.SetMode(gin.TestMode) t.Run("Successful CSV import via HTTP", func(t *testing.T) { // Create temporary test CSV file csvContent := `name,quelle,stufe,category Test Spell HTTP,ARK,3,Beherrschen` tmpFile, err := os.CreateTemp("", "test_http_*.csv") assert.NoError(t, err, "Should create temp file") defer os.Remove(tmpFile.Name()) _, err = tmpFile.WriteString(csvContent) assert.NoError(t, err, "Should write to temp file") tmpFile.Close() // Create test request router := gin.New() router.POST("/test", ImportSpellCSVHandler) req, err := http.NewRequest("POST", "/test?file="+tmpFile.Name(), nil) assert.NoError(t, err, "Should create request") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert response assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK") var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err, "Should parse JSON response") assert.True(t, response["success"].(bool), "Should indicate success") assert.Contains(t, response, "total_spells", "Should contain spell count") // Verify spell was imported var spell models.Spell err = spell.First("Test Spell HTTP") assert.NoError(t, err, "Should find imported spell") assert.Equal(t, 3, spell.Stufe, "Spell level should be 3") }) t.Run("Missing file parameter", func(t *testing.T) { router := gin.New() router.POST("/test", ImportSpellCSVHandler) req, err := http.NewRequest("POST", "/test", nil) assert.NoError(t, err, "Should create request") w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request") var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err, "Should parse JSON response") assert.Equal(t, "Missing file parameter", response["error"], "Should return correct error") }) t.Run("File not found", func(t *testing.T) { router := gin.New() router.POST("/test", ImportSpellCSVHandler) req, err := http.NewRequest("POST", "/test?file=/nonexistent/file.csv", nil) assert.NoError(t, err, "Should create request") w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request") var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err, "Should parse JSON response") assert.Equal(t, "File not found", response["error"], "Should return correct error") }) t.Run("Invalid file type", func(t *testing.T) { // Create temporary non-CSV file tmpFile, err := os.CreateTemp("", "test_*.txt") assert.NoError(t, err, "Should create temp file") defer os.Remove(tmpFile.Name()) tmpFile.Close() router := gin.New() router.POST("/test", ImportSpellCSVHandler) req, err := http.NewRequest("POST", "/test?file="+tmpFile.Name(), nil) assert.NoError(t, err, "Should create request") w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request") var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err, "Should parse JSON response") assert.Equal(t, "Invalid file type", response["error"], "Should return correct error") }) t.Run("File upload with multipart form", func(t *testing.T) { // Setup test database database.SetupTestDB(true, false) models.MigrateStructure() // Create test CSV content csvContent := `name,beschreibung,quelle,stufe,ap Test Spell Upload,Test description,ARK,1,2` // Create temporary file tmpFile, err := os.CreateTemp("", "test_spell_upload_*.csv") assert.NoError(t, err, "Should create temp file") defer os.Remove(tmpFile.Name()) _, err = tmpFile.WriteString(csvContent) assert.NoError(t, err, "Should write CSV content") tmpFile.Close() // Create multipart form data body := &bytes.Buffer{} writer := multipart.NewWriter(body) // Add file field file, err := os.Open(tmpFile.Name()) assert.NoError(t, err, "Should open temp file") defer file.Close() part, err := writer.CreateFormFile("file", "test_spells.csv") assert.NoError(t, err, "Should create form file") _, err = io.Copy(part, file) assert.NoError(t, err, "Should copy file content") err = writer.Close() assert.NoError(t, err, "Should close writer") // Create request router := gin.New() router.POST("/test", ImportSpellCSVHandler) req, err := http.NewRequest("POST", "/test", body) assert.NoError(t, err, "Should create request") req.Header.Set("Content-Type", writer.FormDataContentType()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK") var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err, "Should parse JSON response") assert.True(t, response["success"].(bool), "Should be successful") assert.Contains(t, response["message"], "imported successfully", "Should contain success message") // Verify spell was imported var spell models.Spell err = database.DB.Where("name = ?", "Test Spell Upload").First(&spell).Error assert.NoError(t, err, "Should find imported spell") assert.Equal(t, "Test description", spell.Beschreibung, "Should have correct description") }) }