github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/image/gif/reader_test.go (about) 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. 4 5 package gif 6 7 import ( 8 "bytes" 9 "compress/lzw" 10 "image" 11 "image/color" 12 "reflect" 13 "testing" 14 ) 15 16 // header, palette and trailer are parts of a valid 2x1 GIF image. 17 const ( 18 headerStr = "GIF89a" + 19 "\x02\x00\x01\x00" + // width=2, height=1 20 "\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect 21 paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette 22 trailerStr = "\x3b" 23 ) 24 25 func TestDecode(t *testing.T) { 26 // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. 27 lzwEncode := func(n int) []byte { 28 b := &bytes.Buffer{} 29 w := lzw.NewWriter(b, lzw.LSB, 2) 30 w.Write(make([]byte, n)) 31 w.Close() 32 return b.Bytes() 33 } 34 35 testCases := []struct { 36 nPix int // The number of pixels in the image data. 37 extra bool // Whether to write an extra block after the LZW-encoded data. 38 wantErr error 39 }{ 40 {0, false, errNotEnough}, 41 {1, false, errNotEnough}, 42 {2, false, nil}, 43 {2, true, errTooMuch}, 44 {3, false, errTooMuch}, 45 } 46 for _, tc := range testCases { 47 b := &bytes.Buffer{} 48 b.WriteString(headerStr) 49 b.WriteString(paletteStr) 50 // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2 51 // then this should result in an invalid GIF image. First, write a 52 // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags 53 // byte, and 2-bit LZW literals. 54 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") 55 if tc.nPix > 0 { 56 enc := lzwEncode(tc.nPix) 57 if len(enc) > 0xff { 58 t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc)) 59 continue 60 } 61 b.WriteByte(byte(len(enc))) 62 b.Write(enc) 63 } 64 if tc.extra { 65 b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte. 66 } 67 b.WriteByte(0x00) // An empty block signifies the end of the image data. 68 b.WriteString(trailerStr) 69 70 got, err := Decode(b) 71 if err != tc.wantErr { 72 t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr) 73 } 74 75 if tc.wantErr != nil { 76 continue 77 } 78 want := &image.Paletted{ 79 Pix: []uint8{0, 0}, 80 Stride: 2, 81 Rect: image.Rect(0, 0, 2, 1), 82 Palette: color.Palette{ 83 color.RGBA{0x10, 0x20, 0x30, 0xff}, 84 color.RGBA{0x40, 0x50, 0x60, 0xff}, 85 }, 86 } 87 if !reflect.DeepEqual(got, want) { 88 t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, got, want) 89 } 90 } 91 } 92 93 // testGIF is a simple GIF that we can modify to test different scenarios. 94 var testGIF = []byte{ 95 'G', 'I', 'F', '8', '9', 'a', 96 1, 0, 1, 0, // w=1, h=1 (6) 97 128, 0, 0, // headerFields, bg, aspect (10) 98 0, 0, 0, 1, 1, 1, // color map and graphics control (13) 99 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19) 100 // frame 1 (0,0 - 1,1) 101 0x2c, 102 0x00, 0x00, 0x00, 0x00, 103 0x01, 0x00, 0x01, 0x00, // (32) 104 0x00, 105 0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels 106 // trailer 107 0x3b, 108 } 109 110 func try(t *testing.T, b []byte, want string) { 111 _, err := DecodeAll(bytes.NewReader(b)) 112 var got string 113 if err != nil { 114 got = err.Error() 115 } 116 if got != want { 117 t.Fatalf("got %v, want %v", got, want) 118 } 119 } 120 121 func TestBounds(t *testing.T) { 122 // Make a local copy of testGIF. 123 gif := make([]byte, len(testGIF)) 124 copy(gif, testGIF) 125 // Make the bounds too big, just by one. 126 gif[32] = 2 127 want := "gif: frame bounds larger than image bounds" 128 try(t, gif, want) 129 130 // Make the bounds too small; does not trigger bounds 131 // check, but now there's too much data. 132 gif[32] = 0 133 want = "gif: too much image data" 134 try(t, gif, want) 135 gif[32] = 1 136 137 // Make the bounds really big, expect an error. 138 want = "gif: frame bounds larger than image bounds" 139 for i := 0; i < 4; i++ { 140 gif[32+i] = 0xff 141 } 142 try(t, gif, want) 143 } 144 145 func TestNoPalette(t *testing.T) { 146 b := &bytes.Buffer{} 147 148 // Manufacture a GIF with no palette, so any pixel at all 149 // will be invalid. 150 b.WriteString(headerStr[:len(headerStr)-3]) 151 b.WriteString("\x00\x00\x00") // No global palette. 152 153 // Image descriptor: 2x1, no local palette. 154 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") 155 156 // Encode the pixels: neither is in range, because there is no palette. 157 pix := []byte{0, 128} 158 enc := &bytes.Buffer{} 159 w := lzw.NewWriter(enc, lzw.LSB, 2) 160 w.Write(pix) 161 w.Close() 162 b.WriteByte(byte(len(enc.Bytes()))) 163 b.Write(enc.Bytes()) 164 b.WriteByte(0x00) // An empty block signifies the end of the image data. 165 166 b.WriteString(trailerStr) 167 168 try(t, b.Bytes(), "gif: invalid pixel value") 169 } 170 171 func TestPixelOutsidePaletteRange(t *testing.T) { 172 for _, pval := range []byte{0, 1, 2, 3, 255} { 173 b := &bytes.Buffer{} 174 175 // Manufacture a GIF with a 2 color palette. 176 b.WriteString(headerStr) 177 b.WriteString(paletteStr) 178 179 // Image descriptor: 2x1, no local palette. 180 b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") 181 182 // Encode the pixels; some pvals trigger the expected error. 183 pix := []byte{pval, pval} 184 enc := &bytes.Buffer{} 185 w := lzw.NewWriter(enc, lzw.LSB, 2) 186 w.Write(pix) 187 w.Close() 188 b.WriteByte(byte(len(enc.Bytes()))) 189 b.Write(enc.Bytes()) 190 b.WriteByte(0x00) // An empty block signifies the end of the image data. 191 192 b.WriteString(trailerStr) 193 194 // No error expected, unless the pixels are beyond the 2 color palette. 195 want := "" 196 if pval >= 2 { 197 want = "gif: invalid pixel value" 198 } 199 try(t, b.Bytes(), want) 200 } 201 }