util.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package test
  2. import (
  3. "fmt"
  4. "image"
  5. "image/color"
  6. "image/png"
  7. "math"
  8. "os"
  9. "path/filepath"
  10. "testing"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. )
  14. // AssertImageMatches asserts that the given image is the same as the one stored in the master file.
  15. // The master filename is relative to the `testdata` directory which is relative to the test.
  16. // The test `t` fails if the given image is not equal to the loaded master image.
  17. // In this case the given image is written into a file in `testdata/failed/<masterFilename>` (relative to the test).
  18. // This path is also reported, thus the file can be used as new master.
  19. func AssertImageMatches(t *testing.T, masterFilename string, img image.Image, msgAndArgs ...interface{}) bool {
  20. wd, err := os.Getwd()
  21. require.NoError(t, err)
  22. masterPath := filepath.Join(wd, "testdata", masterFilename)
  23. failedPath := filepath.Join(wd, "testdata/failed", masterFilename)
  24. _, err = os.Stat(masterPath)
  25. if os.IsNotExist(err) {
  26. require.NoError(t, writeImage(failedPath, img))
  27. t.Errorf("Master not found at %s. Image written to %s might be used as master.", masterPath, failedPath)
  28. return false
  29. }
  30. file, err := os.Open(masterPath)
  31. require.NoError(t, err)
  32. defer file.Close()
  33. raw, _, err := image.Decode(file)
  34. require.NoError(t, err)
  35. masterPix := pixelsForImage(t, raw) // let's just compare the pixels directly
  36. capturePix := pixelsForImage(t, img)
  37. var msg string
  38. if len(msgAndArgs) > 0 {
  39. msg = fmt.Sprintf(msgAndArgs[0].(string)+"\n", msgAndArgs[1:]...)
  40. }
  41. if !assert.Equal(t, masterPix, capturePix, "%sImage did not match master. Actual image written to file://%s.", msg, failedPath) {
  42. require.NoError(t, writeImage(failedPath, img))
  43. return false
  44. }
  45. return true
  46. }
  47. // NewCheckedImage returns a new black/white checked image with the specified size
  48. // and the specified amount of horizontal and vertical tiles.
  49. func NewCheckedImage(w, h, hTiles, vTiles int) image.Image {
  50. img := image.NewNRGBA(image.Rect(0, 0, w, h))
  51. colors := []color.Color{color.White, color.Black}
  52. tileWidth := float64(w) / float64(hTiles)
  53. tileHeight := float64(h) / float64(vTiles)
  54. for y := 0; y < h; y++ {
  55. yTile := int(math.Floor(float64(y) / tileHeight))
  56. for x := 0; x < w; x++ {
  57. xTile := int(math.Floor(float64(x) / tileWidth))
  58. img.Set(x, y, colors[(xTile+yTile)%2])
  59. }
  60. }
  61. return img
  62. }
  63. func pixelsForImage(t *testing.T, img image.Image) []uint8 {
  64. var pix []uint8
  65. if data, ok := img.(*image.RGBA); ok {
  66. pix = data.Pix
  67. } else if data, ok := img.(*image.NRGBA); ok {
  68. pix = data.Pix
  69. }
  70. if pix == nil {
  71. t.Error("Master image is unsupported type")
  72. }
  73. return pix
  74. }
  75. func writeImage(path string, img image.Image) error {
  76. if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
  77. return err
  78. }
  79. f, err := os.Create(path)
  80. if err != nil {
  81. return err
  82. }
  83. if err = png.Encode(f, img); err != nil {
  84. f.Close()
  85. return err
  86. }
  87. return f.Close()
  88. }