1 /* 2 * Copyright (C) 2014 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package okio; 17 18 import java.util.Arrays; 19 import java.util.List; 20 import java.util.Random; 21 import org.junit.Test; 22 23 import static java.util.Arrays.asList; 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 public final class OkBufferTest { 30 @Test public void readAndWriteUtf8() throws Exception { 31 OkBuffer buffer = new OkBuffer(); 32 buffer.writeUtf8("ab"); 33 assertEquals(2, buffer.size()); 34 buffer.writeUtf8("cdef"); 35 assertEquals(6, buffer.size()); 36 assertEquals("abcd", buffer.readUtf8(4)); 37 assertEquals(2, buffer.size()); 38 assertEquals("ef", buffer.readUtf8(2)); 39 assertEquals(0, buffer.size()); 40 try { 41 buffer.readUtf8(1); 42 fail(); 43 } catch (ArrayIndexOutOfBoundsException expected) { 44 } 45 } 46 47 @Test public void completeSegmentByteCountOnEmptyBuffer() throws Exception { 48 OkBuffer buffer = new OkBuffer(); 49 assertEquals(0, buffer.completeSegmentByteCount()); 50 } 51 52 @Test public void completeSegmentByteCountOnBufferWithFullSegments() throws Exception { 53 OkBuffer buffer = new OkBuffer(); 54 buffer.writeUtf8(repeat('a', Segment.SIZE * 4)); 55 assertEquals(Segment.SIZE * 4, buffer.completeSegmentByteCount()); 56 } 57 58 @Test public void completeSegmentByteCountOnBufferWithIncompleteTailSegment() throws Exception { 59 OkBuffer buffer = new OkBuffer(); 60 buffer.writeUtf8(repeat('a', Segment.SIZE * 4 - 10)); 61 assertEquals(Segment.SIZE * 3, buffer.completeSegmentByteCount()); 62 } 63 64 @Test public void readUtf8SpansSegments() throws Exception { 65 OkBuffer buffer = new OkBuffer(); 66 buffer.writeUtf8(repeat('a', Segment.SIZE * 2)); 67 buffer.readUtf8(Segment.SIZE - 1); 68 assertEquals("aa", buffer.readUtf8(2)); 69 } 70 71 @Test public void readUtf8EntireBuffer() throws Exception { 72 OkBuffer buffer = new OkBuffer(); 73 buffer.writeUtf8(repeat('a', Segment.SIZE)); 74 assertEquals(repeat('a', Segment.SIZE), buffer.readUtf8(Segment.SIZE)); 75 } 76 77 @Test public void toStringOnEmptyBuffer() throws Exception { 78 OkBuffer buffer = new OkBuffer(); 79 assertEquals("OkBuffer[size=0]", buffer.toString()); 80 } 81 82 @Test public void toStringOnSmallBufferIncludesContents() throws Exception { 83 OkBuffer buffer = new OkBuffer(); 84 buffer.write(ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040")); 85 assertEquals("OkBuffer[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", buffer.toString()); 86 } 87 88 @Test public void toStringOnLargeBufferIncludesMd5() throws Exception { 89 OkBuffer buffer = new OkBuffer(); 90 buffer.write(ByteString.encodeUtf8("12345678901234567")); 91 assertEquals("OkBuffer[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", buffer.toString()); 92 } 93 94 @Test public void toStringOnMultipleSegmentBuffer() throws Exception { 95 OkBuffer buffer = new OkBuffer(); 96 buffer.writeUtf8(repeat('a', 6144)); 97 assertEquals("OkBuffer[size=6144 md5=d890021f28522533c1cc1b9b1f83ce73]", buffer.toString()); 98 } 99 100 @Test public void multipleSegmentBuffers() throws Exception { 101 OkBuffer buffer = new OkBuffer(); 102 buffer.writeUtf8(repeat('a', 1000)); 103 buffer.writeUtf8(repeat('b', 2500)); 104 buffer.writeUtf8(repeat('c', 5000)); 105 buffer.writeUtf8(repeat('d', 10000)); 106 buffer.writeUtf8(repeat('e', 25000)); 107 buffer.writeUtf8(repeat('f', 50000)); 108 109 assertEquals(repeat('a', 999), buffer.readUtf8(999)); // a...a 110 assertEquals("a" + repeat('b', 2500) + "c", buffer.readUtf8(2502)); // ab...bc 111 assertEquals(repeat('c', 4998), buffer.readUtf8(4998)); // c...c 112 assertEquals("c" + repeat('d', 10000) + "e", buffer.readUtf8(10002)); // cd...de 113 assertEquals(repeat('e', 24998), buffer.readUtf8(24998)); // e...e 114 assertEquals("e" + repeat('f', 50000), buffer.readUtf8(50001)); // ef...f 115 assertEquals(0, buffer.size()); 116 } 117 118 @Test public void fillAndDrainPool() throws Exception { 119 OkBuffer buffer = new OkBuffer(); 120 121 // Take 2 * MAX_SIZE segments. This will drain the pool, even if other tests filled it. 122 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 123 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 124 assertEquals(0, SegmentPool.INSTANCE.byteCount); 125 126 // Recycle MAX_SIZE segments. They're all in the pool. 127 buffer.readByteString(SegmentPool.MAX_SIZE); 128 assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount); 129 130 // Recycle MAX_SIZE more segments. The pool is full so they get garbage collected. 131 buffer.readByteString(SegmentPool.MAX_SIZE); 132 assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount); 133 134 // Take MAX_SIZE segments to drain the pool. 135 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 136 assertEquals(0, SegmentPool.INSTANCE.byteCount); 137 138 // Take MAX_SIZE more segments. The pool is drained so these will need to be allocated. 139 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 140 assertEquals(0, SegmentPool.INSTANCE.byteCount); 141 } 142 143 @Test public void moveBytesBetweenBuffersShareSegment() throws Exception { 144 int size = (Segment.SIZE / 2) - 1; 145 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 146 assertEquals(asList(size * 2), segmentSizes); 147 } 148 149 @Test public void moveBytesBetweenBuffersReassignSegment() throws Exception { 150 int size = (Segment.SIZE / 2) + 1; 151 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 152 assertEquals(asList(size, size), segmentSizes); 153 } 154 155 @Test public void moveBytesBetweenBuffersMultipleSegments() throws Exception { 156 int size = 3 * Segment.SIZE + 1; 157 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 158 assertEquals(asList(Segment.SIZE, Segment.SIZE, Segment.SIZE, 1, 159 Segment.SIZE, Segment.SIZE, Segment.SIZE, 1), segmentSizes); 160 } 161 162 private List<Integer> moveBytesBetweenBuffers(String... contents) { 163 StringBuilder expected = new StringBuilder(); 164 OkBuffer buffer = new OkBuffer(); 165 for (String s : contents) { 166 OkBuffer source = new OkBuffer(); 167 source.writeUtf8(s); 168 buffer.write(source, source.size()); 169 expected.append(s); 170 } 171 List<Integer> segmentSizes = buffer.segmentSizes(); 172 assertEquals(expected.toString(), buffer.readUtf8(expected.length())); 173 return segmentSizes; 174 } 175 176 /** The big part of source's first segment is being moved. */ 177 @Test public void writeSplitSourceBufferLeft() throws Exception { 178 int writeSize = Segment.SIZE / 2 + 1; 179 180 OkBuffer sink = new OkBuffer(); 181 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); 182 183 OkBuffer source = new OkBuffer(); 184 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 185 sink.write(source, writeSize); 186 187 assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes()); 188 assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes()); 189 } 190 191 /** The big part of source's first segment is staying put. */ 192 @Test public void writeSplitSourceBufferRight() throws Exception { 193 int writeSize = Segment.SIZE / 2 - 1; 194 195 OkBuffer sink = new OkBuffer(); 196 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); 197 198 OkBuffer source = new OkBuffer(); 199 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 200 sink.write(source, writeSize); 201 202 assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes()); 203 assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes()); 204 } 205 206 @Test public void writePrefixDoesntSplit() throws Exception { 207 OkBuffer sink = new OkBuffer(); 208 sink.writeUtf8(repeat('b', 10)); 209 210 OkBuffer source = new OkBuffer(); 211 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 212 sink.write(source, 20); 213 214 assertEquals(asList(30), sink.segmentSizes()); 215 assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); 216 assertEquals(30, sink.size()); 217 assertEquals(Segment.SIZE * 2 - 20, source.size()); 218 } 219 220 @Test public void writePrefixDoesntSplitButRequiresCompact() throws Exception { 221 OkBuffer sink = new OkBuffer(); 222 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); // limit = size - 10 223 sink.readUtf8(Segment.SIZE - 20); // pos = size = 20 224 225 OkBuffer source = new OkBuffer(); 226 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 227 sink.write(source, 20); 228 229 assertEquals(asList(30), sink.segmentSizes()); 230 assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); 231 assertEquals(30, sink.size()); 232 assertEquals(Segment.SIZE * 2 - 20, source.size()); 233 } 234 235 @Test public void readExhaustedSource() throws Exception { 236 OkBuffer sink = new OkBuffer(); 237 sink.writeUtf8(repeat('a', 10)); 238 239 OkBuffer source = new OkBuffer(); 240 241 assertEquals(-1, source.read(sink, 10)); 242 assertEquals(10, sink.size()); 243 assertEquals(0, source.size()); 244 } 245 246 @Test public void readZeroBytesFromSource() throws Exception { 247 OkBuffer sink = new OkBuffer(); 248 sink.writeUtf8(repeat('a', 10)); 249 250 OkBuffer source = new OkBuffer(); 251 252 // Either 0 or -1 is reasonable here. For consistency with Android's 253 // ByteArrayInputStream we return 0. 254 assertEquals(-1, source.read(sink, 0)); 255 assertEquals(10, sink.size()); 256 assertEquals(0, source.size()); 257 } 258 259 @Test public void moveAllRequestedBytesWithRead() throws Exception { 260 OkBuffer sink = new OkBuffer(); 261 sink.writeUtf8(repeat('a', 10)); 262 263 OkBuffer source = new OkBuffer(); 264 source.writeUtf8(repeat('b', 15)); 265 266 assertEquals(10, source.read(sink, 10)); 267 assertEquals(20, sink.size()); 268 assertEquals(5, source.size()); 269 assertEquals(repeat('a', 10) + repeat('b', 10), sink.readUtf8(20)); 270 } 271 272 @Test public void moveFewerThanRequestedBytesWithRead() throws Exception { 273 OkBuffer sink = new OkBuffer(); 274 sink.writeUtf8(repeat('a', 10)); 275 276 OkBuffer source = new OkBuffer(); 277 source.writeUtf8(repeat('b', 20)); 278 279 assertEquals(20, source.read(sink, 25)); 280 assertEquals(30, sink.size()); 281 assertEquals(0, source.size()); 282 assertEquals(repeat('a', 10) + repeat('b', 20), sink.readUtf8(30)); 283 } 284 285 @Test public void indexOf() throws Exception { 286 OkBuffer buffer = new OkBuffer(); 287 288 // The segment is empty. 289 assertEquals(-1, buffer.indexOf((byte) 'a')); 290 291 // The segment has one value. 292 buffer.writeUtf8("a"); // a 293 assertEquals(0, buffer.indexOf((byte) 'a')); 294 assertEquals(-1, buffer.indexOf((byte) 'b')); 295 296 // The segment has lots of data. 297 buffer.writeUtf8(repeat('b', Segment.SIZE - 2)); // ab...b 298 assertEquals(0, buffer.indexOf((byte) 'a')); 299 assertEquals(1, buffer.indexOf((byte) 'b')); 300 assertEquals(-1, buffer.indexOf((byte) 'c')); 301 302 // The segment doesn't start at 0, it starts at 2. 303 buffer.readUtf8(2); // b...b 304 assertEquals(-1, buffer.indexOf((byte) 'a')); 305 assertEquals(0, buffer.indexOf((byte) 'b')); 306 assertEquals(-1, buffer.indexOf((byte) 'c')); 307 308 // The segment is full. 309 buffer.writeUtf8("c"); // b...bc 310 assertEquals(-1, buffer.indexOf((byte) 'a')); 311 assertEquals(0, buffer.indexOf((byte) 'b')); 312 assertEquals(Segment.SIZE - 3, buffer.indexOf((byte) 'c')); 313 314 // The segment doesn't start at 2, it starts at 4. 315 buffer.readUtf8(2); // b...bc 316 assertEquals(-1, buffer.indexOf((byte) 'a')); 317 assertEquals(0, buffer.indexOf((byte) 'b')); 318 assertEquals(Segment.SIZE - 5, buffer.indexOf((byte) 'c')); 319 320 // Two segments. 321 buffer.writeUtf8("d"); // b...bcd, d is in the 2nd segment. 322 assertEquals(asList(Segment.SIZE - 4, 1), buffer.segmentSizes()); 323 assertEquals(Segment.SIZE - 4, buffer.indexOf((byte) 'd')); 324 assertEquals(-1, buffer.indexOf((byte) 'e')); 325 } 326 327 @Test public void indexOfWithOffset() throws Exception { 328 OkBuffer buffer = new OkBuffer(); 329 int halfSegment = Segment.SIZE / 2; 330 buffer.writeUtf8(repeat('a', halfSegment)); 331 buffer.writeUtf8(repeat('b', halfSegment)); 332 buffer.writeUtf8(repeat('c', halfSegment)); 333 buffer.writeUtf8(repeat('d', halfSegment)); 334 assertEquals(0, buffer.indexOf((byte) 'a', 0)); 335 assertEquals(halfSegment - 1, buffer.indexOf((byte) 'a', halfSegment - 1)); 336 assertEquals(halfSegment, buffer.indexOf((byte) 'b', halfSegment - 1)); 337 assertEquals(halfSegment * 2, buffer.indexOf((byte) 'c', halfSegment - 1)); 338 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment - 1)); 339 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 2)); 340 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 3)); 341 assertEquals(halfSegment * 4 - 1, buffer.indexOf((byte) 'd', halfSegment * 4 - 1)); 342 } 343 344 @Test public void writeBytes() throws Exception { 345 OkBuffer data = new OkBuffer(); 346 data.writeByte(0xab); 347 data.writeByte(0xcd); 348 assertEquals("OkBuffer[size=2 data=abcd]", data.toString()); 349 } 350 351 @Test public void writeLastByteInSegment() throws Exception { 352 OkBuffer data = new OkBuffer(); 353 data.writeUtf8(repeat('a', Segment.SIZE - 1)); 354 data.writeByte(0x20); 355 data.writeByte(0x21); 356 assertEquals(asList(Segment.SIZE, 1), data.segmentSizes()); 357 assertEquals(repeat('a', Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1)); 358 assertEquals("OkBuffer[size=2 data=2021]", data.toString()); 359 } 360 361 @Test public void writeShort() throws Exception { 362 OkBuffer data = new OkBuffer(); 363 data.writeShort(0xabcd); 364 data.writeShort(0x4321); 365 assertEquals("OkBuffer[size=4 data=abcd4321]", data.toString()); 366 } 367 368 @Test public void writeShortLe() throws Exception { 369 OkBuffer data = new OkBuffer(); 370 data.writeShortLe(0xabcd); 371 data.writeShortLe(0x4321); 372 assertEquals("OkBuffer[size=4 data=cdab2143]", data.toString()); 373 } 374 375 @Test public void writeInt() throws Exception { 376 OkBuffer data = new OkBuffer(); 377 data.writeInt(0xabcdef01); 378 data.writeInt(0x87654321); 379 assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString()); 380 } 381 382 @Test public void writeLastIntegerInSegment() throws Exception { 383 OkBuffer data = new OkBuffer(); 384 data.writeUtf8(repeat('a', Segment.SIZE - 4)); 385 data.writeInt(0xabcdef01); 386 data.writeInt(0x87654321); 387 assertEquals(asList(Segment.SIZE, 4), data.segmentSizes()); 388 assertEquals(repeat('a', Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4)); 389 assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString()); 390 } 391 392 @Test public void writeIntegerDoesntQuiteFitInSegment() throws Exception { 393 OkBuffer data = new OkBuffer(); 394 data.writeUtf8(repeat('a', Segment.SIZE - 3)); 395 data.writeInt(0xabcdef01); 396 data.writeInt(0x87654321); 397 assertEquals(asList(Segment.SIZE - 3, 8), data.segmentSizes()); 398 assertEquals(repeat('a', Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3)); 399 assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString()); 400 } 401 402 @Test public void writeIntLe() throws Exception { 403 OkBuffer data = new OkBuffer(); 404 data.writeIntLe(0xabcdef01); 405 data.writeIntLe(0x87654321); 406 assertEquals("OkBuffer[size=8 data=01efcdab21436587]", data.toString()); 407 } 408 409 @Test public void writeLong() throws Exception { 410 OkBuffer data = new OkBuffer(); 411 data.writeLong(0xabcdef0187654321L); 412 data.writeLong(0xcafebabeb0b15c00L); 413 assertEquals("OkBuffer[size=16 data=abcdef0187654321cafebabeb0b15c00]", data.toString()); 414 } 415 416 @Test public void writeLongLe() throws Exception { 417 OkBuffer data = new OkBuffer(); 418 data.writeLongLe(0xabcdef0187654321L); 419 data.writeLongLe(0xcafebabeb0b15c00L); 420 assertEquals("OkBuffer[size=16 data=2143658701efcdab005cb1b0bebafeca]", data.toString()); 421 } 422 423 @Test public void readByte() throws Exception { 424 OkBuffer data = new OkBuffer(); 425 data.write(new byte[] { (byte) 0xab, (byte) 0xcd }); 426 assertEquals(0xab, data.readByte() & 0xff); 427 assertEquals(0xcd, data.readByte() & 0xff); 428 assertEquals(0, data.size()); 429 } 430 431 @Test public void readShort() throws Exception { 432 OkBuffer data = new OkBuffer(); 433 data.write(new byte[] { 434 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01 435 }); 436 assertEquals((short) 0xabcd, data.readShort()); 437 assertEquals((short) 0xef01, data.readShort()); 438 assertEquals(0, data.size()); 439 } 440 441 @Test public void readShortLe() throws Exception { 442 OkBuffer data = new OkBuffer(); 443 data.write(new byte[] { 444 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10 445 }); 446 assertEquals((short) 0xcdab, data.readShortLe()); 447 assertEquals((short) 0x10ef, data.readShortLe()); 448 assertEquals(0, data.size()); 449 } 450 451 @Test public void readShortSplitAcrossMultipleSegments() throws Exception { 452 OkBuffer data = new OkBuffer(); 453 data.writeUtf8(repeat('a', Segment.SIZE - 1)); 454 data.write(new byte[] { (byte) 0xab, (byte) 0xcd }); 455 data.readUtf8(Segment.SIZE - 1); 456 assertEquals((short) 0xabcd, data.readShort()); 457 assertEquals(0, data.size()); 458 } 459 460 @Test public void readInt() throws Exception { 461 OkBuffer data = new OkBuffer(); 462 data.write(new byte[] { 463 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, 464 (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21 465 }); 466 assertEquals(0xabcdef01, data.readInt()); 467 assertEquals(0x87654321, data.readInt()); 468 assertEquals(0, data.size()); 469 } 470 471 @Test public void readIntLe() throws Exception { 472 OkBuffer data = new OkBuffer(); 473 data.write(new byte[] { 474 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, 475 (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21 476 }); 477 assertEquals(0x10efcdab, data.readIntLe()); 478 assertEquals(0x21436587, data.readIntLe()); 479 assertEquals(0, data.size()); 480 } 481 482 @Test public void readIntSplitAcrossMultipleSegments() throws Exception { 483 OkBuffer data = new OkBuffer(); 484 data.writeUtf8(repeat('a', Segment.SIZE - 3)); 485 data.write(new byte[] { 486 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01 487 }); 488 data.readUtf8(Segment.SIZE - 3); 489 assertEquals(0xabcdef01, data.readInt()); 490 assertEquals(0, data.size()); 491 } 492 493 @Test public void readLong() throws Exception { 494 OkBuffer data = new OkBuffer(); 495 data.write(new byte[] { 496 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, 497 (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21, 498 (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69, 499 (byte) 0x12, (byte) 0x23, (byte) 0x34, (byte) 0x45 500 }); 501 assertEquals(0xabcdef1087654321L, data.readLong()); 502 assertEquals(0x3647586912233445L, data.readLong()); 503 assertEquals(0, data.size()); 504 } 505 506 @Test public void readLongLe() throws Exception { 507 OkBuffer data = new OkBuffer(); 508 data.write(new byte[] { 509 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, 510 (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21, 511 (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69, 512 (byte) 0x12, (byte) 0x23, (byte) 0x34, (byte) 0x45 513 }); 514 assertEquals(0x2143658710efcdabL, data.readLongLe()); 515 assertEquals(0x4534231269584736L, data.readLongLe()); 516 assertEquals(0, data.size()); 517 } 518 519 @Test public void readLongSplitAcrossMultipleSegments() throws Exception { 520 OkBuffer data = new OkBuffer(); 521 data.writeUtf8(repeat('a', Segment.SIZE - 7)); 522 data.write(new byte[] { 523 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, 524 (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21, 525 }); 526 data.readUtf8(Segment.SIZE - 7); 527 assertEquals(0xabcdef0187654321L, data.readLong()); 528 assertEquals(0, data.size()); 529 } 530 531 @Test public void byteAt() throws Exception { 532 OkBuffer buffer = new OkBuffer(); 533 buffer.writeUtf8("a"); 534 buffer.writeUtf8(repeat('b', Segment.SIZE)); 535 buffer.writeUtf8("c"); 536 assertEquals('a', buffer.getByte(0)); 537 assertEquals('a', buffer.getByte(0)); // getByte doesn't mutate! 538 assertEquals('c', buffer.getByte(buffer.size - 1)); 539 assertEquals('b', buffer.getByte(buffer.size - 2)); 540 assertEquals('b', buffer.getByte(buffer.size - 3)); 541 } 542 543 @Test public void getByteOfEmptyBuffer() throws Exception { 544 OkBuffer buffer = new OkBuffer(); 545 try { 546 buffer.getByte(0); 547 fail(); 548 } catch (IndexOutOfBoundsException expected) { 549 } 550 } 551 552 @Test public void skip() throws Exception { 553 OkBuffer buffer = new OkBuffer(); 554 buffer.writeUtf8("a"); 555 buffer.writeUtf8(repeat('b', Segment.SIZE)); 556 buffer.writeUtf8("c"); 557 buffer.skip(1); 558 assertEquals('b', buffer.readByte() & 0xff); 559 buffer.skip(Segment.SIZE - 2); 560 assertEquals('b', buffer.readByte() & 0xff); 561 buffer.skip(1); 562 assertEquals(0, buffer.size()); 563 } 564 565 @Test public void testWritePrefixToEmptyBuffer() { 566 OkBuffer sink = new OkBuffer(); 567 OkBuffer source = new OkBuffer(); 568 source.writeUtf8("abcd"); 569 sink.write(source, 2); 570 assertEquals("ab", sink.readUtf8(2)); 571 } 572 573 @Test public void cloneDoesNotObserveWritesToOriginal() throws Exception { 574 OkBuffer original = new OkBuffer(); 575 OkBuffer clone = original.clone(); 576 original.writeUtf8("abc"); 577 assertEquals(0, clone.size()); 578 } 579 580 @Test public void cloneDoesNotObserveReadsFromOriginal() throws Exception { 581 OkBuffer original = new OkBuffer(); 582 original.writeUtf8("abc"); 583 OkBuffer clone = original.clone(); 584 assertEquals("abc", original.readUtf8(3)); 585 assertEquals(3, clone.size()); 586 assertEquals("ab", clone.readUtf8(2)); 587 } 588 589 @Test public void originalDoesNotObserveWritesToClone() throws Exception { 590 OkBuffer original = new OkBuffer(); 591 OkBuffer clone = original.clone(); 592 clone.writeUtf8("abc"); 593 assertEquals(0, original.size()); 594 } 595 596 @Test public void originalDoesNotObserveReadsFromClone() throws Exception { 597 OkBuffer original = new OkBuffer(); 598 original.writeUtf8("abc"); 599 OkBuffer clone = original.clone(); 600 assertEquals("abc", clone.readUtf8(3)); 601 assertEquals(3, original.size()); 602 assertEquals("ab", original.readUtf8(2)); 603 } 604 605 @Test public void cloneMultipleSegments() throws Exception { 606 OkBuffer original = new OkBuffer(); 607 original.writeUtf8(repeat('a', Segment.SIZE * 3)); 608 OkBuffer clone = original.clone(); 609 original.writeUtf8(repeat('b', Segment.SIZE * 3)); 610 clone.writeUtf8(repeat('c', Segment.SIZE * 3)); 611 612 assertEquals(repeat('a', Segment.SIZE * 3) + repeat('b', Segment.SIZE * 3), 613 original.readUtf8(Segment.SIZE * 6)); 614 assertEquals(repeat('a', Segment.SIZE * 3) + repeat('c', Segment.SIZE * 3), 615 clone.readUtf8(Segment.SIZE * 6)); 616 } 617 618 @Test public void testEqualsAndHashCodeEmpty() throws Exception { 619 OkBuffer a = new OkBuffer(); 620 OkBuffer b = new OkBuffer(); 621 assertTrue(a.equals(b)); 622 assertTrue(a.hashCode() == b.hashCode()); 623 } 624 625 @Test public void testEqualsAndHashCode() throws Exception { 626 OkBuffer a = new OkBuffer().writeUtf8("dog"); 627 OkBuffer b = new OkBuffer().writeUtf8("hotdog"); 628 assertFalse(a.equals(b)); 629 assertFalse(a.hashCode() == b.hashCode()); 630 631 b.readUtf8(3); // Leaves b containing 'dog'. 632 assertTrue(a.equals(b)); 633 assertTrue(a.hashCode() == b.hashCode()); 634 } 635 636 @Test public void testEqualsAndHashCodeSpanningSegments() throws Exception { 637 byte[] data = new byte[1024 * 1024]; 638 Random dice = new Random(0); 639 dice.nextBytes(data); 640 641 OkBuffer a = bufferWithRandomSegmentLayout(dice, data); 642 OkBuffer b = bufferWithRandomSegmentLayout(dice, data); 643 assertTrue(a.equals(b)); 644 assertTrue(a.hashCode() == b.hashCode()); 645 646 data[data.length / 2]++; // Change a single byte. 647 OkBuffer c = bufferWithRandomSegmentLayout(dice, data); 648 assertFalse(a.equals(c)); 649 assertFalse(a.hashCode() == c.hashCode()); 650 } 651 652 /** 653 * Returns a new buffer containing the data in {@code data}, and a segment 654 * layout determined by {@code dice}. 655 */ 656 private OkBuffer bufferWithRandomSegmentLayout(Random dice, byte[] data) { 657 OkBuffer result = new OkBuffer(); 658 659 // Writing to result directly will yield packed segments. Instead, write to 660 // other buffers, then write those buffers to result. 661 for (int pos = 0, byteCount; pos < data.length; pos += byteCount) { 662 byteCount = (Segment.SIZE / 2) + dice.nextInt(Segment.SIZE / 2); 663 if (byteCount > data.length - pos) byteCount = data.length - pos; 664 int offset = dice.nextInt(Segment.SIZE - byteCount); 665 666 OkBuffer segment = new OkBuffer(); 667 segment.write(new byte[offset]); 668 segment.write(data, pos, byteCount); 669 segment.skip(offset); 670 671 result.write(segment, byteCount); 672 } 673 674 return result; 675 } 676 677 private String repeat(char c, int count) { 678 char[] array = new char[count]; 679 Arrays.fill(array, c); 680 return new String(array); 681 } 682 } 683