Some checks failed
CI / Test (Go 1.24.x, ubuntu-latest) (push) Successful in 1m53s
CI / Code Quality (push) Failing after 26s
CI / Security Scan (push) Failing after 11s
CI / Test Coverage (push) Successful in 1m13s
CI / Benchmarks (push) Failing after 10m22s
CI / Build CLI (push) Failing after 8s
Benchmarks / Run Benchmarks (push) Failing after 10m13s
Release / Test (push) Successful in 55s
Release / Build (amd64, darwin, ) (push) Failing after 12s
Release / Build (amd64, linux, ) (push) Failing after 6s
Release / Build (amd64, windows, .exe) (push) Failing after 12s
Release / Build (arm64, darwin, ) (push) Failing after 12s
Release / Build (arm64, linux, ) (push) Failing after 12s
Release / Release (push) Has been skipped
CI / Test (Go 1.24.x, macos-latest) (push) Has been cancelled
CI / Test (Go 1.24.x, windows-latest) (push) Has been cancelled
Move hosting from GitHub to private Gitea instance.
242 lines
5.6 KiB
Go
242 lines
5.6 KiB
Go
package renderer
|
|
|
|
import (
|
|
"bytes"
|
|
"image/png"
|
|
"testing"
|
|
|
|
"gitea.dockr.co/kev/go-jdenticon/internal/engine"
|
|
)
|
|
|
|
func TestNewPNGRenderer(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
|
|
if renderer.GetSize() != 100 {
|
|
t.Errorf("NewPNGRenderer(100).GetSize() = %v, want 100", renderer.GetSize())
|
|
}
|
|
|
|
if renderer == nil {
|
|
t.Error("PNGRenderer should be initialized")
|
|
}
|
|
}
|
|
|
|
func TestPNGRenderer_SetBackground(t *testing.T) {
|
|
renderer := NewPNGRenderer(50)
|
|
|
|
renderer.SetBackground("#ff0000", 1.0)
|
|
|
|
// Check that background was set on base renderer
|
|
bg, op := renderer.GetBackground()
|
|
if bg != "#ff0000" {
|
|
t.Errorf("background color = %v, want #ff0000", bg)
|
|
}
|
|
if op != 1.0 {
|
|
t.Errorf("background opacity = %v, want 1.0", op)
|
|
}
|
|
}
|
|
|
|
func TestPNGRenderer_SetBackgroundWithOpacity(t *testing.T) {
|
|
renderer := NewPNGRenderer(50)
|
|
|
|
renderer.SetBackground("#00ff00", 0.5)
|
|
|
|
bg, op := renderer.GetBackground()
|
|
if bg != "#00ff00" {
|
|
t.Errorf("background color = %v, want #00ff00", bg)
|
|
}
|
|
if op != 0.5 {
|
|
t.Errorf("background opacity = %v, want 0.5", op)
|
|
}
|
|
}
|
|
|
|
func TestPNGRenderer_BeginEndShape(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
|
|
renderer.BeginShape("#0000ff")
|
|
|
|
// Check that current color was set
|
|
if renderer.GetCurrentColor() != "#0000ff" {
|
|
t.Errorf("currentColor = %v, want #0000ff", renderer.GetCurrentColor())
|
|
}
|
|
|
|
renderer.EndShape()
|
|
// EndShape is a no-op for PNG, just verify it doesn't panic
|
|
}
|
|
|
|
func TestPNGRenderer_AddPolygon(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
renderer.BeginShape("#ff0000")
|
|
|
|
// Create a simple triangle
|
|
points := []engine.Point{
|
|
{X: 10, Y: 10},
|
|
{X: 30, Y: 10},
|
|
{X: 20, Y: 30},
|
|
}
|
|
|
|
// Should not panic
|
|
renderer.AddPolygon(points)
|
|
}
|
|
|
|
func TestPNGRenderer_AddPolygonEmpty(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
renderer.BeginShape("#ff0000")
|
|
|
|
// Empty polygon should not panic
|
|
renderer.AddPolygon([]engine.Point{})
|
|
|
|
// Polygon with < 3 points should not panic
|
|
renderer.AddPolygon([]engine.Point{{X: 10, Y: 10}})
|
|
renderer.AddPolygon([]engine.Point{{X: 10, Y: 10}, {X: 20, Y: 20}})
|
|
}
|
|
|
|
func TestPNGRenderer_AddCircle(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
renderer.BeginShape("#00ff00")
|
|
|
|
// Circle with center at (50, 50) and radius 20 means topLeft at (30, 30) and size 40
|
|
topLeft := engine.Point{X: 30, Y: 30}
|
|
size := 40.0
|
|
|
|
// Should not panic
|
|
renderer.AddCircle(topLeft, size, false)
|
|
}
|
|
|
|
func TestPNGRenderer_AddCircleInvert(t *testing.T) {
|
|
renderer := NewPNGRenderer(100)
|
|
|
|
// First fill with background
|
|
renderer.SetBackground("#ffffff", 1.0)
|
|
renderer.BeginShape("#ff0000")
|
|
|
|
// Add inverted circle (should not panic)
|
|
topLeft := engine.Point{X: 30, Y: 30}
|
|
size := 40.0
|
|
|
|
renderer.AddCircle(topLeft, size, true)
|
|
}
|
|
|
|
func TestPNGRenderer_ToPNG(t *testing.T) {
|
|
renderer := NewPNGRenderer(50)
|
|
renderer.SetBackground("#ffffff", 1.0)
|
|
|
|
renderer.BeginShape("#ff0000")
|
|
points := []engine.Point{
|
|
{X: 10, Y: 10},
|
|
{X: 40, Y: 10},
|
|
{X: 40, Y: 40},
|
|
{X: 10, Y: 40},
|
|
}
|
|
renderer.AddPolygon(points)
|
|
|
|
pngData, err := renderer.ToPNG()
|
|
if err != nil {
|
|
t.Fatalf("Failed to generate PNG: %v", err)
|
|
}
|
|
|
|
if len(pngData) == 0 {
|
|
t.Error("ToPNG() should return non-empty data")
|
|
}
|
|
|
|
// Verify it's valid PNG data by decoding it
|
|
reader := bytes.NewReader(pngData)
|
|
decodedImg, err := png.Decode(reader)
|
|
if err != nil {
|
|
t.Errorf("ToPNG() returned invalid PNG data: %v", err)
|
|
}
|
|
|
|
// Check dimensions
|
|
bounds := decodedImg.Bounds()
|
|
if bounds.Max.X != 50 || bounds.Max.Y != 50 {
|
|
t.Errorf("decoded image bounds = %v, want 50x50", bounds)
|
|
}
|
|
}
|
|
|
|
func TestPNGRenderer_ToPNGWithSize(t *testing.T) {
|
|
renderer := NewPNGRenderer(50)
|
|
renderer.SetBackground("#ffffff", 1.0)
|
|
|
|
renderer.BeginShape("#ff0000")
|
|
points := []engine.Point{
|
|
{X: 10, Y: 10},
|
|
{X: 40, Y: 10},
|
|
{X: 40, Y: 40},
|
|
{X: 10, Y: 40},
|
|
}
|
|
renderer.AddPolygon(points)
|
|
|
|
// Test generating at different size
|
|
pngData, err := renderer.ToPNGWithSize(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to generate PNG with size: %v", err)
|
|
}
|
|
|
|
if len(pngData) == 0 {
|
|
t.Error("ToPNGWithSize() should return non-empty data")
|
|
}
|
|
|
|
// Verify it's valid PNG data by decoding it
|
|
reader := bytes.NewReader(pngData)
|
|
decodedImg, err := png.Decode(reader)
|
|
if err != nil {
|
|
t.Errorf("ToPNGWithSize() returned invalid PNG data: %v", err)
|
|
}
|
|
|
|
// Check dimensions - should be 100x100 instead of 50x50
|
|
bounds := decodedImg.Bounds()
|
|
if bounds.Max.X != 100 || bounds.Max.Y != 100 {
|
|
t.Errorf("decoded image bounds = %v, want 100x100", bounds)
|
|
}
|
|
}
|
|
|
|
func TestPNGRenderer_ToPNGEmpty(t *testing.T) {
|
|
renderer := NewPNGRenderer(10)
|
|
|
|
pngData, err := renderer.ToPNG()
|
|
if err != nil {
|
|
t.Fatalf("Failed to generate PNG: %v", err)
|
|
}
|
|
|
|
if len(pngData) == 0 {
|
|
t.Error("ToPNG() should return data even for empty image")
|
|
}
|
|
|
|
// Should be valid PNG
|
|
reader := bytes.NewReader(pngData)
|
|
decodedImg, err := png.Decode(reader)
|
|
if err != nil {
|
|
t.Errorf("ToPNG() returned invalid PNG data: %v", err)
|
|
}
|
|
|
|
// Check dimensions
|
|
bounds := decodedImg.Bounds()
|
|
if bounds.Max.X != 10 || bounds.Max.Y != 10 {
|
|
t.Errorf("decoded image bounds = %v, want 10x10", bounds)
|
|
}
|
|
}
|
|
|
|
func BenchmarkPNGRenderer_ToPNG(b *testing.B) {
|
|
renderer := NewPNGRenderer(200)
|
|
renderer.SetBackground("#ffffff", 1.0)
|
|
|
|
// Add some shapes for a realistic benchmark
|
|
renderer.BeginShape("#ff0000")
|
|
renderer.AddPolygon([]engine.Point{
|
|
{X: 20, Y: 20}, {X: 80, Y: 20}, {X: 80, Y: 80}, {X: 20, Y: 80},
|
|
})
|
|
|
|
renderer.BeginShape("#00ff00")
|
|
renderer.AddCircle(engine.Point{X: 100, Y: 100}, 30, false)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
pngData, err := renderer.ToPNG()
|
|
if err != nil {
|
|
b.Fatalf("Failed to generate PNG: %v", err)
|
|
}
|
|
if len(pngData) == 0 {
|
|
b.Fatal("ToPNG returned empty data")
|
|
}
|
|
}
|
|
}
|