Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compare images by pixels instead of bytes #208

Merged
merged 3 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 54 additions & 25 deletions pkg/images/imageExpander_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
package images

import (
"bytes"
"image"
"image/color"
"image/png"
"log"
"os"
"runtime"
Expand All @@ -16,6 +20,10 @@ import (
"github.com/stretchr/testify/assert"
)

var (
BLACK = color.RGBA{0, 0, 0, 255}
)

func TestCanCalculateTargetPathsOk(t *testing.T) {
fs := files.NewMockFileSystem()
embeddedFs := embedded.NewMockReadOnlyFileSystem()
Expand Down Expand Up @@ -154,36 +162,57 @@ func compareImage(t *testing.T, renderedImageToCompare []byte, compareFolderPath
func compareTwoImages(t *testing.T, renderedContents []byte, expectedContents []byte) (bool, error) {
var isSame bool = true
var err error
renderedImageLength := len(renderedContents)
expectedImageLength := len(expectedContents)
if renderedImageLength != expectedImageLength {
assert.Fail(t, "error", "rendered contents length %v is different to the expected contents %v", renderedImageLength, expectedImageLength)
isSame = false
} else {

for i, valueGotBack := range renderedContents {
valueExpected := expectedContents[i]

if valueGotBack != valueExpected {
isSame = false
assert.Fail(t, "error", "rendered image byte %d differs from expected image byte %d", i, i)
break
var renderedImage image.Image
var expectedImage image.Image

renderedImage, err = png.Decode(bytes.NewReader(renderedContents))
if err == nil {
expectedImage, err = png.Decode(bytes.NewReader(expectedContents))

renderedImageBounds := renderedImage.Bounds()
expectedImageBounds := expectedImage.Bounds()

// Make sure the rendered image is the same size as the expected image
if renderedImageBounds == expectedImageBounds {
for column := expectedImage.Bounds().Min.Y; column < expectedImage.Bounds().Max.Y; column++ {
for row := expectedImage.Bounds().Min.X; row < expectedImage.Bounds().Max.X; row++ {
expectedPixelColor := expectedImage.At(column, row)
renderedPixelColor := renderedImage.At(column, row)

// We're ignoring colors because some pixels may have slight differences in RGB values, which
// causes tests to fail. Whenever the expected pixel is black, the rendered pixel should also
// be black, and when the expected pixel is a color, the rendered pixel should also be a color.
if (expectedPixelColor == BLACK && renderedPixelColor != BLACK) ||
(expectedPixelColor != BLACK && renderedPixelColor == BLACK) {
assert.Fail(t, "error", "rendered RGBA value %v does not match expected RGBA value %v at (x: %d, y: %d)", renderedPixelColor, expectedPixelColor, column, row)
isSame = false
break
}
}
if !isSame {
break
}
}
} else {
assert.Fail(t, "error", "rendered image bounds %v are different to expected image bounds %v", renderedImageBounds, expectedImageBounds)
isSame = false
}
}

if isSame {
log.Printf("Rendered file and stored file to compare against were exactly the same.\n")
} else {
// Files don't match, so save the file we got for manual inspection.
// If the user wants, they can copy this file into the project as expected test data.
var renderedFile *os.File
if isSame {
log.Printf("Rendered file and stored file to compare against were exactly the same.\n")
} else {
// Files don't match, so save the file we got for manual inspection.
// If the user wants, they can copy this file into the project as expected test data.
var renderedFile *os.File

renderedFile, err = os.CreateTemp("", "rendered-image-*.png")
defer renderedFile.Close()
renderedFile.Write(renderedContents)
renderedFile, err = os.CreateTemp("", "rendered-image-*.png")
if err == nil {
defer renderedFile.Close()
renderedFile.Write(renderedContents)

log.Printf("A copy of the rendered file has been saved to %s for manual inspection if required.\n", renderedFile.Name())
log.Printf("A copy of the rendered file has been saved to %s for manual inspection if required.\n", renderedFile.Name())
}
}
}

return isSame, err
Expand Down
14 changes: 0 additions & 14 deletions pkg/images/imageRenderer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,6 @@ func assertTerminalImageMatchesExpectedSnapshot(t *testing.T, actualImageBytes [
compareImage(t, actualImageBytes, "./testdata/renderedimages/images-to-compare", t.Name()+".png")
}

func writeRenderedImageToTempDir(t *testing.T, fs files.FileSystem, actualImageBytes []byte) {
outputDirectory, err := fs.MkTempDir()
filePath := filepath.Join(outputDirectory, t.Name()+".png")
if err == nil {
err = fs.WriteBinaryFile(filePath, actualImageBytes)
}

if err != nil {
t.Log("Failed to write the rendered image to a temporary directory")
} else {
fmt.Printf("Rendered image written to: %s", filePath)
}
}

func createTextField(row int, column int, text string, textColor string) TerminalField {
fieldContents := FieldContents{Text: text}

Expand Down