diff --git a/backend/pdfrender/api_comparison_test.go b/backend/pdfrender/api_comparison_test.go new file mode 100644 index 0000000..efe5fee --- /dev/null +++ b/backend/pdfrender/api_comparison_test.go @@ -0,0 +1,141 @@ +package pdfrender + +import ( + "bamort/config" + "bamort/database" + "bamort/models" + "bytes" + "os" + "path/filepath" + "testing" + + "github.com/pdfcpu/pdfcpu/pkg/api" +) + +// TestAPIvsTestOutput_ShouldBeIdentical verifies that the API handler and test produce identical PDFs +func TestAPIvsTestOutput_ShouldBeIdentical(t *testing.T) { + database.SetupTestDB() + + // Load character with ID 18 (same as visual inspection test) + char := &models.Char{} + err := char.FirstID("18") + if err != nil { + t.Fatalf("Failed to load character: %v", err) + } + + // === PATH 1: Test method (current working) === + viewModel1, err := MapCharacterToViewModel(char) + if err != nil { + t.Fatalf("Failed to map character (test path): %v", err) + } + + loader1 := NewTemplateLoader("../templates/Default_A4_Quer") + if err := loader1.LoadTemplates(); err != nil { + t.Fatalf("Failed to load templates (test path): %v", err) + } + + renderer1 := NewPDFRenderer() + testDate := "28.12.2025" + + var testPDFs [][]byte + page1PDFs, _ := RenderPageWithContinuations(viewModel1, "page_1.html", 1, testDate, loader1, renderer1) + testPDFs = append(testPDFs, page1PDFs...) + page2PDFs, _ := RenderPageWithContinuations(viewModel1, "page_2.html", 2, testDate, loader1, renderer1) + testPDFs = append(testPDFs, page2PDFs...) + page3PDFs, _ := RenderPageWithContinuations(viewModel1, "page_3.html", 3, testDate, loader1, renderer1) + testPDFs = append(testPDFs, page3PDFs...) + page4PDFs, _ := RenderPageWithContinuations(viewModel1, "page_4.html", 4, testDate, loader1, renderer1) + testPDFs = append(testPDFs, page4PDFs...) + + // === PATH 2: API handler method === + viewModel2, err := MapCharacterToViewModel(char) + if err != nil { + t.Fatalf("Failed to map character (API path): %v", err) + } + + // Use same template resolution as API handler + templateID := "Default_A4_Quer" + templateDir := filepath.Join(config.Cfg.TemplatesDir, templateID) + t.Logf("API template dir: %s", templateDir) + + loader2 := NewTemplateLoader(templateDir) + if err := loader2.LoadTemplates(); err != nil { + t.Fatalf("Failed to load templates (API path): %v", err) + } + + renderer2 := NewPDFRenderer() + currentDate := testDate // Use same date as test for exact comparison + t.Logf("Using date: %s", currentDate) + + var apiPDFs [][]byte + page1PDFs, _ = RenderPageWithContinuations(viewModel2, "page_1.html", 1, currentDate, loader2, renderer2) + apiPDFs = append(apiPDFs, page1PDFs...) + page2PDFs, _ = RenderPageWithContinuations(viewModel2, "page_2.html", 2, currentDate, loader2, renderer2) + apiPDFs = append(apiPDFs, page2PDFs...) + page3PDFs, _ = RenderPageWithContinuations(viewModel2, "page_3.html", 3, currentDate, loader2, renderer2) + apiPDFs = append(apiPDFs, page3PDFs...) + page4PDFs, _ = RenderPageWithContinuations(viewModel2, "page_4.html", 4, currentDate, loader2, renderer2) + apiPDFs = append(apiPDFs, page4PDFs...) + + // === COMPARISON === + if len(testPDFs) != len(apiPDFs) { + t.Fatalf("Different number of PDFs: test=%d, api=%d", len(testPDFs), len(apiPDFs)) + } + + t.Logf("Both methods generated %d page PDFs", len(testPDFs)) + + // Merge both for final comparison + tmpDir1 := "/tmp/bamort_test_compare" + tmpDir2 := "/tmp/bamort_api_compare" + os.MkdirAll(tmpDir1, 0755) + os.MkdirAll(tmpDir2, 0755) + defer os.RemoveAll(tmpDir1) + defer os.RemoveAll(tmpDir2) + + // Save and merge test PDFs + var testPaths []string + for i, pdf := range testPDFs { + path := filepath.Join(tmpDir1, "page_"+string(rune('0'+i))+".pdf") + os.WriteFile(path, pdf, 0644) + testPaths = append(testPaths, path) + } + testMerged := filepath.Join(tmpDir1, "merged.pdf") + api.MergeCreateFile(testPaths, testMerged, false, nil) + + // Save and merge API PDFs + var apiPaths []string + for i, pdf := range apiPDFs { + path := filepath.Join(tmpDir2, "page_"+string(rune('0'+i))+".pdf") + os.WriteFile(path, pdf, 0644) + apiPaths = append(apiPaths, path) + } + apiMerged := filepath.Join(tmpDir2, "merged.pdf") + api.MergeCreateFile(apiPaths, apiMerged, false, nil) + + // Read merged PDFs + testBytes, _ := os.ReadFile(testMerged) + apiBytes, _ := os.ReadFile(apiMerged) + + t.Logf("Test PDF size: %d bytes", len(testBytes)) + t.Logf("API PDF size: %d bytes", len(apiBytes)) + + // Check if identical (excluding date metadata) + if bytes.Equal(testBytes, apiBytes) { + t.Log("✓ PDFs are byte-identical") + } else { + // Save for manual inspection + os.WriteFile("/tmp/test_output.pdf", testBytes, 0644) + os.WriteFile("/tmp/api_output.pdf", apiBytes, 0644) + t.Logf("PDFs differ - saved to /tmp/test_output.pdf and /tmp/api_output.pdf for comparison") + t.Log("Note: Difference might be due to date stamps - checking individual pages...") + + // Compare individual pages + for i := 0; i < len(testPDFs); i++ { + if bytes.Equal(testPDFs[i], apiPDFs[i]) { + t.Logf(" Page %d: identical", i+1) + } else { + t.Logf(" Page %d: DIFFERENT (test=%d bytes, api=%d bytes)", i+1, len(testPDFs[i]), len(apiPDFs[i])) + } + } + } +} diff --git a/backend/pdfrender/handlers.go b/backend/pdfrender/handlers.go index 0954f85..73e4151 100644 --- a/backend/pdfrender/handlers.go +++ b/backend/pdfrender/handlers.go @@ -87,7 +87,7 @@ func ExportCharacterToPDF(c *gin.Context) { renderer := NewPDFRenderer() currentDate := time.Now().Format("02.01.2006") - // Render all 4 pages with continuations + // Generate all pages with continuations if needed var allPDFs [][]byte // Page 1: Stats @@ -96,7 +96,10 @@ func ExportCharacterToPDF(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render page 1: " + err.Error()}) return } - allPDFs = append(allPDFs, page1PDFs...) + //allPDFs = append(allPDFs, page1PDFs...) + for _, pdf := range page1PDFs { + allPDFs = append(allPDFs, pdf) + } // Page 2: Play page2PDFs, err := RenderPageWithContinuations(viewModel, "page_2.html", 2, currentDate, loader, renderer) @@ -104,7 +107,10 @@ func ExportCharacterToPDF(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render page 2: " + err.Error()}) return } - allPDFs = append(allPDFs, page2PDFs...) + //allPDFs = append(allPDFs, page2PDFs...) + for _, pdf := range page2PDFs { + allPDFs = append(allPDFs, pdf) + } // Page 3: Spells page3PDFs, err := RenderPageWithContinuations(viewModel, "page_3.html", 3, currentDate, loader, renderer) @@ -112,7 +118,10 @@ func ExportCharacterToPDF(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render page 3: " + err.Error()}) return } - allPDFs = append(allPDFs, page3PDFs...) + //allPDFs = append(allPDFs, page3PDFs...) + for _, pdf := range page3PDFs { + allPDFs = append(allPDFs, pdf) + } // Page 4: Equipment page4PDFs, err := RenderPageWithContinuations(viewModel, "page_4.html", 4, currentDate, loader, renderer) @@ -120,7 +129,10 @@ func ExportCharacterToPDF(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render page 4: " + err.Error()}) return } - allPDFs = append(allPDFs, page4PDFs...) + //allPDFs = append(allPDFs, page4PDFs...) + for _, pdf := range page4PDFs { + allPDFs = append(allPDFs, pdf) + } // Merge PDFs if needed var finalPDF []byte @@ -128,7 +140,7 @@ func ExportCharacterToPDF(c *gin.Context) { finalPDF = allPDFs[0] } else { // Merge multiple PDFs - tmpDir := "/tmp/bamort_pdf_export" + tmpDir := fmt.Sprintf("/tmp/bamort_pdf_export_%d", time.Now().UnixNano()) if err := os.MkdirAll(tmpDir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create temp directory"}) return @@ -147,7 +159,7 @@ func ExportCharacterToPDF(c *gin.Context) { } // Merge PDFs - combinedPath := fmt.Sprintf("%s/combined.pdf", tmpDir) + combinedPath := fmt.Sprintf("%s/combined_%d.pdf", tmpDir, time.Now().UnixNano()) if err := api.MergeCreateFile(filePaths, combinedPath, false, nil); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to merge PDFs: " + err.Error()}) return diff --git a/backend/pdfrender/integration_test.go b/backend/pdfrender/integration_test.go index de96c01..bddeb53 100644 --- a/backend/pdfrender/integration_test.go +++ b/backend/pdfrender/integration_test.go @@ -1,6 +1,7 @@ package pdfrender import ( + "bamort/config" "bamort/database" "bamort/models" "fmt" @@ -8,6 +9,7 @@ import ( "path/filepath" "strings" "testing" + "time" "github.com/pdfcpu/pdfcpu/pkg/api" ) @@ -519,10 +521,10 @@ func TestVisualInspection_AllPages(t *testing.T) { database.SetupTestDB() // Load character Fanjo Vetrani with ID 18 from test database + charID := "18" char := &models.Char{} - err := char.FirstID("18") - if err != nil { - t.Fatalf("Failed to load character with ID 18 (Fanjo Vetrani): %v", err) + if err := char.FirstID(charID); err != nil { + t.Fatalf("Failed to load character with ID %s (Fanjo Vetrani): %v", charID, err) } // Verify we loaded the correct character @@ -537,25 +539,32 @@ func TestVisualInspection_AllPages(t *testing.T) { t.Fatalf("Failed to map character: %v", err) } + templateID := "Default_A4_Quer" // Load templates - loader := NewTemplateLoader("../templates/Default_A4_Quer") - if err = loader.LoadTemplates(); err != nil { + templateDir := filepath.Join(config.Cfg.TemplatesDir, templateID) + + // Load templates + loader := NewTemplateLoader(templateDir) + if err := loader.LoadTemplates(); err != nil { t.Fatalf("Failed to load templates: %v", err) } renderer := NewPDFRenderer() + currentDate := time.Now().Format("02.01.2006") // Generate all pages with continuations if needed - allPDFs := [][]byte{} + var allPDFs [][]byte + //##################################### var filePaths []string outputDir := "/tmp/bamort_pdf_test" if err := os.MkdirAll(outputDir, 0755); err != nil { t.Fatalf("Failed to create output directory: %v", err) } + //##################################### // Page 1: Stats page with skills (may have continuations) t.Log("Generating Page 1: Stats...") - page1PDFs, err := RenderPageWithContinuations(viewModel, "page_1.html", 1, "18.12.2025", loader, renderer) + page1PDFs, err := RenderPageWithContinuations(viewModel, "page_1.html", 1, currentDate, loader, renderer) if err != nil { t.Fatalf("Failed to generate page1: %v", err) } @@ -580,7 +589,7 @@ func TestVisualInspection_AllPages(t *testing.T) { // Page 2: Play/Adventure page with weapons (may have continuations) t.Log("Generating Page 2: Play...") - page2PDFs, err := RenderPageWithContinuations(viewModel, "page_2.html", 2, "18.12.2025", loader, renderer) + page2PDFs, err := RenderPageWithContinuations(viewModel, "page_2.html", 2, currentDate, loader, renderer) if err != nil { t.Fatalf("Failed to generate page2: %v", err) } @@ -605,7 +614,7 @@ func TestVisualInspection_AllPages(t *testing.T) { // Page 3: Spells page (may have continuations) t.Log("Generating Page 3: Spells...") - page3PDFs, err := RenderPageWithContinuations(viewModel, "page_3.html", 3, "18.12.2025", loader, renderer) + page3PDFs, err := RenderPageWithContinuations(viewModel, "page_3.html", 3, currentDate, loader, renderer) if err != nil { t.Fatalf("Failed to generate page3: %v", err) }