1package fwd 2 3import ( 4 "bytes" 5 "io" 6 "io/ioutil" 7 "math/rand" 8 "testing" 9 "unsafe" 10) 11 12// partialReader reads into only 13// part of the supplied byte slice 14// to the underlying reader 15type partialReader struct { 16 r io.Reader 17} 18 19func (p partialReader) Read(b []byte) (int, error) { 20 n := max(1, rand.Intn(len(b))) 21 return p.r.Read(b[:n]) 22} 23 24func randomBts(sz int) []byte { 25 o := make([]byte, sz) 26 for i := 0; i < len(o); i += 8 { 27 j := (*int64)(unsafe.Pointer(&o[i])) 28 *j = rand.Int63() 29 } 30 return o 31} 32 33func TestRead(t *testing.T) { 34 bts := randomBts(512) 35 36 // make the buffer much 37 // smaller than the underlying 38 // bytes to incur multiple fills 39 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 128) 40 41 if rd.BufferSize() != cap(rd.data) { 42 t.Errorf("BufferSize() returned %d; should return %d", rd.BufferSize(), cap(rd.data)) 43 } 44 45 // starting Buffered() should be 0 46 if rd.Buffered() != 0 { 47 t.Errorf("Buffered() should return 0 at initialization; got %d", rd.Buffered()) 48 } 49 50 some := make([]byte, 32) 51 n, err := rd.Read(some) 52 if err != nil { 53 t.Fatal(err) 54 } 55 if n == 0 { 56 t.Fatal("read 0 bytes w/ a non-nil error!") 57 } 58 some = some[:n] 59 60 more := make([]byte, 64) 61 j, err := rd.Read(more) 62 if err != nil { 63 t.Fatal(err) 64 } 65 if j == 0 { 66 t.Fatal("read 0 bytes w/ a non-nil error") 67 } 68 more = more[:j] 69 70 out, err := ioutil.ReadAll(rd) 71 if err != nil { 72 t.Fatal(err) 73 } 74 75 all := append(some, more...) 76 all = append(all, out...) 77 78 if !bytes.Equal(bts, all) { 79 t.Errorf("bytes not equal; %d bytes in and %d bytes out", len(bts), len(out)) 80 } 81 82 // test filling out of the underlying reader 83 big := randomBts(1 << 21) 84 rd = NewReaderSize(partialReader{bytes.NewReader(big)}, 2048) 85 buf := make([]byte, 3100) 86 87 n, err = rd.ReadFull(buf) 88 if err != nil { 89 t.Fatal(err) 90 } 91 if n != 3100 { 92 t.Errorf("expected 3100 bytes read by ReadFull; got %d", n) 93 } 94 if !bytes.Equal(buf[:n], big[:n]) { 95 t.Error("data parity") 96 } 97 rest := make([]byte, (1<<21)-3100) 98 n, err = io.ReadFull(rd, rest) 99 if err != nil { 100 t.Fatal(err) 101 } 102 if n != len(rest) { 103 t.Errorf("expected %d bytes read by io.ReadFull; got %d", len(rest), n) 104 } 105 if !bytes.Equal(append(buf, rest...), big) { 106 t.Fatal("data parity") 107 } 108} 109 110func TestReadByte(t *testing.T) { 111 bts := randomBts(512) 112 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 98) 113 114 var ( 115 err error 116 i int 117 b byte 118 ) 119 120 // scan through the whole 121 // array byte-by-byte 122 for err != io.EOF { 123 b, err = rd.ReadByte() 124 if err == nil { 125 if b != bts[i] { 126 t.Fatalf("offset %d: %d in; %d out", i, b, bts[i]) 127 } 128 } 129 i++ 130 } 131 if err != io.EOF { 132 t.Fatal(err) 133 } 134} 135 136func TestSkipNoSeek(t *testing.T) { 137 bts := randomBts(1024) 138 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 200) 139 140 n, err := rd.Skip(512) 141 if err != nil { 142 t.Fatal(err) 143 } 144 if n != 512 { 145 t.Fatalf("Skip() returned a nil error, but skipped %d bytes instead of %d", n, 512) 146 } 147 148 var b byte 149 b, err = rd.ReadByte() 150 if err != nil { 151 t.Fatal(err) 152 } 153 154 if b != bts[512] { 155 t.Fatalf("at index %d: %d in; %d out", 512, bts[512], b) 156 } 157 158 n, err = rd.Skip(10) 159 if err != nil { 160 t.Fatal(err) 161 } 162 if n != 10 { 163 t.Fatalf("Skip() returned a nil error, but skipped %d bytes instead of %d", n, 10) 164 } 165 166 // now try to skip past the end 167 rd = NewReaderSize(partialReader{bytes.NewReader(bts)}, 200) 168 169 n, err = rd.Skip(2000) 170 if err != io.ErrUnexpectedEOF { 171 t.Fatalf("expected error %q; got %q", io.EOF, err) 172 } 173 if n != 1024 { 174 t.Fatalf("expected to skip only 1024 bytes; skipped %d", n) 175 } 176} 177 178func TestSkipSeek(t *testing.T) { 179 bts := randomBts(1024) 180 181 // bytes.Reader implements io.Seeker 182 rd := NewReaderSize(bytes.NewReader(bts), 200) 183 184 n, err := rd.Skip(512) 185 if err != nil { 186 t.Fatal(err) 187 } 188 if n != 512 { 189 t.Fatalf("Skip() returned a nil error, but skipped %d bytes instead of %d", n, 512) 190 } 191 192 var b byte 193 b, err = rd.ReadByte() 194 if err != nil { 195 t.Fatal(err) 196 } 197 198 if b != bts[512] { 199 t.Fatalf("at index %d: %d in; %d out", 512, bts[512], b) 200 } 201 202 n, err = rd.Skip(10) 203 if err != nil { 204 t.Fatal(err) 205 } 206 if n != 10 { 207 t.Fatalf("Skip() returned a nil error, but skipped %d bytes instead of %d", n, 10) 208 } 209 210 // now try to skip past the end 211 rd.Reset(bytes.NewReader(bts)) 212 213 // because of how bytes.Reader 214 // implements Seek, this should 215 // return (2000, nil) 216 n, err = rd.Skip(2000) 217 if err != nil { 218 t.Fatal(err) 219 } 220 if n != 2000 { 221 t.Fatalf("should have returned %d bytes; returned %d", 2000, n) 222 } 223 224 // the next call to Read() 225 // should return io.EOF 226 n, err = rd.Read([]byte{0, 0, 0}) 227 if err != io.EOF { 228 t.Errorf("expected %q; got %q", io.EOF, err) 229 } 230 if n != 0 { 231 t.Errorf("expected 0 bytes read; got %d", n) 232 } 233 234} 235 236func TestPeek(t *testing.T) { 237 bts := randomBts(1024) 238 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 200) 239 240 // first, a peek < buffer size 241 var ( 242 peek []byte 243 err error 244 ) 245 peek, err = rd.Peek(100) 246 if err != nil { 247 t.Fatal(err) 248 } 249 if len(peek) != 100 { 250 t.Fatalf("asked for %d bytes; got %d", 100, len(peek)) 251 } 252 if !bytes.Equal(peek, bts[:100]) { 253 t.Fatal("peeked bytes not equal") 254 } 255 256 // now, a peek > buffer size 257 peek, err = rd.Peek(256) 258 if err != nil { 259 t.Fatal(err) 260 } 261 if len(peek) != 256 { 262 t.Fatalf("asked for %d bytes; got %d", 100, len(peek)) 263 } 264 if !bytes.Equal(peek, bts[:256]) { 265 t.Fatal("peeked bytes not equal") 266 } 267 268 // now try to peek past EOF 269 peek, err = rd.Peek(2048) 270 if err != io.EOF { 271 t.Fatalf("expected error %q; got %q", io.EOF, err) 272 } 273 if len(peek) != 1024 { 274 t.Fatalf("expected %d bytes peek-able; got %d", 1024, len(peek)) 275 } 276} 277 278func TestNext(t *testing.T) { 279 size := 1024 280 bts := randomBts(size) 281 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 200) 282 283 chunksize := 256 284 chunks := size / chunksize 285 286 for i := 0; i < chunks; i++ { 287 out, err := rd.Next(chunksize) 288 if err != nil { 289 t.Fatal(err) 290 } 291 start := chunksize * i 292 if !bytes.Equal(bts[start:start+chunksize], out) { 293 t.Fatalf("chunk %d: chunks not equal", i+1) 294 } 295 } 296} 297 298func TestWriteTo(t *testing.T) { 299 bts := randomBts(2048) 300 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 200) 301 302 // cause the buffer 303 // to fill a little, just 304 // to complicate things 305 rd.Peek(25) 306 307 var out bytes.Buffer 308 n, err := rd.WriteTo(&out) 309 if err != nil { 310 t.Fatal(err) 311 } 312 if n != 2048 { 313 t.Fatalf("should have written %d bytes; wrote %d", 2048, n) 314 } 315 if !bytes.Equal(out.Bytes(), bts) { 316 t.Fatal("bytes not equal") 317 } 318} 319 320func TestReadFull(t *testing.T) { 321 bts := randomBts(1024) 322 rd := NewReaderSize(partialReader{bytes.NewReader(bts)}, 256) 323 324 // try to ReadFull() the whole thing 325 out := make([]byte, 1024) 326 n, err := rd.ReadFull(out) 327 if err != nil { 328 t.Fatal(err) 329 } 330 if n != 1024 { 331 t.Fatalf("expected to read %d bytes; read %d", 1024, n) 332 } 333 if !bytes.Equal(bts, out) { 334 t.Fatal("bytes not equal") 335 } 336 337 // we've read everything; this should EOF 338 n, err = rd.Read(out) 339 if err != io.EOF { 340 t.Fatalf("expected %q; got %q", io.EOF, err) 341 } 342 343 rd.Reset(partialReader{bytes.NewReader(bts)}) 344 345 // now try to read *past* EOF 346 out = make([]byte, 1500) 347 n, err = rd.ReadFull(out) 348 if err != io.ErrUnexpectedEOF { 349 t.Fatalf("expected error %q; got %q", io.EOF, err) 350 } 351 if n != 1024 { 352 t.Fatalf("expected to read %d bytes; read %d", 1024, n) 353 } 354} 355 356type readCounter struct { 357 r io.Reader 358 count int 359} 360 361func (r *readCounter) Read(p []byte) (int, error) { 362 r.count++ 363 return r.r.Read(p) 364} 365 366func TestReadFullPerf(t *testing.T) { 367 const size = 1 << 22 368 data := randomBts(size) 369 370 c := readCounter{ 371 r: &partialReader{ 372 r: bytes.NewReader(data), 373 }, 374 } 375 376 r := NewReader(&c) 377 378 const segments = 4 379 out := make([]byte, size/segments) 380 381 for i := 0; i < segments; i++ { 382 // force an unaligned read 383 _, err := r.Peek(5) 384 if err != nil { 385 t.Fatal(err) 386 } 387 388 n, err := r.ReadFull(out) 389 if err != nil { 390 t.Fatal(err) 391 } 392 if n != size/segments { 393 t.Fatalf("read %d bytes, not %d", n, size/segments) 394 } 395 } 396 397 t.Logf("called Read() on the underlying reader %d times to fill %d buffers", c.count, size/r.BufferSize()) 398} 399