github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/image/gif/reader_test.go (about)

     1  package gif
     2  
     3  import (
     4  	"bytes"
     5  	"compress/lzw"
     6  	"image"
     7  	"image/color"
     8  	"reflect"
     9  	"testing"
    10  )
    11  
    12  func TestDecode(t *testing.T) {
    13  	// header and trailer are parts of a valid 2x1 GIF image.
    14  	const (
    15  		header = "GIF89a" +
    16  			"\x02\x00\x01\x00" + // width=2, height=1
    17  			"\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
    18  			"\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
    19  		trailer = "\x3b"
    20  	)
    21  
    22  	// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
    23  	lzwEncode := func(n int) []byte {
    24  		b := &bytes.Buffer{}
    25  		w := lzw.NewWriter(b, lzw.LSB, 2)
    26  		w.Write(make([]byte, n))
    27  		w.Close()
    28  		return b.Bytes()
    29  	}
    30  
    31  	testCases := []struct {
    32  		nPix    int  // The number of pixels in the image data.
    33  		extra   bool // Whether to write an extra block after the LZW-encoded data.
    34  		wantErr error
    35  	}{
    36  		{0, false, errNotEnough},
    37  		{1, false, errNotEnough},
    38  		{2, false, nil},
    39  		{2, true, errTooMuch},
    40  		{3, false, errTooMuch},
    41  	}
    42  	for _, tc := range testCases {
    43  		b := &bytes.Buffer{}
    44  		b.WriteString(header)
    45  		// Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
    46  		// then this should result in an invalid GIF image. First, write a
    47  		// magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
    48  		// byte, and 2-bit LZW literals.
    49  		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
    50  		if tc.nPix > 0 {
    51  			enc := lzwEncode(tc.nPix)
    52  			if len(enc) > 0xff {
    53  				t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
    54  				continue
    55  			}
    56  			b.WriteByte(byte(len(enc)))
    57  			b.Write(enc)
    58  		}
    59  		if tc.extra {
    60  			b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
    61  		}
    62  		b.WriteByte(0x00) // An empty block signifies the end of the image data.
    63  		b.WriteString(trailer)
    64  
    65  		got, err := Decode(b)
    66  		if err != tc.wantErr {
    67  			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
    68  		}
    69  
    70  		if tc.wantErr != nil {
    71  			continue
    72  		}
    73  		want := &image.Paletted{
    74  			Pix:    []uint8{0, 0},
    75  			Stride: 2,
    76  			Rect:   image.Rect(0, 0, 2, 1),
    77  			Palette: color.Palette{
    78  				color.RGBA{0x10, 0x20, 0x30, 0xff},
    79  				color.RGBA{0x40, 0x50, 0x60, 0xff},
    80  			},
    81  		}
    82  		if !reflect.DeepEqual(got, want) {
    83  			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, got, want)
    84  		}
    85  	}
    86  }
    87  
    88  // testGIF is a simple GIF that we can modify to test different scenarios.
    89  var testGIF = []byte{
    90  	'G', 'I', 'F', '8', '9', 'a',
    91  	1, 0, 1, 0, // w=1, h=1 (6)
    92  	128, 0, 0, // headerFields, bg, aspect (10)
    93  	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
    94  	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
    95  	// frame 1 (0,0 - 1,1)
    96  	0x2c,
    97  	0x00, 0x00, 0x00, 0x00,
    98  	0x01, 0x00, 0x01, 0x00, // (32)
    99  	0x00,
   100  	0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
   101  	// trailer
   102  	0x3b,
   103  }
   104  
   105  func try(t *testing.T, b []byte, want string) {
   106  	_, err := DecodeAll(bytes.NewReader(b))
   107  	var got string
   108  	if err != nil {
   109  		got = err.Error()
   110  	}
   111  	if got != want {
   112  		t.Fatalf("got %v, want %v", got, want)
   113  	}
   114  }
   115  
   116  func TestBounds(t *testing.T) {
   117  	// make a local copy of testGIF
   118  	gif := make([]byte, len(testGIF))
   119  	copy(gif, testGIF)
   120  	// Make the bounds too big, just by one.
   121  	gif[32] = 2
   122  	want := "gif: frame bounds larger than image bounds"
   123  	try(t, gif, want)
   124  
   125  	// Make the bounds too small; does not trigger bounds
   126  	// check, but now there's too much data.
   127  	gif[32] = 0
   128  	want = "gif: too much image data"
   129  	try(t, gif, want)
   130  	gif[32] = 1
   131  
   132  	// Make the bounds really big, expect an error.
   133  	want = "gif: frame bounds larger than image bounds"
   134  	for i := 0; i < 4; i++ {
   135  		gif[32+i] = 0xff
   136  	}
   137  	try(t, gif, want)
   138  }