1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.Internal.UTF_8; 34 35 import java.io.ByteArrayInputStream; 36 import java.io.ByteArrayOutputStream; 37 import java.io.EOFException; 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.io.ObjectInputStream; 41 import java.io.ObjectOutputStream; 42 import java.io.OutputStream; 43 import java.io.UnsupportedEncodingException; 44 import java.nio.BufferOverflowException; 45 import java.nio.ByteBuffer; 46 import java.util.Arrays; 47 import java.util.List; 48 import java.util.NoSuchElementException; 49 import junit.framework.TestCase; 50 51 /** Tests for {@link NioByteString}. */ 52 public class NioByteStringTest extends TestCase { 53 private static final ByteString EMPTY = new NioByteString(ByteBuffer.wrap(new byte[0])); 54 private static final String CLASSNAME = NioByteString.class.getSimpleName(); 55 private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L); 56 private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode(); 57 58 private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone()); 59 private final ByteString testString = new NioByteString(backingBuffer); 60 testExpectedType()61 public void testExpectedType() { 62 String actualClassName = getActualClassName(testString); 63 assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName); 64 } 65 getActualClassName(Object object)66 protected String getActualClassName(Object object) { 67 String actualClassName = object.getClass().getName(); 68 actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1); 69 return actualClassName; 70 } 71 testByteAt()72 public void testByteAt() { 73 boolean stillEqual = true; 74 for (int i = 0; stillEqual && i < BYTES.length; ++i) { 75 stillEqual = (BYTES[i] == testString.byteAt(i)); 76 } 77 assertTrue(CLASSNAME + " must capture the right bytes", stillEqual); 78 } 79 testByteIterator()80 public void testByteIterator() { 81 boolean stillEqual = true; 82 ByteString.ByteIterator iter = testString.iterator(); 83 for (int i = 0; stillEqual && i < BYTES.length; ++i) { 84 stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte()); 85 } 86 assertTrue(CLASSNAME + " must capture the right bytes", stillEqual); 87 assertFalse(CLASSNAME + " must have exhausted the iterator", iter.hasNext()); 88 89 try { 90 iter.nextByte(); 91 fail("Should have thrown an exception."); 92 } catch (NoSuchElementException e) { 93 // This is success 94 } 95 } 96 testByteIterable()97 public void testByteIterable() { 98 boolean stillEqual = true; 99 int j = 0; 100 for (byte quantum : testString) { 101 stillEqual = (BYTES[j] == quantum); 102 ++j; 103 } 104 assertTrue(CLASSNAME + " must capture the right bytes as Bytes", stillEqual); 105 assertEquals(CLASSNAME + " iterable character count", BYTES.length, j); 106 } 107 testSize()108 public void testSize() { 109 assertEquals(CLASSNAME + " must have the expected size", BYTES.length, testString.size()); 110 } 111 testGetTreeDepth()112 public void testGetTreeDepth() { 113 assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth()); 114 } 115 testIsBalanced()116 public void testIsBalanced() { 117 assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced()); 118 } 119 testCopyTo_ByteArrayOffsetLength()120 public void testCopyTo_ByteArrayOffsetLength() { 121 int destinationOffset = 50; 122 int length = 100; 123 byte[] destination = new byte[destinationOffset + length]; 124 int sourceOffset = 213; 125 testString.copyTo(destination, sourceOffset, destinationOffset, length); 126 boolean stillEqual = true; 127 for (int i = 0; stillEqual && i < length; ++i) { 128 stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset]; 129 } 130 assertTrue(CLASSNAME + ".copyTo(4 arg) must give the expected bytes", stillEqual); 131 } 132 testCopyTo_ByteArrayOffsetLengthErrors()133 public void testCopyTo_ByteArrayOffsetLengthErrors() { 134 int destinationOffset = 50; 135 int length = 100; 136 byte[] destination = new byte[destinationOffset + length]; 137 138 try { 139 // Copy one too many bytes 140 testString.copyTo(destination, testString.size() + 1 - length, destinationOffset, length); 141 fail("Should have thrown an exception when copying too many bytes of a " + CLASSNAME); 142 } catch (IndexOutOfBoundsException expected) { 143 // This is success 144 } 145 146 try { 147 // Copy with illegal negative sourceOffset 148 testString.copyTo(destination, -1, destinationOffset, length); 149 fail("Should have thrown an exception when given a negative sourceOffset in " + CLASSNAME); 150 } catch (IndexOutOfBoundsException expected) { 151 // This is success 152 } 153 154 try { 155 // Copy with illegal negative destinationOffset 156 testString.copyTo(destination, 0, -1, length); 157 fail( 158 "Should have thrown an exception when given a negative destinationOffset in " 159 + CLASSNAME); 160 } catch (IndexOutOfBoundsException expected) { 161 // This is success 162 } 163 164 try { 165 // Copy with illegal negative size 166 testString.copyTo(destination, 0, 0, -1); 167 fail("Should have thrown an exception when given a negative size in " + CLASSNAME); 168 } catch (IndexOutOfBoundsException expected) { 169 // This is success 170 } 171 172 try { 173 // Copy with illegal too-large sourceOffset 174 testString.copyTo(destination, 2 * testString.size(), 0, length); 175 fail( 176 "Should have thrown an exception when the destinationOffset is too large in " 177 + CLASSNAME); 178 } catch (IndexOutOfBoundsException expected) { 179 // This is success 180 } 181 182 try { 183 // Copy with illegal too-large destinationOffset 184 testString.copyTo(destination, 0, 2 * destination.length, length); 185 fail( 186 "Should have thrown an exception when the destinationOffset is too large in " 187 + CLASSNAME); 188 } catch (IndexOutOfBoundsException expected) { 189 // This is success 190 } 191 } 192 testCopyTo_ByteBuffer()193 public void testCopyTo_ByteBuffer() { 194 // Same length. 195 ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length); 196 testString.copyTo(myBuffer); 197 myBuffer.flip(); 198 assertEquals( 199 CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes", backingBuffer, myBuffer); 200 201 // Target buffer bigger than required. 202 myBuffer = ByteBuffer.allocate(testString.size() + 1); 203 testString.copyTo(myBuffer); 204 myBuffer.flip(); 205 assertEquals(backingBuffer, myBuffer); 206 207 // Target buffer has no space. 208 myBuffer = ByteBuffer.allocate(0); 209 try { 210 testString.copyTo(myBuffer); 211 fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); 212 } catch (BufferOverflowException e) { 213 // Expected. 214 } 215 216 // Target buffer too small. 217 myBuffer = ByteBuffer.allocate(1); 218 try { 219 testString.copyTo(myBuffer); 220 fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); 221 } catch (BufferOverflowException e) { 222 // Expected. 223 } 224 } 225 testMarkSupported()226 public void testMarkSupported() { 227 InputStream stream = testString.newInput(); 228 assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported()); 229 } 230 testMarkAndReset()231 public void testMarkAndReset() throws IOException { 232 int fraction = testString.size() / 3; 233 234 InputStream stream = testString.newInput(); 235 stream.mark(testString.size()); // First, mark() the end. 236 237 skipFully(stream, fraction); // Skip a large fraction, but not all. 238 assertEquals( 239 CLASSNAME + ": after skipping to the 'middle', half the bytes are available", 240 (testString.size() - fraction), 241 stream.available()); 242 stream.reset(); 243 assertEquals( 244 CLASSNAME + ": after resetting, all bytes are available", 245 testString.size(), 246 stream.available()); 247 248 skipFully(stream, testString.size()); // Skip to the end. 249 assertEquals( 250 CLASSNAME + ": after skipping to the end, no more bytes are available", 251 0, 252 stream.available()); 253 } 254 255 /** 256 * Discards {@code n} bytes of data from the input stream. This method will block until the full 257 * amount has been skipped. Does not close the stream. 258 * 259 * <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency. 260 * 261 * @param in the input stream to read from 262 * @param n the number of bytes to skip 263 * @throws EOFException if this stream reaches the end before skipping all the bytes 264 * @throws IOException if an I/O error occurs, or the stream does not support skipping 265 */ skipFully(InputStream in, long n)266 static void skipFully(InputStream in, long n) throws IOException { 267 long toSkip = n; 268 while (n > 0) { 269 long amt = in.skip(n); 270 if (amt == 0) { 271 // Force a blocking read to avoid infinite loop 272 if (in.read() == -1) { 273 long skipped = toSkip - n; 274 throw new EOFException( 275 "reached end of stream after skipping " 276 + skipped 277 + " bytes; " 278 + toSkip 279 + " bytes expected"); 280 } 281 n--; 282 } else { 283 n -= amt; 284 } 285 } 286 } 287 testAsReadOnlyByteBuffer()288 public void testAsReadOnlyByteBuffer() { 289 ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer(); 290 byte[] roundTripBytes = new byte[BYTES.length]; 291 assertTrue(byteBuffer.remaining() == BYTES.length); 292 assertTrue(byteBuffer.isReadOnly()); 293 byteBuffer.get(roundTripBytes); 294 assertTrue( 295 CLASSNAME + ".asReadOnlyByteBuffer() must give back the same bytes", 296 Arrays.equals(BYTES, roundTripBytes)); 297 } 298 testAsReadOnlyByteBufferList()299 public void testAsReadOnlyByteBufferList() { 300 List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList(); 301 int bytesSeen = 0; 302 byte[] roundTripBytes = new byte[BYTES.length]; 303 for (ByteBuffer byteBuffer : byteBuffers) { 304 int thisLength = byteBuffer.remaining(); 305 assertTrue(byteBuffer.isReadOnly()); 306 assertTrue(bytesSeen + thisLength <= BYTES.length); 307 byteBuffer.get(roundTripBytes, bytesSeen, thisLength); 308 bytesSeen += thisLength; 309 } 310 assertTrue(bytesSeen == BYTES.length); 311 assertTrue( 312 CLASSNAME + ".asReadOnlyByteBufferTest() must give back the same bytes", 313 Arrays.equals(BYTES, roundTripBytes)); 314 } 315 testToByteArray()316 public void testToByteArray() { 317 byte[] roundTripBytes = testString.toByteArray(); 318 assertTrue( 319 CLASSNAME + ".toByteArray() must give back the same bytes", 320 Arrays.equals(BYTES, roundTripBytes)); 321 } 322 testWriteTo()323 public void testWriteTo() throws IOException { 324 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 325 testString.writeTo(bos); 326 byte[] roundTripBytes = bos.toByteArray(); 327 assertTrue( 328 CLASSNAME + ".writeTo() must give back the same bytes", 329 Arrays.equals(BYTES, roundTripBytes)); 330 } 331 testWriteToShouldNotExposeInternalBufferToOutputStream()332 public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException { 333 OutputStream os = 334 new OutputStream() { 335 @Override 336 public void write(byte[] b, int off, int len) { 337 Arrays.fill(b, off, off + len, (byte) 0); 338 } 339 340 @Override 341 public void write(int b) { 342 throw new UnsupportedOperationException(); 343 } 344 }; 345 346 byte[] original = Arrays.copyOf(BYTES, BYTES.length); 347 testString.writeTo(os); 348 assertTrue( 349 CLASSNAME + ".writeTo() must NOT grant access to underlying buffer", 350 Arrays.equals(original, BYTES)); 351 } 352 testWriteToInternalShouldExposeInternalBufferToOutputStream()353 public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException { 354 OutputStream os = 355 new OutputStream() { 356 @Override 357 public void write(byte[] b, int off, int len) { 358 Arrays.fill(b, off, off + len, (byte) 0); 359 } 360 361 @Override 362 public void write(int b) { 363 throw new UnsupportedOperationException(); 364 } 365 }; 366 367 testString.writeToInternal(os, 0, testString.size()); 368 byte[] allZeros = new byte[testString.size()]; 369 assertTrue( 370 CLASSNAME + ".writeToInternal() must grant access to underlying buffer", 371 Arrays.equals(allZeros, backingBuffer.array())); 372 } 373 testWriteToShouldExposeInternalBufferToByteOutput()374 public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException { 375 ByteOutput out = 376 new ByteOutput() { 377 @Override 378 public void write(byte value) throws IOException { 379 throw new UnsupportedOperationException(); 380 } 381 382 @Override 383 public void write(byte[] value, int offset, int length) throws IOException { 384 throw new UnsupportedOperationException(); 385 } 386 387 @Override 388 public void write(ByteBuffer value) throws IOException { 389 throw new UnsupportedOperationException(); 390 } 391 392 @Override 393 public void writeLazy(byte[] value, int offset, int length) throws IOException { 394 throw new UnsupportedOperationException(); 395 } 396 397 @Override 398 public void writeLazy(ByteBuffer value) throws IOException { 399 Arrays.fill( 400 value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(), (byte) 0); 401 } 402 }; 403 404 testString.writeTo(out); 405 byte[] allZeros = new byte[testString.size()]; 406 assertTrue( 407 CLASSNAME + ".writeTo() must grant access to underlying buffer", 408 Arrays.equals(allZeros, backingBuffer.array())); 409 } 410 testNewOutput()411 public void testNewOutput() throws IOException { 412 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 413 ByteString.Output output = ByteString.newOutput(); 414 testString.writeTo(output); 415 assertEquals("Output Size returns correct result", output.size(), testString.size()); 416 output.writeTo(bos); 417 assertTrue( 418 "Output.writeTo() must give back the same bytes", Arrays.equals(BYTES, bos.toByteArray())); 419 420 // write the output stream to itself! This should cause it to double 421 output.writeTo(output); 422 assertEquals( 423 "Writing an output stream to itself is successful", 424 testString.concat(testString), 425 output.toByteString()); 426 427 output.reset(); 428 assertEquals("Output.reset() resets the output", 0, output.size()); 429 assertEquals("Output.reset() resets the output", EMPTY, output.toByteString()); 430 } 431 testToString()432 public void testToString() { 433 String testString = "I love unicode \u1234\u5678 characters"; 434 ByteString unicode = forString(testString); 435 String roundTripString = unicode.toString(UTF_8); 436 assertEquals(CLASSNAME + " unicode must match", testString, roundTripString); 437 } 438 testCharsetToString()439 public void testCharsetToString() { 440 String testString = "I love unicode \u1234\u5678 characters"; 441 ByteString unicode = forString(testString); 442 String roundTripString = unicode.toString(UTF_8); 443 assertEquals(CLASSNAME + " unicode must match", testString, roundTripString); 444 } 445 testToString_returnsCanonicalEmptyString()446 public void testToString_returnsCanonicalEmptyString() { 447 assertSame( 448 CLASSNAME + " must be the same string references", 449 EMPTY.toString(UTF_8), 450 new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8)); 451 } 452 testToString_raisesException()453 public void testToString_raisesException() { 454 try { 455 EMPTY.toString("invalid"); 456 fail("Should have thrown an exception."); 457 } catch (UnsupportedEncodingException expected) { 458 // This is success 459 } 460 461 try { 462 testString.toString("invalid"); 463 fail("Should have thrown an exception."); 464 } catch (UnsupportedEncodingException expected) { 465 // This is success 466 } 467 } 468 testEquals()469 public void testEquals() { 470 assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null)); 471 assertEquals(CLASSNAME + " must equal self", testString, testString); 472 assertFalse(CLASSNAME + " must not equal the empty string", testString.equals(EMPTY)); 473 assertEquals(CLASSNAME + " empty strings must be equal", EMPTY, testString.substring(55, 55)); 474 assertEquals( 475 CLASSNAME + " must equal another string with the same value", 476 testString, 477 new NioByteString(backingBuffer)); 478 479 byte[] mungedBytes = mungedBytes(); 480 assertFalse( 481 CLASSNAME + " must not equal every string with the same length", 482 testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes)))); 483 } 484 testEqualsLiteralByteString()485 public void testEqualsLiteralByteString() { 486 ByteString literal = ByteString.copyFrom(BYTES); 487 assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal, testString); 488 assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString, literal); 489 assertFalse( 490 CLASSNAME + " must not equal the empty string", testString.equals(ByteString.EMPTY)); 491 assertEquals( 492 CLASSNAME + " empty strings must be equal", ByteString.EMPTY, testString.substring(55, 55)); 493 494 literal = ByteString.copyFrom(mungedBytes()); 495 assertFalse( 496 CLASSNAME + " must not equal every LiteralByteString with the same length", 497 testString.equals(literal)); 498 assertFalse( 499 CLASSNAME + " must not equal every LiteralByteString with the same length", 500 literal.equals(testString)); 501 } 502 testEqualsRopeByteString()503 public void testEqualsRopeByteString() { 504 ByteString p1 = ByteString.copyFrom(BYTES, 0, 5); 505 ByteString p2 = ByteString.copyFrom(BYTES, 5, BYTES.length - 5); 506 ByteString rope = p1.concat(p2); 507 508 assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope, testString); 509 assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString, rope); 510 assertFalse( 511 CLASSNAME + " must not equal the empty string", 512 testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY))); 513 assertEquals( 514 CLASSNAME + " empty strings must be equal", 515 ByteString.EMPTY.concat(ByteString.EMPTY), 516 testString.substring(55, 55)); 517 518 byte[] mungedBytes = mungedBytes(); 519 p1 = ByteString.copyFrom(mungedBytes, 0, 5); 520 p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5); 521 rope = p1.concat(p2); 522 assertFalse( 523 CLASSNAME + " must not equal every RopeByteString with the same length", 524 testString.equals(rope)); 525 assertFalse( 526 CLASSNAME + " must not equal every RopeByteString with the same length", 527 rope.equals(testString)); 528 } 529 mungedBytes()530 private byte[] mungedBytes() { 531 byte[] mungedBytes = new byte[BYTES.length]; 532 System.arraycopy(BYTES, 0, mungedBytes, 0, BYTES.length); 533 mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF); 534 return mungedBytes; 535 } 536 testHashCode()537 public void testHashCode() { 538 int hash = testString.hashCode(); 539 assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash); 540 } 541 testPeekCachedHashCode()542 public void testPeekCachedHashCode() { 543 ByteString newString = new NioByteString(backingBuffer); 544 assertEquals( 545 CLASSNAME + ".peekCachedHashCode() should return zero at first", 546 0, 547 newString.peekCachedHashCode()); 548 newString.hashCode(); 549 assertEquals( 550 CLASSNAME + ".peekCachedHashCode should return zero at first", 551 EXPECTED_HASH, 552 newString.peekCachedHashCode()); 553 } 554 testPartialHash()555 public void testPartialHash() { 556 // partialHash() is more strenuously tested elsewhere by testing hashes of substrings. 557 // This test would fail if the expected hash were 1. It's not. 558 int hash = testString.partialHash(testString.size(), 0, testString.size()); 559 assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode", EXPECTED_HASH, hash); 560 } 561 testNewInput()562 public void testNewInput() throws IOException { 563 InputStream input = testString.newInput(); 564 assertEquals( 565 "InputStream.available() returns correct value", testString.size(), input.available()); 566 boolean stillEqual = true; 567 for (byte referenceByte : BYTES) { 568 int expectedInt = (referenceByte & 0xFF); 569 stillEqual = (expectedInt == input.read()); 570 } 571 assertEquals("InputStream.available() returns correct value", 0, input.available()); 572 assertTrue(CLASSNAME + " must give the same bytes from the InputStream", stillEqual); 573 assertEquals(CLASSNAME + " InputStream must now be exhausted", -1, input.read()); 574 } 575 testNewInput_skip()576 public void testNewInput_skip() throws IOException { 577 InputStream input = testString.newInput(); 578 int stringSize = testString.size(); 579 int nearEndIndex = stringSize * 2 / 3; 580 long skipped1 = input.skip(nearEndIndex); 581 assertEquals("InputStream.skip()", skipped1, nearEndIndex); 582 assertEquals("InputStream.available()", stringSize - skipped1, input.available()); 583 assertTrue("InputStream.mark() is available", input.markSupported()); 584 input.mark(0); 585 assertEquals( 586 "InputStream.skip(), read()", testString.byteAt(nearEndIndex) & 0xFF, input.read()); 587 assertEquals("InputStream.available()", stringSize - skipped1 - 1, input.available()); 588 long skipped2 = input.skip(stringSize); 589 assertEquals("InputStream.skip() incomplete", skipped2, stringSize - skipped1 - 1); 590 assertEquals("InputStream.skip(), no more input", 0, input.available()); 591 assertEquals("InputStream.skip(), no more input", -1, input.read()); 592 input.reset(); 593 assertEquals("InputStream.reset() succeeded", stringSize - skipped1, input.available()); 594 assertEquals( 595 "InputStream.reset(), read()", testString.byteAt(nearEndIndex) & 0xFF, input.read()); 596 } 597 testNewCodedInput()598 public void testNewCodedInput() throws IOException { 599 CodedInputStream cis = testString.newCodedInput(); 600 byte[] roundTripBytes = cis.readRawBytes(BYTES.length); 601 assertTrue( 602 CLASSNAME + " must give the same bytes back from the CodedInputStream", 603 Arrays.equals(BYTES, roundTripBytes)); 604 assertTrue(CLASSNAME + " CodedInputStream must now be exhausted", cis.isAtEnd()); 605 } 606 607 /** 608 * Make sure we keep things simple when concatenating with empty. See also {@link 609 * ByteStringTest#testConcat_empty()}. 610 */ testConcat_empty()611 public void testConcat_empty() { 612 assertSame( 613 CLASSNAME + " concatenated with empty must give " + CLASSNAME, 614 testString.concat(EMPTY), 615 testString); 616 assertSame( 617 "empty concatenated with " + CLASSNAME + " must give " + CLASSNAME, 618 EMPTY.concat(testString), 619 testString); 620 } 621 testJavaSerialization()622 public void testJavaSerialization() throws Exception { 623 ByteArrayOutputStream out = new ByteArrayOutputStream(); 624 ObjectOutputStream oos = new ObjectOutputStream(out); 625 oos.writeObject(testString); 626 oos.close(); 627 byte[] pickled = out.toByteArray(); 628 InputStream in = new ByteArrayInputStream(pickled); 629 ObjectInputStream ois = new ObjectInputStream(in); 630 Object o = ois.readObject(); 631 assertTrue("Didn't get a ByteString back", o instanceof ByteString); 632 assertEquals("Should get an equal ByteString back", testString, o); 633 } 634 forString(String str)635 private static ByteString forString(String str) { 636 return new NioByteString(ByteBuffer.wrap(str.getBytes(UTF_8))); 637 } 638 } 639