From c4a3de09d89c7bf410d692ff7d37c22784a8eb54 Mon Sep 17 00:00:00 2001 From: Jacek Olszak Date: Sun, 21 Sep 2025 00:39:37 +0200 Subject: [PATCH 1/2] test: Add unit tests for pitest package There is no need to check source.W and source.H in AssertSpriteEqual, because there is no way to create two different canvases pointing to the same array. --- pitest/pitest.go | 10 ---- pitest/pitest_test.go | 127 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 pitest/pitest_test.go diff --git a/pitest/pitest.go b/pitest/pitest.go index d67219e..14dce35 100644 --- a/pitest/pitest.go +++ b/pitest/pitest.go @@ -57,17 +57,7 @@ func AssertSpriteEqual(t *testing.T, expected, actual pi.Sprite) { expectedArrayPointer := unsafe.SliceData(expectedSource.Data()) actualArrayPointer := unsafe.SliceData(actualSource.Data()) sameArrayPointer := actualArrayPointer == expectedArrayPointer - sameWidth := expectedSource.W() == actualSource.W() - sameHeight := expectedSource.H() == actualSource.H() - if !sameWidth { - t.Errorf("sprites are using different sources, "+ - "expected Canvas width: %d, actual width: %d", expectedSource.W(), actualSource.W()) - } - if !sameHeight { - t.Errorf("sprites are using different sources, "+ - "expected Canvas height: %d, actual height: %d", expectedSource.H(), actualSource.H()) - } if !sameArrayPointer { t.Errorf("sprites are using different sources, "+ "pointers to Canvas data are not the same, expected: %+v, actual: %+v", diff --git a/pitest/pitest_test.go b/pitest/pitest_test.go new file mode 100644 index 0000000..3e1e251 --- /dev/null +++ b/pitest/pitest_test.go @@ -0,0 +1,127 @@ +// Copyright 2025 Jacek Olszak +// This code is licensed under MIT license (see LICENSE for details) + +package pitest_test + +import ( + "testing" + + "github.com/elgopher/pi" + "github.com/elgopher/pi/pitest" + "github.com/stretchr/testify/assert" +) + +func TestAssertSurfaceEqual(t *testing.T) { + t.Run("should not fail when surfaces are equal", func(t *testing.T) { + surface1 := pi.NewSurface[int](2, 3) + surface1.SetAll(0, 1, 2, 3, 4, 5) + surface2 := surface1.Clone() + mockT := new(testing.T) + // when + actual := pitest.AssertSurfaceEqual(mockT, surface1, surface2) + // then + assert.False(t, mockT.Failed()) + assert.True(t, actual) + }) + + t.Run("should fail when surfaces are not equal", func(t *testing.T) { + tests := map[string]struct { + surface1, surface2 pi.Surface[int] + }{ + "different data": { + surface1: func() pi.Surface[int] { + surface := pi.NewSurface[int](1, 1) + surface.SetAll(1, 2) + return surface + }(), + surface2: pi.NewSurface[int](1, 1), + }, + "different width": { + surface1: pi.NewSurface[int](1, 1), + surface2: pi.NewSurface[int](2, 1), + }, + "different height": { + surface1: pi.NewSurface[int](1, 1), + surface2: pi.NewSurface[int](1, 2), + }, + } + for testName, testCase := range tests { + t.Run(testName, func(t *testing.T) { + mockT := new(testing.T) + // when + actual := pitest.AssertSurfaceEqual(mockT, testCase.surface1, testCase.surface2) + // then + assert.True(t, mockT.Failed()) + assert.False(t, actual) + }) + } + }) +} + +func TestAssertSpriteEqual(t *testing.T) { + t.Run("should not fail when sprites are equal", func(t *testing.T) { + canvas := pi.NewCanvas(1, 1) + canvas.SetAll(1, 2) + sprite1 := pi.CanvasSprite(canvas) + sprite2 := pi.CanvasSprite(canvas) + mockT := new(testing.T) + // when + pitest.AssertSpriteEqual(mockT, sprite1, sprite2) + // then + assert.False(t, mockT.Failed()) + }) + + t.Run("should fail when sprites are not equal", func(t *testing.T) { + var data = []pi.Color{1, 2} + canvas := pi.NewCanvas(1, 1) + canvas.SetData(data) + + tests := map[string]struct { + sprite1, sprite2 pi.Sprite + }{ + "different canvas": { + sprite1: func() pi.Sprite { + return pi.CanvasSprite(canvas) + }(), + sprite2: func() pi.Sprite { + canvas := pi.NewCanvas(1, 1) + canvas.SetData(data) + return pi.CanvasSprite(canvas) + }(), + }, + "different area": { + sprite1: func() pi.Sprite { + return pi.CanvasSprite(canvas) + }(), + sprite2: func() pi.Sprite { + return pi.SpriteFrom(canvas, 1, 1, 0, 0) + }(), + }, + "different flipX": { + sprite1: func() pi.Sprite { + return pi.CanvasSprite(canvas).WithFlipX(true) + }(), + sprite2: func() pi.Sprite { + return pi.CanvasSprite(canvas) + }(), + }, + "different flipY": { + sprite1: func() pi.Sprite { + return pi.CanvasSprite(canvas).WithFlipY(true) + }(), + sprite2: func() pi.Sprite { + return pi.CanvasSprite(canvas) + }(), + }, + } + for testName, testCase := range tests { + t.Run(testName, func(t *testing.T) { + mockT := new(testing.T) + // when + pitest.AssertSpriteEqual(mockT, testCase.sprite1, testCase.sprite2) + // then + assert.True(t, mockT.Failed()) + }) + } + }) +} From 712b4feea7c9468f03bf8f9f29947d2db32c77ba Mon Sep 17 00:00:00 2001 From: Jacek Olszak Date: Sun, 21 Sep 2025 01:10:41 +0200 Subject: [PATCH 2/2] test: Add unit tests for pisnap package CaptureOrErr works only on non js OS. --- pisnap/pisnap.go | 3 +- pisnap/pisnap_js_test.go | 20 +++++++++++++ pisnap/pisnap_nonjs_test.go | 37 +++++++++++++++++++++++ pisnap/pisnap_test.go | 60 +++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 pisnap/pisnap_js_test.go create mode 100644 pisnap/pisnap_nonjs_test.go create mode 100644 pisnap/pisnap_test.go diff --git a/pisnap/pisnap.go b/pisnap/pisnap.go index 2a87926..66c9446 100644 --- a/pisnap/pisnap.go +++ b/pisnap/pisnap.go @@ -7,12 +7,13 @@ package pisnap import ( "errors" "fmt" - "github.com/elgopher/pi" "image" "image/color" "image/png" "os" "runtime" + + "github.com/elgopher/pi" ) // CaptureOrErr captures a screenshot and saves it to the temporary directory. diff --git a/pisnap/pisnap_js_test.go b/pisnap/pisnap_js_test.go new file mode 100644 index 0000000..dcb0223 --- /dev/null +++ b/pisnap/pisnap_js_test.go @@ -0,0 +1,20 @@ +// Copyright 2025 Jacek Olszak +// This code is licensed under MIT license (see LICENSE for details) + +//go:build js + +package pisnap_test + +import ( + "testing" + + "github.com/elgopher/pi/pisnap" + + "github.com/stretchr/testify/assert" +) + +func TestCaptureOrErr(t *testing.T) { + file, err := pisnap.CaptureOrErr() + assert.Error(t, err) + assert.Empty(t, file) +} diff --git a/pisnap/pisnap_nonjs_test.go b/pisnap/pisnap_nonjs_test.go new file mode 100644 index 0000000..1c81a7a --- /dev/null +++ b/pisnap/pisnap_nonjs_test.go @@ -0,0 +1,37 @@ +// Copyright 2025 Jacek Olszak +// This code is licensed under MIT license (see LICENSE for details) + +//go:build !js + +package pisnap_test + +import ( + "bytes" + "image" + "image/png" + "os" + "testing" + + "github.com/elgopher/pi" + "github.com/elgopher/pi/pisnap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCaptureOrErr(t *testing.T) { + // when + file, err := pisnap.CaptureOrErr() + // then + require.NoError(t, err) + assert.NotEmpty(t, file) + // and file exists + f, err := os.ReadFile(file) + require.NoError(t, err, "cannot read PNG file") + // and + img, err := png.Decode(bytes.NewReader(f)) + require.NoError(t, err, "file is not a valid PNG") + // and + palettedImage, ok := img.(*image.Paletted) + require.True(t, ok, "image is not a Paletted") + assertPalettedImage(t, palettedImage, pi.Screen()) +} diff --git a/pisnap/pisnap_test.go b/pisnap/pisnap_test.go new file mode 100644 index 0000000..af4ab8f --- /dev/null +++ b/pisnap/pisnap_test.go @@ -0,0 +1,60 @@ +// Copyright 2025 Jacek Olszak +// This code is licensed under MIT license (see LICENSE for details) + +package pisnap_test + +import ( + "image" + "testing" + + "github.com/elgopher/pi" + "github.com/elgopher/pi/pisnap" + "github.com/stretchr/testify/assert" +) + +func TestPalettedImage(t *testing.T) { + pi.SetScreenSize(2, 3) + pi.Palette[1] = 0xffaa44 + pi.Palette[2] = 0xff0000 + pi.Palette[3] = 0x00ff00 + pi.Palette[4] = 0x0000ff + pi.Palette[5] = 0x00ffff + pi.Palette[6] = 0xff00ff + screen := pi.Screen() + screen.SetAll(1, 2, 3, 4, 5, 6) + // when + img := pisnap.PalettedImage() + // then + assertPalettedImage(t, img, screen) +} + +func assertPalettedImage(t *testing.T, img image.PalettedImage, screen pi.Canvas) { + t.Helper() + + // then color indexes are the same + for y := 0; y < screen.H(); y++ { + for x := 0; x < screen.W(); x++ { + actual := img.ColorIndexAt(x, y) + expected := screen.Get(x, y) + assert.Equal(t, expected, actual) + } + } + // and RGBA colors match + for y := 0; y < screen.H(); y++ { + for x := 0; x < screen.W(); x++ { + r, g, b, a := img.At(x, y).RGBA() + assert.Equal(t, uint8(0xff), uint8(a)) + actual := pi.FromRGB(uint8(r), uint8(g), uint8(b)) + expected := pi.Palette[screen.Get(x, y)] + assert.Equal(t, expected, actual) + } + } + // and size is the same + assert.Equal(t, + image.Rectangle{ + Max: image.Point{X: screen.W(), Y: screen.H()}, + }, + img.Bounds(), + "image size is not same as screen size", + ) +}