1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.core;
21  
22  import java.nio.BufferOverflowException;
23  import java.nio.ByteBuffer;
24  import java.nio.ByteOrder;
25  import java.nio.ReadOnlyBufferException;
26  import java.nio.charset.CharacterCodingException;
27  import java.nio.charset.Charset;
28  import java.nio.charset.CharsetDecoder;
29  import java.nio.charset.CharsetEncoder;
30  import java.util.ArrayList;
31  import java.util.Date;
32  import java.util.EnumSet;
33  import java.util.List;
34  
35  import junit.framework.Assert;
36  import junit.framework.TestCase;
37  
38  import org.apache.mina.core.buffer.IoBuffer;
39  import org.apache.mina.util.Bar;
40  
41  /**
42   * Tests {@link IoBuffer}.
43   *
44   * @author The Apache MINA Project (dev@mina.apache.org)
45   * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (jeu, 26 jun 2008) $
46   */
47  public class IoBufferTest extends TestCase {
48  
49      public static void main(String[] args) {
50          junit.textui.TestRunner.run(IoBufferTest.class);
51      }
52  
53      @Override
54      protected void setUp() throws Exception {
55      }
56  
57      @Override
58      protected void tearDown() throws Exception {
59      }
60  
61      public void testAllocate() throws Exception {
62          for (int i = 10; i < 1048576 * 2; i = i * 11 / 10) // increase by 10%
63          {
64              IoBuffer buf = IoBuffer.allocate(i);
65              Assert.assertEquals(0, buf.position());
66              Assert.assertEquals(buf.capacity(), buf.remaining());
67              Assert.assertTrue(buf.capacity() >= i);
68              Assert.assertTrue(buf.capacity() < i * 2);
69          }
70      }
71  
72      public void testAutoExpand() throws Exception {
73          IoBuffer buf = IoBuffer.allocate(1);
74  
75          buf.put((byte) 0);
76          try {
77              buf.put((byte) 0);
78              Assert.fail();
79          } catch (BufferOverflowException e) {
80              // ignore
81          }
82  
83          buf.setAutoExpand(true);
84          buf.put((byte) 0);
85          Assert.assertEquals(2, buf.position());
86          Assert.assertEquals(2, buf.limit());
87          Assert.assertEquals(2, buf.capacity());
88  
89          buf.setAutoExpand(false);
90          try {
91              buf.put(3, (byte) 0);
92              Assert.fail();
93          } catch (IndexOutOfBoundsException e) {
94              // ignore
95          }
96  
97          buf.setAutoExpand(true);
98          buf.put(3, (byte) 0);
99          Assert.assertEquals(2, buf.position());
100         Assert.assertEquals(4, buf.limit());
101         Assert.assertEquals(4, buf.capacity());
102 
103         // Make sure the buffer is doubled up.
104         buf = IoBuffer.allocate(1).setAutoExpand(true);
105         int lastCapacity = buf.capacity();
106         for (int i = 0; i < 1048576; i ++) {
107             buf.put((byte) 0);
108             if (lastCapacity != buf.capacity()) {
109                 Assert.assertEquals(lastCapacity * 2, buf.capacity());
110                 lastCapacity = buf.capacity();
111             }
112         }
113     }
114 
115     public void testAutoExpandMark() throws Exception {
116         IoBuffer buf = IoBuffer.allocate(4).setAutoExpand(true);
117 
118         buf.put((byte) 0);
119         buf.put((byte) 0);
120         buf.put((byte) 0);
121 
122         // Position should be 3 when we reset this buffer.
123         buf.mark();
124 
125         // Overflow it
126         buf.put((byte) 0);
127         buf.put((byte) 0);
128 
129         Assert.assertEquals(5, buf.position());
130         buf.reset();
131         Assert.assertEquals(3, buf.position());
132     }
133 
134     public void testAutoShrink() throws Exception {
135         IoBuffer buf = IoBuffer.allocate(8).setAutoShrink(true);
136 
137         // Make sure the buffer doesn't shrink too much (less than the initial
138         // capacity.)
139         buf.sweep((byte) 1);
140         buf.fill(7);
141         buf.compact();
142         Assert.assertEquals(8, buf.capacity());
143         Assert.assertEquals(1, buf.position());
144         Assert.assertEquals(8, buf.limit());
145         buf.clear();
146         Assert.assertEquals(1, buf.get());
147 
148         // Expand the buffer.
149         buf.capacity(32).clear();
150         Assert.assertEquals(32, buf.capacity());
151 
152         // Make sure the buffer shrinks when only 1/4 is being used.
153         buf.sweep((byte) 1);
154         buf.fill(24);
155         buf.compact();
156         Assert.assertEquals(16, buf.capacity());
157         Assert.assertEquals(8, buf.position());
158         Assert.assertEquals(16, buf.limit());
159         buf.clear();
160         for (int i = 0; i < 8; i ++) {
161             Assert.assertEquals(1, buf.get());
162         }
163 
164         // Expand the buffer.
165         buf.capacity(32).clear();
166         Assert.assertEquals(32, buf.capacity());
167 
168         // Make sure the buffer shrinks when only 1/8 is being used.
169         buf.sweep((byte) 1);
170         buf.fill(28);
171         buf.compact();
172         Assert.assertEquals(8, buf.capacity());
173         Assert.assertEquals(4, buf.position());
174         Assert.assertEquals(8, buf.limit());
175         buf.clear();
176         for (int i = 0; i < 4; i ++) {
177             Assert.assertEquals(1, buf.get());
178         }
179 
180         // Expand the buffer.
181         buf.capacity(32).clear();
182         Assert.assertEquals(32, buf.capacity());
183 
184         // Make sure the buffer shrinks when 0 byte is being used.
185         buf.fill(32);
186         buf.compact();
187         Assert.assertEquals(8, buf.capacity());
188         Assert.assertEquals(0, buf.position());
189         Assert.assertEquals(8, buf.limit());
190 
191         // Expand the buffer.
192         buf.capacity(32).clear();
193         Assert.assertEquals(32, buf.capacity());
194 
195         // Make sure the buffer doesn't shrink when more than 1/4 is being used.
196         buf.sweep((byte) 1);
197         buf.fill(23);
198         buf.compact();
199         Assert.assertEquals(32, buf.capacity());
200         Assert.assertEquals(9, buf.position());
201         Assert.assertEquals(32, buf.limit());
202         buf.clear();
203         for (int i = 0; i < 9; i ++) {
204             Assert.assertEquals(1, buf.get());
205         }
206     }
207 
208     public void testGetString() throws Exception {
209         IoBuffer buf = IoBuffer.allocate(16);
210         CharsetDecoder decoder;
211 
212         Charset charset = Charset.forName("UTF-8");
213         buf.clear();
214         buf.putString("hello", charset.newEncoder());
215         buf.put((byte) 0);
216         buf.flip();
217         Assert.assertEquals("hello", buf.getString(charset.newDecoder()));
218 
219         buf.clear();
220         buf.putString("hello", charset.newEncoder());
221         buf.flip();
222         Assert.assertEquals("hello", buf.getString(charset.newDecoder()));
223 
224         decoder = Charset.forName("ISO-8859-1").newDecoder();
225         buf.clear();
226         buf.put((byte) 'A');
227         buf.put((byte) 'B');
228         buf.put((byte) 'C');
229         buf.put((byte) 0);
230 
231         buf.position(0);
232         Assert.assertEquals("ABC", buf.getString(decoder));
233         Assert.assertEquals(4, buf.position());
234 
235         buf.position(0);
236         buf.limit(1);
237         Assert.assertEquals("A", buf.getString(decoder));
238         Assert.assertEquals(1, buf.position());
239 
240         buf.clear();
241         Assert.assertEquals("ABC", buf.getString(10, decoder));
242         Assert.assertEquals(10, buf.position());
243 
244         buf.clear();
245         Assert.assertEquals("A", buf.getString(1, decoder));
246         Assert.assertEquals(1, buf.position());
247 
248         // Test a trailing garbage
249         buf.clear();
250         buf.put((byte) 'A');
251         buf.put((byte) 'B');
252         buf.put((byte) 0);
253         buf.put((byte) 'C');
254         buf.position(0);
255         Assert.assertEquals("AB", buf.getString(4, decoder));
256         Assert.assertEquals(4, buf.position());
257 
258         buf.clear();
259         buf.fillAndReset(buf.limit());
260         decoder = Charset.forName("UTF-16").newDecoder();
261         buf.put((byte) 0);
262         buf.put((byte) 'A');
263         buf.put((byte) 0);
264         buf.put((byte) 'B');
265         buf.put((byte) 0);
266         buf.put((byte) 'C');
267         buf.put((byte) 0);
268         buf.put((byte) 0);
269 
270         buf.position(0);
271         Assert.assertEquals("ABC", buf.getString(decoder));
272         Assert.assertEquals(8, buf.position());
273 
274         buf.position(0);
275         buf.limit(2);
276         Assert.assertEquals("A", buf.getString(decoder));
277         Assert.assertEquals(2, buf.position());
278 
279         buf.position(0);
280         buf.limit(3);
281         Assert.assertEquals("A", buf.getString(decoder));
282         Assert.assertEquals(2, buf.position());
283 
284         buf.clear();
285         Assert.assertEquals("ABC", buf.getString(10, decoder));
286         Assert.assertEquals(10, buf.position());
287 
288         buf.clear();
289         Assert.assertEquals("A", buf.getString(2, decoder));
290         Assert.assertEquals(2, buf.position());
291 
292         buf.clear();
293         try {
294             buf.getString(1, decoder);
295             Assert.fail();
296         } catch (IllegalArgumentException e) {
297             // ignore
298         }
299 
300         // Test getting strings from an empty buffer.
301         buf.clear();
302         buf.limit(0);
303         Assert.assertEquals("", buf.getString(decoder));
304         Assert.assertEquals("", buf.getString(2, decoder));
305 
306         // Test getting strings from non-empty buffer which is filled with 0x00
307         buf.clear();
308         buf.putInt(0);
309         buf.clear();
310         buf.limit(4);
311         Assert.assertEquals("", buf.getString(decoder));
312         Assert.assertEquals(2, buf.position());
313         Assert.assertEquals(4, buf.limit());
314 
315         buf.position(0);
316         Assert.assertEquals("", buf.getString(2, decoder));
317         Assert.assertEquals(2, buf.position());
318         Assert.assertEquals(4, buf.limit());
319     }
320 
321     public void testGetStringWithFailure() throws Exception {
322         String test = "\u30b3\u30e1\u30f3\u30c8\u7de8\u96c6";
323         IoBuffer buffer = IoBuffer.wrap(test.getBytes("Shift_JIS"));
324 
325         // Make sure the limit doesn't change when an exception arose.
326         int oldLimit = buffer.limit();
327         int oldPos = buffer.position();
328         try {
329             buffer.getString(3, Charset.forName("ASCII").newDecoder());
330             Assert.fail();
331         } catch (Exception e) {
332             Assert.assertEquals(oldLimit, buffer.limit());
333             Assert.assertEquals(oldPos, buffer.position());
334         }
335 
336         try {
337             buffer.getString(Charset.forName("ASCII").newDecoder());
338             Assert.fail();
339         } catch (Exception e) {
340             Assert.assertEquals(oldLimit, buffer.limit());
341             Assert.assertEquals(oldPos, buffer.position());
342         }
343     }
344 
345     public void testPutString() throws Exception {
346         CharsetEncoder encoder;
347         IoBuffer buf = IoBuffer.allocate(16);
348         encoder = Charset.forName("ISO-8859-1").newEncoder();
349 
350         buf.putString("ABC", encoder);
351         Assert.assertEquals(3, buf.position());
352         buf.clear();
353         Assert.assertEquals('A', buf.get(0));
354         Assert.assertEquals('B', buf.get(1));
355         Assert.assertEquals('C', buf.get(2));
356 
357         buf.putString("D", 5, encoder);
358         Assert.assertEquals(5, buf.position());
359         buf.clear();
360         Assert.assertEquals('D', buf.get(0));
361         Assert.assertEquals(0, buf.get(1));
362 
363         buf.putString("EFG", 2, encoder);
364         Assert.assertEquals(2, buf.position());
365         buf.clear();
366         Assert.assertEquals('E', buf.get(0));
367         Assert.assertEquals('F', buf.get(1));
368         Assert.assertEquals('C', buf.get(2)); // C may not be overwritten
369 
370         // UTF-16: We specify byte order to omit BOM.
371         encoder = Charset.forName("UTF-16BE").newEncoder();
372         buf.clear();
373 
374         buf.putString("ABC", encoder);
375         Assert.assertEquals(6, buf.position());
376         buf.clear();
377 
378         Assert.assertEquals(0, buf.get(0));
379         Assert.assertEquals('A', buf.get(1));
380         Assert.assertEquals(0, buf.get(2));
381         Assert.assertEquals('B', buf.get(3));
382         Assert.assertEquals(0, buf.get(4));
383         Assert.assertEquals('C', buf.get(5));
384 
385         buf.putString("D", 10, encoder);
386         Assert.assertEquals(10, buf.position());
387         buf.clear();
388         Assert.assertEquals(0, buf.get(0));
389         Assert.assertEquals('D', buf.get(1));
390         Assert.assertEquals(0, buf.get(2));
391         Assert.assertEquals(0, buf.get(3));
392 
393         buf.putString("EFG", 4, encoder);
394         Assert.assertEquals(4, buf.position());
395         buf.clear();
396         Assert.assertEquals(0, buf.get(0));
397         Assert.assertEquals('E', buf.get(1));
398         Assert.assertEquals(0, buf.get(2));
399         Assert.assertEquals('F', buf.get(3));
400         Assert.assertEquals(0, buf.get(4)); // C may not be overwritten
401         Assert.assertEquals('C', buf.get(5)); // C may not be overwritten
402 
403         // Test putting an emptry string
404         buf.putString("", encoder);
405         Assert.assertEquals(0, buf.position());
406         buf.putString("", 4, encoder);
407         Assert.assertEquals(4, buf.position());
408         Assert.assertEquals(0, buf.get(0));
409         Assert.assertEquals(0, buf.get(1));
410     }
411 
412     public void testGetPrefixedString() throws Exception {
413         IoBuffer buf = IoBuffer.allocate(16);
414         CharsetEncoder encoder;
415         CharsetDecoder decoder;
416         encoder = Charset.forName("ISO-8859-1").newEncoder();
417         decoder = Charset.forName("ISO-8859-1").newDecoder();
418 
419         buf.putShort((short) 3);
420         buf.putString("ABCD", encoder);
421         buf.clear();
422         Assert.assertEquals("ABC", buf.getPrefixedString(decoder));
423     }
424 
425     public void testPutPrefixedString() throws Exception {
426         CharsetEncoder encoder;
427         IoBuffer buf = IoBuffer.allocate(16);
428         buf.fillAndReset(buf.remaining());
429         encoder = Charset.forName("ISO-8859-1").newEncoder();
430 
431         // Without autoExpand
432         buf.putPrefixedString("ABC", encoder);
433         Assert.assertEquals(5, buf.position());
434         Assert.assertEquals(0, buf.get(0));
435         Assert.assertEquals(3, buf.get(1));
436         Assert.assertEquals('A', buf.get(2));
437         Assert.assertEquals('B', buf.get(3));
438         Assert.assertEquals('C', buf.get(4));
439 
440         buf.clear();
441         try {
442             buf.putPrefixedString("123456789012345", encoder);
443             Assert.fail();
444         } catch (BufferOverflowException e) {
445             // OK
446         }
447 
448         // With autoExpand
449         buf.clear();
450         buf.setAutoExpand(true);
451         buf.putPrefixedString("123456789012345", encoder);
452         Assert.assertEquals(17, buf.position());
453         Assert.assertEquals(0, buf.get(0));
454         Assert.assertEquals(15, buf.get(1));
455         Assert.assertEquals('1', buf.get(2));
456         Assert.assertEquals('2', buf.get(3));
457         Assert.assertEquals('3', buf.get(4));
458         Assert.assertEquals('4', buf.get(5));
459         Assert.assertEquals('5', buf.get(6));
460         Assert.assertEquals('6', buf.get(7));
461         Assert.assertEquals('7', buf.get(8));
462         Assert.assertEquals('8', buf.get(9));
463         Assert.assertEquals('9', buf.get(10));
464         Assert.assertEquals('0', buf.get(11));
465         Assert.assertEquals('1', buf.get(12));
466         Assert.assertEquals('2', buf.get(13));
467         Assert.assertEquals('3', buf.get(14));
468         Assert.assertEquals('4', buf.get(15));
469         Assert.assertEquals('5', buf.get(16));
470     }
471 
472     public void testPutPrefixedStringWithPrefixLength() throws Exception {
473         CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
474         IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true);
475 
476         buf.putPrefixedString("A", 1, encoder);
477         Assert.assertEquals(2, buf.position());
478         Assert.assertEquals(1, buf.get(0));
479         Assert.assertEquals('A', buf.get(1));
480 
481         buf.sweep();
482         buf.putPrefixedString("A", 2, encoder);
483         Assert.assertEquals(3, buf.position());
484         Assert.assertEquals(0, buf.get(0));
485         Assert.assertEquals(1, buf.get(1));
486         Assert.assertEquals('A', buf.get(2));
487 
488         buf.sweep();
489         buf.putPrefixedString("A", 4, encoder);
490         Assert.assertEquals(5, buf.position());
491         Assert.assertEquals(0, buf.get(0));
492         Assert.assertEquals(0, buf.get(1));
493         Assert.assertEquals(0, buf.get(2));
494         Assert.assertEquals(1, buf.get(3));
495         Assert.assertEquals('A', buf.get(4));
496     }
497 
498     public void testPutPrefixedStringWithPadding() throws Exception {
499         CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
500         IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true);
501 
502         buf.putPrefixedString("A", 1, 2, (byte) 32, encoder);
503         Assert.assertEquals(3, buf.position());
504         Assert.assertEquals(2, buf.get(0));
505         Assert.assertEquals('A', buf.get(1));
506         Assert.assertEquals(' ', buf.get(2));
507 
508         buf.sweep();
509         buf.putPrefixedString("A", 1, 4, (byte) 32, encoder);
510         Assert.assertEquals(5, buf.position());
511         Assert.assertEquals(4, buf.get(0));
512         Assert.assertEquals('A', buf.get(1));
513         Assert.assertEquals(' ', buf.get(2));
514         Assert.assertEquals(' ', buf.get(3));
515         Assert.assertEquals(' ', buf.get(4));
516     }
517 
518     public void testWideUtf8Characters() throws Exception {
519         Runnable r = new Runnable() {
520             public void run() {
521                 IoBuffer buffer = IoBuffer.allocate(1);
522                 buffer.setAutoExpand(true);
523 
524                 Charset charset = Charset.forName("UTF-8");
525 
526                 CharsetEncoder encoder = charset.newEncoder();
527 
528                 for (int i = 0; i < 5; i++) {
529                     try {
530                         buffer.putString("\u89d2", encoder);
531                         buffer.putPrefixedString("\u89d2", encoder);
532                     } catch (CharacterCodingException e) {
533                         fail(e.getMessage());
534                     }
535                 }
536             }
537         };
538 
539         Thread t = new Thread(r);
540         t.setDaemon(true);
541         t.start();
542 
543         for (int i = 0; i < 50; i++) {
544             Thread.sleep(100);
545             if (!t.isAlive()) {
546                 break;
547             }
548         }
549 
550         if (t.isAlive()) {
551             t.interrupt();
552 
553             fail("Went into endless loop trying to encode character");
554         }
555     }
556 
557     public void testObjectSerialization() throws Exception {
558         IoBuffer buf = IoBuffer.allocate(16);
559         buf.setAutoExpand(true);
560         List<Object> o = new ArrayList<Object>();
561         o.add(new Date());
562         o.add(long.class);
563 
564         // Test writing an object.
565         buf.putObject(o);
566 
567         // Test reading an object.
568         buf.clear();
569         Object o2 = buf.getObject();
570         Assert.assertEquals(o, o2);
571 
572         // This assertion is just to make sure that deserialization occurred.
573         Assert.assertNotSame(o, o2);
574     }
575 
576     public void testInheritedObjectSerialization() throws Exception {
577         IoBuffer buf = IoBuffer.allocate(16);
578         buf.setAutoExpand(true);
579 
580         Bar expected = new Bar();
581         expected.setFooValue(0x12345678);
582         expected.setBarValue(0x90ABCDEF);
583 
584         // Test writing an object.
585         buf.putObject(expected);
586 
587         // Test reading an object.
588         buf.clear();
589         Bar actual = (Bar) buf.getObject();
590         Assert.assertSame(Bar.class, actual.getClass());
591         Assert.assertEquals(expected.getFooValue(), actual.getFooValue());
592         Assert.assertEquals(expected.getBarValue(), actual.getBarValue());
593 
594         // This assertion is just to make sure that deserialization occurred.
595         Assert.assertNotSame(expected, actual);
596     }
597 
598     public void testSweepWithZeros() throws Exception {
599         IoBuffer buf = IoBuffer.allocate(4);
600         buf.putInt(0xdeadbeef);
601         buf.clear();
602         Assert.assertEquals(0xdeadbeef, buf.getInt());
603         Assert.assertEquals(4, buf.position());
604         Assert.assertEquals(4, buf.limit());
605 
606         buf.sweep();
607         Assert.assertEquals(0, buf.position());
608         Assert.assertEquals(4, buf.limit());
609         Assert.assertEquals(0x0, buf.getInt());
610     }
611 
612     public void testSweepNonZeros() throws Exception {
613         IoBuffer buf = IoBuffer.allocate(4);
614         buf.putInt(0xdeadbeef);
615         buf.clear();
616         Assert.assertEquals(0xdeadbeef, buf.getInt());
617         Assert.assertEquals(4, buf.position());
618         Assert.assertEquals(4, buf.limit());
619 
620         buf.sweep((byte) 0x45);
621         Assert.assertEquals(0, buf.position());
622         Assert.assertEquals(4, buf.limit());
623         Assert.assertEquals(0x45454545, buf.getInt());
624     }
625 
626     public void testWrapNioBuffer() throws Exception {
627         ByteBuffer nioBuf = ByteBuffer.allocate(10);
628         nioBuf.position(3);
629         nioBuf.limit(7);
630 
631         IoBuffer buf = IoBuffer.wrap(nioBuf);
632         Assert.assertEquals(3, buf.position());
633         Assert.assertEquals(7, buf.limit());
634         Assert.assertEquals(10, buf.capacity());
635     }
636 
637     public void testWrapSubArray() throws Exception {
638         byte[] array = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
639 
640         IoBuffer buf = IoBuffer.wrap(array, 3, 4);
641         Assert.assertEquals(3, buf.position());
642         Assert.assertEquals(7, buf.limit());
643         Assert.assertEquals(10, buf.capacity());
644 
645         buf.clear();
646         Assert.assertEquals(0, buf.position());
647         Assert.assertEquals(10, buf.limit());
648         Assert.assertEquals(10, buf.capacity());
649     }
650 
651     public void testDuplicate() throws Exception {
652         IoBuffer original;
653         IoBuffer duplicate;
654 
655         // Test if the buffer is duplicated correctly.
656         original = IoBuffer.allocate(16).sweep();
657         original.position(4);
658         original.limit(10);
659         duplicate = original.duplicate();
660         original.put(4, (byte) 127);
661         Assert.assertEquals(4, duplicate.position());
662         Assert.assertEquals(10, duplicate.limit());
663         Assert.assertEquals(16, duplicate.capacity());
664         Assert.assertNotSame(original.buf(), duplicate.buf());
665         Assert.assertSame(original.buf().array(), duplicate.buf().array());
666         Assert.assertEquals(127, duplicate.get(4));
667 
668         // Test a duplicate of a duplicate.
669         original = IoBuffer.allocate(16);
670         duplicate = original.duplicate().duplicate();
671         Assert.assertNotSame(original.buf(), duplicate.buf());
672         Assert.assertSame(original.buf().array(), duplicate.buf().array());
673 
674         // Try to expand.
675         original = IoBuffer.allocate(16);
676         original.setAutoExpand(true);
677         duplicate = original.duplicate();
678         Assert.assertFalse(original.isAutoExpand());
679 
680         try {
681             original.setAutoExpand(true);
682             Assert.fail();
683         } catch (IllegalStateException e) {
684             // OK
685         }
686 
687         try {
688             duplicate.setAutoExpand(true);
689             Assert.fail();
690         } catch (IllegalStateException e) {
691             // OK
692         }
693     }
694 
695     public void testSlice() throws Exception {
696         IoBuffer original;
697         IoBuffer slice;
698 
699         // Test if the buffer is sliced correctly.
700         original = IoBuffer.allocate(16).sweep();
701         original.position(4);
702         original.limit(10);
703         slice = original.slice();
704         original.put(4, (byte) 127);
705         Assert.assertEquals(0, slice.position());
706         Assert.assertEquals(6, slice.limit());
707         Assert.assertEquals(6, slice.capacity());
708         Assert.assertNotSame(original.buf(), slice.buf());
709         Assert.assertEquals(127, slice.get(0));
710     }
711 
712     public void testReadOnlyBuffer() throws Exception {
713         IoBuffer original;
714         IoBuffer duplicate;
715 
716         // Test if the buffer is duplicated correctly.
717         original = IoBuffer.allocate(16).sweep();
718         original.position(4);
719         original.limit(10);
720         duplicate = original.asReadOnlyBuffer();
721         original.put(4, (byte) 127);
722         Assert.assertEquals(4, duplicate.position());
723         Assert.assertEquals(10, duplicate.limit());
724         Assert.assertEquals(16, duplicate.capacity());
725         Assert.assertNotSame(original.buf(), duplicate.buf());
726         Assert.assertEquals(127, duplicate.get(4));
727 
728         // Try to expand.
729         try {
730             original = IoBuffer.allocate(16);
731             duplicate = original.asReadOnlyBuffer();
732             duplicate.putString("A very very very very looooooong string",
733                     Charset.forName("ISO-8859-1").newEncoder());
734             Assert.fail();
735         } catch (ReadOnlyBufferException e) {
736             // OK
737         }
738     }
739 
740     public void testGetUnsigned() throws Exception {
741         IoBuffer buf = IoBuffer.allocate(16);
742         buf.put((byte) 0xA4);
743         buf.put((byte) 0xD0);
744         buf.put((byte) 0xB3);
745         buf.put((byte) 0xCD);
746         buf.flip();
747 
748         buf.order(ByteOrder.LITTLE_ENDIAN);
749 
750         buf.mark();
751         Assert.assertEquals(0xA4, buf.getUnsigned());
752         buf.reset();
753         Assert.assertEquals(0xD0A4, buf.getUnsignedShort());
754         buf.reset();
755         Assert.assertEquals(0xCDB3D0A4L, buf.getUnsignedInt());
756     }
757 
758     public void testIndexOf() throws Exception {
759         boolean direct = false;
760         for (int i = 0; i < 2; i++, direct = !direct) {
761             IoBuffer buf = IoBuffer.allocate(16, direct);
762             buf.put((byte) 0x1);
763             buf.put((byte) 0x2);
764             buf.put((byte) 0x3);
765             buf.put((byte) 0x4);
766             buf.put((byte) 0x1);
767             buf.put((byte) 0x2);
768             buf.put((byte) 0x3);
769             buf.put((byte) 0x4);
770             buf.position(2);
771             buf.limit(5);
772 
773             Assert.assertEquals(4, buf.indexOf((byte) 0x1));
774             Assert.assertEquals(-1, buf.indexOf((byte) 0x2));
775             Assert.assertEquals(2, buf.indexOf((byte) 0x3));
776             Assert.assertEquals(3, buf.indexOf((byte) 0x4));
777         }
778     }
779 
780     // We need an enum with 64 values
781     private static enum TestEnum {
782         E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E77, E48, E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62, E63, E64
783     }
784 
785     private static enum TooBigEnum {
786         E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E77, E48, E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62, E63, E64, E65
787     }
788 
789     public void testPutEnumSet() {
790         IoBuffer buf = IoBuffer.allocate(8);
791 
792         // Test empty set
793         buf.putEnumSet(EnumSet.noneOf(TestEnum.class));
794         buf.flip();
795         assertEquals(0, buf.get());
796 
797         buf.clear();
798         buf.putEnumSetShort(EnumSet.noneOf(TestEnum.class));
799         buf.flip();
800         assertEquals(0, buf.getShort());
801 
802         buf.clear();
803         buf.putEnumSetInt(EnumSet.noneOf(TestEnum.class));
804         buf.flip();
805         assertEquals(0, buf.getInt());
806 
807         buf.clear();
808         buf.putEnumSetLong(EnumSet.noneOf(TestEnum.class));
809         buf.flip();
810         assertEquals(0, buf.getLong());
811 
812         // Test complete set
813         buf.clear();
814         buf.putEnumSet(EnumSet.range(TestEnum.E1, TestEnum.E8));
815         buf.flip();
816         assertEquals((byte) -1, buf.get());
817 
818         buf.clear();
819         buf.putEnumSetShort(EnumSet.range(TestEnum.E1, TestEnum.E16));
820         buf.flip();
821         assertEquals((short) -1, buf.getShort());
822 
823         buf.clear();
824         buf.putEnumSetInt(EnumSet.range(TestEnum.E1, TestEnum.E32));
825         buf.flip();
826         assertEquals(-1, buf.getInt());
827 
828         buf.clear();
829         buf.putEnumSetLong(EnumSet.allOf(TestEnum.class));
830         buf.flip();
831         assertEquals(-1L, buf.getLong());
832 
833         // Test high bit set
834         buf.clear();
835         buf.putEnumSet(EnumSet.of(TestEnum.E8));
836         buf.flip();
837         assertEquals(Byte.MIN_VALUE, buf.get());
838 
839         buf.clear();
840         buf.putEnumSetShort(EnumSet.of(TestEnum.E16));
841         buf.flip();
842         assertEquals(Short.MIN_VALUE, buf.getShort());
843 
844         buf.clear();
845         buf.putEnumSetInt(EnumSet.of(TestEnum.E32));
846         buf.flip();
847         assertEquals(Integer.MIN_VALUE, buf.getInt());
848 
849         buf.clear();
850         buf.putEnumSetLong(EnumSet.of(TestEnum.E64));
851         buf.flip();
852         assertEquals(Long.MIN_VALUE, buf.getLong());
853 
854         // Test high low bits set
855         buf.clear();
856         buf.putEnumSet(EnumSet.of(TestEnum.E1, TestEnum.E8));
857         buf.flip();
858         assertEquals(Byte.MIN_VALUE + 1, buf.get());
859 
860         buf.clear();
861         buf.putEnumSetShort(EnumSet.of(TestEnum.E1, TestEnum.E16));
862         buf.flip();
863         assertEquals(Short.MIN_VALUE + 1, buf.getShort());
864 
865         buf.clear();
866         buf.putEnumSetInt(EnumSet.of(TestEnum.E1, TestEnum.E32));
867         buf.flip();
868         assertEquals(Integer.MIN_VALUE + 1, buf.getInt());
869 
870         buf.clear();
871         buf.putEnumSetLong(EnumSet.of(TestEnum.E1, TestEnum.E64));
872         buf.flip();
873         assertEquals(Long.MIN_VALUE + 1, buf.getLong());
874     }
875 
876     public void testGetEnumSet() {
877         IoBuffer buf = IoBuffer.allocate(8);
878 
879         // Test empty set
880         buf.put((byte) 0);
881         buf.flip();
882         assertEquals(EnumSet.noneOf(TestEnum.class), buf
883                 .getEnumSet(TestEnum.class));
884 
885         buf.clear();
886         buf.putShort((short) 0);
887         buf.flip();
888         assertEquals(EnumSet.noneOf(TestEnum.class), buf
889                 .getEnumSet(TestEnum.class));
890 
891         buf.clear();
892         buf.putInt(0);
893         buf.flip();
894         assertEquals(EnumSet.noneOf(TestEnum.class), buf
895                 .getEnumSet(TestEnum.class));
896 
897         buf.clear();
898         buf.putLong(0L);
899         buf.flip();
900         assertEquals(EnumSet.noneOf(TestEnum.class), buf
901                 .getEnumSet(TestEnum.class));
902 
903         // Test complete set
904         buf.clear();
905         buf.put((byte) -1);
906         buf.flip();
907         assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E8), buf
908                 .getEnumSet(TestEnum.class));
909 
910         buf.clear();
911         buf.putShort((short) -1);
912         buf.flip();
913         assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E16), buf
914                 .getEnumSetShort(TestEnum.class));
915 
916         buf.clear();
917         buf.putInt(-1);
918         buf.flip();
919         assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E32), buf
920                 .getEnumSetInt(TestEnum.class));
921 
922         buf.clear();
923         buf.putLong(-1L);
924         buf.flip();
925         assertEquals(EnumSet.allOf(TestEnum.class), buf
926                 .getEnumSetLong(TestEnum.class));
927 
928         // Test high bit set
929         buf.clear();
930         buf.put(Byte.MIN_VALUE);
931         buf.flip();
932         assertEquals(EnumSet.of(TestEnum.E8), buf.getEnumSet(TestEnum.class));
933 
934         buf.clear();
935         buf.putShort(Short.MIN_VALUE);
936         buf.flip();
937         assertEquals(EnumSet.of(TestEnum.E16), buf
938                 .getEnumSetShort(TestEnum.class));
939 
940         buf.clear();
941         buf.putInt(Integer.MIN_VALUE);
942         buf.flip();
943         assertEquals(EnumSet.of(TestEnum.E32), buf
944                 .getEnumSetInt(TestEnum.class));
945 
946         buf.clear();
947         buf.putLong(Long.MIN_VALUE);
948         buf.flip();
949         assertEquals(EnumSet.of(TestEnum.E64), buf
950                 .getEnumSetLong(TestEnum.class));
951 
952         // Test high low bits set
953         buf.clear();
954         byte b = Byte.MIN_VALUE + 1;
955         buf.put(b);
956         buf.flip();
957         assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E8), buf
958                 .getEnumSet(TestEnum.class));
959 
960         buf.clear();
961         short s = Short.MIN_VALUE + 1;
962         buf.putShort(s);
963         buf.flip();
964         assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E16), buf
965                 .getEnumSetShort(TestEnum.class));
966 
967         buf.clear();
968         buf.putInt(Integer.MIN_VALUE + 1);
969         buf.flip();
970         assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E32), buf
971                 .getEnumSetInt(TestEnum.class));
972 
973         buf.clear();
974         buf.putLong(Long.MIN_VALUE + 1);
975         buf.flip();
976         assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E64), buf
977                 .getEnumSetLong(TestEnum.class));
978     }
979 
980     public void testBitVectorOverFlow() {
981         IoBuffer buf = IoBuffer.allocate(8);
982         try {
983             buf.putEnumSet(EnumSet.of(TestEnum.E9));
984             fail("Should have thrown IllegalArgumentException");
985         } catch (IllegalArgumentException e) {
986             // pass
987         }
988 
989         try {
990             buf.putEnumSetShort(EnumSet.of(TestEnum.E17));
991             fail("Should have thrown IllegalArgumentException");
992         } catch (IllegalArgumentException e) {
993             // pass
994         }
995 
996         try {
997             buf.putEnumSetInt(EnumSet.of(TestEnum.E33));
998             fail("Should have thrown IllegalArgumentException");
999         } catch (IllegalArgumentException e) {
1000             // pass
1001         }
1002 
1003         try {
1004             buf.putEnumSetLong(EnumSet.of(TooBigEnum.E65));
1005             fail("Should have thrown IllegalArgumentException");
1006         } catch (IllegalArgumentException e) {
1007             // pass
1008         }
1009     }
1010 
1011     public void testGetPutEnum() {
1012         IoBuffer buf = IoBuffer.allocate(4);
1013 
1014         buf.putEnum(TestEnum.E64);
1015         buf.flip();
1016         assertEquals(TestEnum.E64, buf.getEnum(TestEnum.class));
1017 
1018         buf.clear();
1019         buf.putEnumShort(TestEnum.E64);
1020         buf.flip();
1021         assertEquals(TestEnum.E64, buf.getEnumShort(TestEnum.class));
1022 
1023         buf.clear();
1024         buf.putEnumInt(TestEnum.E64);
1025         buf.flip();
1026         assertEquals(TestEnum.E64, buf.getEnumInt(TestEnum.class));
1027     }
1028 
1029     public void testGetMediumInt() {
1030         IoBuffer buf = IoBuffer.allocate(3);
1031 
1032         buf.put((byte) 0x01);
1033         buf.put((byte) 0x02);
1034         buf.put((byte) 0x03);
1035         assertEquals(3, buf.position());
1036 
1037         buf.flip();
1038         assertEquals(0x010203, buf.getMediumInt());
1039         assertEquals(0x010203, buf.getMediumInt(0));
1040         buf.flip();
1041         assertEquals(0x010203, buf.getUnsignedMediumInt());
1042         assertEquals(0x010203, buf.getUnsignedMediumInt(0));
1043         buf.flip();
1044         assertEquals(0x010203, buf.getUnsignedMediumInt());
1045         buf.flip().order(ByteOrder.LITTLE_ENDIAN);
1046         assertEquals(0x030201, buf.getMediumInt());
1047         assertEquals(0x030201, buf.getMediumInt(0));
1048 
1049         // Test max medium int
1050         buf.flip().order(ByteOrder.BIG_ENDIAN);
1051         buf.put((byte) 0x7f);
1052         buf.put((byte) 0xff);
1053         buf.put((byte) 0xff);
1054         buf.flip();
1055         assertEquals(0x7fffff, buf.getMediumInt());
1056         assertEquals(0x7fffff, buf.getMediumInt(0));
1057 
1058         // Test negative number
1059         buf.flip().order(ByteOrder.BIG_ENDIAN);
1060         buf.put((byte) 0xff);
1061         buf.put((byte) 0x02);
1062         buf.put((byte) 0x03);
1063         buf.flip();
1064 
1065         assertEquals(0xffff0203, buf.getMediumInt());
1066         assertEquals(0xffff0203, buf.getMediumInt(0));
1067         buf.flip();
1068 
1069         assertEquals(0x00ff0203, buf.getUnsignedMediumInt());
1070         assertEquals(0x00ff0203, buf.getUnsignedMediumInt(0));
1071     }
1072 
1073     public void testPutMediumInt() {
1074         IoBuffer buf = IoBuffer.allocate(3);
1075 
1076         checkMediumInt(buf, 0);
1077         checkMediumInt(buf, 1);
1078         checkMediumInt(buf, -1);
1079         checkMediumInt(buf, 0x7fffff);
1080     }
1081 
1082     private void checkMediumInt(IoBuffer buf, int x) {
1083         buf.putMediumInt(x);
1084         assertEquals(3, buf.position());
1085         buf.flip();
1086         assertEquals(x, buf.getMediumInt());
1087         assertEquals(3, buf.position());
1088 
1089         buf.putMediumInt(0, x);
1090         assertEquals(3, buf.position());
1091         assertEquals(x, buf.getMediumInt(0));
1092 
1093         buf.flip();
1094     }
1095 
1096 }