001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.util.byteaccess; 021 022import static org.easymock.EasyMock.createStrictControl; 023import static org.junit.Assert.assertEquals; 024 025import java.nio.ByteOrder; 026import java.util.ArrayList; 027import java.util.List; 028 029import org.apache.mina.core.buffer.IoBuffer; 030import org.apache.mina.util.byteaccess.ByteArray.Cursor; 031import org.apache.mina.util.byteaccess.CompositeByteArray.CursorListener; 032import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.ChunkedExpander; 033import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.Flusher; 034import org.easymock.IMocksControl; 035import org.junit.Test; 036 037/** 038 * Tests classes in the <code>byteaccess</code> package. 039 * 040 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 041 */ 042public class ByteAccessTest { 043 044 private List<String> operations = new ArrayList<String>(); 045 046 private void resetOperations() { 047 operations.clear(); 048 } 049 050 private void assertOperationCountEquals(int expectedCount) { 051 assertEquals("Operations: " + operations, expectedCount, operations.size()); 052 } 053 054 private void addOperation(String description) { 055 operations.add(description); 056 } 057 058 @Test 059 public void testBufferByteArray() throws Exception { 060 ByteArray ba = getByteArrayFactory().create(1000); 061 testAbsoluteReaderAndWriter(0, 1000, ba, ba); 062 testAbsoluteReaderAndWriter(0, 1000, ba, ba); 063 Cursor readCursor = ba.cursor(); 064 Cursor writeCursor = ba.cursor(); 065 testRelativeReaderAndWriter(1000, readCursor, writeCursor); 066 } 067 068 @Test 069 public void testCompositeAddAndRemove() throws Exception { 070 CompositeByteArray cba = new CompositeByteArray(); 071 assertEquals(0, cba.first()); 072 assertEquals(0, cba.last()); 073 cba.addFirst(getByteArrayFactory().create(100)); 074 assertEquals(-100, cba.first()); 075 assertEquals(0, cba.last()); 076 cba.addFirst(getByteArrayFactory().create(100)); 077 assertEquals(-200, cba.first()); 078 assertEquals(0, cba.last()); 079 cba.addLast(getByteArrayFactory().create(100)); 080 assertEquals(-200, cba.first()); 081 assertEquals(100, cba.last()); 082 cba.removeFirst(); 083 assertEquals(-100, cba.first()); 084 assertEquals(100, cba.last()); 085 cba.addLast(getByteArrayFactory().create(100)); 086 assertEquals(-100, cba.first()); 087 assertEquals(200, cba.last()); 088 cba.removeLast(); 089 assertEquals(-100, cba.first()); 090 assertEquals(100, cba.last()); 091 cba.removeFirst(); 092 assertEquals(0, cba.first()); 093 assertEquals(100, cba.last()); 094 cba.removeFirst(); 095 assertEquals(100, cba.first()); 096 assertEquals(100, cba.last()); 097 cba.addLast(getByteArrayFactory().create(100)); 098 assertEquals(100, cba.first()); 099 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}