package gg import ( "crypto/md5" "flag" "fmt" "image/color" "math/rand" "testing" ) var save bool func init() { flag.BoolVar(&save, "save", false, "save PNG output for each test case") flag.Parse() } func hash(dc *Context) string { return fmt.Sprintf("%x", md5.Sum(dc.im.Pix)) } func checkHash(t *testing.T, dc *Context, expected string) { actual := hash(dc) if actual != expected { t.Fatalf("expected hash: %s != actual hash: %s", expected, actual) } } func saveImage(dc *Context, name string) error { if save { return SavePNG(name+".png", dc.Image()) } return nil } func TestBlank(t *testing.T) { dc := NewContext(100, 100) saveImage(dc, "TestBlank") checkHash(t, dc, "4e0a293a5b638f0aba2c4fe2c3418d0e") } func TestGrid(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() for i := 10; i < 100; i += 10 { x := float64(i) + 0.5 dc.DrawLine(x, 0, x, 100) dc.DrawLine(0, x, 100, x) } dc.SetRGB(0, 0, 0) dc.Stroke() saveImage(dc, "TestGrid") checkHash(t, dc, "78606adda71d8abfbd8bb271087e4d69") } func TestLines(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(0.5, 0.5, 0.5) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 100; i++ { x1 := rnd.Float64() * 100 y1 := rnd.Float64() * 100 x2 := rnd.Float64() * 100 y2 := rnd.Float64() * 100 dc.DrawLine(x1, y1, x2, y2) dc.SetLineWidth(rnd.Float64() * 3) dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Stroke() } saveImage(dc, "TestLines") checkHash(t, dc, "036bd220e2529955cc48425dd72bb686") } func TestCircles(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 10; i++ { x := rnd.Float64() * 100 y := rnd.Float64() * 100 r := rnd.Float64()*10 + 5 dc.DrawCircle(x, y, r) dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.FillPreserve() dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.SetLineWidth(rnd.Float64() * 3) dc.Stroke() } saveImage(dc, "TestCircles") checkHash(t, dc, "c52698000df96fabafe7863701afe922") } func TestQuadratic(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(0.25, 0.25, 0.25) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 100; i++ { x1 := rnd.Float64() * 100 y1 := rnd.Float64() * 100 x2 := rnd.Float64() * 100 y2 := rnd.Float64() * 100 x3 := rnd.Float64() * 100 y3 := rnd.Float64() * 100 dc.MoveTo(x1, y1) dc.QuadraticTo(x2, y2, x3, y3) dc.SetLineWidth(rnd.Float64() * 3) dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Stroke() } saveImage(dc, "TestQuadratic") checkHash(t, dc, "56b842d814aee94b52495addae764a77") } func TestCubic(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(0.75, 0.75, 0.75) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 100; i++ { x1 := rnd.Float64() * 100 y1 := rnd.Float64() * 100 x2 := rnd.Float64() * 100 y2 := rnd.Float64() * 100 x3 := rnd.Float64() * 100 y3 := rnd.Float64() * 100 x4 := rnd.Float64() * 100 y4 := rnd.Float64() * 100 dc.MoveTo(x1, y1) dc.CubicTo(x2, y2, x3, y3, x4, y4) dc.SetLineWidth(rnd.Float64() * 3) dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Stroke() } saveImage(dc, "TestCubic") checkHash(t, dc, "4a7960fc4eaaa33ce74131c5ce0afca8") } func TestFill(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 10; i++ { dc.NewSubPath() for j := 0; j < 10; j++ { x := rnd.Float64() * 100 y := rnd.Float64() * 100 dc.LineTo(x, y) } dc.ClosePath() dc.SetRGBA(rnd.Float64(), rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Fill() } saveImage(dc, "TestFill") checkHash(t, dc, "7ccb3a2443906a825e57ab94db785467") } func TestClip(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() dc.DrawCircle(50, 50, 40) dc.Clip() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 1000; i++ { x := rnd.Float64() * 100 y := rnd.Float64() * 100 r := rnd.Float64()*10 + 5 dc.DrawCircle(x, y, r) dc.SetRGBA(rnd.Float64(), rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Fill() } saveImage(dc, "TestClip") checkHash(t, dc, "762c32374d529fd45ffa038b05be7865") } func TestPushPop(t *testing.T) { const S = 100 dc := NewContext(S, S) dc.SetRGBA(0, 0, 0, 0.1) for i := 0; i < 360; i += 15 { dc.Push() dc.RotateAbout(Radians(float64(i)), S/2, S/2) dc.DrawEllipse(S/2, S/2, S*7/16, S/8) dc.Fill() dc.Pop() } saveImage(dc, "TestPushPop") checkHash(t, dc, "e0d6724eb72033577811a55f7a642f6a") } func TestDrawStringWrapped(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() dc.SetRGB(0, 0, 0) dc.DrawStringWrapped("Hello, world! How are you?", 50, 50, 0.5, 0.5, 90, 1.5, AlignCenter) saveImage(dc, "TestDrawStringWrapped") checkHash(t, dc, "8d92f6aae9e8b38563f171abd00893f8") } func TestDrawImage(t *testing.T) { src := NewContext(100, 100) src.SetRGB(1, 1, 1) src.Clear() for i := 10; i < 100; i += 10 { x := float64(i) + 0.5 src.DrawLine(x, 0, x, 100) src.DrawLine(0, x, 100, x) } src.SetRGB(0, 0, 0) src.Stroke() dc := NewContext(200, 200) dc.SetRGB(0, 0, 0) dc.Clear() dc.DrawImage(src.Image(), 50, 50) saveImage(dc, "TestDrawImage") checkHash(t, dc, "282afbc134676722960b6bec21305b15") } func TestSetPixel(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(0, 0, 0) dc.Clear() dc.SetRGB(0, 1, 0) i := 0 for y := 0; y < 100; y++ { for x := 0; x < 100; x++ { if i%31 == 0 { dc.SetPixel(x, y) } i++ } } saveImage(dc, "TestSetPixel") checkHash(t, dc, "27dda6b4b1d94f061018825b11982793") } func TestDrawPoint(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(0, 0, 0) dc.Clear() dc.SetRGB(0, 1, 0) dc.Scale(10, 10) for y := 0; y <= 10; y++ { for x := 0; x <= 10; x++ { dc.DrawPoint(float64(x), float64(y), 3) dc.Fill() } } saveImage(dc, "TestDrawPoint") checkHash(t, dc, "55af8874531947ea6eeb62222fb33e0e") } func TestLinearGradient(t *testing.T) { dc := NewContext(100, 100) g := NewLinearGradient(0, 0, 100, 100) g.AddColorStop(0, color.RGBA{0, 255, 0, 255}) g.AddColorStop(1, color.RGBA{0, 0, 255, 255}) g.AddColorStop(0.5, color.RGBA{255, 0, 0, 255}) dc.SetFillStyle(g) dc.DrawRectangle(0, 0, 100, 100) dc.Fill() saveImage(dc, "TestLinearGradient") checkHash(t, dc, "75eb9385c1219b1d5bb6f4c961802c7a") } func TestRadialGradient(t *testing.T) { dc := NewContext(100, 100) g := NewRadialGradient(30, 50, 0, 70, 50, 50) g.AddColorStop(0, color.RGBA{0, 255, 0, 255}) g.AddColorStop(1, color.RGBA{0, 0, 255, 255}) g.AddColorStop(0.5, color.RGBA{255, 0, 0, 255}) dc.SetFillStyle(g) dc.DrawRectangle(0, 0, 100, 100) dc.Fill() saveImage(dc, "TestRadialGradient") checkHash(t, dc, "f170f39c3f35c29de11e00428532489d") } func TestDashes(t *testing.T) { dc := NewContext(100, 100) dc.SetRGB(1, 1, 1) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < 100; i++ { x1 := rnd.Float64() * 100 y1 := rnd.Float64() * 100 x2 := rnd.Float64() * 100 y2 := rnd.Float64() * 100 dc.SetDash(rnd.Float64()*3+1, rnd.Float64()*3+3) dc.DrawLine(x1, y1, x2, y2) dc.SetLineWidth(rnd.Float64() * 3) dc.SetRGB(rnd.Float64(), rnd.Float64(), rnd.Float64()) dc.Stroke() } saveImage(dc, "TestDashes") checkHash(t, dc, "d188069c69dcc3970edfac80f552b53c") } func BenchmarkCircles(b *testing.B) { dc := NewContext(1000, 1000) dc.SetRGB(1, 1, 1) dc.Clear() rnd := rand.New(rand.NewSource(99)) for i := 0; i < b.N; i++ { x := rnd.Float64() * 1000 y := rnd.Float64() * 1000 dc.DrawCircle(x, y, 10) if i%2 == 0 { dc.SetRGB(0, 0, 0) } else { dc.SetRGB(1, 1, 1) } dc.Fill() } }