View Javadoc
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.util.byteaccess;
21  
22  import static org.easymock.EasyMock.createStrictControl;
23  import static org.junit.Assert.assertEquals;
24  
25  import java.nio.ByteOrder;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.apache.mina.core.buffer.IoBuffer;
30  import org.apache.mina.util.byteaccess.ByteArray.Cursor;
31  import org.apache.mina.util.byteaccess.CompositeByteArray.CursorListener;
32  import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.ChunkedExpander;
33  import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.Flusher;
34  import org.easymock.IMocksControl;
35  import org.junit.Test;
36  
37  /**
38   * Tests classes in the <code>byteaccess</code> package.
39   * 
40   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
41   */
42  public class ByteAccessTest {
43  
44      private List<String> operations = new ArrayList<String>();
45  
46      private void resetOperations() {
47          operations.clear();
48      }
49  
50      private void assertOperationCountEquals(int expectedCount) {
51          assertEquals("Operations: " + operations, expectedCount, operations.size());
52      }
53  
54      private void addOperation(String description) {
55          operations.add(description);
56      }
57  
58      @Test
59      public void testBufferByteArray() throws Exception {
60          ByteArray ba = getByteArrayFactory().create(1000);
61          testAbsoluteReaderAndWriter(0, 1000, ba, ba);
62          testAbsoluteReaderAndWriter(0, 1000, ba, ba);
63          Cursor readCursor = ba.cursor();
64          Cursor writeCursor = ba.cursor();
65          testRelativeReaderAndWriter(1000, readCursor, writeCursor);
66      }
67  
68      @Test
69      public void testCompositeAddAndRemove() throws Exception {
70          CompositeByteArray cba = new CompositeByteArray();
71          assertEquals(0, cba.first());
72          assertEquals(0, cba.last());
73          cba.addFirst(getByteArrayFactory().create(100));
74          assertEquals(-100, cba.first());
75          assertEquals(0, cba.last());
76          cba.addFirst(getByteArrayFactory().create(100));
77          assertEquals(-200, cba.first());
78          assertEquals(0, cba.last());
79          cba.addLast(getByteArrayFactory().create(100));
80          assertEquals(-200, cba.first());
81          assertEquals(100, cba.last());
82          cba.removeFirst();
83          assertEquals(-100, cba.first());
84          assertEquals(100, cba.last());
85          cba.addLast(getByteArrayFactory().create(100));
86          assertEquals(-100, cba.first());
87          assertEquals(200, cba.last());
88          cba.removeLast();
89          assertEquals(-100, cba.first());
90          assertEquals(100, cba.last());
91          cba.removeFirst();
92          assertEquals(0, cba.first());
93          assertEquals(100, cba.last());
94          cba.removeFirst();
95          assertEquals(100, cba.first());
96          assertEquals(100, cba.last());
97          cba.addLast(getByteArrayFactory().create(100));
98          assertEquals(100, cba.first());
99          assertEquals(200, cba.last());
100     }
101 
102     private BufferByteArray wrapString(String string) {
103         byte[] bytes = string.getBytes();
104         IoBuffer bb = IoBuffer.wrap(bytes);
105         BufferByteArray ba = new BufferByteArray(bb) {
106 
107             @Override
108             public void free() {
109                 addOperation(this + ".free()");
110                 // Nothing to do.
111             }
112 
113         };
114         return ba;
115     }
116 
117     private String toString(ByteArray ba) {
118         IoBuffer bb = IoBuffer.allocate(ba.length());
119         ba.get(0, bb);
120         byte[] bytes = bb.array();
121         String string = new String(bytes);
122         return string;
123     }
124 
125     @Test
126     public void testCompositeStringJoin() throws Exception {
127         ByteArray ba1 = wrapString("Hello");
128         ByteArray ba2 = wrapString("MINA");
129         ByteArray ba3 = wrapString("World");
130 
131         CompositeByteArray cba = new CompositeByteArray();
132         cba.addLast(ba1);
133         cba.addLast(ba2);
134         cba.addLast(ba3);
135 
136         assertEquals("HelloMINAWorld", toString(cba));
137     }
138 
139     @Test
140     public void testCompositeCursor() throws Exception {
141         IMocksControl mc = createStrictControl();
142 
143         ByteArray ba1 = getByteArrayFactory().create(10);
144         ByteArray ba2 = getByteArrayFactory().create(10);
145         ByteArray ba3 = getByteArrayFactory().create(10);
146 
147         CompositeByteArray cba = new CompositeByteArray();
148         cba.addLast(ba1);
149         cba.addLast(ba2);
150         cba.addLast(ba3);
151 
152         CursorListener cl = mc.createMock(CursorListener.class);
153 
154         mc.reset();
155         mc.replay();
156         Cursor cursor = cba.cursor(cl);
157         mc.verify();
158 
159         mc.reset();
160         cl.enteredFirstComponent(0, ba1);
161         mc.replay();
162         cursor.get();
163         mc.verify();
164 
165         mc.reset();
166         mc.replay();
167         cursor.setIndex(10);
168         mc.verify();
169 
170         mc.reset();
171         cl.enteredNextComponent(10, ba2);
172         mc.replay();
173         cursor.put((byte) 55);
174         mc.verify();
175 
176         mc.reset();
177         mc.replay();
178         cursor.setIndex(9);
179         mc.verify();
180 
181         mc.reset();
182         cl.enteredPreviousComponent(0, ba1);
183         cl.enteredNextComponent(10, ba2);
184         mc.replay();
185         cursor.putInt(66);
186         mc.verify();
187 
188         mc.reset();
189         cl.enteredNextComponent(20, ba3);
190         mc.replay();
191         cursor.setIndex(29);
192         cursor.get();
193         mc.verify();
194 
195         cba.removeLast(); // Force cursor to relocate itself.
196 
197         mc.reset();
198         cl.enteredLastComponent(10, ba2);
199         mc.replay();
200         cursor.setIndex(15);
201         cursor.get();
202         mc.verify();
203 
204         mc.reset();
205         cl.enteredPreviousComponent(0, ba1);
206         mc.replay();
207         cursor.setIndex(0);
208         cursor.get();
209         mc.verify();
210     }
211 
212     @Test
213     public void testCompositeByteArray() throws Exception {
214         CompositeByteArray ba = new CompositeByteArray();
215         for (int i = 0; i < 1000; i += 100) {
216             ba.addLast(getByteArrayFactory().create(100));
217         }
218         resetOperations();
219         testAbsoluteReaderAndWriter(0, 1000, ba, ba);
220         testAbsoluteReaderAndWriter(0, 1000, ba, ba);
221         assertOperationCountEquals(0);
222         Cursor readCursor = ba.cursor();
223         Cursor writeCursor = ba.cursor();
224         testRelativeReaderAndWriter(1000, readCursor, writeCursor);
225         assertOperationCountEquals(0);
226     }
227 
228     @Test
229     public void testCompositeByteArrayRelativeReaderAndWriter() throws Exception {
230         CompositeByteArray cba = new CompositeByteArray();
231         CompositeByteArrayRelativeReader cbarr = new CompositeByteArrayRelativeReader(cba, true);
232         CompositeByteArrayRelativeWriter cbarw = new CompositeByteArrayRelativeWriter(cba, getExpander(100),
233                 getFlusher(), false);
234         resetOperations();
235         testRelativeReaderAndWriter(10, cbarr, cbarw);
236         assertOperationCountEquals(2);
237         resetOperations();
238         testRelativeReaderAndWriter(100, cbarr, cbarw);
239         assertOperationCountEquals(3);
240         resetOperations();
241         testRelativeReaderAndWriter(1000, cbarr, cbarw);
242         assertOperationCountEquals(30);
243         resetOperations();
244         testRelativeReaderAndWriter(10000, cbarr, cbarw);
245         assertOperationCountEquals(300);
246         resetOperations();
247         testRelativeReaderAndWriter(90, cbarr, cbarw);
248         assertOperationCountEquals(0); // Last free doesn't occur, since cursor only moves lazily.
249     }
250 
251     @Test
252     public void testCompositeByteArrayRelativeReaderAndWriterWithFlush() throws Exception {
253         CompositeByteArray cba = new CompositeByteArray();
254         CompositeByteArrayRelativeReader cbarr = new CompositeByteArrayRelativeReader(cba, true);
255         CompositeByteArrayRelativeWriter cbarw = new CompositeByteArrayRelativeWriter(cba, getExpander(100),
256                 getFlusher(), true);
257         resetOperations();
258         testRelativeReaderAndWriter(10, cbarr, cbarw);
259         assertOperationCountEquals(2);
260         resetOperations();
261         testRelativeReaderAndWriter(100, cbarr, cbarw);
262         assertOperationCountEquals(4);
263         resetOperations();
264         testRelativeReaderAndWriter(1000, cbarr, cbarw);
265         assertOperationCountEquals(40);
266         resetOperations();
267         testRelativeReaderAndWriter(10000, cbarr, cbarw);
268         assertOperationCountEquals(400);
269         resetOperations();
270         testRelativeReaderAndWriter(90, cbarr, cbarw);
271         assertOperationCountEquals(0); // Last free doesn't occur, since cursor only moves lazily.
272     }
273 
274     @Test
275     public void testCompositeRemoveTo() throws Exception {
276         CompositeByteArray cba = new CompositeByteArray();
277         {
278             // Remove nothing.
279             resetOperations();
280             ByteArray removed = cba.removeTo(0);
281             assertEquals(0, removed.first());
282             assertEquals(0, removed.last());
283             assertEquals(0, cba.first());
284             assertEquals(0, cba.last());
285             removed.free();
286             assertOperationCountEquals(0);
287         }
288         cba.addLast(getByteArrayFactory().create(100));
289         {
290             // Remove nothing.
291             resetOperations();
292             ByteArray removed = cba.removeTo(0);
293             assertEquals(0, removed.first());
294             assertEquals(0, removed.last());
295             assertEquals(0, cba.first());
296             assertEquals(100, cba.last());
297             removed.free();
298             assertOperationCountEquals(0);
299         }
300         {
301             // Remove entire component.
302             resetOperations();
303             ByteArray removed = cba.removeTo(100);
304             assertEquals(0, removed.first());
305             assertEquals(100, removed.last());
306             assertEquals(100, cba.first());
307             assertEquals(100, cba.last());
308             removed.free();
309             assertOperationCountEquals(1);
310         }
311         {
312             // Remove nothing.
313             resetOperations();
314             ByteArray removed = cba.removeTo(100);
315             assertEquals(0, removed.first());
316             assertEquals(0, removed.last());
317             assertEquals(100, cba.first());
318             assertEquals(100, cba.last());
319             removed.free();
320             assertOperationCountEquals(0);
321         }
322         cba.addLast(getByteArrayFactory().create(100));
323         {
324             // Remove nothing.
325             resetOperations();
326             ByteArray removed = cba.removeTo(100);
327             assertEquals(0, removed.first());
328             assertEquals(0, removed.last());
329             assertEquals(100, cba.first());
330             assertEquals(200, cba.last());
331             removed.free();
332             assertOperationCountEquals(0);
333         }
334         {
335             // Remove half a component.
336             resetOperations();
337             ByteArray removed = cba.removeTo(150);
338             assertEquals(0, removed.first());
339             assertEquals(50, removed.last());
340             assertEquals(150, cba.first());
341             assertEquals(200, cba.last());
342             removed.free();
343             assertOperationCountEquals(0); // Doesn't free until component finished.
344         }
345         {
346             // Remove nothing.
347             resetOperations();
348             ByteArray removed = cba.removeTo(150);
349             assertEquals(0, removed.first());
350             assertEquals(0, removed.last());
351             assertEquals(150, cba.first());
352             assertEquals(200, cba.last());
353             removed.free();
354             assertOperationCountEquals(0);
355         }
356         {
357             // Remove other half.
358             resetOperations();
359             ByteArray removed = cba.removeTo(200);
360             assertEquals(0, removed.first());
361             assertEquals(50, removed.last());
362             assertEquals(200, cba.first());
363             assertEquals(200, cba.last());
364             removed.free();
365             assertOperationCountEquals(1); // Frees ByteArray behind both buffers.
366         }
367     }
368 
369     @Test
370     public void testCompositeByteArraySlicing() {
371         CompositeByteArray cba = new CompositeByteArray();
372         cba.addLast(getByteArrayFactory().create(10));
373         cba.addLast(getByteArrayFactory().create(10));
374         cba.addLast(getByteArrayFactory().create(10));
375         testByteArraySlicing(cba, 0, 30);
376         testByteArraySlicing(cba, 5, 10);
377         testByteArraySlicing(cba, 10, 20);
378         testByteArraySlicing(cba, 1, 28);
379         testByteArraySlicing(cba, 19, 2);
380     }
381 
382     @Test
383     public void testBufferByteArraySlicing() {
384         ByteArray bba = getByteArrayFactory().create(30);
385         testByteArraySlicing(bba, 0, 30);
386         testByteArraySlicing(bba, 5, 10);
387         testByteArraySlicing(bba, 10, 20);
388         testByteArraySlicing(bba, 1, 28);
389         testByteArraySlicing(bba, 19, 2);
390 
391     }
392 
393     private void testByteArraySlicing(ByteArray ba, int start, int length) {
394         ByteArray slice = ba.slice(start, length);
395         for (int i = 0; i < length; i++) {
396             byte b1 = (byte) (i % 67);
397             byte b2 = (byte) (i % 36);
398             int sourceIndex = i + start;
399             int sliceIndex = i;
400             ba.put(sourceIndex, b1);
401             assertEquals(b1, ba.get(sourceIndex));
402             assertEquals(b1, slice.get(sliceIndex));
403             slice.put(sliceIndex, b2);
404             assertEquals(b2, ba.get(sourceIndex));
405             assertEquals(b2, slice.get(sliceIndex));
406         }
407     }
408 
409     private ChunkedExpander getExpander(final int chunkSize) {
410         return new ChunkedExpander(getByteArrayFactory(), chunkSize) {
411             @Override
412             public void expand(CompositeByteArray cba, int minSize) {
413                 addOperation("ChunkedExpander(" + chunkSize + ").expand(" + cba + "," + minSize + ")");
414                 super.expand(cba, minSize);
415             }
416         };
417     }
418 
419     private Flusher getFlusher() {
420         return new CompositeByteArrayRelativeWriter.Flusher() {
421 
422             public void flush(ByteArray ba) {
423                 addOperation("Flusher().flush(" + ba + ")");
424                 ba.free();
425             }
426 
427         };
428     }
429 
430     private SimpleByteArrayFactory getByteArrayFactory() {
431         return new SimpleByteArrayFactory() {
432             @Override
433             public ByteArray create(final int size) {
434                 if (size < 0) {
435                     throw new IllegalArgumentException("Buffer size must not be negative:" + size);
436                 }
437                 IoBuffer bb = IoBuffer.allocate(size);
438                 ByteArray ba = new BufferByteArray(bb) {
439 
440                     @Override
441                     public void free() {
442                         addOperation(this + ".free()");
443                         // Nothing to do.
444                     }
445 
446                 };
447                 addOperation("SimpleByteArrayFactory().create(" + size + ") = " + ba);
448                 return ba;
449             }
450         };
451     }
452 
453     private void testRelativeReaderAndWriter(int length, IoRelativeReader reader, IoRelativeWriter writer) {
454         for (int i = 0; i < length; i++) {
455             byte b = (byte) (i % 67);
456             writer.put(b);
457             assertEquals(b, reader.get());
458         }
459     }
460 
461     private void testAbsoluteReaderAndWriter(int start, int length, IoAbsoluteReader reader, IoAbsoluteWriter writer) {
462         for (int i = start; i < length; i++) {
463             byte b = (byte) (i % 67);
464             writer.put(i, b);
465             assertEquals(b, reader.get(i));
466         }
467     }
468 
469     @Test
470     public void testByteArrayPrimitiveAccess() {
471         ByteArray bbaBig = getByteArrayFactory().create(1000);
472         bbaBig.order(ByteOrder.BIG_ENDIAN);
473         testPrimitiveAccess(bbaBig.cursor(), bbaBig.cursor());
474 
475         ByteArray bbaLittle = getByteArrayFactory().create(1000);
476         bbaLittle.order(ByteOrder.LITTLE_ENDIAN);
477         testPrimitiveAccess(bbaLittle.cursor(), bbaLittle.cursor());
478     }
479 
480     @Test
481     public void testByteArrayBufferAccess() {
482         ByteArray ba = getByteArrayFactory().create(1);
483         ba.put(0, (byte) 99);
484         IoBuffer bb = IoBuffer.allocate(2);
485 
486         bb.clear();
487         Cursor cursor = ba.cursor();
488         assertEquals(0, cursor.getIndex());
489         assertEquals(1, cursor.getRemaining());
490         assertEquals(0, bb.position());
491         assertEquals(2, bb.remaining());
492         cursor.get(bb);
493         assertEquals(1, cursor.getIndex());
494         assertEquals(0, cursor.getRemaining());
495         assertEquals(1, bb.position());
496         assertEquals(1, bb.remaining());
497     }
498 
499     @Test
500     public void testCompositeByteArrayPrimitiveAccess() {
501         CompositeByteArray cbaBig = new CompositeByteArray();
502         cbaBig.order(ByteOrder.BIG_ENDIAN);
503         for (int i = 0; i < 1000; i++) {
504             ByteArray component = getByteArrayFactory().create(1);
505             component.order(ByteOrder.BIG_ENDIAN);
506             cbaBig.addLast(component);
507         }
508         testPrimitiveAccess(cbaBig.cursor(), cbaBig.cursor());
509 
510         CompositeByteArray cbaLittle = new CompositeByteArray();
511         cbaLittle.order(ByteOrder.LITTLE_ENDIAN);
512         for (int i = 0; i < 1000; i++) {
513             ByteArray component = getByteArrayFactory().create(1);
514             component.order(ByteOrder.LITTLE_ENDIAN);
515             cbaLittle.addLast(component);
516         }
517         testPrimitiveAccess(cbaLittle.cursor(), cbaLittle.cursor());
518     }
519 
520     @Test
521     public void testCompositeByteArrayWrapperPrimitiveAccess() {
522         CompositeByteArray cbaBig = new CompositeByteArray();
523         cbaBig.order(ByteOrder.BIG_ENDIAN);
524         for (int i = 0; i < 1000; i++) {
525             ByteArray component = getByteArrayFactory().create(1);
526             component.order(ByteOrder.BIG_ENDIAN);
527             cbaBig.addLast(component);
528         }
529         testPrimitiveAccess(new CompositeByteArrayRelativeWriter(cbaBig, getExpander(10), getFlusher(), false),
530                 new CompositeByteArrayRelativeReader(cbaBig, true));
531 
532         CompositeByteArray cbaLittle = new CompositeByteArray();
533         cbaLittle.order(ByteOrder.LITTLE_ENDIAN);
534         for (int i = 0; i < 1000; i++) {
535             ByteArray component = getByteArrayFactory().create(1);
536             component.order(ByteOrder.LITTLE_ENDIAN);
537             cbaLittle.addLast(component);
538         }
539         testPrimitiveAccess(new CompositeByteArrayRelativeWriter(cbaLittle, getExpander(10), getFlusher(), false),
540                 new CompositeByteArrayRelativeReader(cbaLittle, true));
541     }
542 
543     private void testPrimitiveAccess(IoRelativeWriter write, IoRelativeReader read) {
544         byte b = (byte) 0x12;
545         write.put(b);
546         assertEquals(b, read.get());
547 
548         short s = (short) 0x12;
549         write.putShort(s);
550         assertEquals(s, read.getShort());
551 
552         int i = 0x12345678;
553         write.putInt(i);
554         assertEquals(i, read.getInt());
555 
556         long l = 0x1234567890123456L;
557         write.putLong(l);
558         assertEquals(l, read.getLong());
559 
560         float f = Float.intBitsToFloat(i);
561         write.putFloat(f);
562         assertEquals(f, read.getFloat(), 0);
563 
564         double d = Double.longBitsToDouble(l);
565         write.putDouble(d);
566         assertEquals(d, read.getDouble(), 0);
567 
568         char c = (char) 0x1234;
569         write.putChar(c);
570         assertEquals(c, read.getChar());
571     }
572 
573 }