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 */ 16package okio; 17 18import java.io.ByteArrayInputStream; 19import java.io.ByteArrayOutputStream; 20import java.io.IOException; 21import java.io.InputStream; 22import java.util.Arrays; 23import java.util.List; 24import java.util.Random; 25import org.junit.Test; 26 27import static java.util.Arrays.asList; 28import static okio.TestUtil.repeat; 29import static okio.Util.UTF_8; 30import static org.junit.Assert.assertEquals; 31import static org.junit.Assert.assertFalse; 32import static org.junit.Assert.assertTrue; 33import static org.junit.Assert.fail; 34 35/** 36 * Tests solely for the behavior of Buffer's implementation. For generic BufferedSink or 37 * BufferedSource behavior use BufferedSinkTest or BufferedSourceTest, respectively. 38 */ 39public final class BufferTest { 40 @Test public void readAndWriteUtf8() throws Exception { 41 Buffer buffer = new Buffer(); 42 buffer.writeUtf8("ab"); 43 assertEquals(2, buffer.size()); 44 buffer.writeUtf8("cdef"); 45 assertEquals(6, buffer.size()); 46 assertEquals("abcd", buffer.readUtf8(4)); 47 assertEquals(2, buffer.size()); 48 assertEquals("ef", buffer.readUtf8(2)); 49 assertEquals(0, buffer.size()); 50 try { 51 buffer.readUtf8(1); 52 fail(); 53 } catch (ArrayIndexOutOfBoundsException expected) { 54 } 55 } 56 57 @Test public void completeSegmentByteCountOnEmptyBuffer() throws Exception { 58 Buffer buffer = new Buffer(); 59 assertEquals(0, buffer.completeSegmentByteCount()); 60 } 61 62 @Test public void completeSegmentByteCountOnBufferWithFullSegments() throws Exception { 63 Buffer buffer = new Buffer(); 64 buffer.writeUtf8(repeat('a', Segment.SIZE * 4)); 65 assertEquals(Segment.SIZE * 4, buffer.completeSegmentByteCount()); 66 } 67 68 @Test public void completeSegmentByteCountOnBufferWithIncompleteTailSegment() throws Exception { 69 Buffer buffer = new Buffer(); 70 buffer.writeUtf8(repeat('a', Segment.SIZE * 4 - 10)); 71 assertEquals(Segment.SIZE * 3, buffer.completeSegmentByteCount()); 72 } 73 74 @Test public void toStringOnEmptyBuffer() throws Exception { 75 Buffer buffer = new Buffer(); 76 assertEquals("Buffer[size=0]", buffer.toString()); 77 } 78 79 @Test public void toStringOnSmallBufferIncludesContents() throws Exception { 80 Buffer buffer = new Buffer(); 81 buffer.write(ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040")); 82 assertEquals("Buffer[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", buffer.toString()); 83 } 84 85 @Test public void toStringOnLargeBufferIncludesMd5() throws Exception { 86 Buffer buffer = new Buffer(); 87 buffer.write(ByteString.encodeUtf8("12345678901234567")); 88 assertEquals("Buffer[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", buffer.toString()); 89 } 90 91 @Test public void toStringOnMultipleSegmentBuffer() throws Exception { 92 Buffer buffer = new Buffer(); 93 buffer.writeUtf8(repeat('a', 6144)); 94 assertEquals("Buffer[size=6144 md5=d890021f28522533c1cc1b9b1f83ce73]", buffer.toString()); 95 } 96 97 @Test public void multipleSegmentBuffers() throws Exception { 98 Buffer buffer = new Buffer(); 99 buffer.writeUtf8(repeat('a', 1000)); 100 buffer.writeUtf8(repeat('b', 2500)); 101 buffer.writeUtf8(repeat('c', 5000)); 102 buffer.writeUtf8(repeat('d', 10000)); 103 buffer.writeUtf8(repeat('e', 25000)); 104 buffer.writeUtf8(repeat('f', 50000)); 105 106 assertEquals(repeat('a', 999), buffer.readUtf8(999)); // a...a 107 assertEquals("a" + repeat('b', 2500) + "c", buffer.readUtf8(2502)); // ab...bc 108 assertEquals(repeat('c', 4998), buffer.readUtf8(4998)); // c...c 109 assertEquals("c" + repeat('d', 10000) + "e", buffer.readUtf8(10002)); // cd...de 110 assertEquals(repeat('e', 24998), buffer.readUtf8(24998)); // e...e 111 assertEquals("e" + repeat('f', 50000), buffer.readUtf8(50001)); // ef...f 112 assertEquals(0, buffer.size()); 113 } 114 115 @Test public void fillAndDrainPool() throws Exception { 116 Buffer buffer = new Buffer(); 117 118 // Take 2 * MAX_SIZE segments. This will drain the pool, even if other tests filled it. 119 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 120 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 121 assertEquals(0, SegmentPool.byteCount); 122 123 // Recycle MAX_SIZE segments. They're all in the pool. 124 buffer.readByteString(SegmentPool.MAX_SIZE); 125 assertEquals(SegmentPool.MAX_SIZE, SegmentPool.byteCount); 126 127 // Recycle MAX_SIZE more segments. The pool is full so they get garbage collected. 128 buffer.readByteString(SegmentPool.MAX_SIZE); 129 assertEquals(SegmentPool.MAX_SIZE, SegmentPool.byteCount); 130 131 // Take MAX_SIZE segments to drain the pool. 132 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 133 assertEquals(0, SegmentPool.byteCount); 134 135 // Take MAX_SIZE more segments. The pool is drained so these will need to be allocated. 136 buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); 137 assertEquals(0, SegmentPool.byteCount); 138 } 139 140 @Test public void moveBytesBetweenBuffersShareSegment() throws Exception { 141 int size = (Segment.SIZE / 2) - 1; 142 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 143 assertEquals(asList(size * 2), segmentSizes); 144 } 145 146 @Test public void moveBytesBetweenBuffersReassignSegment() throws Exception { 147 int size = (Segment.SIZE / 2) + 1; 148 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 149 assertEquals(asList(size, size), segmentSizes); 150 } 151 152 @Test public void moveBytesBetweenBuffersMultipleSegments() throws Exception { 153 int size = 3 * Segment.SIZE + 1; 154 List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size)); 155 assertEquals(asList(Segment.SIZE, Segment.SIZE, Segment.SIZE, 1, 156 Segment.SIZE, Segment.SIZE, Segment.SIZE, 1), segmentSizes); 157 } 158 159 private List<Integer> moveBytesBetweenBuffers(String... contents) throws IOException { 160 StringBuilder expected = new StringBuilder(); 161 Buffer buffer = new Buffer(); 162 for (String s : contents) { 163 Buffer source = new Buffer(); 164 source.writeUtf8(s); 165 buffer.writeAll(source); 166 expected.append(s); 167 } 168 List<Integer> segmentSizes = buffer.segmentSizes(); 169 assertEquals(expected.toString(), buffer.readUtf8(expected.length())); 170 return segmentSizes; 171 } 172 173 /** The big part of source's first segment is being moved. */ 174 @Test public void writeSplitSourceBufferLeft() throws Exception { 175 int writeSize = Segment.SIZE / 2 + 1; 176 177 Buffer sink = new Buffer(); 178 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); 179 180 Buffer source = new Buffer(); 181 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 182 sink.write(source, writeSize); 183 184 assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes()); 185 assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes()); 186 } 187 188 /** The big part of source's first segment is staying put. */ 189 @Test public void writeSplitSourceBufferRight() throws Exception { 190 int writeSize = Segment.SIZE / 2 - 1; 191 192 Buffer sink = new Buffer(); 193 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); 194 195 Buffer source = new Buffer(); 196 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 197 sink.write(source, writeSize); 198 199 assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes()); 200 assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes()); 201 } 202 203 @Test public void writePrefixDoesntSplit() throws Exception { 204 Buffer sink = new Buffer(); 205 sink.writeUtf8(repeat('b', 10)); 206 207 Buffer source = new Buffer(); 208 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 209 sink.write(source, 20); 210 211 assertEquals(asList(30), sink.segmentSizes()); 212 assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); 213 assertEquals(30, sink.size()); 214 assertEquals(Segment.SIZE * 2 - 20, source.size()); 215 } 216 217 @Test public void writePrefixDoesntSplitButRequiresCompact() throws Exception { 218 Buffer sink = new Buffer(); 219 sink.writeUtf8(repeat('b', Segment.SIZE - 10)); // limit = size - 10 220 sink.readUtf8(Segment.SIZE - 20); // pos = size = 20 221 222 Buffer source = new Buffer(); 223 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 224 sink.write(source, 20); 225 226 assertEquals(asList(30), sink.segmentSizes()); 227 assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); 228 assertEquals(30, sink.size()); 229 assertEquals(Segment.SIZE * 2 - 20, source.size()); 230 } 231 232 @Test public void copyToSpanningSegments() throws Exception { 233 Buffer source = new Buffer(); 234 source.writeUtf8(repeat('a', Segment.SIZE * 2)); 235 source.writeUtf8(repeat('b', Segment.SIZE * 2)); 236 237 ByteArrayOutputStream out = new ByteArrayOutputStream(); 238 source.copyTo(out, 10, Segment.SIZE * 3); 239 240 assertEquals(repeat('a', Segment.SIZE * 2 - 10) + repeat('b', Segment.SIZE + 10), 241 out.toString()); 242 assertEquals(repeat('a', Segment.SIZE * 2) + repeat('b', Segment.SIZE * 2), 243 source.readUtf8(Segment.SIZE * 4)); 244 } 245 246 @Test public void copyToStream() throws Exception { 247 Buffer buffer = new Buffer().writeUtf8("hello, world!"); 248 ByteArrayOutputStream out = new ByteArrayOutputStream(); 249 buffer.copyTo(out); 250 String outString = new String(out.toByteArray(), UTF_8); 251 assertEquals("hello, world!", outString); 252 assertEquals("hello, world!", buffer.readUtf8()); 253 } 254 255 @Test public void writeToSpanningSegments() throws Exception { 256 Buffer buffer = new Buffer(); 257 buffer.writeUtf8(repeat('a', Segment.SIZE * 2)); 258 buffer.writeUtf8(repeat('b', Segment.SIZE * 2)); 259 260 ByteArrayOutputStream out = new ByteArrayOutputStream(); 261 buffer.skip(10); 262 buffer.writeTo(out, Segment.SIZE * 3); 263 264 assertEquals(repeat('a', Segment.SIZE * 2 - 10) + repeat('b', Segment.SIZE + 10), 265 out.toString()); 266 assertEquals(repeat('b', Segment.SIZE - 10), buffer.readUtf8(buffer.size)); 267 } 268 269 @Test public void writeToStream() throws Exception { 270 Buffer buffer = new Buffer().writeUtf8("hello, world!"); 271 ByteArrayOutputStream out = new ByteArrayOutputStream(); 272 buffer.writeTo(out); 273 String outString = new String(out.toByteArray(), UTF_8); 274 assertEquals("hello, world!", outString); 275 assertEquals(0, buffer.size()); 276 } 277 278 @Test public void readFromStream() throws Exception { 279 InputStream in = new ByteArrayInputStream("hello, world!".getBytes(UTF_8)); 280 Buffer buffer = new Buffer(); 281 buffer.readFrom(in); 282 String out = buffer.readUtf8(); 283 assertEquals("hello, world!", out); 284 } 285 286 @Test public void readFromSpanningSegments() throws Exception { 287 InputStream in = new ByteArrayInputStream("hello, world!".getBytes(UTF_8)); 288 Buffer buffer = new Buffer().writeUtf8(repeat('a', Segment.SIZE - 10)); 289 buffer.readFrom(in); 290 String out = buffer.readUtf8(); 291 assertEquals(repeat('a', Segment.SIZE - 10) + "hello, world!", out); 292 } 293 294 @Test public void readFromStreamWithCount() throws Exception { 295 InputStream in = new ByteArrayInputStream("hello, world!".getBytes(UTF_8)); 296 Buffer buffer = new Buffer(); 297 buffer.readFrom(in, 10); 298 String out = buffer.readUtf8(); 299 assertEquals("hello, wor", out); 300 } 301 302 @Test public void moveAllRequestedBytesWithRead() throws Exception { 303 Buffer sink = new Buffer(); 304 sink.writeUtf8(repeat('a', 10)); 305 306 Buffer source = new Buffer(); 307 source.writeUtf8(repeat('b', 15)); 308 309 assertEquals(10, source.read(sink, 10)); 310 assertEquals(20, sink.size()); 311 assertEquals(5, source.size()); 312 assertEquals(repeat('a', 10) + repeat('b', 10), sink.readUtf8(20)); 313 } 314 315 @Test public void moveFewerThanRequestedBytesWithRead() throws Exception { 316 Buffer sink = new Buffer(); 317 sink.writeUtf8(repeat('a', 10)); 318 319 Buffer source = new Buffer(); 320 source.writeUtf8(repeat('b', 20)); 321 322 assertEquals(20, source.read(sink, 25)); 323 assertEquals(30, sink.size()); 324 assertEquals(0, source.size()); 325 assertEquals(repeat('a', 10) + repeat('b', 20), sink.readUtf8(30)); 326 } 327 328 @Test public void indexOfWithOffset() throws Exception { 329 Buffer buffer = new Buffer(); 330 int halfSegment = Segment.SIZE / 2; 331 buffer.writeUtf8(repeat('a', halfSegment)); 332 buffer.writeUtf8(repeat('b', halfSegment)); 333 buffer.writeUtf8(repeat('c', halfSegment)); 334 buffer.writeUtf8(repeat('d', halfSegment)); 335 assertEquals(0, buffer.indexOf((byte) 'a', 0)); 336 assertEquals(halfSegment - 1, buffer.indexOf((byte) 'a', halfSegment - 1)); 337 assertEquals(halfSegment, buffer.indexOf((byte) 'b', halfSegment - 1)); 338 assertEquals(halfSegment * 2, buffer.indexOf((byte) 'c', halfSegment - 1)); 339 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment - 1)); 340 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 2)); 341 assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 3)); 342 assertEquals(halfSegment * 4 - 1, buffer.indexOf((byte) 'd', halfSegment * 4 - 1)); 343 } 344 345 @Test public void byteAt() throws Exception { 346 Buffer buffer = new Buffer(); 347 buffer.writeUtf8("a"); 348 buffer.writeUtf8(repeat('b', Segment.SIZE)); 349 buffer.writeUtf8("c"); 350 assertEquals('a', buffer.getByte(0)); 351 assertEquals('a', buffer.getByte(0)); // getByte doesn't mutate! 352 assertEquals('c', buffer.getByte(buffer.size - 1)); 353 assertEquals('b', buffer.getByte(buffer.size - 2)); 354 assertEquals('b', buffer.getByte(buffer.size - 3)); 355 } 356 357 @Test public void getByteOfEmptyBuffer() throws Exception { 358 Buffer buffer = new Buffer(); 359 try { 360 buffer.getByte(0); 361 fail(); 362 } catch (IndexOutOfBoundsException expected) { 363 } 364 } 365 366 @Test public void writePrefixToEmptyBuffer() throws IOException { 367 Buffer sink = new Buffer(); 368 Buffer source = new Buffer(); 369 source.writeUtf8("abcd"); 370 sink.write(source, 2); 371 assertEquals("ab", sink.readUtf8(2)); 372 } 373 374 @Test public void cloneDoesNotObserveWritesToOriginal() throws Exception { 375 Buffer original = new Buffer(); 376 Buffer clone = original.clone(); 377 original.writeUtf8("abc"); 378 assertEquals(0, clone.size()); 379 } 380 381 @Test public void cloneDoesNotObserveReadsFromOriginal() throws Exception { 382 Buffer original = new Buffer(); 383 original.writeUtf8("abc"); 384 Buffer clone = original.clone(); 385 assertEquals("abc", original.readUtf8(3)); 386 assertEquals(3, clone.size()); 387 assertEquals("ab", clone.readUtf8(2)); 388 } 389 390 @Test public void originalDoesNotObserveWritesToClone() throws Exception { 391 Buffer original = new Buffer(); 392 Buffer clone = original.clone(); 393 clone.writeUtf8("abc"); 394 assertEquals(0, original.size()); 395 } 396 397 @Test public void originalDoesNotObserveReadsFromClone() throws Exception { 398 Buffer original = new Buffer(); 399 original.writeUtf8("abc"); 400 Buffer clone = original.clone(); 401 assertEquals("abc", clone.readUtf8(3)); 402 assertEquals(3, original.size()); 403 assertEquals("ab", original.readUtf8(2)); 404 } 405 406 @Test public void cloneMultipleSegments() throws Exception { 407 Buffer original = new Buffer(); 408 original.writeUtf8(repeat('a', Segment.SIZE * 3)); 409 Buffer clone = original.clone(); 410 original.writeUtf8(repeat('b', Segment.SIZE * 3)); 411 clone.writeUtf8(repeat('c', Segment.SIZE * 3)); 412 413 assertEquals(repeat('a', Segment.SIZE * 3) + repeat('b', Segment.SIZE * 3), 414 original.readUtf8(Segment.SIZE * 6)); 415 assertEquals(repeat('a', Segment.SIZE * 3) + repeat('c', Segment.SIZE * 3), 416 clone.readUtf8(Segment.SIZE * 6)); 417 } 418 419 @Test public void equalsAndHashCodeEmpty() throws Exception { 420 Buffer a = new Buffer(); 421 Buffer b = new Buffer(); 422 assertTrue(a.equals(b)); 423 assertTrue(a.hashCode() == b.hashCode()); 424 } 425 426 @Test public void equalsAndHashCode() throws Exception { 427 Buffer a = new Buffer().writeUtf8("dog"); 428 Buffer b = new Buffer().writeUtf8("hotdog"); 429 assertFalse(a.equals(b)); 430 assertFalse(a.hashCode() == b.hashCode()); 431 432 b.readUtf8(3); // Leaves b containing 'dog'. 433 assertTrue(a.equals(b)); 434 assertTrue(a.hashCode() == b.hashCode()); 435 } 436 437 @Test public void equalsAndHashCodeSpanningSegments() throws Exception { 438 byte[] data = new byte[1024 * 1024]; 439 Random dice = new Random(0); 440 dice.nextBytes(data); 441 442 Buffer a = bufferWithRandomSegmentLayout(dice, data); 443 Buffer b = bufferWithRandomSegmentLayout(dice, data); 444 assertTrue(a.equals(b)); 445 assertTrue(a.hashCode() == b.hashCode()); 446 447 data[data.length / 2]++; // Change a single byte. 448 Buffer c = bufferWithRandomSegmentLayout(dice, data); 449 assertFalse(a.equals(c)); 450 assertFalse(a.hashCode() == c.hashCode()); 451 } 452 453 @Test public void bufferInputStreamByteByByte() throws Exception { 454 Buffer source = new Buffer(); 455 source.writeUtf8("abc"); 456 457 InputStream in = source.inputStream(); 458 assertEquals(3, in.available()); 459 assertEquals('a', in.read()); 460 assertEquals('b', in.read()); 461 assertEquals('c', in.read()); 462 assertEquals(-1, in.read()); 463 assertEquals(0, in.available()); 464 } 465 466 @Test public void bufferInputStreamBulkReads() throws Exception { 467 Buffer source = new Buffer(); 468 source.writeUtf8("abc"); 469 470 byte[] byteArray = new byte[4]; 471 472 Arrays.fill(byteArray, (byte) -5); 473 InputStream in = source.inputStream(); 474 assertEquals(3, in.read(byteArray)); 475 assertEquals("[97, 98, 99, -5]", Arrays.toString(byteArray)); 476 477 Arrays.fill(byteArray, (byte) -7); 478 assertEquals(-1, in.read(byteArray)); 479 assertEquals("[-7, -7, -7, -7]", Arrays.toString(byteArray)); 480 } 481 482 /** 483 * When writing data that's already buffered, there's no reason to page the 484 * data by segment. 485 */ 486 @Test public void readAllWritesAllSegmentsAtOnce() throws Exception { 487 Buffer write1 = new Buffer().writeUtf8("" 488 + TestUtil.repeat('a', Segment.SIZE) 489 + TestUtil.repeat('b', Segment.SIZE) 490 + TestUtil.repeat('c', Segment.SIZE)); 491 492 Buffer source = new Buffer().writeUtf8("" 493 + TestUtil.repeat('a', Segment.SIZE) 494 + TestUtil.repeat('b', Segment.SIZE) 495 + TestUtil.repeat('c', Segment.SIZE)); 496 497 MockSink mockSink = new MockSink(); 498 499 assertEquals(Segment.SIZE * 3, source.readAll(mockSink)); 500 assertEquals(0, source.size()); 501 mockSink.assertLog("write(" + write1 + ", " + write1.size() + ")"); 502 } 503 504 @Test public void writeAllMultipleSegments() throws Exception { 505 Buffer source = new Buffer().writeUtf8(TestUtil.repeat('a', Segment.SIZE * 3)); 506 Buffer sink = new Buffer(); 507 508 assertEquals(Segment.SIZE * 3, sink.writeAll(source)); 509 assertEquals(0, source.size()); 510 assertEquals(TestUtil.repeat('a', Segment.SIZE * 3), sink.readUtf8()); 511 } 512 513 @Test public void copyTo() throws Exception { 514 Buffer source = new Buffer(); 515 source.writeUtf8("party"); 516 517 Buffer target = new Buffer(); 518 source.copyTo(target, 1, 3); 519 520 assertEquals("art", target.readUtf8()); 521 assertEquals("party", source.readUtf8()); 522 } 523 524 @Test public void copyToOnSegmentBoundary() throws Exception { 525 String as = repeat('a', Segment.SIZE); 526 String bs = repeat('b', Segment.SIZE); 527 String cs = repeat('c', Segment.SIZE); 528 String ds = repeat('d', Segment.SIZE); 529 530 Buffer source = new Buffer(); 531 source.writeUtf8(as); 532 source.writeUtf8(bs); 533 source.writeUtf8(cs); 534 535 Buffer target = new Buffer(); 536 target.writeUtf8(ds); 537 538 source.copyTo(target, as.length(), bs.length() + cs.length()); 539 assertEquals(ds + bs + cs, target.readUtf8()); 540 } 541 542 @Test public void copyToOffSegmentBoundary() throws Exception { 543 String as = repeat('a', Segment.SIZE - 1); 544 String bs = repeat('b', Segment.SIZE + 2); 545 String cs = repeat('c', Segment.SIZE - 4); 546 String ds = repeat('d', Segment.SIZE + 8); 547 548 Buffer source = new Buffer(); 549 source.writeUtf8(as); 550 source.writeUtf8(bs); 551 source.writeUtf8(cs); 552 553 Buffer target = new Buffer(); 554 target.writeUtf8(ds); 555 556 source.copyTo(target, as.length(), bs.length() + cs.length()); 557 assertEquals(ds + bs + cs, target.readUtf8()); 558 } 559 560 @Test public void copyToSourceAndTargetCanBeTheSame() throws Exception { 561 String as = repeat('a', Segment.SIZE); 562 String bs = repeat('b', Segment.SIZE); 563 564 Buffer source = new Buffer(); 565 source.writeUtf8(as); 566 source.writeUtf8(bs); 567 568 source.copyTo(source, 0, source.size()); 569 assertEquals(as + bs + as + bs, source.readUtf8()); 570 } 571 572 @Test public void copyToEmptySource() throws Exception { 573 Buffer source = new Buffer(); 574 Buffer target = new Buffer().writeUtf8("aaa"); 575 source.copyTo(target, 0L, 0L); 576 assertEquals("", source.readUtf8()); 577 assertEquals("aaa", target.readUtf8()); 578 } 579 580 @Test public void copyToEmptyTarget() throws Exception { 581 Buffer source = new Buffer().writeUtf8("aaa"); 582 Buffer target = new Buffer(); 583 source.copyTo(target, 0L, 3L); 584 assertEquals("aaa", source.readUtf8()); 585 assertEquals("aaa", target.readUtf8()); 586 } 587 588 /** 589 * Returns a new buffer containing the data in {@code data}, and a segment 590 * layout determined by {@code dice}. 591 */ 592 private Buffer bufferWithRandomSegmentLayout(Random dice, byte[] data) throws IOException { 593 Buffer result = new Buffer(); 594 595 // Writing to result directly will yield packed segments. Instead, write to 596 // other buffers, then write those buffers to result. 597 for (int pos = 0, byteCount; pos < data.length; pos += byteCount) { 598 byteCount = (Segment.SIZE / 2) + dice.nextInt(Segment.SIZE / 2); 599 if (byteCount > data.length - pos) byteCount = data.length - pos; 600 int offset = dice.nextInt(Segment.SIZE - byteCount); 601 602 Buffer segment = new Buffer(); 603 segment.write(new byte[offset]); 604 segment.write(data, pos, byteCount); 605 segment.skip(offset); 606 607 result.write(segment, byteCount); 608 } 609 610 return result; 611 } 612} 613