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 
148         CompositeByteArray cba = new CompositeByteArray();
149         cba.addLast(ba1);
150         cba.addLast(ba2);
151         cba.addLast(ba3);
152 
153         CursorListener cl = mc.createMock(CursorListener.class);
154 
155         mc.reset();
156         mc.replay();
157         Cursor cursor = cba.cursor(cl);
158         mc.verify();
159 
160         mc.reset();
161         cl.enteredFirstComponent(0, ba1);
162         mc.replay();
163         cursor.get();
164         mc.verify();
165 
166         mc.reset();
167         mc.replay();
168         cursor.setIndex(10);
169         mc.verify();
170 
171         mc.reset();
172         cl.enteredNextComponent(10, ba2);
173         mc.replay();
174         cursor.put((byte) 55);
175         mc.verify();
176 
177         mc.reset();
178         mc.replay();
179         cursor.setIndex(9);
180         mc.verify();
181 
182         mc.reset();
183         cl.enteredPreviousComponent(0, ba1);
184         cl.enteredNextComponent(10, ba2);
185         mc.replay();
186         cursor.putInt(66);
187         mc.verify();
188 
189         mc.reset();
190         cl.enteredNextComponent(20, ba3);
191         mc.replay();
192         cursor.setIndex(29);
193         cursor.get();
194         mc.verify();
195 
196         cba.removeLast(); // Force cursor to relocate itself.
197 
198         mc.reset();
199         cl.enteredLastComponent(10, ba2);
200         mc.replay();
201         cursor.setIndex(15);
202         cursor.get();
203         mc.verify();
204 
205         mc.reset();
206         cl.enteredPreviousComponent(0, ba1);
207         mc.replay();
208         cursor.setIndex(0);
209         cursor.get();
210         mc.verify();
211     }
212 
213     @Test
214     public void testCompositeByteArray() throws Exception {
215         CompositeByteArray ba = new CompositeByteArray();
216         for (int i = 0; i < 1000; i += 100) {
217             ba.addLast(getByteArrayFactory().create(100));
218         }
219         resetOperations();
220         testAbsoluteReaderAndWriter(0, 1000, ba, ba);
221         testAbsoluteReaderAndWriter(0, 1000, ba, ba);
222         assertOperationCountEquals(0);
223         Cursor readCursor = ba.cursor();
224         Cursor writeCursor = ba.cursor();
225         testRelativeReaderAndWriter(1000, readCursor, writeCursor);
226         assertOperationCountEquals(0);
227     }
228 
229     @Test
230     public void testCompositeByteArrayRelativeReaderAndWriter() throws Exception {
231         CompositeByteArray cba = new CompositeByteArray();
232         CompositeByteArrayRelativeReader cbarr = new CompositeByteArrayRelativeReader(cba, true);
233         CompositeByteArrayRelativeWriter cbarw = new CompositeByteArrayRelativeWriter(cba, getExpander(100), 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), getFlusher(), true);
256         resetOperations();
257         testRelativeReaderAndWriter(10, cbarr, cbarw);
258         assertOperationCountEquals(2);
259         resetOperations();
260         testRelativeReaderAndWriter(100, cbarr, cbarw);
261         assertOperationCountEquals(4);
262         resetOperations();
263         testRelativeReaderAndWriter(1000, cbarr, cbarw);
264         assertOperationCountEquals(40);
265         resetOperations();
266         testRelativeReaderAndWriter(10000, cbarr, cbarw);
267         assertOperationCountEquals(400);
268         resetOperations();
269         testRelativeReaderAndWriter(90, cbarr, cbarw);
270         assertOperationCountEquals(0); // Last free doesn't occur, since cursor only moves lazily.
271     }
272 
273     @Test
274     public void testCompositeRemoveTo() throws Exception {
275         CompositeByteArray cba = new CompositeByteArray();
276         {
277             // Remove nothing.
278             resetOperations();
279             ByteArray removed = cba.removeTo(0);
280             assertEquals(0, removed.first());
281             assertEquals(0, removed.last());
282             assertEquals(0, cba.first());
283             assertEquals(0, cba.last());
284             removed.free();
285             assertOperationCountEquals(0);
286         }
287         cba.addLast(getByteArrayFactory().create(100));
288         {
289             // Remove nothing.
290             resetOperations();
291             ByteArray removed = cba.removeTo(0);
292             assertEquals(0, removed.first());
293             assertEquals(0, removed.last());
294             assertEquals(0, cba.first());
295             assertEquals(100, cba.last());
296             removed.free();
297             assertOperationCountEquals(0);
298         }
299         {
300             // Remove entire component.
301             resetOperations();
302             ByteArray removed = cba.removeTo(100);
303             assertEquals(0, removed.first());
304             assertEquals(100, removed.last());
305             assertEquals(100, cba.first());
306             assertEquals(100, cba.last());
307             removed.free();
308             assertOperationCountEquals(1);
309         }
310         {
311             // Remove nothing.
312             resetOperations();
313             ByteArray removed = cba.removeTo(100);
314             assertEquals(0, removed.first());
315             assertEquals(0, removed.last());
316             assertEquals(100, cba.first());
317             assertEquals(100, cba.last());
318             removed.free();
319             assertOperationCountEquals(0);
320         }
321         cba.addLast(getByteArrayFactory().create(100));
322         {
323             // Remove nothing.
324             resetOperations();
325             ByteArray removed = cba.removeTo(100);
326             assertEquals(0, removed.first());
327             assertEquals(0, removed.last());
328             assertEquals(100, cba.first());
329             assertEquals(200, cba.last());
330             removed.free();
331             assertOperationCountEquals(0);
332         }
333         {
334             // Remove half a component.
335             resetOperations();
336             ByteArray removed = cba.removeTo(150);
337             assertEquals(0, removed.first());
338             assertEquals(50, removed.last());
339             assertEquals(150, cba.first());
340             assertEquals(200, cba.last());
341             removed.free();
342             assertOperationCountEquals(0); // Doesn't free until component finished.
343         }
344         {
345             // Remove nothing.
346             resetOperations();
347             ByteArray removed = cba.removeTo(150);
348             assertEquals(0, removed.first());
349             assertEquals(0, removed.last());
350             assertEquals(150, cba.first());
351             assertEquals(200, cba.last());
352             removed.free();
353             assertOperationCountEquals(0);
354         }
355         {
356             // Remove other half.
357             resetOperations();
358             ByteArray removed = cba.removeTo(200);
359             assertEquals(0, removed.first());
360             assertEquals(50, removed.last());
361             assertEquals(200, cba.first());
362             assertEquals(200, cba.last());
363             removed.free();
364             assertOperationCountEquals(1); // Frees ByteArray behind both buffers.
365         }
366     }
367     
368     @Test
369     public void testCompositeByteArraySlicing() {
370         CompositeByteArray cba = new CompositeByteArray();
371         cba.addLast(getByteArrayFactory().create(10));
372         cba.addLast(getByteArrayFactory().create(10));
373         cba.addLast(getByteArrayFactory().create(10));
374         testByteArraySlicing(cba, 0, 30);
375         testByteArraySlicing(cba, 5, 10);
376         testByteArraySlicing(cba, 10, 20);
377         testByteArraySlicing(cba, 1, 28);
378         testByteArraySlicing(cba, 19, 2);
379     }
380     
381     @Test
382     public void testBufferByteArraySlicing() {
383         ByteArray bba = getByteArrayFactory().create(30);
384         testByteArraySlicing(bba, 0, 30);
385         testByteArraySlicing(bba, 5, 10);
386         testByteArraySlicing(bba, 10, 20);
387         testByteArraySlicing(bba, 1, 28);
388         testByteArraySlicing(bba, 19, 2);
389         
390     }
391     
392     private void testByteArraySlicing(ByteArray ba, int start, int length) {
393         ByteArray slice = ba.slice(start, length);
394         for (int i = 0; i < length; i++) {
395             byte b1 = (byte) (i % 67);
396             byte b2 = (byte) (i % 36);
397             int sourceIndex = i + start;
398             int sliceIndex = i;
399             ba.put(sourceIndex, b1);
400             assertEquals(b1, ba.get(sourceIndex));
401             assertEquals(b1, slice.get(sliceIndex));
402             slice.put(sliceIndex, b2);
403             assertEquals(b2, ba.get(sourceIndex));
404             assertEquals(b2, slice.get(sliceIndex));
405         }
406     }
407 
408     private ChunkedExpander getExpander(final int chunkSize) {
409         return new ChunkedExpander(getByteArrayFactory(), chunkSize) {
410             @Override
411             public void expand(CompositeByteArray cba, int minSize) {
412                 addOperation("ChunkedExpander(" + chunkSize + ").expand(" + cba + "," + minSize + ")");
413                 super.expand(cba, minSize);
414             }
415         };
416     }
417 
418     private Flusher getFlusher() {
419         return new CompositeByteArrayRelativeWriter.Flusher() {
420 
421             public void flush(ByteArray ba) {
422                 addOperation("Flusher().flush(" + ba + ")");
423                 ba.free();
424             }
425 
426         };
427     }
428 
429     private SimpleByteArrayFactory getByteArrayFactory() {
430         return new SimpleByteArrayFactory() {
431             @Override
432             public ByteArray create(final int size) {
433                 if (size < 0) {
434                     throw new IllegalArgumentException(
435                             "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), new CompositeByteArrayRelativeReader(cbaBig, true));
530 
531         CompositeByteArray cbaLittle = new CompositeByteArray();
532         cbaLittle.order(ByteOrder.LITTLE_ENDIAN);
533         for (int i = 0; i < 1000; i++) {
534             ByteArray component = getByteArrayFactory().create(1);
535             component.order(ByteOrder.LITTLE_ENDIAN);
536             cbaLittle.addLast(component);
537         }
538         testPrimitiveAccess(new CompositeByteArrayRelativeWriter(cbaLittle, getExpander(10), getFlusher(), false), new CompositeByteArrayRelativeReader(cbaLittle, true));
539     }
540 
541     private void testPrimitiveAccess(IoRelativeWriter write, IoRelativeReader read) {
542         byte b = (byte) 0x12;
543         write.put(b);
544         assertEquals(b, read.get());
545 
546         short s = (short) 0x12;
547         write.putShort(s);
548         assertEquals(s, read.getShort());
549 
550         int i = 0x12345678;
551         write.putInt(i);
552         assertEquals(i, read.getInt());
553 
554         long l = 0x1234567890123456L;
555         write.putLong(l);
556         assertEquals(l, read.getLong());
557 
558         float f = Float.intBitsToFloat(i);
559         write.putFloat(f);
560         assertEquals(f, read.getFloat(), 0);
561 
562         double d = Double.longBitsToDouble(l);
563         write.putDouble(d);
564         assertEquals(d, read.getDouble(), 0);
565 
566         char c = (char) 0x1234;
567         write.putChar(c);
568         assertEquals(c, read.getChar());
569     }
570 
571 }