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