github.com/o1egl/govatar@v0.4.1/govatar_test.go (about) 1 package govatar 2 3 import ( 4 "image" 5 "image/color" 6 "math/rand" 7 "net/http" 8 "os" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestGenerate(t *testing.T) { 15 testCases := map[string]struct { 16 gender Gender 17 err error 18 }{ 19 "male": { 20 gender: MALE, 21 }, 22 "female": { 23 gender: FEMALE, 24 }, 25 "unsupported": { 26 gender: Gender(-1), 27 err: ErrUnsupportedGender, 28 }, 29 } 30 31 for name, test := range testCases { 32 t.Run(name, func(t *testing.T) { 33 avatar, err := Generate(test.gender) 34 assert.Equal(t, test.err, err) 35 if test.err == nil && assert.NotNil(t, avatar) { 36 bounds := avatar.Bounds() 37 if assert.False(t, bounds.Empty()) { 38 assert.Equal(t, 400, bounds.Dx()) 39 assert.Equal(t, 400, bounds.Dy()) 40 } 41 } 42 }) 43 } 44 } 45 46 var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz") 47 48 func randStringRunes(n int) string { 49 b := make([]rune, n) 50 for i := range b { 51 b[i] = letterRunes[rand.Intn(len(letterRunes))] 52 } 53 return string(b) 54 } 55 56 func TestGenerateFile(t *testing.T) { 57 fileName := randStringRunes(6) 58 testCases := map[string]struct { 59 imageName string 60 mimeType string 61 }{ 62 "jpeg": {imageName: fileName + ".jpeg", mimeType: "image/jpeg"}, 63 "jpg": {imageName: fileName + ".jpg", mimeType: "image/jpeg"}, 64 "png": {imageName: fileName + ".png", mimeType: "image/png"}, 65 "gif": {imageName: fileName + ".gif", mimeType: "image/gif"}, 66 "xyz": {imageName: fileName + ".xyz", mimeType: "image/png"}, 67 } 68 69 for name, test := range testCases { 70 t.Run(name, func(t *testing.T) { 71 os.Remove(test.imageName) 72 defer os.Remove(test.imageName) 73 err := GenerateFile(MALE, test.imageName) 74 if assert.NoError(t, err) { 75 buf := make([]byte, 512) 76 f, err := os.Open(test.imageName) 77 if assert.NoError(t, err) { 78 defer f.Close() 79 80 _, err = f.Read(buf) 81 if assert.NoError(t, err) { 82 assert.Equal(t, test.mimeType, http.DetectContentType(buf)) 83 } 84 } 85 } 86 }) 87 } 88 } 89 90 func TestGenerateFromString(t *testing.T) { 91 testCases := map[string]struct { 92 gender Gender 93 areEqual bool 94 username1 string 95 username2 string 96 err error 97 }{ 98 "equal": { 99 gender: MALE, 100 areEqual: true, 101 username1: "username@site.com", 102 username2: "username@site.com", 103 }, 104 "not equal": { 105 gender: MALE, 106 areEqual: false, 107 username1: "username@site.com", 108 username2: "another-username@site.com", 109 }, 110 "error": { 111 gender: Gender(-1), 112 username1: "username@site.com", 113 username2: "username@site.com", 114 err: ErrUnsupportedGender, 115 }, 116 } 117 118 for name, test := range testCases { 119 t.Run(name, func(t *testing.T) { 120 avatar1, err := GenerateForUsername(test.gender, test.username1) 121 assert.Equal(t, test.err, err) 122 if test.err == nil && assert.NotNil(t, avatar1) { 123 bounds := avatar1.Bounds() 124 assert.False(t, bounds.Empty()) 125 assert.Equal(t, 400, bounds.Dx()) 126 assert.Equal(t, 400, bounds.Dy()) 127 128 avatar2, err := GenerateForUsername(test.gender, test.username2) 129 if assert.NoError(t, err) { 130 assert.Equal(t, test.areEqual, areImagesEqual(avatar1, avatar2)) 131 } 132 } 133 }) 134 } 135 136 } 137 138 func TestGenerateFileFromString(t *testing.T) { 139 fileName := randStringRunes(6) 140 testCases := map[string]struct { 141 imageName string 142 mimeType string 143 }{ 144 "jpeg": {imageName: fileName + ".jpeg", mimeType: "image/jpeg"}, 145 "jpg": {imageName: fileName + ".jpg", mimeType: "image/jpeg"}, 146 "png": {imageName: fileName + ".png", mimeType: "image/png"}, 147 "gif": {imageName: fileName + ".gif", mimeType: "image/gif"}, 148 "xyz": {imageName: fileName + ".xyz", mimeType: "image/png"}, 149 } 150 151 for name, test := range testCases { 152 t.Run(name, func(t *testing.T) { 153 os.Remove(test.imageName) 154 defer os.Remove(test.imageName) 155 err := GenerateFileForUsername(MALE, "username@site.com", test.imageName) 156 if assert.NoError(t, err) { 157 buf := make([]byte, 512) 158 f, err := os.Open(test.imageName) 159 if assert.NoError(t, err) { 160 defer f.Close() 161 162 _, err = f.Read(buf) 163 if assert.NoError(t, err) { 164 assert.Equal(t, test.mimeType, http.DetectContentType(buf)) 165 } 166 } 167 } 168 }) 169 } 170 } 171 172 func areImagesEqual(a, b image.Image) bool { 173 ab, bb := a.Bounds(), b.Bounds() 174 w, h := ab.Dx(), ab.Dy() 175 if w != bb.Dx() || h != bb.Dy() { 176 return false 177 } 178 n := 0 179 for y := 0; y < h; y++ { 180 for x := 0; x < w; x++ { 181 d := diffColor(a.At(ab.Min.X+x, ab.Min.Y+y), b.At(bb.Min.X+x, bb.Min.Y+y)) 182 c := color.RGBA{0, 0, 0, 0xff} 183 if d > 0 { 184 c.R = 0xff 185 n++ 186 } 187 } 188 } 189 return n == 0 190 } 191 192 func diffColor(c1, c2 color.Color) int64 { 193 r1, g1, b1, a1 := c1.RGBA() 194 r2, g2, b2, a2 := c2.RGBA() 195 var diff int64 196 diff += abs(int64(r1) - int64(r2)) 197 diff += abs(int64(g1) - int64(g2)) 198 diff += abs(int64(b1) - int64(b2)) 199 diff += abs(int64(a1) - int64(a2)) 200 return diff 201 } 202 203 func abs(x int64) int64 { 204 if x < 0 { 205 return -x 206 } 207 return x 208 }