libgo: update to go1.9
[official-gcc.git] / libgo / go / image / gif / reader_test.go
blob51c64b7328f2ec09da20e7b54d1af0591c28aae7
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package gif
7 import (
8 "bytes"
9 "compress/lzw"
10 "image"
11 "image/color"
12 "reflect"
13 "strings"
14 "testing"
17 // header, palette and trailer are parts of a valid 2x1 GIF image.
18 const (
19 headerStr = "GIF89a" +
20 "\x02\x00\x01\x00" + // width=2, height=1
21 "\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
22 paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
23 trailerStr = "\x3b"
26 // lzwEncode returns an LZW encoding (with 2-bit literals) of in.
27 func lzwEncode(in []byte) []byte {
28 b := &bytes.Buffer{}
29 w := lzw.NewWriter(b, lzw.LSB, 2)
30 if _, err := w.Write(in); err != nil {
31 panic(err)
33 if err := w.Close(); err != nil {
34 panic(err)
36 return b.Bytes()
39 func TestDecode(t *testing.T) {
40 // extra contains superfluous bytes to inject into the GIF, either at the end
41 // of an existing data sub-block (past the LZW End of Information code) or in
42 // a separate data sub-block. The 0x02 values are arbitrary.
43 const extra = "\x02\x02\x02\x02"
45 testCases := []struct {
46 nPix int // The number of pixels in the image data.
47 // If non-zero, write this many extra bytes inside the data sub-block
48 // containing the LZW end code.
49 extraExisting int
50 // If non-zero, write an extra block of this many bytes.
51 extraSeparate int
52 wantErr error
54 {0, 0, 0, errNotEnough},
55 {1, 0, 0, errNotEnough},
56 {2, 0, 0, nil},
57 // An extra data sub-block after the compressed section with 1 byte which we
58 // silently skip.
59 {2, 0, 1, nil},
60 // An extra data sub-block after the compressed section with 2 bytes. In
61 // this case we complain that there is too much data.
62 {2, 0, 2, errTooMuch},
63 // Too much pixel data.
64 {3, 0, 0, errTooMuch},
65 // An extra byte after LZW data, but inside the same data sub-block.
66 {2, 1, 0, nil},
67 // Two extra bytes after LZW data, but inside the same data sub-block.
68 {2, 2, 0, nil},
70 for _, tc := range testCases {
71 b := &bytes.Buffer{}
72 b.WriteString(headerStr)
73 b.WriteString(paletteStr)
74 // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
75 // then this should result in an invalid GIF image. First, write a
76 // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
77 // byte, and 2-bit LZW literals.
78 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
79 if tc.nPix > 0 {
80 enc := lzwEncode(make([]byte, tc.nPix))
81 if len(enc)+tc.extraExisting > 0xff {
82 t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d: compressed length %d is too large",
83 tc.nPix, tc.extraExisting, tc.extraSeparate, len(enc))
84 continue
87 // Write the size of the data sub-block containing the LZW data.
88 b.WriteByte(byte(len(enc) + tc.extraExisting))
90 // Write the LZW data.
91 b.Write(enc)
93 // Write extra bytes inside the same data sub-block where LZW data
94 // ended. Each arbitrarily 0x02.
95 b.WriteString(extra[:tc.extraExisting])
98 if tc.extraSeparate > 0 {
99 // Data sub-block size. This indicates how many extra bytes follow.
100 b.WriteByte(byte(tc.extraSeparate))
101 b.WriteString(extra[:tc.extraSeparate])
103 b.WriteByte(0x00) // An empty block signifies the end of the image data.
104 b.WriteString(trailerStr)
106 got, err := Decode(b)
107 if err != tc.wantErr {
108 t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot %v\nwant %v",
109 tc.nPix, tc.extraExisting, tc.extraSeparate, err, tc.wantErr)
112 if tc.wantErr != nil {
113 continue
115 want := &image.Paletted{
116 Pix: []uint8{0, 0},
117 Stride: 2,
118 Rect: image.Rect(0, 0, 2, 1),
119 Palette: color.Palette{
120 color.RGBA{0x10, 0x20, 0x30, 0xff},
121 color.RGBA{0x40, 0x50, 0x60, 0xff},
124 if !reflect.DeepEqual(got, want) {
125 t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot %v\nwant %v",
126 tc.nPix, tc.extraExisting, tc.extraSeparate, got, want)
131 func TestTransparentIndex(t *testing.T) {
132 b := &bytes.Buffer{}
133 b.WriteString(headerStr)
134 b.WriteString(paletteStr)
135 for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
136 if transparentIndex < 2 {
137 // Write the graphic control for the transparent index.
138 b.WriteString("\x21\xf9\x04\x01\x00\x00")
139 b.WriteByte(byte(transparentIndex))
140 b.WriteByte(0)
142 // Write an image with bounds 2x1, as per TestDecode.
143 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
144 enc := lzwEncode([]byte{0x00, 0x00})
145 if len(enc) > 0xff {
146 t.Fatalf("compressed length %d is too large", len(enc))
148 b.WriteByte(byte(len(enc)))
149 b.Write(enc)
150 b.WriteByte(0x00)
152 b.WriteString(trailerStr)
154 g, err := DecodeAll(b)
155 if err != nil {
156 t.Fatalf("DecodeAll: %v", err)
158 c0 := color.RGBA{paletteStr[0], paletteStr[1], paletteStr[2], 0xff}
159 c1 := color.RGBA{paletteStr[3], paletteStr[4], paletteStr[5], 0xff}
160 cz := color.RGBA{}
161 wants := []color.Palette{
162 {cz, c1},
163 {c0, cz},
164 {c0, c1},
166 if len(g.Image) != len(wants) {
167 t.Fatalf("got %d images, want %d", len(g.Image), len(wants))
169 for i, want := range wants {
170 got := g.Image[i].Palette
171 if !reflect.DeepEqual(got, want) {
172 t.Errorf("palette #%d:\ngot %v\nwant %v", i, got, want)
177 // testGIF is a simple GIF that we can modify to test different scenarios.
178 var testGIF = []byte{
179 'G', 'I', 'F', '8', '9', 'a',
180 1, 0, 1, 0, // w=1, h=1 (6)
181 128, 0, 0, // headerFields, bg, aspect (10)
182 0, 0, 0, 1, 1, 1, // color table and graphics control (13)
183 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
184 // frame 1 (0,0 - 1,1)
185 0x2c,
186 0x00, 0x00, 0x00, 0x00,
187 0x01, 0x00, 0x01, 0x00, // (32)
188 0x00,
189 0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
190 // trailer
191 0x3b,
194 func try(t *testing.T, b []byte, want string) {
195 _, err := DecodeAll(bytes.NewReader(b))
196 var got string
197 if err != nil {
198 got = err.Error()
200 if got != want {
201 t.Fatalf("got %v, want %v", got, want)
205 func TestBounds(t *testing.T) {
206 // Make a local copy of testGIF.
207 gif := make([]byte, len(testGIF))
208 copy(gif, testGIF)
209 // Make the bounds too big, just by one.
210 gif[32] = 2
211 want := "gif: frame bounds larger than image bounds"
212 try(t, gif, want)
214 // Make the bounds too small; does not trigger bounds
215 // check, but now there's too much data.
216 gif[32] = 0
217 want = "gif: too much image data"
218 try(t, gif, want)
219 gif[32] = 1
221 // Make the bounds really big, expect an error.
222 want = "gif: frame bounds larger than image bounds"
223 for i := 0; i < 4; i++ {
224 gif[32+i] = 0xff
226 try(t, gif, want)
229 func TestNoPalette(t *testing.T) {
230 b := &bytes.Buffer{}
232 // Manufacture a GIF with no palette, so any pixel at all
233 // will be invalid.
234 b.WriteString(headerStr[:len(headerStr)-3])
235 b.WriteString("\x00\x00\x00") // No global palette.
237 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
238 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
240 // Encode the pixels: neither is in range, because there is no palette.
241 enc := lzwEncode([]byte{0x00, 0x03})
242 b.WriteByte(byte(len(enc)))
243 b.Write(enc)
244 b.WriteByte(0x00) // An empty block signifies the end of the image data.
246 b.WriteString(trailerStr)
248 try(t, b.Bytes(), "gif: no color table")
251 func TestPixelOutsidePaletteRange(t *testing.T) {
252 for _, pval := range []byte{0, 1, 2, 3} {
253 b := &bytes.Buffer{}
255 // Manufacture a GIF with a 2 color palette.
256 b.WriteString(headerStr)
257 b.WriteString(paletteStr)
259 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
260 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
262 // Encode the pixels; some pvals trigger the expected error.
263 enc := lzwEncode([]byte{pval, pval})
264 b.WriteByte(byte(len(enc)))
265 b.Write(enc)
266 b.WriteByte(0x00) // An empty block signifies the end of the image data.
268 b.WriteString(trailerStr)
270 // No error expected, unless the pixels are beyond the 2 color palette.
271 want := ""
272 if pval >= 2 {
273 want = "gif: invalid pixel value"
275 try(t, b.Bytes(), want)
279 func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
280 b := &bytes.Buffer{}
282 // Manufacture a GIF with a 2 color palette.
283 b.WriteString(headerStr)
284 b.WriteString(paletteStr)
286 // Graphic Control Extension: transparency, transparent color index = 3.
288 // This index, 3, is out of range of the global palette and there is no
289 // local palette in the subsequent image descriptor. This is an error
290 // according to the spec, but Firefox and Google Chrome seem OK with this.
292 // See golang.org/issue/15059.
293 b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
295 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
296 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
298 // Encode the pixels.
299 enc := lzwEncode([]byte{0x03, 0x03})
300 b.WriteByte(byte(len(enc)))
301 b.Write(enc)
302 b.WriteByte(0x00) // An empty block signifies the end of the image data.
304 b.WriteString(trailerStr)
306 try(t, b.Bytes(), "")
309 func TestLoopCount(t *testing.T) {
310 data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
311 "\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
312 img, err := DecodeAll(bytes.NewReader(data))
313 if err != nil {
314 t.Fatal("DecodeAll:", err)
316 w := new(bytes.Buffer)
317 err = EncodeAll(w, img)
318 if err != nil {
319 t.Fatal("EncodeAll:", err)
321 img1, err := DecodeAll(w)
322 if err != nil {
323 t.Fatal("DecodeAll:", err)
325 if img.LoopCount != img1.LoopCount {
326 t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
330 func TestUnexpectedEOF(t *testing.T) {
331 for i := len(testGIF) - 1; i >= 0; i-- {
332 _, err := Decode(bytes.NewReader(testGIF[:i]))
333 if err == errNotEnough {
334 continue
336 text := ""
337 if err != nil {
338 text = err.Error()
340 if !strings.HasPrefix(text, "gif:") || !strings.HasSuffix(text, ": unexpected EOF") {
341 t.Errorf("Decode(testGIF[:%d]) = %v, want gif: ...: unexpected EOF", i, err)