// 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 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.ByteBuffer; import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; /** * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}. * This class is designed to be extended for testing extensions of {@link LiteralByteString} * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}. * * @author carlanton@google.com (Carl Haverl) */ public class LiteralByteStringTest extends TestCase { protected static final String UTF_8 = "UTF-8"; protected String classUnderTest; protected byte[] referenceBytes; protected ByteString stringUnderTest; protected int expectedHashCode; @Override protected void setUp() throws Exception { classUnderTest = "LiteralByteString"; referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L); stringUnderTest = ByteString.copyFrom(referenceBytes); expectedHashCode = 331161852; } public void testExpectedType() { String actualClassName = getActualClassName(stringUnderTest); assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName); } protected String getActualClassName(Object object) { return object.getClass().getSimpleName(); } public void testByteAt() { boolean stillEqual = true; for (int i = 0; stillEqual && i < referenceBytes.length; ++i) { stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i)); } assertTrue(classUnderTest + " must capture the right bytes", stillEqual); } public void testByteIterator() { boolean stillEqual = true; ByteString.ByteIterator iter = stringUnderTest.iterator(); for (int i = 0; stillEqual && i < referenceBytes.length; ++i) { stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte()); } assertTrue(classUnderTest + " must capture the right bytes", stillEqual); assertFalse(classUnderTest + " 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 : stringUnderTest) { stillEqual = (referenceBytes[j] == quantum); ++j; } assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual); assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j); } public void testSize() { assertEquals(classUnderTest + " must have the expected size", referenceBytes.length, stringUnderTest.size()); } public void testGetTreeDepth() { assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth()); } public void testIsBalanced() { assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced()); } public void testCopyTo_ByteArrayOffsetLength() { int destinationOffset = 50; int length = 100; byte[] destination = new byte[destinationOffset + length]; int sourceOffset = 213; stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length); boolean stillEqual = true; for (int i = 0; stillEqual && i < length; ++i) { stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset]; } assertTrue(classUnderTest + ".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 stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length, destinationOffset, length); fail("Should have thrown an exception when copying too many bytes of a " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } try { // Copy with illegal negative sourceOffset stringUnderTest.copyTo(destination, -1, destinationOffset, length); fail("Should have thrown an exception when given a negative sourceOffset in " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } try { // Copy with illegal negative destinationOffset stringUnderTest.copyTo(destination, 0, -1, length); fail("Should have thrown an exception when given a negative destinationOffset in " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } try { // Copy with illegal negative size stringUnderTest.copyTo(destination, 0, 0, -1); fail("Should have thrown an exception when given a negative size in " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } try { // Copy with illegal too-large sourceOffset stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length); fail("Should have thrown an exception when the destinationOffset is too large in " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } try { // Copy with illegal too-large destinationOffset stringUnderTest.copyTo(destination, 0, 2 * destination.length, length); fail("Should have thrown an exception when the destinationOffset is too large in " + classUnderTest); } catch (IndexOutOfBoundsException expected) { // This is success } } public void testCopyTo_ByteBuffer() { ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length); stringUnderTest.copyTo(myBuffer); assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes", Arrays.equals(referenceBytes, myBuffer.array())); } public void testMarkSupported() { InputStream stream = stringUnderTest.newInput(); assertTrue(classUnderTest + ".newInput() must support marking", stream.markSupported()); } public void testMarkAndReset() throws IOException { int fraction = stringUnderTest.size() / 3; InputStream stream = stringUnderTest.newInput(); stream.mark(stringUnderTest.size()); // First, mark() the end. skipFully(stream, fraction); // Skip a large fraction, but not all. int available = stream.available(); assertTrue( classUnderTest + ": after skipping to the 'middle', half the bytes are available", (stringUnderTest.size() - fraction) == available); stream.reset(); skipFully(stream, stringUnderTest.size()); // Skip to the end. available = stream.available(); assertTrue( classUnderTest + ": after skipping to the end, no more bytes are available", 0 == 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. *
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 = stringUnderTest.asReadOnlyByteBuffer();
byte[] roundTripBytes = new byte[referenceBytes.length];
assertTrue(byteBuffer.remaining() == referenceBytes.length);
assertTrue(byteBuffer.isReadOnly());
byteBuffer.get(roundTripBytes);
assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
Arrays.equals(referenceBytes, roundTripBytes));
}
public void testAsReadOnlyByteBufferList() {
List