Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
This commit is contained in:
@@ -3,7 +3,7 @@ package renderer
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kevin/go-jdenticon/internal/engine"
|
||||
"github.com/ungluedlabs/go-jdenticon/internal/engine"
|
||||
)
|
||||
|
||||
func TestNewBaseRenderer(t *testing.T) {
|
||||
@@ -30,12 +30,12 @@ func TestNewBaseRenderer(t *testing.T) {
|
||||
|
||||
func TestBaseRendererSetBackground(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
color := "#ff0000"
|
||||
opacity := 0.5
|
||||
|
||||
|
||||
r.SetBackground(color, opacity)
|
||||
|
||||
|
||||
bg, bgOp := r.GetBackground()
|
||||
if bg != color {
|
||||
t.Errorf("Expected background color %s, got %s", color, bg)
|
||||
@@ -47,14 +47,14 @@ func TestBaseRendererSetBackground(t *testing.T) {
|
||||
|
||||
func TestBaseRendererBeginShape(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
color := "#00ff00"
|
||||
r.BeginShape(color)
|
||||
|
||||
|
||||
if r.GetCurrentColor() != color {
|
||||
t.Errorf("Expected current color %s, got %s", color, r.GetCurrentColor())
|
||||
}
|
||||
|
||||
|
||||
// Path should be reset when beginning a shape
|
||||
if len(r.GetCurrentPath()) != 0 {
|
||||
t.Errorf("Expected empty path after BeginShape, got %d commands", len(r.GetCurrentPath()))
|
||||
@@ -63,24 +63,24 @@ func TestBaseRendererBeginShape(t *testing.T) {
|
||||
|
||||
func TestBaseRendererMoveTo(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
x, y := 10.5, 20.3
|
||||
r.MoveTo(x, y)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
if len(path) != 1 {
|
||||
t.Fatalf("Expected 1 path command, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
cmd := path[0]
|
||||
if cmd.Type != MoveToCommand {
|
||||
t.Errorf("Expected MoveToCommand, got %v", cmd.Type)
|
||||
}
|
||||
|
||||
|
||||
if len(cmd.Points) != 1 {
|
||||
t.Fatalf("Expected 1 point, got %d", len(cmd.Points))
|
||||
}
|
||||
|
||||
|
||||
point := cmd.Points[0]
|
||||
if point.X != x || point.Y != y {
|
||||
t.Errorf("Expected point (%f, %f), got (%f, %f)", x, y, point.X, point.Y)
|
||||
@@ -89,27 +89,27 @@ func TestBaseRendererMoveTo(t *testing.T) {
|
||||
|
||||
func TestBaseRendererLineTo(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
// Move to start point first
|
||||
r.MoveTo(0, 0)
|
||||
|
||||
|
||||
x, y := 15.7, 25.9
|
||||
r.LineTo(x, y)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
if len(path) != 2 {
|
||||
t.Fatalf("Expected 2 path commands, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
cmd := path[1] // Second command should be LineTo
|
||||
if cmd.Type != LineToCommand {
|
||||
t.Errorf("Expected LineToCommand, got %v", cmd.Type)
|
||||
}
|
||||
|
||||
|
||||
if len(cmd.Points) != 1 {
|
||||
t.Fatalf("Expected 1 point, got %d", len(cmd.Points))
|
||||
}
|
||||
|
||||
|
||||
point := cmd.Points[0]
|
||||
if point.X != x || point.Y != y {
|
||||
t.Errorf("Expected point (%f, %f), got (%f, %f)", x, y, point.X, point.Y)
|
||||
@@ -118,30 +118,30 @@ func TestBaseRendererLineTo(t *testing.T) {
|
||||
|
||||
func TestBaseRendererCurveTo(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
// Move to start point first
|
||||
r.MoveTo(0, 0)
|
||||
|
||||
|
||||
x1, y1 := 10.0, 5.0
|
||||
x2, y2 := 20.0, 15.0
|
||||
x, y := 30.0, 25.0
|
||||
|
||||
|
||||
r.CurveTo(x1, y1, x2, y2, x, y)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
if len(path) != 2 {
|
||||
t.Fatalf("Expected 2 path commands, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
cmd := path[1] // Second command should be CurveTo
|
||||
if cmd.Type != CurveToCommand {
|
||||
t.Errorf("Expected CurveToCommand, got %v", cmd.Type)
|
||||
}
|
||||
|
||||
|
||||
if len(cmd.Points) != 3 {
|
||||
t.Fatalf("Expected 3 points, got %d", len(cmd.Points))
|
||||
}
|
||||
|
||||
|
||||
// Check control points and end point
|
||||
if cmd.Points[0].X != x1 || cmd.Points[0].Y != y1 {
|
||||
t.Errorf("Expected first control point (%f, %f), got (%f, %f)", x1, y1, cmd.Points[0].X, cmd.Points[0].Y)
|
||||
@@ -156,22 +156,22 @@ func TestBaseRendererCurveTo(t *testing.T) {
|
||||
|
||||
func TestBaseRendererClosePath(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
// Move to start point first
|
||||
r.MoveTo(0, 0)
|
||||
r.LineTo(10, 10)
|
||||
r.ClosePath()
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
if len(path) != 3 {
|
||||
t.Fatalf("Expected 3 path commands, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
cmd := path[2] // Third command should be ClosePath
|
||||
if cmd.Type != ClosePathCommand {
|
||||
t.Errorf("Expected ClosePathCommand, got %v", cmd.Type)
|
||||
}
|
||||
|
||||
|
||||
if len(cmd.Points) != 0 {
|
||||
t.Errorf("Expected 0 points for ClosePath, got %d", len(cmd.Points))
|
||||
}
|
||||
@@ -180,29 +180,29 @@ func TestBaseRendererClosePath(t *testing.T) {
|
||||
func TestBaseRendererAddPolygon(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
r.BeginShape("#ff0000")
|
||||
|
||||
|
||||
points := []engine.Point{
|
||||
{X: 0, Y: 0},
|
||||
{X: 10, Y: 0},
|
||||
{X: 10, Y: 10},
|
||||
{X: 0, Y: 10},
|
||||
}
|
||||
|
||||
|
||||
r.AddPolygon(points)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
|
||||
|
||||
// Should have MoveTo + 3 LineTo + ClosePath = 5 commands
|
||||
expectedCommands := len(points) + 1 // +1 for ClosePath
|
||||
if len(path) != expectedCommands {
|
||||
t.Fatalf("Expected %d path commands, got %d", expectedCommands, len(path))
|
||||
}
|
||||
|
||||
|
||||
// Check first command is MoveTo
|
||||
if path[0].Type != MoveToCommand {
|
||||
t.Errorf("Expected first command to be MoveTo, got %v", path[0].Type)
|
||||
}
|
||||
|
||||
|
||||
// Check last command is ClosePath
|
||||
if path[len(path)-1].Type != ClosePathCommand {
|
||||
t.Errorf("Expected last command to be ClosePath, got %v", path[len(path)-1].Type)
|
||||
@@ -212,30 +212,30 @@ func TestBaseRendererAddPolygon(t *testing.T) {
|
||||
func TestBaseRendererAddRectangle(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
r.BeginShape("#0000ff")
|
||||
|
||||
|
||||
x, y, width, height := 5.0, 10.0, 20.0, 15.0
|
||||
r.AddRectangle(x, y, width, height)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
|
||||
|
||||
// Should have MoveTo + 3 LineTo + ClosePath = 5 commands
|
||||
if len(path) != 5 {
|
||||
t.Fatalf("Expected 5 path commands, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
// Verify the rectangle points
|
||||
expectedPoints := []engine.Point{
|
||||
{X: x, Y: y}, // bottom-left
|
||||
{X: x + width, Y: y}, // bottom-right
|
||||
{X: x + width, Y: y + height}, // top-right
|
||||
{X: x, Y: y + height}, // top-left
|
||||
{X: x, Y: y}, // bottom-left
|
||||
{X: x + width, Y: y}, // bottom-right
|
||||
{X: x + width, Y: y + height}, // top-right
|
||||
{X: x, Y: y + height}, // top-left
|
||||
}
|
||||
|
||||
|
||||
// Check MoveTo point
|
||||
if path[0].Points[0] != expectedPoints[0] {
|
||||
t.Errorf("Expected first point %v, got %v", expectedPoints[0], path[0].Points[0])
|
||||
}
|
||||
|
||||
|
||||
// Check LineTo points
|
||||
for i := 1; i < 4; i++ {
|
||||
if path[i].Type != LineToCommand {
|
||||
@@ -250,20 +250,20 @@ func TestBaseRendererAddRectangle(t *testing.T) {
|
||||
func TestBaseRendererAddTriangle(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
r.BeginShape("#00ffff")
|
||||
|
||||
|
||||
p1 := engine.Point{X: 0, Y: 0}
|
||||
p2 := engine.Point{X: 10, Y: 0}
|
||||
p3 := engine.Point{X: 5, Y: 10}
|
||||
|
||||
|
||||
r.AddTriangle(p1, p2, p3)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
|
||||
|
||||
// Should have MoveTo + 2 LineTo + ClosePath = 4 commands
|
||||
if len(path) != 4 {
|
||||
t.Fatalf("Expected 4 path commands, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
// Check the triangle points
|
||||
if path[0].Points[0] != p1 {
|
||||
t.Errorf("Expected first point %v, got %v", p1, path[0].Points[0])
|
||||
@@ -279,24 +279,24 @@ func TestBaseRendererAddTriangle(t *testing.T) {
|
||||
func TestBaseRendererAddCircle(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
r.BeginShape("#ffff00")
|
||||
|
||||
|
||||
center := engine.Point{X: 50, Y: 50}
|
||||
radius := 25.0
|
||||
|
||||
|
||||
r.AddCircle(center, radius, false)
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
|
||||
|
||||
// Should have MoveTo + 4 CurveTo + ClosePath = 6 commands
|
||||
if len(path) != 6 {
|
||||
t.Fatalf("Expected 6 path commands for circle, got %d", len(path))
|
||||
}
|
||||
|
||||
|
||||
// Check first command is MoveTo
|
||||
if path[0].Type != MoveToCommand {
|
||||
t.Errorf("Expected first command to be MoveTo, got %v", path[0].Type)
|
||||
}
|
||||
|
||||
|
||||
// Check that we have 4 CurveTo commands
|
||||
curveCount := 0
|
||||
for i := 1; i < len(path)-1; i++ {
|
||||
@@ -307,7 +307,7 @@ func TestBaseRendererAddCircle(t *testing.T) {
|
||||
if curveCount != 4 {
|
||||
t.Errorf("Expected 4 CurveTo commands for circle, got %d", curveCount)
|
||||
}
|
||||
|
||||
|
||||
// Check last command is ClosePath
|
||||
if path[len(path)-1].Type != ClosePathCommand {
|
||||
t.Errorf("Expected last command to be ClosePath, got %v", path[len(path)-1].Type)
|
||||
@@ -316,13 +316,13 @@ func TestBaseRendererAddCircle(t *testing.T) {
|
||||
|
||||
func TestBaseRendererClear(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
|
||||
|
||||
// Set some state
|
||||
r.BeginShape("#ff0000")
|
||||
r.SetBackground("#ffffff", 0.8)
|
||||
r.MoveTo(10, 20)
|
||||
r.LineTo(30, 40)
|
||||
|
||||
|
||||
// Verify state is set
|
||||
if r.GetCurrentColor() == "" {
|
||||
t.Error("Expected current color to be set before clear")
|
||||
@@ -330,10 +330,10 @@ func TestBaseRendererClear(t *testing.T) {
|
||||
if len(r.GetCurrentPath()) == 0 {
|
||||
t.Error("Expected path commands before clear")
|
||||
}
|
||||
|
||||
|
||||
// Clear the renderer
|
||||
r.Clear()
|
||||
|
||||
|
||||
// Verify state is cleared
|
||||
if r.GetCurrentColor() != "" {
|
||||
t.Errorf("Expected empty current color after clear, got %s", r.GetCurrentColor())
|
||||
@@ -341,7 +341,7 @@ func TestBaseRendererClear(t *testing.T) {
|
||||
if len(r.GetCurrentPath()) != 0 {
|
||||
t.Errorf("Expected empty path after clear, got %d commands", len(r.GetCurrentPath()))
|
||||
}
|
||||
|
||||
|
||||
bg, bgOp := r.GetBackground()
|
||||
if bg != "" || bgOp != 0 {
|
||||
t.Errorf("Expected empty background after clear, got %s with opacity %f", bg, bgOp)
|
||||
@@ -351,12 +351,12 @@ func TestBaseRendererClear(t *testing.T) {
|
||||
func TestBaseRendererEmptyPolygon(t *testing.T) {
|
||||
r := NewBaseRenderer(100)
|
||||
r.BeginShape("#ff0000")
|
||||
|
||||
|
||||
// Test with empty points slice
|
||||
r.AddPolygon([]engine.Point{})
|
||||
|
||||
|
||||
path := r.GetCurrentPath()
|
||||
if len(path) != 0 {
|
||||
t.Errorf("Expected no path commands for empty polygon, got %d", len(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user