public void testRandomReads() throws IOException {
   int length = randomIntBetween(10, scaledRandomIntBetween(PAGE_SIZE * 2, PAGE_SIZE * 20));
   BytesReference pbr = newBytesReference(length);
   StreamInput streamInput = pbr.streamInput();
   BytesRefBuilder target = new BytesRefBuilder();
   while (target.length() < pbr.length()) {
     switch (randomIntBetween(0, 10)) {
       case 6:
       case 5:
         target.append(new BytesRef(new byte[] {streamInput.readByte()}));
         break;
       case 4:
       case 3:
         BytesRef bytesRef =
             streamInput.readBytesRef(scaledRandomIntBetween(1, pbr.length() - target.length()));
         target.append(bytesRef);
         break;
       default:
         byte[] buffer = new byte[scaledRandomIntBetween(1, pbr.length() - target.length())];
         int offset = scaledRandomIntBetween(0, buffer.length - 1);
         int read = streamInput.read(buffer, offset, buffer.length - offset);
         target.append(new BytesRef(buffer, offset, read));
         break;
     }
   }
   assertEquals(pbr.length(), target.length());
   BytesRef targetBytes = target.get();
   assertArrayEquals(
       pbr.toBytes(),
       Arrays.copyOfRange(targetBytes.bytes, targetBytes.offset, targetBytes.length));
 }
  public void testSliceStreamInput() throws IOException {
    int length = randomIntBetween(10, scaledRandomIntBetween(PAGE_SIZE * 2, PAGE_SIZE * 20));
    BytesReference pbr = newBytesReference(length);

    // test stream input over slice (upper half of original)
    int sliceOffset = randomIntBetween(1, length / 2);
    int sliceLength = length - sliceOffset;
    BytesReference slice = pbr.slice(sliceOffset, sliceLength);
    StreamInput sliceInput = slice.streamInput();
    assertEquals(sliceInput.available(), sliceLength);

    // single reads
    assertEquals(slice.get(0), sliceInput.readByte());
    assertEquals(slice.get(1), sliceInput.readByte());
    assertEquals(slice.get(2), sliceInput.readByte());
    assertEquals(sliceInput.available(), sliceLength - 3);

    // reset the slice stream for bulk reading
    sliceInput.reset();
    assertEquals(sliceInput.available(), sliceLength);

    // bulk read
    byte[] sliceBytes = new byte[sliceLength];
    sliceInput.readFully(sliceBytes);
    assertEquals(sliceInput.available(), 0);

    // compare slice content with upper half of original
    byte[] pbrSliceBytes = Arrays.copyOfRange(pbr.toBytes(), sliceOffset, length);
    assertArrayEquals(pbrSliceBytes, sliceBytes);

    // compare slice bytes with bytes read from slice via streamInput :D
    byte[] sliceToBytes = slice.toBytes();
    assertEquals(sliceBytes.length, sliceToBytes.length);
    assertArrayEquals(sliceBytes, sliceToBytes);

    sliceInput.reset();
    assertEquals(sliceInput.available(), sliceLength);
    byte[] buffer = new byte[sliceLength + scaledRandomIntBetween(1, 100)];
    int offset = scaledRandomIntBetween(0, Math.max(1, buffer.length - sliceLength - 1));
    int read = sliceInput.read(buffer, offset, sliceLength / 2);
    assertEquals(sliceInput.available(), sliceLength - read);
    sliceInput.read(buffer, offset + read, sliceLength - read);
    assertArrayEquals(sliceBytes, Arrays.copyOfRange(buffer, offset, offset + sliceLength));
    assertEquals(sliceInput.available(), 0);
  }
  public void testStreamInput() throws IOException {
    int length = randomIntBetween(10, scaledRandomIntBetween(PAGE_SIZE * 2, PAGE_SIZE * 20));
    BytesReference pbr = newBytesReference(length);
    StreamInput si = pbr.streamInput();
    assertNotNull(si);

    // read single bytes one by one
    assertEquals(pbr.get(0), si.readByte());
    assertEquals(pbr.get(1), si.readByte());
    assertEquals(pbr.get(2), si.readByte());

    // reset the stream for bulk reading
    si.reset();

    // buffer for bulk reads
    byte[] origBuf = new byte[length];
    random().nextBytes(origBuf);
    byte[] targetBuf = Arrays.copyOf(origBuf, origBuf.length);

    // bulk-read 0 bytes: must not modify buffer
    si.readBytes(targetBuf, 0, 0);
    assertEquals(origBuf[0], targetBuf[0]);
    si.reset();

    // read a few few bytes as ints
    int bytesToRead = randomIntBetween(1, length / 2);
    for (int i = 0; i < bytesToRead; i++) {
      int b = si.read();
      assertEquals(pbr.get(i) & 0xff, b);
    }
    si.reset();

    // bulk-read all
    si.readFully(targetBuf);
    assertArrayEquals(pbr.toBytes(), targetBuf);

    // continuing to read should now fail with EOFException
    try {
      si.readByte();
      fail("expected EOF");
    } catch (EOFException | IndexOutOfBoundsException eof) {
      // yay
    }

    // try to read more than the stream contains
    si.reset();
    expectThrows(IndexOutOfBoundsException.class, () -> si.readBytes(targetBuf, 0, length * 2));
  }