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