package renderer import ( "testing" "gitea.dockr.co/kev/go-jdenticon/internal/engine" ) var benchmarkSizes = []int{ 16, 32, 64, 128, 256, 512, } var benchmarkColors = []string{ "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#800000", "#008000", "#000080", "#808000", "#800080", "#008080", "#c0c0c0", "#808080", "#000000", "#ffffff", } var benchmarkPoints = [][]engine.Point{ // Triangle {{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 0.5, Y: 1}}, // Square {{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 0, Y: 1}}, // Pentagon {{X: 0.5, Y: 0}, {X: 1, Y: 0.4}, {X: 0.8, Y: 1}, {X: 0.2, Y: 1}, {X: 0, Y: 0.4}}, // Hexagon {{X: 0.25, Y: 0}, {X: 0.75, Y: 0}, {X: 1, Y: 0.5}, {X: 0.75, Y: 1}, {X: 0.25, Y: 1}, {X: 0, Y: 0.5}}, } // Benchmark SVG renderer creation func BenchmarkNewSVGRenderer(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { size := benchmarkSizes[i%len(benchmarkSizes)] _ = NewSVGRenderer(size) } } // Benchmark SVG shape rendering func BenchmarkSVGAddPolygon(b *testing.B) { renderer := NewSVGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] points := benchmarkPoints[i%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } } // Benchmark SVG circle rendering func BenchmarkSVGAddCircle(b *testing.B) { renderer := NewSVGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] topLeft := engine.Point{X: 0.25, Y: 0.25} size := 0.5 renderer.BeginShape(color) renderer.AddCircle(topLeft, size, false) renderer.EndShape() } } // Benchmark SVG background setting func BenchmarkSVGSetBackground(b *testing.B) { renderer := NewSVGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] opacity := 0.8 renderer.SetBackground(color, opacity) } } // Benchmark complete SVG generation func BenchmarkSVGToSVG(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { size := benchmarkSizes[i%len(benchmarkSizes)] renderer := NewSVGRenderer(size) // Add some shapes renderer.SetBackground("#f0f0f0", 1.0) for j := 0; j < 3; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _ = renderer.ToSVG() } } // Benchmark PNG renderer creation func BenchmarkNewPNGRenderer(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { size := benchmarkSizes[i%len(benchmarkSizes)] _ = NewPNGRenderer(size) } } // Benchmark PNG shape rendering func BenchmarkPNGAddPolygon(b *testing.B) { renderer := NewPNGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] points := benchmarkPoints[i%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } } // Benchmark PNG circle rendering func BenchmarkPNGAddCircle(b *testing.B) { renderer := NewPNGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] topLeft := engine.Point{X: 0.25, Y: 0.25} size := 0.5 renderer.BeginShape(color) renderer.AddCircle(topLeft, size, false) renderer.EndShape() } } // Benchmark PNG background setting func BenchmarkPNGSetBackground(b *testing.B) { renderer := NewPNGRenderer(256) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { color := benchmarkColors[i%len(benchmarkColors)] opacity := 0.8 renderer.SetBackground(color, opacity) } } // Benchmark complete PNG generation func BenchmarkPNGToPNG(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { size := benchmarkSizes[i%len(benchmarkSizes)] renderer := NewPNGRenderer(size) // Add some shapes renderer.SetBackground("#f0f0f0", 1.0) for j := 0; j < 3; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _, err := renderer.ToPNG() if err != nil { b.Fatalf("ToPNG failed: %v", err) } } } // Benchmark PNG generation with different output sizes func BenchmarkPNGToPNGWithSize(b *testing.B) { renderer := NewPNGRenderer(128) // Add some test shapes renderer.SetBackground("#ffffff", 1.0) renderer.BeginShape("#ff0000") renderer.AddPolygon(benchmarkPoints[0]) renderer.EndShape() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { outputSize := benchmarkSizes[i%len(benchmarkSizes)] _, err := renderer.ToPNGWithSize(outputSize) if err != nil { b.Fatalf("ToPNGWithSize failed: %v", err) } } } // Benchmark complex shape rendering (many polygons) func BenchmarkComplexSVGRendering(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewSVGRenderer(256) renderer.SetBackground("#f8f8f8", 1.0) // Render many shapes to simulate complex icon for j := 0; j < 12; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _ = renderer.ToSVG() } } // Benchmark complex shape rendering (many polygons) for PNG func BenchmarkComplexPNGRendering(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewPNGRenderer(256) renderer.SetBackground("#f8f8f8", 1.0) // Render many shapes to simulate complex icon for j := 0; j < 12; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _, err := renderer.ToPNG() if err != nil { b.Fatalf("ToPNG failed: %v", err) } } } // Benchmark SVG vs PNG rendering comparison func BenchmarkSVGvsPNG64px(b *testing.B) { // Shared test data testShapes := []struct { color string points []engine.Point }{ {"#ff0000", benchmarkPoints[0]}, {"#00ff00", benchmarkPoints[1]}, {"#0000ff", benchmarkPoints[2]}, } b.Run("SVG", func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewSVGRenderer(64) renderer.SetBackground("#ffffff", 1.0) for _, shape := range testShapes { renderer.BeginShape(shape.color) renderer.AddPolygon(shape.points) renderer.EndShape() } _ = renderer.ToSVG() } }) b.Run("PNG", func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewPNGRenderer(64) renderer.SetBackground("#ffffff", 1.0) for _, shape := range testShapes { renderer.BeginShape(shape.color) renderer.AddPolygon(shape.points) renderer.EndShape() } _, err := renderer.ToPNG() if err != nil { b.Fatalf("ToPNG failed: %v", err) } } }) } // Benchmark memory allocation patterns func BenchmarkRendererMemoryPatterns(b *testing.B) { b.Run("SVGMemory", func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewSVGRenderer(128) // Allocate many small shapes to test memory patterns for j := 0; j < 20; j++ { renderer.BeginShape("#808080") renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)]) renderer.EndShape() } } }) b.Run("PNGMemory", func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { renderer := NewPNGRenderer(128) // Allocate many small shapes to test memory patterns for j := 0; j < 20; j++ { renderer.BeginShape("#808080") renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)]) renderer.EndShape() } } }) } // Benchmark concurrent rendering scenarios func BenchmarkRendererParallel(b *testing.B) { b.Run("SVGParallel", func(b *testing.B) { b.ReportAllocs() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { size := benchmarkSizes[i%len(benchmarkSizes)] renderer := NewSVGRenderer(size) renderer.SetBackground("#ffffff", 1.0) for j := 0; j < 3; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _ = renderer.ToSVG() i++ } }) }) b.Run("PNGParallel", func(b *testing.B) { b.ReportAllocs() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { size := benchmarkSizes[i%len(benchmarkSizes)] renderer := NewPNGRenderer(size) renderer.SetBackground("#ffffff", 1.0) for j := 0; j < 3; j++ { color := benchmarkColors[j%len(benchmarkColors)] points := benchmarkPoints[j%len(benchmarkPoints)] renderer.BeginShape(color) renderer.AddPolygon(points) renderer.EndShape() } _, err := renderer.ToPNG() if err != nil { b.Errorf("ToPNG failed: %v", err) } i++ } }) }) } // Benchmark shape rendering with different complexities func BenchmarkShapeComplexity(b *testing.B) { renderer := NewSVGRenderer(256) b.Run("Triangle", func(b *testing.B) { b.ReportAllocs() trianglePoints := benchmarkPoints[0] // Triangle for i := 0; i < b.N; i++ { renderer.BeginShape("#ff0000") renderer.AddPolygon(trianglePoints) renderer.EndShape() } }) b.Run("Square", func(b *testing.B) { b.ReportAllocs() squarePoints := benchmarkPoints[1] // Square for i := 0; i < b.N; i++ { renderer.BeginShape("#00ff00") renderer.AddPolygon(squarePoints) renderer.EndShape() } }) b.Run("Pentagon", func(b *testing.B) { b.ReportAllocs() pentagonPoints := benchmarkPoints[2] // Pentagon for i := 0; i < b.N; i++ { renderer.BeginShape("#0000ff") renderer.AddPolygon(pentagonPoints) renderer.EndShape() } }) b.Run("Hexagon", func(b *testing.B) { b.ReportAllocs() hexagonPoints := benchmarkPoints[3] // Hexagon for i := 0; i < b.N; i++ { renderer.BeginShape("#ffff00") renderer.AddPolygon(hexagonPoints) renderer.EndShape() } }) }