1 // Copyright 2009 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 gzip 6 7 import ( 8 "bytes" 9 "io" 10 "io/ioutil" 11 "os" 12 "strings" 13 "testing" 14 "time" 15 ) 16 17 type gunzipTest struct { 18 name string 19 desc string 20 raw string 21 gzip []byte 22 err error 23 } 24 25 var gunzipTests = []gunzipTest{ 26 { // has 1 empty fixed-huffman block 27 "empty.txt", 28 "empty.txt", 29 "", 30 []byte{ 31 0x1f, 0x8b, 0x08, 0x08, 0xf7, 0x5e, 0x14, 0x4a, 32 0x00, 0x03, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 33 0x74, 0x78, 0x74, 0x00, 0x03, 0x00, 0x00, 0x00, 34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 }, 36 nil, 37 }, 38 { // has 1 non-empty fixed huffman block 39 "hello.txt", 40 "hello.txt", 41 "hello world\n", 42 []byte{ 43 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 44 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 45 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 46 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 47 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 48 0x00, 0x00, 49 }, 50 nil, 51 }, 52 { // concatenation 53 "hello.txt", 54 "hello.txt x2", 55 "hello world\n" + 56 "hello world\n", 57 []byte{ 58 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 59 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 60 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 61 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 62 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 63 0x00, 0x00, 64 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 65 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 66 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 67 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 68 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 69 0x00, 0x00, 70 }, 71 nil, 72 }, 73 { // has a fixed huffman block with some length-distance pairs 74 "shesells.txt", 75 "shesells.txt", 76 "she sells seashells by the seashore\n", 77 []byte{ 78 0x1f, 0x8b, 0x08, 0x08, 0x72, 0x66, 0x8b, 0x4a, 79 0x00, 0x03, 0x73, 0x68, 0x65, 0x73, 0x65, 0x6c, 80 0x6c, 0x73, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b, 81 0xce, 0x48, 0x55, 0x28, 0x4e, 0xcd, 0xc9, 0x29, 82 0x06, 0x92, 0x89, 0xc5, 0x19, 0x60, 0x56, 0x52, 83 0xa5, 0x42, 0x09, 0x58, 0x18, 0x28, 0x90, 0x5f, 84 0x94, 0xca, 0x05, 0x00, 0x76, 0xb0, 0x3b, 0xeb, 85 0x24, 0x00, 0x00, 0x00, 86 }, 87 nil, 88 }, 89 { // has dynamic huffman blocks 90 "gettysburg", 91 "gettysburg", 92 " Four score and seven years ago our fathers brought forth on\n" + 93 "this continent, a new nation, conceived in Liberty, and dedicated\n" + 94 "to the proposition that all men are created equal.\n" + 95 " Now we are engaged in a great Civil War, testing whether that\n" + 96 "nation, or any nation so conceived and so dedicated, can long\n" + 97 "endure.\n" + 98 " We are met on a great battle-field of that war.\n" + 99 " We have come to dedicate a portion of that field, as a final\n" + 100 "resting place for those who here gave their lives that that\n" + 101 "nation might live. It is altogether fitting and proper that\n" + 102 "we should do this.\n" + 103 " But, in a larger sense, we can not dedicate we can not\n" + 104 "consecrate we can not hallow this ground.\n" + 105 " The brave men, living and dead, who struggled here, have\n" + 106 "consecrated it, far above our poor power to add or detract.\n" + 107 "The world will little note, nor long remember what we say here,\n" + 108 "but it can never forget what they did here.\n" + 109 " It is for us the living, rather, to be dedicated here to the\n" + 110 "unfinished work which they who fought here have thus far so\n" + 111 "nobly advanced. It is rather for us to be here dedicated to\n" + 112 "the great task remaining before us that from these honored\n" + 113 "dead we take increased devotion to that cause for which they\n" + 114 "gave the last full measure of devotion \n" + 115 " that we here highly resolve that these dead shall not have\n" + 116 "died in vain that this nation, under God, shall have a new\n" + 117 "birth of freedom and that government of the people, by the\n" + 118 "people, for the people, shall not perish from this earth.\n" + 119 "\n" + 120 "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n", 121 []byte{ 122 0x1f, 0x8b, 0x08, 0x08, 0xd1, 0x12, 0x2b, 0x4a, 123 0x00, 0x03, 0x67, 0x65, 0x74, 0x74, 0x79, 0x73, 124 0x62, 0x75, 0x72, 0x67, 0x00, 0x65, 0x54, 0xcd, 125 0x6e, 0xd4, 0x30, 0x10, 0xbe, 0xfb, 0x29, 0xe6, 126 0x01, 0x42, 0xa5, 0x0a, 0x09, 0xc1, 0x11, 0x90, 127 0x40, 0x48, 0xa8, 0xe2, 0x80, 0xd4, 0xf3, 0x24, 128 0x9e, 0x24, 0x56, 0xbd, 0x9e, 0xc5, 0x76, 0x76, 129 0x95, 0x1b, 0x0f, 0xc1, 0x13, 0xf2, 0x24, 0x7c, 130 0x63, 0x77, 0x9b, 0x4a, 0x5c, 0xaa, 0x6e, 0x6c, 131 0xcf, 0x7c, 0x7f, 0x33, 0x44, 0x5f, 0x74, 0xcb, 132 0x54, 0x26, 0xcd, 0x42, 0x9c, 0x3c, 0x15, 0xb9, 133 0x48, 0xa2, 0x5d, 0x38, 0x17, 0xe2, 0x45, 0xc9, 134 0x4e, 0x67, 0xae, 0xab, 0xe0, 0xf7, 0x98, 0x75, 135 0x5b, 0xd6, 0x4a, 0xb3, 0xe6, 0xba, 0x92, 0x26, 136 0x57, 0xd7, 0x50, 0x68, 0xd2, 0x54, 0x43, 0x92, 137 0x54, 0x07, 0x62, 0x4a, 0x72, 0xa5, 0xc4, 0x35, 138 0x68, 0x1a, 0xec, 0x60, 0x92, 0x70, 0x11, 0x4f, 139 0x21, 0xd1, 0xf7, 0x30, 0x4a, 0xae, 0xfb, 0xd0, 140 0x9a, 0x78, 0xf1, 0x61, 0xe2, 0x2a, 0xde, 0x55, 141 0x25, 0xd4, 0xa6, 0x73, 0xd6, 0xb3, 0x96, 0x60, 142 0xef, 0xf0, 0x9b, 0x2b, 0x71, 0x8c, 0x74, 0x02, 143 0x10, 0x06, 0xac, 0x29, 0x8b, 0xdd, 0x25, 0xf9, 144 0xb5, 0x71, 0xbc, 0x73, 0x44, 0x0f, 0x7a, 0xa5, 145 0xab, 0xb4, 0x33, 0x49, 0x0b, 0x2f, 0xbd, 0x03, 146 0xd3, 0x62, 0x17, 0xe9, 0x73, 0xb8, 0x84, 0x48, 147 0x8f, 0x9c, 0x07, 0xaa, 0x52, 0x00, 0x6d, 0xa1, 148 0xeb, 0x2a, 0xc6, 0xa0, 0x95, 0x76, 0x37, 0x78, 149 0x9a, 0x81, 0x65, 0x7f, 0x46, 0x4b, 0x45, 0x5f, 150 0xe1, 0x6d, 0x42, 0xe8, 0x01, 0x13, 0x5c, 0x38, 151 0x51, 0xd4, 0xb4, 0x38, 0x49, 0x7e, 0xcb, 0x62, 152 0x28, 0x1e, 0x3b, 0x82, 0x93, 0x54, 0x48, 0xf1, 153 0xd2, 0x7d, 0xe4, 0x5a, 0xa3, 0xbc, 0x99, 0x83, 154 0x44, 0x4f, 0x3a, 0x77, 0x36, 0x57, 0xce, 0xcf, 155 0x2f, 0x56, 0xbe, 0x80, 0x90, 0x9e, 0x84, 0xea, 156 0x51, 0x1f, 0x8f, 0xcf, 0x90, 0xd4, 0x60, 0xdc, 157 0x5e, 0xb4, 0xf7, 0x10, 0x0b, 0x26, 0xe0, 0xff, 158 0xc4, 0xd1, 0xe5, 0x67, 0x2e, 0xe7, 0xc8, 0x93, 159 0x98, 0x05, 0xb8, 0xa8, 0x45, 0xc0, 0x4d, 0x09, 160 0xdc, 0x84, 0x16, 0x2b, 0x0d, 0x9a, 0x21, 0x53, 161 0x04, 0x8b, 0xd2, 0x0b, 0xbd, 0xa2, 0x4c, 0xa7, 162 0x60, 0xee, 0xd9, 0xe1, 0x1d, 0xd1, 0xb7, 0x4a, 163 0x30, 0x8f, 0x63, 0xd5, 0xa5, 0x8b, 0x33, 0x87, 164 0xda, 0x1a, 0x18, 0x79, 0xf3, 0xe3, 0xa6, 0x17, 165 0x94, 0x2e, 0xab, 0x6e, 0xa0, 0xe3, 0xcd, 0xac, 166 0x50, 0x8c, 0xca, 0xa7, 0x0d, 0x76, 0x37, 0xd1, 167 0x23, 0xe7, 0x05, 0x57, 0x8b, 0xa4, 0x22, 0x83, 168 0xd9, 0x62, 0x52, 0x25, 0xad, 0x07, 0xbb, 0xbf, 169 0xbf, 0xff, 0xbc, 0xfa, 0xee, 0x20, 0x73, 0x91, 170 0x29, 0xff, 0x7f, 0x02, 0x71, 0x62, 0x84, 0xb5, 171 0xf6, 0xb5, 0x25, 0x6b, 0x41, 0xde, 0x92, 0xb7, 172 0x76, 0x3f, 0x91, 0x91, 0x31, 0x1b, 0x41, 0x84, 173 0x62, 0x30, 0x0a, 0x37, 0xa4, 0x5e, 0x18, 0x3a, 174 0x99, 0x08, 0xa5, 0xe6, 0x6d, 0x59, 0x22, 0xec, 175 0x33, 0x39, 0x86, 0x26, 0xf5, 0xab, 0x66, 0xc8, 176 0x08, 0x20, 0xcf, 0x0c, 0xd7, 0x47, 0x45, 0x21, 177 0x0b, 0xf6, 0x59, 0xd5, 0xfe, 0x5c, 0x8d, 0xaa, 178 0x12, 0x7b, 0x6f, 0xa1, 0xf0, 0x52, 0x33, 0x4f, 179 0xf5, 0xce, 0x59, 0xd3, 0xab, 0x66, 0x10, 0xbf, 180 0x06, 0xc4, 0x31, 0x06, 0x73, 0xd6, 0x80, 0xa2, 181 0x78, 0xc2, 0x45, 0xcb, 0x03, 0x65, 0x39, 0xc9, 182 0x09, 0xd1, 0x06, 0x04, 0x33, 0x1a, 0x5a, 0xf1, 183 0xde, 0x01, 0xb8, 0x71, 0x83, 0xc4, 0xb5, 0xb3, 184 0xc3, 0x54, 0x65, 0x33, 0x0d, 0x5a, 0xf7, 0x9b, 185 0x90, 0x7c, 0x27, 0x1f, 0x3a, 0x58, 0xa3, 0xd8, 186 0xfd, 0x30, 0x5f, 0xb7, 0xd2, 0x66, 0xa2, 0x93, 187 0x1c, 0x28, 0xb7, 0xe9, 0x1b, 0x0c, 0xe1, 0x28, 188 0x47, 0x26, 0xbb, 0xe9, 0x7d, 0x7e, 0xdc, 0x96, 189 0x10, 0x92, 0x50, 0x56, 0x7c, 0x06, 0xe2, 0x27, 190 0xb4, 0x08, 0xd3, 0xda, 0x7b, 0x98, 0x34, 0x73, 191 0x9f, 0xdb, 0xf6, 0x62, 0xed, 0x31, 0x41, 0x13, 192 0xd3, 0xa2, 0xa8, 0x4b, 0x3a, 0xc6, 0x1d, 0xe4, 193 0x2f, 0x8c, 0xf8, 0xfb, 0x97, 0x64, 0xf4, 0xb6, 194 0x2f, 0x80, 0x5a, 0xf3, 0x56, 0xe0, 0x40, 0x50, 195 0xd5, 0x19, 0xd0, 0x1e, 0xfc, 0xca, 0xe5, 0xc9, 196 0xd4, 0x60, 0x00, 0x81, 0x2e, 0xa3, 0xcc, 0xb6, 197 0x52, 0xf0, 0xb4, 0xdb, 0x69, 0x99, 0xce, 0x7a, 198 0x32, 0x4c, 0x08, 0xed, 0xaa, 0x10, 0x10, 0xe3, 199 0x6f, 0xee, 0x99, 0x68, 0x95, 0x9f, 0x04, 0x71, 200 0xb2, 0x49, 0x2f, 0x62, 0xa6, 0x5e, 0xb4, 0xef, 201 0x02, 0xed, 0x4f, 0x27, 0xde, 0x4a, 0x0f, 0xfd, 202 0xc1, 0xcc, 0xdd, 0x02, 0x8f, 0x08, 0x16, 0x54, 203 0xdf, 0xda, 0xca, 0xe0, 0x82, 0xf1, 0xb4, 0x31, 204 0x7a, 0xa9, 0x81, 0xfe, 0x90, 0xb7, 0x3e, 0xdb, 205 0xd3, 0x35, 0xc0, 0x20, 0x80, 0x33, 0x46, 0x4a, 206 0x63, 0xab, 0xd1, 0x0d, 0x29, 0xd2, 0xe2, 0x84, 207 0xb8, 0xdb, 0xfa, 0xe9, 0x89, 0x44, 0x86, 0x7c, 208 0xe8, 0x0b, 0xe6, 0x02, 0x6a, 0x07, 0x9b, 0x96, 209 0xd0, 0xdb, 0x2e, 0x41, 0x4c, 0xa1, 0xd5, 0x57, 210 0x45, 0x14, 0xfb, 0xe3, 0xa6, 0x72, 0x5b, 0x87, 211 0x6e, 0x0c, 0x6d, 0x5b, 0xce, 0xe0, 0x2f, 0xe2, 212 0x21, 0x81, 0x95, 0xb0, 0xe8, 0xb6, 0x32, 0x0b, 213 0xb2, 0x98, 0x13, 0x52, 0x5d, 0xfb, 0xec, 0x63, 214 0x17, 0x8a, 0x9e, 0x23, 0x22, 0x36, 0xee, 0xcd, 215 0xda, 0xdb, 0xcf, 0x3e, 0xf1, 0xc7, 0xf1, 0x01, 216 0x12, 0x93, 0x0a, 0xeb, 0x6f, 0xf2, 0x02, 0x15, 217 0x96, 0x77, 0x5d, 0xef, 0x9c, 0xfb, 0x88, 0x91, 218 0x59, 0xf9, 0x84, 0xdd, 0x9b, 0x26, 0x8d, 0x80, 219 0xf9, 0x80, 0x66, 0x2d, 0xac, 0xf7, 0x1f, 0x06, 220 0xba, 0x7f, 0xff, 0xee, 0xed, 0x40, 0x5f, 0xa5, 221 0xd6, 0xbd, 0x8c, 0x5b, 0x46, 0xd2, 0x7e, 0x48, 222 0x4a, 0x65, 0x8f, 0x08, 0x42, 0x60, 0xf7, 0x0f, 223 0xb9, 0x16, 0x0b, 0x0c, 0x1a, 0x06, 0x00, 0x00, 224 }, 225 nil, 226 }, 227 { // has 1 non-empty fixed huffman block then garbage 228 "hello.txt", 229 "hello.txt + garbage", 230 "hello world\n", 231 []byte{ 232 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 233 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 234 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 235 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 236 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 237 0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!', 238 }, 239 ErrHeader, 240 }, 241 { // has 1 non-empty fixed huffman block not enough header 242 "hello.txt", 243 "hello.txt + garbage", 244 "hello world\n", 245 []byte{ 246 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 247 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 248 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 249 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 250 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 251 0x00, 0x00, gzipID1, 252 }, 253 io.ErrUnexpectedEOF, 254 }, 255 { // has 1 non-empty fixed huffman block but corrupt checksum 256 "hello.txt", 257 "hello.txt + corrupt checksum", 258 "hello world\n", 259 []byte{ 260 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 261 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 262 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 263 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 264 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, 265 0x00, 0x00, 266 }, 267 ErrChecksum, 268 }, 269 { // has 1 non-empty fixed huffman block but corrupt size 270 "hello.txt", 271 "hello.txt + corrupt size", 272 "hello world\n", 273 []byte{ 274 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, 275 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 276 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 277 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 278 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00, 279 0x00, 0x00, 280 }, 281 ErrChecksum, 282 }, 283 } 284 285 func TestDecompressor(t *testing.T) { 286 b := new(bytes.Buffer) 287 for _, tt := range gunzipTests { 288 in := bytes.NewReader(tt.gzip) 289 gzip, err := NewReader(in) 290 if err != nil { 291 t.Errorf("%s: NewReader: %s", tt.name, err) 292 continue 293 } 294 defer gzip.Close() 295 if tt.name != gzip.Name { 296 t.Errorf("%s: got name %s", tt.name, gzip.Name) 297 } 298 b.Reset() 299 n, err := io.Copy(b, gzip) 300 if err != tt.err { 301 t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err) 302 } 303 s := b.String() 304 if s != tt.raw { 305 t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) 306 } 307 308 // Test Reader Reset. 309 in = bytes.NewReader(tt.gzip) 310 err = gzip.Reset(in) 311 if err != nil { 312 t.Errorf("%s: Reset: %s", tt.name, err) 313 continue 314 } 315 if tt.name != gzip.Name { 316 t.Errorf("%s: got name %s", tt.name, gzip.Name) 317 } 318 b.Reset() 319 n, err = io.Copy(b, gzip) 320 if err != tt.err { 321 t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err) 322 } 323 s = b.String() 324 if s != tt.raw { 325 t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) 326 } 327 } 328 } 329 330 func TestIssue6550(t *testing.T) { 331 f, err := os.Open("testdata/issue6550.gz") 332 if err != nil { 333 t.Fatal(err) 334 } 335 gzip, err := NewReader(f) 336 if err != nil { 337 t.Fatalf("NewReader(testdata/issue6550.gz): %v", err) 338 } 339 defer gzip.Close() 340 done := make(chan bool, 1) 341 go func() { 342 _, err := io.Copy(ioutil.Discard, gzip) 343 if err == nil { 344 t.Errorf("Copy succeeded") 345 } else { 346 t.Logf("Copy failed (correctly): %v", err) 347 } 348 done <- true 349 }() 350 select { 351 case <-time.After(1 * time.Second): 352 t.Errorf("Copy hung") 353 case <-done: 354 // ok 355 } 356 } 357 358 func TestInitialReset(t *testing.T) { 359 var r Reader 360 if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil { 361 t.Error(err) 362 } 363 var buf bytes.Buffer 364 if _, err := io.Copy(&buf, &r); err != nil { 365 t.Error(err) 366 } 367 if s := buf.String(); s != gunzipTests[1].raw { 368 t.Errorf("got %q want %q", s, gunzipTests[1].raw) 369 } 370 } 371 372 func TestMultistreamFalse(t *testing.T) { 373 // Find concatenation test. 374 var tt gunzipTest 375 for _, tt = range gunzipTests { 376 if strings.HasSuffix(tt.desc, " x2") { 377 goto Found 378 } 379 } 380 t.Fatal("cannot find hello.txt x2 in gunzip tests") 381 382 Found: 383 br := bytes.NewReader(tt.gzip) 384 var r Reader 385 if err := r.Reset(br); err != nil { 386 t.Fatalf("first reset: %v", err) 387 } 388 389 // Expect two streams with "hello world\n", then real EOF. 390 const hello = "hello world\n" 391 392 r.Multistream(false) 393 data, err := ioutil.ReadAll(&r) 394 if string(data) != hello || err != nil { 395 t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil) 396 } 397 398 if err := r.Reset(br); err != nil { 399 t.Fatalf("second reset: %v", err) 400 } 401 r.Multistream(false) 402 data, err = ioutil.ReadAll(&r) 403 if string(data) != hello || err != nil { 404 t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil) 405 } 406 407 if err := r.Reset(br); err != io.EOF { 408 t.Fatalf("third reset: err=%v, want io.EOF", err) 409 } 410 } 411