| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package com.google.protobuf; |
| |
| import static com.google.protobuf.Internal.UTF_8; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.nio.BufferOverflowException; |
| import java.nio.ByteBuffer; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| |
| /** |
| * Tests for {@link NioByteString}. |
| */ |
| public class NioByteStringTest extends TestCase { |
| private static final ByteString EMPTY = new NioByteString(ByteBuffer.wrap(new byte[0])); |
| private static final String CLASSNAME = NioByteString.class.getSimpleName(); |
| private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L); |
| private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode(); |
| |
| private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone()); |
| private final ByteString testString = new NioByteString(backingBuffer); |
| |
| public void testExpectedType() { |
| String actualClassName = getActualClassName(testString); |
| assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName); |
| } |
| |
| protected String getActualClassName(Object object) { |
| String actualClassName = object.getClass().getName(); |
| actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1); |
| return actualClassName; |
| } |
| |
| public void testByteAt() { |
| boolean stillEqual = true; |
| for (int i = 0; stillEqual && i < BYTES.length; ++i) { |
| stillEqual = (BYTES[i] == testString.byteAt(i)); |
| } |
| assertTrue(CLASSNAME + " must capture the right bytes", stillEqual); |
| } |
| |
| public void testByteIterator() { |
| boolean stillEqual = true; |
| ByteString.ByteIterator iter = testString.iterator(); |
| for (int i = 0; stillEqual && i < BYTES.length; ++i) { |
| stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte()); |
| } |
| assertTrue(CLASSNAME + " must capture the right bytes", stillEqual); |
| assertFalse(CLASSNAME + " must have exhausted the itertor", iter.hasNext()); |
| |
| try { |
| iter.nextByte(); |
| fail("Should have thrown an exception."); |
| } catch (NoSuchElementException e) { |
| // This is success |
| } |
| } |
| |
| public void testByteIterable() { |
| boolean stillEqual = true; |
| int j = 0; |
| for (byte quantum : testString) { |
| stillEqual = (BYTES[j] == quantum); |
| ++j; |
| } |
| assertTrue(CLASSNAME + " must capture the right bytes as Bytes", stillEqual); |
| assertEquals(CLASSNAME + " iterable character count", BYTES.length, j); |
| } |
| |
| public void testSize() { |
| assertEquals(CLASSNAME + " must have the expected size", BYTES.length, |
| testString.size()); |
| } |
| |
| public void testGetTreeDepth() { |
| assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth()); |
| } |
| |
| public void testIsBalanced() { |
| assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced()); |
| } |
| |
| public void testCopyTo_ByteArrayOffsetLength() { |
| int destinationOffset = 50; |
| int length = 100; |
| byte[] destination = new byte[destinationOffset + length]; |
| int sourceOffset = 213; |
| testString.copyTo(destination, sourceOffset, destinationOffset, length); |
| boolean stillEqual = true; |
| for (int i = 0; stillEqual && i < length; ++i) { |
| stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset]; |
| } |
| assertTrue(CLASSNAME + ".copyTo(4 arg) must give the expected bytes", stillEqual); |
| } |
| |
| public void testCopyTo_ByteArrayOffsetLengthErrors() { |
| int destinationOffset = 50; |
| int length = 100; |
| byte[] destination = new byte[destinationOffset + length]; |
| |
| try { |
| // Copy one too many bytes |
| testString.copyTo(destination, testString.size() + 1 - length, |
| destinationOffset, length); |
| fail("Should have thrown an exception when copying too many bytes of a " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| |
| try { |
| // Copy with illegal negative sourceOffset |
| testString.copyTo(destination, -1, destinationOffset, length); |
| fail("Should have thrown an exception when given a negative sourceOffset in " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| |
| try { |
| // Copy with illegal negative destinationOffset |
| testString.copyTo(destination, 0, -1, length); |
| fail("Should have thrown an exception when given a negative destinationOffset in " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| |
| try { |
| // Copy with illegal negative size |
| testString.copyTo(destination, 0, 0, -1); |
| fail("Should have thrown an exception when given a negative size in " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| |
| try { |
| // Copy with illegal too-large sourceOffset |
| testString.copyTo(destination, 2 * testString.size(), 0, length); |
| fail("Should have thrown an exception when the destinationOffset is too large in " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| |
| try { |
| // Copy with illegal too-large destinationOffset |
| testString.copyTo(destination, 0, 2 * destination.length, length); |
| fail("Should have thrown an exception when the destinationOffset is too large in " |
| + CLASSNAME); |
| } catch (IndexOutOfBoundsException expected) { |
| // This is success |
| } |
| } |
| |
| public void testCopyTo_ByteBuffer() { |
| // Same length. |
| ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length); |
| testString.copyTo(myBuffer); |
| myBuffer.flip(); |
| assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes", |
| backingBuffer, myBuffer); |
| |
| // Target buffer bigger than required. |
| myBuffer = ByteBuffer.allocate(testString.size() + 1); |
| testString.copyTo(myBuffer); |
| myBuffer.flip(); |
| assertEquals(backingBuffer, myBuffer); |
| |
| // Target buffer has no space. |
| myBuffer = ByteBuffer.allocate(0); |
| try { |
| testString.copyTo(myBuffer); |
| fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); |
| } catch (BufferOverflowException e) { |
| // Expected. |
| } |
| |
| // Target buffer too small. |
| myBuffer = ByteBuffer.allocate(1); |
| try { |
| testString.copyTo(myBuffer); |
| fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); |
| } catch (BufferOverflowException e) { |
| // Expected. |
| } |
| } |
| |
| public void testMarkSupported() { |
| InputStream stream = testString.newInput(); |
| assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported()); |
| } |
| |
| public void testMarkAndReset() throws IOException { |
| int fraction = testString.size() / 3; |
| |
| InputStream stream = testString.newInput(); |
| stream.mark(testString.size()); // First, mark() the end. |
| |
| skipFully(stream, fraction); // Skip a large fraction, but not all. |
| assertEquals( |
| CLASSNAME + ": after skipping to the 'middle', half the bytes are available", |
| (testString.size() - fraction), stream.available()); |
| stream.reset(); |
| assertEquals( |
| CLASSNAME + ": after resetting, all bytes are available", |
| testString.size(), stream.available()); |
| |
| skipFully(stream, testString.size()); // Skip to the end. |
| assertEquals( |
| CLASSNAME + ": after skipping to the end, no more bytes are available", |
| 0, stream.available()); |
| } |
| |
| /** |
| * Discards {@code n} bytes of data from the input stream. This method |
| * will block until the full amount has been skipped. Does not close the |
| * stream. |
| * <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency. |
| * |
| * @param in the input stream to read from |
| * @param n the number of bytes to skip |
| * @throws EOFException if this stream reaches the end before skipping all |
| * the bytes |
| * @throws IOException if an I/O error occurs, or the stream does not |
| * support skipping |
| */ |
| static void skipFully(InputStream in, long n) throws IOException { |
| long toSkip = n; |
| while (n > 0) { |
| long amt = in.skip(n); |
| if (amt == 0) { |
| // Force a blocking read to avoid infinite loop |
| if (in.read() == -1) { |
| long skipped = toSkip - n; |
| throw new EOFException("reached end of stream after skipping " |
| + skipped + " bytes; " + toSkip + " bytes expected"); |
| } |
| n--; |
| } else { |
| n -= amt; |
| } |
| } |
| } |
| |
| public void testAsReadOnlyByteBuffer() { |
| ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer(); |
| byte[] roundTripBytes = new byte[BYTES.length]; |
| assertTrue(byteBuffer.remaining() == BYTES.length); |
| assertTrue(byteBuffer.isReadOnly()); |
| byteBuffer.get(roundTripBytes); |
| assertTrue(CLASSNAME + ".asReadOnlyByteBuffer() must give back the same bytes", |
| Arrays.equals(BYTES, roundTripBytes)); |
| } |
| |
| public void testAsReadOnlyByteBufferList() { |
| List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList(); |
| int bytesSeen = 0; |
| byte[] roundTripBytes = new byte[BYTES.length]; |
| for (ByteBuffer byteBuffer : byteBuffers) { |
| int thisLength = byteBuffer.remaining(); |
| assertTrue(byteBuffer.isReadOnly()); |
| assertTrue(bytesSeen + thisLength <= BYTES.length); |
| byteBuffer.get(roundTripBytes, bytesSeen, thisLength); |
| bytesSeen += thisLength; |
| } |
| assertTrue(bytesSeen == BYTES.length); |
| assertTrue(CLASSNAME + ".asReadOnlyByteBufferTest() must give back the same bytes", |
| Arrays.equals(BYTES, roundTripBytes)); |
| } |
| |
| public void testToByteArray() { |
| byte[] roundTripBytes = testString.toByteArray(); |
| assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes", |
| Arrays.equals(BYTES, roundTripBytes)); |
| } |
| |
| public void testWriteTo() throws IOException { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| testString.writeTo(bos); |
| byte[] roundTripBytes = bos.toByteArray(); |
| assertTrue(CLASSNAME + ".writeTo() must give back the same bytes", |
| Arrays.equals(BYTES, roundTripBytes)); |
| } |
| |
| public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException { |
| OutputStream os = new OutputStream() { |
| @Override |
| public void write(byte[] b, int off, int len) { |
| Arrays.fill(b, off, off + len, (byte) 0); |
| } |
| |
| @Override |
| public void write(int b) { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| |
| byte[] original = Arrays.copyOf(BYTES, BYTES.length); |
| testString.writeTo(os); |
| assertTrue(CLASSNAME + ".writeTo() must NOT grant access to underlying buffer", |
| Arrays.equals(original, BYTES)); |
| } |
| |
| public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException { |
| OutputStream os = new OutputStream() { |
| @Override |
| public void write(byte[] b, int off, int len) { |
| Arrays.fill(b, off, off + len, (byte) 0); |
| } |
| |
| @Override |
| public void write(int b) { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| |
| testString.writeToInternal(os, 0, testString.size()); |
| byte[] allZeros = new byte[testString.size()]; |
| assertTrue(CLASSNAME + ".writeToInternal() must grant access to underlying buffer", |
| Arrays.equals(allZeros, backingBuffer.array())); |
| } |
| |
| public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException { |
| ByteOutput out = new ByteOutput() { |
| @Override |
| public void write(byte value) throws IOException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void write(byte[] value, int offset, int length) throws IOException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void writeLazy(byte[] value, int offset, int length) throws IOException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void write(ByteBuffer value) throws IOException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void writeLazy(ByteBuffer value) throws IOException { |
| Arrays.fill(value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(), |
| (byte) 0); |
| } |
| }; |
| |
| testString.writeTo(out); |
| byte[] allZeros = new byte[testString.size()]; |
| assertTrue(CLASSNAME + ".writeTo() must grant access to underlying buffer", |
| Arrays.equals(allZeros, backingBuffer.array())); |
| } |
| |
| public void testNewOutput() throws IOException { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| ByteString.Output output = ByteString.newOutput(); |
| testString.writeTo(output); |
| assertEquals("Output Size returns correct result", |
| output.size(), testString.size()); |
| output.writeTo(bos); |
| assertTrue("Output.writeTo() must give back the same bytes", |
| Arrays.equals(BYTES, bos.toByteArray())); |
| |
| // write the output stream to itself! This should cause it to double |
| output.writeTo(output); |
| assertEquals("Writing an output stream to itself is successful", |
| testString.concat(testString), output.toByteString()); |
| |
| output.reset(); |
| assertEquals("Output.reset() resets the output", 0, output.size()); |
| assertEquals("Output.reset() resets the output", |
| EMPTY, output.toByteString()); |
| } |
| |
| public void testToString() { |
| String testString = "I love unicode \u1234\u5678 characters"; |
| ByteString unicode = forString(testString); |
| String roundTripString = unicode.toString(UTF_8); |
| assertEquals(CLASSNAME + " unicode must match", testString, roundTripString); |
| } |
| |
| public void testCharsetToString() { |
| String testString = "I love unicode \u1234\u5678 characters"; |
| ByteString unicode = forString(testString); |
| String roundTripString = unicode.toString(UTF_8); |
| assertEquals(CLASSNAME + " unicode must match", testString, roundTripString); |
| } |
| |
| public void testToString_returnsCanonicalEmptyString() { |
| assertSame(CLASSNAME + " must be the same string references", |
| EMPTY.toString(UTF_8), |
| new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8)); |
| } |
| |
| public void testToString_raisesException() { |
| try { |
| EMPTY.toString("invalid"); |
| fail("Should have thrown an exception."); |
| } catch (UnsupportedEncodingException expected) { |
| // This is success |
| } |
| |
| try { |
| testString.toString("invalid"); |
| fail("Should have thrown an exception."); |
| } catch (UnsupportedEncodingException expected) { |
| // This is success |
| } |
| } |
| |
| public void testEquals() { |
| assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null)); |
| assertEquals(CLASSNAME + " must equal self", testString, testString); |
| assertFalse(CLASSNAME + " must not equal the empty string", |
| testString.equals(EMPTY)); |
| assertEquals(CLASSNAME + " empty strings must be equal", |
| EMPTY, testString.substring(55, 55)); |
| assertEquals(CLASSNAME + " must equal another string with the same value", |
| testString, new NioByteString(backingBuffer)); |
| |
| byte[] mungedBytes = mungedBytes(); |
| assertFalse(CLASSNAME + " must not equal every string with the same length", |
| testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes)))); |
| } |
| |
| public void testEqualsLiteralByteString() { |
| ByteString literal = ByteString.copyFrom(BYTES); |
| assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal, |
| testString); |
| assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString, |
| literal); |
| assertFalse(CLASSNAME + " must not equal the empty string", |
| testString.equals(ByteString.EMPTY)); |
| assertEquals(CLASSNAME + " empty strings must be equal", |
| ByteString.EMPTY, testString.substring(55, 55)); |
| |
| literal = ByteString.copyFrom(mungedBytes()); |
| assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length", |
| testString.equals(literal)); |
| assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length", |
| literal.equals(testString)); |
| } |
| |
| public void testEqualsRopeByteString() { |
| ByteString p1 = ByteString.copyFrom(BYTES, 0, 5); |
| ByteString p2 = ByteString.copyFrom(BYTES, 5, BYTES.length - 5); |
| ByteString rope = p1.concat(p2); |
| |
| assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope, |
| testString); |
| assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString, |
| rope); |
| assertFalse(CLASSNAME + " must not equal the empty string", |
| testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY))); |
| assertEquals(CLASSNAME + " empty strings must be equal", |
| ByteString.EMPTY.concat(ByteString.EMPTY), testString.substring(55, 55)); |
| |
| byte[] mungedBytes = mungedBytes(); |
| p1 = ByteString.copyFrom(mungedBytes, 0, 5); |
| p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5); |
| rope = p1.concat(p2); |
| assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length", |
| testString.equals(rope)); |
| assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length", |
| rope.equals(testString)); |
| } |
| |
| private byte[] mungedBytes() { |
| byte[] mungedBytes = new byte[BYTES.length]; |
| System.arraycopy(BYTES, 0, mungedBytes, 0, BYTES.length); |
| mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF); |
| return mungedBytes; |
| } |
| |
| public void testHashCode() { |
| int hash = testString.hashCode(); |
| assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash); |
| } |
| |
| public void testPeekCachedHashCode() { |
| ByteString newString = new NioByteString(backingBuffer); |
| assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0, |
| newString.peekCachedHashCode()); |
| newString.hashCode(); |
| assertEquals(CLASSNAME + ".peekCachedHashCode should return zero at first", |
| EXPECTED_HASH, newString.peekCachedHashCode()); |
| } |
| |
| public void testPartialHash() { |
| // partialHash() is more strenuously tested elsewhere by testing hashes of substrings. |
| // This test would fail if the expected hash were 1. It's not. |
| int hash = testString.partialHash(testString.size(), 0, testString.size()); |
| assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode", |
| EXPECTED_HASH, hash); |
| } |
| |
| public void testNewInput() throws IOException { |
| InputStream input = testString.newInput(); |
| assertEquals("InputStream.available() returns correct value", |
| testString.size(), input.available()); |
| boolean stillEqual = true; |
| for (byte referenceByte : BYTES) { |
| int expectedInt = (referenceByte & 0xFF); |
| stillEqual = (expectedInt == input.read()); |
| } |
| assertEquals("InputStream.available() returns correct value", |
| 0, input.available()); |
| assertTrue(CLASSNAME + " must give the same bytes from the InputStream", stillEqual); |
| assertEquals(CLASSNAME + " InputStream must now be exhausted", -1, input.read()); |
| } |
| |
| public void testNewInput_skip() throws IOException { |
| InputStream input = testString.newInput(); |
| int stringSize = testString.size(); |
| int nearEndIndex = stringSize * 2 / 3; |
| long skipped1 = input.skip(nearEndIndex); |
| assertEquals("InputStream.skip()", skipped1, nearEndIndex); |
| assertEquals("InputStream.available()", |
| stringSize - skipped1, input.available()); |
| assertTrue("InputStream.mark() is available", input.markSupported()); |
| input.mark(0); |
| assertEquals("InputStream.skip(), read()", |
| testString.byteAt(nearEndIndex) & 0xFF, input.read()); |
| assertEquals("InputStream.available()", |
| stringSize - skipped1 - 1, input.available()); |
| long skipped2 = input.skip(stringSize); |
| assertEquals("InputStream.skip() incomplete", |
| skipped2, stringSize - skipped1 - 1); |
| assertEquals("InputStream.skip(), no more input", 0, input.available()); |
| assertEquals("InputStream.skip(), no more input", -1, input.read()); |
| input.reset(); |
| assertEquals("InputStream.reset() succeded", |
| stringSize - skipped1, input.available()); |
| assertEquals("InputStream.reset(), read()", |
| testString.byteAt(nearEndIndex) & 0xFF, input.read()); |
| } |
| |
| public void testNewCodedInput() throws IOException { |
| CodedInputStream cis = testString.newCodedInput(); |
| byte[] roundTripBytes = cis.readRawBytes(BYTES.length); |
| assertTrue(CLASSNAME + " must give the same bytes back from the CodedInputStream", |
| Arrays.equals(BYTES, roundTripBytes)); |
| assertTrue(CLASSNAME + " CodedInputStream must now be exhausted", cis.isAtEnd()); |
| } |
| |
| /** |
| * Make sure we keep things simple when concatenating with empty. See also |
| * {@link ByteStringTest#testConcat_empty()}. |
| */ |
| public void testConcat_empty() { |
| assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME, |
| testString.concat(EMPTY), testString); |
| assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME, |
| EMPTY.concat(testString), testString); |
| } |
| |
| public void testJavaSerialization() throws Exception { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(out); |
| oos.writeObject(testString); |
| oos.close(); |
| byte[] pickled = out.toByteArray(); |
| InputStream in = new ByteArrayInputStream(pickled); |
| ObjectInputStream ois = new ObjectInputStream(in); |
| Object o = ois.readObject(); |
| assertTrue("Didn't get a ByteString back", o instanceof ByteString); |
| assertEquals("Should get an equal ByteString back", testString, o); |
| } |
| |
| private static ByteString forString(String str) { |
| return new NioByteString(ByteBuffer.wrap(str.getBytes(UTF_8))); |
| } |
| } |