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 }