001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.nio;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNotEquals;
023import static org.junit.Assert.assertTrue;
024import static org.junit.Assert.fail;
025
026import java.io.IOException;
027import java.nio.BufferOverflowException;
028import java.nio.BufferUnderflowException;
029import java.nio.ByteBuffer;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.testclassification.MiscTests;
032import org.apache.hadoop.hbase.testclassification.SmallTests;
033import org.apache.hadoop.hbase.util.ByteBufferUtils;
034import org.apache.hadoop.hbase.util.Bytes;
035import org.apache.hadoop.hbase.util.ObjectIntPair;
036import org.junit.ClassRule;
037import org.junit.Test;
038import org.junit.experimental.categories.Category;
039
040@Category({ MiscTests.class, SmallTests.class })
041public class TestMultiByteBuff {
042
043  @ClassRule
044  public static final HBaseClassTestRule CLASS_RULE =
045    HBaseClassTestRule.forClass(TestMultiByteBuff.class);
046
047  /**
048   * Test right answer though we span many sub-buffers.
049   */
050  @Test
051  public void testGetShort() {
052    ByteBuffer bb1 = ByteBuffer.allocate(1);
053    bb1.put((byte) 1);
054    ByteBuffer bb2 = ByteBuffer.allocate(1);
055    bb2.put((byte) 0);
056    ByteBuffer bb3 = ByteBuffer.allocate(1);
057    bb3.put((byte) 2);
058    ByteBuffer bb4 = ByteBuffer.allocate(1);
059    bb4.put((byte) 3);
060    MultiByteBuff mbb = new MultiByteBuff(bb1, bb2, bb3, bb4);
061    assertEquals(256, mbb.getShortAfterPosition(0));
062    assertEquals(2, mbb.getShortAfterPosition(1));
063    assertEquals(515, mbb.getShortAfterPosition(2));
064  }
065
066  @Test
067  public void testWritesAndReads() {
068    // Absolute reads
069    ByteBuffer bb1 = ByteBuffer.allocate(15);
070    ByteBuffer bb2 = ByteBuffer.allocate(15);
071    int i1 = 4;
072    bb1.putInt(i1);
073    long l1 = 45L, l2 = 100L, l3 = 12345L;
074    bb1.putLong(l1);
075    short s1 = 2;
076    bb1.putShort(s1);
077    byte[] b = Bytes.toBytes(l2);
078    bb1.put(b, 0, 1);
079    bb2.put(b, 1, 7);
080    bb2.putLong(l3);
081    MultiByteBuff mbb = new MultiByteBuff(bb1, bb2);
082    assertEquals(l1, mbb.getLong(4));
083    assertEquals(l2, mbb.getLong(14));
084    assertEquals(l3, mbb.getLong(22));
085    assertEquals(i1, mbb.getInt(0));
086    assertEquals(s1, mbb.getShort(12));
087    // Relative reads
088    assertEquals(i1, mbb.getInt());
089    assertEquals(l1, mbb.getLong());
090    assertEquals(s1, mbb.getShort());
091    assertEquals(l2, mbb.getLong());
092    assertEquals(l3, mbb.getLong());
093    // Absolute writes
094    bb1 = ByteBuffer.allocate(15);
095    bb2 = ByteBuffer.allocate(15);
096    mbb = new MultiByteBuff(bb1, bb2);
097    byte b1 = 5, b2 = 31;
098    mbb.put(b1);
099    mbb.putLong(l1);
100    mbb.putInt(i1);
101    mbb.putLong(l2);
102    mbb.put(b2);
103    mbb.position(mbb.position() + 2);
104    try {
105      mbb.putLong(l3);
106      fail("'Should have thrown BufferOverflowException");
107    } catch (BufferOverflowException e) {
108    }
109    mbb.position(mbb.position() - 2);
110    mbb.putLong(l3);
111    mbb.rewind();
112    assertEquals(b1, mbb.get());
113    assertEquals(l1, mbb.getLong());
114    assertEquals(i1, mbb.getInt());
115    assertEquals(l2, mbb.getLong());
116    assertEquals(b2, mbb.get());
117    assertEquals(l3, mbb.getLong());
118    mbb.put(21, b1);
119    mbb.position(21);
120    assertEquals(b1, mbb.get());
121    mbb.put(b);
122    assertEquals(l2, mbb.getLong(22));
123  }
124
125  @Test
126  public void testPutPrimitives() {
127    ByteBuffer bb = ByteBuffer.allocate(10);
128    SingleByteBuff s = new SingleByteBuff(bb);
129    s.putLong(-4465109508325701663L);
130    bb.rewind();
131    long long1 = bb.getLong();
132    assertEquals(-4465109508325701663L, long1);
133    s.position(8);
134  }
135
136  @Test
137  public void testArrayBasedMethods() {
138    byte[] b = new byte[15];
139    ByteBuffer bb1 = ByteBuffer.wrap(b, 1, 10).slice();
140    ByteBuffer bb2 = ByteBuffer.allocate(15);
141    ByteBuff mbb1 = new MultiByteBuff(bb1, bb2);
142    assertFalse(mbb1.hasArray());
143    try {
144      mbb1.array();
145      fail();
146    } catch (UnsupportedOperationException e) {
147    }
148    try {
149      mbb1.arrayOffset();
150      fail();
151    } catch (UnsupportedOperationException e) {
152    }
153    mbb1 = new SingleByteBuff(bb1);
154    assertTrue(mbb1.hasArray());
155    assertEquals(1, mbb1.arrayOffset());
156    assertEquals(b, mbb1.array());
157    mbb1 = new SingleByteBuff(ByteBuffer.allocateDirect(10));
158    assertFalse(mbb1.hasArray());
159    try {
160      mbb1.array();
161      fail();
162    } catch (UnsupportedOperationException e) {
163    }
164    try {
165      mbb1.arrayOffset();
166      fail();
167    } catch (UnsupportedOperationException e) {
168    }
169  }
170
171  @Test
172  public void testMarkAndResetWithMBB() {
173    ByteBuffer bb1 = ByteBuffer.allocateDirect(15);
174    ByteBuffer bb2 = ByteBuffer.allocateDirect(15);
175    bb1.putInt(4);
176    long l1 = 45L, l2 = 100L, l3 = 12345L;
177    bb1.putLong(l1);
178    bb1.putShort((short) 2);
179    byte[] b = Bytes.toBytes(l2);
180    bb1.put(b, 0, 1);
181    bb2.put(b, 1, 7);
182    bb2.putLong(l3);
183    ByteBuff multi = new MultiByteBuff(bb1, bb2);
184    assertEquals(4, multi.getInt());
185    assertEquals(l1, multi.getLong());
186    multi.mark();
187    assertEquals((short) 2, multi.getShort());
188    multi.reset();
189    assertEquals((short) 2, multi.getShort());
190    multi.mark();
191    assertEquals(l2, multi.getLong());
192    multi.reset();
193    assertEquals(l2, multi.getLong());
194    multi.mark();
195    assertEquals(l3, multi.getLong());
196    multi.reset();
197    assertEquals(l3, multi.getLong());
198    // Try absolute gets with mark and reset
199    multi.mark();
200    assertEquals(l2, multi.getLong(14));
201    multi.reset();
202    assertEquals(l3, multi.getLong(22));
203    // Just reset to see what happens
204    multi.reset();
205    assertEquals(l2, multi.getLong(14));
206    multi.mark();
207    assertEquals(l3, multi.getLong(22));
208    multi.reset();
209  }
210
211  @Test
212  public void testSkipNBytes() {
213    ByteBuffer bb1 = ByteBuffer.allocate(15);
214    ByteBuffer bb2 = ByteBuffer.allocate(15);
215    bb1.putInt(4);
216    long l1 = 45L, l2 = 100L, l3 = 12345L;
217    bb1.putLong(l1);
218    bb1.putShort((short) 2);
219    byte[] b = Bytes.toBytes(l2);
220    bb1.put(b, 0, 1);
221    bb2.put(b, 1, 7);
222    bb2.putLong(l3);
223    MultiByteBuff multi = new MultiByteBuff(bb1, bb2);
224    assertEquals(4, multi.getInt());
225    assertEquals(l1, multi.getLong());
226    multi.skip(10);
227    assertEquals(l3, multi.getLong());
228  }
229
230  @Test
231  public void testMoveBack() {
232    ByteBuffer bb1 = ByteBuffer.allocate(15);
233    ByteBuffer bb2 = ByteBuffer.allocate(15);
234    bb1.putInt(4);
235    long l1 = 45L, l2 = 100L, l3 = 12345L;
236    bb1.putLong(l1);
237    bb1.putShort((short) 2);
238    byte[] b = Bytes.toBytes(l2);
239    bb1.put(b, 0, 1);
240    bb2.put(b, 1, 7);
241    bb2.putLong(l3);
242    MultiByteBuff multi = new MultiByteBuff(bb1, bb2);
243    assertEquals(4, multi.getInt());
244    assertEquals(l1, multi.getLong());
245    multi.skip(10);
246    multi.moveBack(4);
247    multi.moveBack(6);
248    multi.moveBack(8);
249    assertEquals(l1, multi.getLong());
250  }
251
252  @Test
253  public void testSubBuffer() {
254    ByteBuffer bb1 = ByteBuffer.allocateDirect(10);
255    ByteBuffer bb2 = ByteBuffer.allocateDirect(10);
256    MultiByteBuff multi = new MultiByteBuff(bb1, bb2);
257    long l1 = 1234L, l2 = 100L;
258    multi.putLong(l1);
259    multi.putLong(l2);
260    multi.rewind();
261    ByteBuffer sub = multi.asSubByteBuffer(Bytes.SIZEOF_LONG);
262    assertEquals(bb1, sub);
263    assertEquals(l1, ByteBufferUtils.toLong(sub, sub.position()));
264    multi.skip(Bytes.SIZEOF_LONG);
265    sub = multi.asSubByteBuffer(Bytes.SIZEOF_LONG);
266    assertNotEquals(bb1, sub);
267    assertNotEquals(bb2, sub);
268    assertEquals(l2, ByteBufferUtils.toLong(sub, sub.position()));
269    multi.rewind();
270    ObjectIntPair<ByteBuffer> p = new ObjectIntPair<>();
271    multi.asSubByteBuffer(8, Bytes.SIZEOF_LONG, p);
272    assertNotEquals(bb1, p.getFirst());
273    assertNotEquals(bb2, p.getFirst());
274    assertEquals(0, p.getSecond());
275    assertEquals(l2, ByteBufferUtils.toLong(sub, p.getSecond()));
276  }
277
278  @Test
279  public void testSliceDuplicateMethods() throws Exception {
280    ByteBuffer bb1 = ByteBuffer.allocateDirect(10);
281    ByteBuffer bb2 = ByteBuffer.allocateDirect(15);
282    MultiByteBuff multi = new MultiByteBuff(bb1, bb2);
283    long l1 = 1234L, l2 = 100L;
284    multi.put((byte) 2);
285    multi.putLong(l1);
286    multi.putLong(l2);
287    multi.putInt(45);
288    multi.position(1);
289    multi.limit(multi.position() + (2 * Bytes.SIZEOF_LONG));
290    ByteBuff sliced = multi.slice();
291    assertEquals(0, sliced.position());
292    assertEquals((2 * Bytes.SIZEOF_LONG), sliced.limit());
293    assertEquals(l1, sliced.getLong());
294    assertEquals(l2, sliced.getLong());
295    ByteBuff dup = multi.duplicate();
296    assertEquals(1, dup.position());
297    assertEquals(dup.position() + (2 * Bytes.SIZEOF_LONG), dup.limit());
298    assertEquals(l1, dup.getLong());
299    assertEquals(l2, dup.getLong());
300  }
301
302  @Test
303  public void testGetWithPosOnMultiBuffers() throws IOException {
304    byte[] b = new byte[4];
305    byte[] b1 = new byte[4];
306    ByteBuffer bb1 = ByteBuffer.wrap(b);
307    ByteBuffer bb2 = ByteBuffer.wrap(b1);
308    MultiByteBuff mbb1 = new MultiByteBuff(bb1, bb2);
309    mbb1.position(2);
310    mbb1.putInt(4);
311    int res = mbb1.getInt(2);
312    byte[] bres = new byte[4];
313    bres[0] = mbb1.get(2);
314    bres[1] = mbb1.get(3);
315    bres[2] = mbb1.get(4);
316    bres[3] = mbb1.get(5);
317    int expected = Bytes.toInt(bres);
318    assertEquals(expected, res);
319  }
320
321  @Test
322  public void testGetIntStrictlyForwardWithPosOnMultiBuffers() throws IOException {
323    byte[] b = new byte[4];
324    byte[] b1 = new byte[8];
325    ByteBuffer bb1 = ByteBuffer.wrap(b);
326    ByteBuffer bb2 = ByteBuffer.wrap(b1);
327    MultiByteBuff mbb1 = new MultiByteBuff(bb1, bb2);
328    mbb1.position(2);
329    mbb1.putInt(4);
330    mbb1.position(7);
331    mbb1.put((byte) 2);
332    mbb1.putInt(3);
333    mbb1.rewind();
334    mbb1.getIntAfterPosition(4);
335    byte res = mbb1.get(7);
336    assertEquals((byte) 2, res);
337    mbb1.position(7);
338    int intRes = mbb1.getIntAfterPosition(1);
339    assertEquals(3, intRes);
340  }
341
342  @Test
343  public void testPositonalCopyToByteArray() throws Exception {
344    byte[] b = new byte[4];
345    byte[] b1 = new byte[8];
346    ByteBuffer bb1 = ByteBuffer.wrap(b);
347    ByteBuffer bb2 = ByteBuffer.wrap(b1);
348    MultiByteBuff mbb1 = new MultiByteBuff(bb1, bb2);
349    mbb1.position(2);
350    mbb1.putInt(4);
351    mbb1.position(7);
352    mbb1.put((byte) 2);
353    mbb1.putInt(3);
354    byte[] dst = new byte[4];
355    mbb1.get(2, dst, 0, 4);
356    assertEquals(4, Bytes.toInt(dst));
357    assertEquals(12, mbb1.position());
358    mbb1.position(1);
359    dst = new byte[4];
360    mbb1.get(8, dst, 0, 4);
361    assertEquals(3, Bytes.toInt(dst));
362    assertEquals(1, mbb1.position());
363    mbb1.position(12);
364    dst = new byte[1];
365    mbb1.get(7, dst, 0, 1);
366    assertEquals(2, dst[0]);
367    assertEquals(12, mbb1.position());
368  }
369
370  @Test
371  public void testToBytes() throws Exception {
372    byte[] b = new byte[4];
373    byte[] b1 = new byte[8];
374    for (int i = 0; i < b.length; i++) {
375      b[i] = (byte) i;
376    }
377    for (int i = 0; i < b1.length; i++) {
378      b1[i] = (byte) (b1.length + i);
379    }
380    ByteBuffer bb1 = ByteBuffer.wrap(b);
381    ByteBuffer bb2 = ByteBuffer.wrap(b1);
382    MultiByteBuff mbb1 = new MultiByteBuff(bb1, bb2);
383
384    // Test 1 Offset hitting exclusive second element
385    byte[] actual = mbb1.toBytes(6, 4);
386    assertTrue(Bytes.equals(actual, 0, actual.length, b1, 2, 4));
387    // Test 2 offset hitting exclusive second element
388    // but continuing to the end of the second one
389    actual = mbb1.toBytes(5, 7);
390    assertTrue(Bytes.equals(actual, 0, actual.length, b1, 1, 7));
391    // Test 3 with offset hitting in first element,
392    // continuing to next
393    actual = mbb1.toBytes(2, 7);
394    byte[] expected = new byte[7];
395    System.arraycopy(b, 2, expected, 0, 2);
396    System.arraycopy(b1, 0, expected, 2, 5);
397    assertTrue(Bytes.equals(actual, expected));
398    // Test 4 hitting only in first exclusively
399    actual = mbb1.toBytes(1, 3);
400    assertTrue(Bytes.equals(actual, 0, actual.length, b, 1, 3));
401  }
402
403  @Test
404  public void testHasRemaining() {
405    ByteBuffer b1 = ByteBuffer.allocate(8);
406    ByteBuffer b2 = ByteBuffer.allocate(8);
407    ByteBuffer b3 = ByteBuffer.allocate(8);
408    MultiByteBuff mbb1 = new MultiByteBuff(b1, b2, b3);
409    assertTrue(mbb1.hasRemaining());
410    mbb1.limit(20); // Limit in mid of last of BB
411    mbb1.position(15);
412    mbb1.get();// We are at the end of second BB
413    assertTrue(mbb1.hasRemaining());
414    mbb1.position(20);
415    assertFalse(mbb1.hasRemaining());
416    mbb1.limit(12); // Limit in mid of second BB
417    mbb1.position(11);
418    assertTrue(mbb1.hasRemaining());
419    mbb1.get(); // Now we have reached the limit
420    assertFalse(mbb1.hasRemaining());
421    mbb1.limit(16);// Limit at begin of the last BB
422    mbb1.position(15);
423    assertTrue(mbb1.hasRemaining());
424    mbb1.get(); // Now we have reached the limit
425    assertFalse(mbb1.hasRemaining());
426  }
427
428  @Test
429  public void testGetPrimitivesWithSmallIndividualBBs() {
430    short s = 45;
431    int i = 2345;
432    long l = 75681526L;
433    ByteBuffer bb = ByteBuffer.allocate(14);
434    bb.putShort(s);
435    bb.putInt(i);
436    bb.putLong(l);
437
438    ByteBuffer bb1 = ((ByteBuffer) bb.duplicate().position(0).limit(1)).slice();
439    ByteBuffer bb2 = ((ByteBuffer) bb.duplicate().position(1).limit(3)).slice();
440    ByteBuffer bb3 = ((ByteBuffer) bb.duplicate().position(3).limit(5)).slice();
441    ByteBuffer bb4 = ((ByteBuffer) bb.duplicate().position(5).limit(11)).slice();
442    ByteBuffer bb5 = ((ByteBuffer) bb.duplicate().position(11).limit(12)).slice();
443    ByteBuffer bb6 = ((ByteBuffer) bb.duplicate().position(12).limit(14)).slice();
444    MultiByteBuff mbb = new MultiByteBuff(bb1, bb2, bb3, bb4, bb5, bb6);
445    assertEquals(s, mbb.getShortAfterPosition(0));
446    assertEquals(i, mbb.getIntAfterPosition(2));
447    assertEquals(l, mbb.getLongAfterPosition(6));
448
449    assertEquals(s, mbb.getShort(0));
450    assertEquals(i, mbb.getInt(2));
451    assertEquals(l, mbb.getLong(6));
452
453    mbb.position(0);
454    assertEquals(s, mbb.getShort());
455    assertEquals(i, mbb.getInt());
456    assertEquals(l, mbb.getLong());
457  }
458
459  @Test
460  public void testGetByteBufferWithOffsetAndPos() {
461    byte[] a = Bytes.toBytes("abcd");
462    byte[] b = Bytes.toBytes("efghijkl");
463    ByteBuffer aa = ByteBuffer.wrap(a);
464    ByteBuffer bb = ByteBuffer.wrap(b);
465    MultiByteBuff mbb = new MultiByteBuff(aa, bb);
466    ByteBuffer out = ByteBuffer.allocate(12);
467    mbb.get(out, 0, 1);
468    assertEquals(out.position(), 1);
469    assertTrue(Bytes.equals(Bytes.toBytes("a"), 0, 1, out.array(), 0, 1));
470
471    mbb.get(out, 1, 4);
472    assertEquals(out.position(), 5);
473    assertTrue(Bytes.equals(Bytes.toBytes("abcde"), 0, 5, out.array(), 0, 5));
474
475    mbb.get(out, 10, 1);
476    assertEquals(out.position(), 6);
477    assertTrue(Bytes.equals(Bytes.toBytes("abcdek"), 0, 6, out.array(), 0, 6));
478
479    mbb.get(out, 0, 6);
480    assertEquals(out.position(), 12);
481    assertTrue(Bytes.equals(Bytes.toBytes("abcdekabcdef"), 0, 12, out.array(), 0, 12));
482  }
483
484  @Test
485  public void testPositionalPutByteBuff() throws Exception {
486    ByteBuffer bb1 = ByteBuffer.allocate(100);
487    ByteBuffer bb2 = ByteBuffer.allocate(100);
488    MultiByteBuff srcMultiByteBuff = new MultiByteBuff(bb1, bb2);
489    for (int i = 0; i < 25; i++) {
490      srcMultiByteBuff.putLong(i * 8L);
491    }
492    // Test MultiByteBuff To MultiByteBuff
493    doTestPositionalPutByteBuff(srcMultiByteBuff);
494
495    ByteBuffer bb3 = ByteBuffer.allocate(200);
496    SingleByteBuff srcSingleByteBuff = new SingleByteBuff(bb3);
497    for (int i = 0; i < 25; i++) {
498      srcSingleByteBuff.putLong(i * 8L);
499    }
500    // Test SingleByteBuff To MultiByteBuff
501    doTestPositionalPutByteBuff(srcSingleByteBuff);
502  }
503
504  private void doTestPositionalPutByteBuff(ByteBuff srcByteBuff) throws Exception {
505    ByteBuffer bb3 = ByteBuffer.allocate(50);
506    ByteBuffer bb4 = ByteBuffer.allocate(50);
507    ByteBuffer bb5 = ByteBuffer.allocate(50);
508    ByteBuffer bb6 = ByteBuffer.allocate(50);
509    MultiByteBuff destMultiByteBuff = new MultiByteBuff(bb3, bb4, bb5, bb6);
510
511    // full copy
512    destMultiByteBuff.put(0, srcByteBuff, 0, 200);
513    int compareTo = ByteBuff.compareTo(srcByteBuff, 0, 200, destMultiByteBuff, 0, 200);
514    assertTrue(compareTo == 0);
515
516    // Test src to dest first ByteBuffer
517    destMultiByteBuff.put(0, srcByteBuff, 32, 63);
518    compareTo = ByteBuff.compareTo(srcByteBuff, 32, 63, destMultiByteBuff, 0, 63);
519    assertTrue(compareTo == 0);
520
521    // Test src to dest first and second ByteBuffer
522    destMultiByteBuff.put(0, srcByteBuff, 0, 63);
523    compareTo = ByteBuff.compareTo(srcByteBuff, 0, 63, destMultiByteBuff, 0, 63);
524    assertTrue(compareTo == 0);
525
526    // Test src to dest third ByteBuffer
527    destMultiByteBuff.put(100, srcByteBuff, 100, 50);
528    compareTo = ByteBuff.compareTo(srcByteBuff, 100, 50, destMultiByteBuff, 100, 50);
529    assertTrue(compareTo == 0);
530
531    // Test src to dest first,second and third ByteBuffer
532    destMultiByteBuff.put(48, srcByteBuff, 32, 63);
533    compareTo = ByteBuff.compareTo(srcByteBuff, 32, 63, destMultiByteBuff, 48, 63);
534    assertTrue(compareTo == 0);
535
536    // Test src to dest first,second,third and fourth ByteBuffer
537    destMultiByteBuff.put(48, srcByteBuff, 32, 120);
538    compareTo = ByteBuff.compareTo(srcByteBuff, 32, 120, destMultiByteBuff, 48, 120);
539    assertTrue(compareTo == 0);
540
541    // Test src to dest first and second ByteBuffer
542    destMultiByteBuff.put(0, srcByteBuff, 132, 63);
543    compareTo = ByteBuff.compareTo(srcByteBuff, 132, 63, destMultiByteBuff, 0, 63);
544    assertTrue(compareTo == 0);
545
546    // Test src to dest second,third and fourth ByteBuffer
547    destMultiByteBuff.put(95, srcByteBuff, 132, 67);
548    compareTo = ByteBuff.compareTo(srcByteBuff, 132, 67, destMultiByteBuff, 95, 67);
549    assertTrue(compareTo == 0);
550
551    // Test src to dest fourth ByteBuffer
552    destMultiByteBuff.put(162, srcByteBuff, 132, 24);
553    compareTo = ByteBuff.compareTo(srcByteBuff, 132, 24, destMultiByteBuff, 162, 24);
554    assertTrue(compareTo == 0);
555
556    // Test src BufferUnderflowException
557    try {
558      destMultiByteBuff.put(0, srcByteBuff, 0, 300);
559      fail();
560    } catch (BufferUnderflowException e) {
561      assertTrue(e != null);
562    }
563
564    try {
565      destMultiByteBuff.put(95, srcByteBuff, 132, 89);
566      fail();
567    } catch (BufferUnderflowException e) {
568      assertTrue(e != null);
569    }
570
571    // Test dest BufferOverflowException
572    try {
573      destMultiByteBuff.put(100, srcByteBuff, 0, 101);
574      fail();
575    } catch (BufferOverflowException e) {
576      assertTrue(e != null);
577    }
578
579    try {
580      destMultiByteBuff.put(151, srcByteBuff, 132, 68);
581      fail();
582    } catch (BufferOverflowException e) {
583      assertTrue(e != null);
584    }
585
586    destMultiByteBuff = new MultiByteBuff(bb3, bb4);
587    try {
588      destMultiByteBuff.put(0, srcByteBuff, 0, 101);
589      fail();
590    } catch (BufferOverflowException e) {
591      assertTrue(e != null);
592    }
593  }
594
595  @Test
596  public void testPositionalPutByte() throws Exception {
597    ByteBuffer bb1 = ByteBuffer.allocate(50);
598    ByteBuffer bb2 = ByteBuffer.allocate(50);
599    ByteBuffer bb3 = ByteBuffer.allocate(50);
600    ByteBuffer bb4 = ByteBuffer.allocate(50);
601    MultiByteBuff srcMultiByteBuff = new MultiByteBuff(bb1, bb2, bb3, bb4);
602    for (int i = 1; i <= 200; i++) {
603      srcMultiByteBuff.put((byte) 0xff);
604    }
605
606    srcMultiByteBuff.put(20, (byte) 0);
607    byte val = srcMultiByteBuff.get(20);
608    assertTrue(val == 0);
609
610    srcMultiByteBuff.put(50, (byte) 0);
611    val = srcMultiByteBuff.get(50);
612    assertTrue(val == 0);
613
614    srcMultiByteBuff.put(80, (byte) 0);
615    val = srcMultiByteBuff.get(80);
616    assertTrue(val == 0);
617
618    srcMultiByteBuff.put(100, (byte) 0);
619    val = srcMultiByteBuff.get(100);
620    assertTrue(val == 0);
621
622    srcMultiByteBuff.put(121, (byte) 0);
623    val = srcMultiByteBuff.get(121);
624    assertTrue(val == 0);
625
626    srcMultiByteBuff.put(150, (byte) 0);
627    val = srcMultiByteBuff.get(150);
628    assertTrue(val == 0);
629
630    srcMultiByteBuff.put(180, (byte) 0);
631    val = srcMultiByteBuff.get(180);
632    assertTrue(val == 0);
633
634    try {
635      srcMultiByteBuff.put(200, (byte) 0);
636      fail();
637    } catch (IndexOutOfBoundsException e) {
638      assertTrue(e != null);
639    }
640
641    try {
642      srcMultiByteBuff.put(260, (byte) 0);
643      fail();
644    } catch (IndexOutOfBoundsException e) {
645      assertTrue(e != null);
646    }
647  }
648}