| Index: third_party/protobuf/java/src/test/java/com/google/protobuf/ByteStringTest.java
|
| ===================================================================
|
| --- third_party/protobuf/java/src/test/java/com/google/protobuf/ByteStringTest.java (revision 0)
|
| +++ third_party/protobuf/java/src/test/java/com/google/protobuf/ByteStringTest.java (revision 0)
|
| @@ -0,0 +1,692 @@
|
| +// Protocol Buffers - Google's data interchange format
|
| +// Copyright 2008 Google Inc. All rights reserved.
|
| +// http://code.google.com/p/protobuf/
|
| +//
|
| +// 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 com.google.protobuf.ByteString.Output;
|
| +
|
| +import junit.framework.TestCase;
|
| +
|
| +import java.io.ByteArrayInputStream;
|
| +import java.io.IOException;
|
| +import java.io.InputStream;
|
| +import java.io.OutputStream;
|
| +import java.io.UnsupportedEncodingException;
|
| +import java.nio.ByteBuffer;
|
| +import java.util.ArrayList;
|
| +import java.util.Arrays;
|
| +import java.util.Iterator;
|
| +import java.util.List;
|
| +import java.util.NoSuchElementException;
|
| +import java.util.Random;
|
| +
|
| +/**
|
| + * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
|
| + * tests.
|
| + *
|
| + * @author carlanton@google.com (Carl Haverl)
|
| + */
|
| +public class ByteStringTest extends TestCase {
|
| +
|
| + private static final String UTF_16 = "UTF-16";
|
| +
|
| + static byte[] getTestBytes(int size, long seed) {
|
| + Random random = new Random(seed);
|
| + byte[] result = new byte[size];
|
| + random.nextBytes(result);
|
| + return result;
|
| + }
|
| +
|
| + private byte[] getTestBytes(int size) {
|
| + return getTestBytes(size, 445566L);
|
| + }
|
| +
|
| + private byte[] getTestBytes() {
|
| + return getTestBytes(1000);
|
| + }
|
| +
|
| + // Compare the entire left array with a subset of the right array.
|
| + private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
|
| + boolean stillEqual = (left.length == length);
|
| + for (int i = 0; (stillEqual && i < length); ++i) {
|
| + stillEqual = (left[i] == right[rightOffset + i]);
|
| + }
|
| + return stillEqual;
|
| + }
|
| +
|
| + // Returns true only if the given two arrays have identical contents.
|
| + private boolean isArray(byte[] left, byte[] right) {
|
| + return left.length == right.length && isArrayRange(left, right, 0, left.length);
|
| + }
|
| +
|
| + public void testSubstring_BeginIndex() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString substring = ByteString.copyFrom(bytes).substring(500);
|
| + assertTrue("substring must contain the tail of the string",
|
| + isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
|
| + }
|
| +
|
| + public void testCopyFrom_BytesOffsetSize() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
|
| + assertTrue("copyFrom sub-range must contain the expected bytes",
|
| + isArrayRange(byteString.toByteArray(), bytes, 500, 200));
|
| + }
|
| +
|
| + public void testCopyFrom_Bytes() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString byteString = ByteString.copyFrom(bytes);
|
| + assertTrue("copyFrom must contain the expected bytes",
|
| + isArray(byteString.toByteArray(), bytes));
|
| + }
|
| +
|
| + public void testCopyFrom_ByteBufferSize() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
|
| + byteBuffer.put(bytes);
|
| + byteBuffer.position(500);
|
| + ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
|
| + assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
| + isArrayRange(byteString.toByteArray(), bytes, 500, 200));
|
| + }
|
| +
|
| + public void testCopyFrom_ByteBuffer() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
|
| + byteBuffer.put(bytes);
|
| + byteBuffer.position(500);
|
| + ByteString byteString = ByteString.copyFrom(byteBuffer);
|
| + assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
| + isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
|
| + }
|
| +
|
| + public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
|
| + String testString = "I love unicode \u1234\u5678 characters";
|
| + ByteString byteString = ByteString.copyFrom(testString, UTF_16);
|
| + byte[] testBytes = testString.getBytes(UTF_16);
|
| + assertTrue("copyFrom string must respect the charset",
|
| + isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
| + }
|
| +
|
| + public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
|
| + String testString = "I love unicode \u1234\u5678 characters";
|
| + ByteString byteString = ByteString.copyFromUtf8(testString);
|
| + byte[] testBytes = testString.getBytes("UTF-8");
|
| + assertTrue("copyFromUtf8 string must respect the charset",
|
| + isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
| + }
|
| +
|
| + public void testCopyFrom_Iterable() {
|
| + byte[] testBytes = getTestBytes(77777, 113344L);
|
| + final List<ByteString> pieces = makeConcretePieces(testBytes);
|
| + // Call copyFrom() on a Collection
|
| + ByteString byteString = ByteString.copyFrom(pieces);
|
| + assertTrue("copyFrom a List must contain the expected bytes",
|
| + isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
| + // Call copyFrom on an iteration that's not a collection
|
| + ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
|
| + public Iterator<ByteString> iterator() {
|
| + return pieces.iterator();
|
| + }
|
| + });
|
| + assertEquals("copyFrom from an Iteration must contain the expected bytes",
|
| + byteString, byteStringAlt);
|
| + }
|
| +
|
| + public void testCopyTo_TargetOffset() {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString byteString = ByteString.copyFrom(bytes);
|
| + byte[] target = new byte[bytes.length + 1000];
|
| + byteString.copyTo(target, 400);
|
| + assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
| + isArrayRange(bytes, target, 400, bytes.length));
|
| + }
|
| +
|
| + public void testReadFrom_emptyStream() throws IOException {
|
| + ByteString byteString =
|
| + ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
|
| + assertSame("reading an empty stream must result in the EMPTY constant "
|
| + + "byte string", ByteString.EMPTY, byteString);
|
| + }
|
| +
|
| + public void testReadFrom_smallStream() throws IOException {
|
| + assertReadFrom(getTestBytes(10));
|
| + }
|
| +
|
| + public void testReadFrom_mutating() throws IOException {
|
| + byte[] capturedArray = null;
|
| + EvilInputStream eis = new EvilInputStream();
|
| + ByteString byteString = ByteString.readFrom(eis);
|
| +
|
| + capturedArray = eis.capturedArray;
|
| + byte[] originalValue = byteString.toByteArray();
|
| + for (int x = 0; x < capturedArray.length; ++x) {
|
| + capturedArray[x] = (byte) 0;
|
| + }
|
| +
|
| + byte[] newValue = byteString.toByteArray();
|
| + assertTrue("copyFrom byteBuffer must not grant access to underlying array",
|
| + Arrays.equals(originalValue, newValue));
|
| + }
|
| +
|
| + // Tests sizes that are near the rope copy-out threshold.
|
| + public void testReadFrom_mediumStream() throws IOException {
|
| + assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
|
| + assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
|
| + assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1));
|
| + assertReadFrom(getTestBytes(200));
|
| + }
|
| +
|
| + // Tests sizes that are over multi-segment rope threshold.
|
| + public void testReadFrom_largeStream() throws IOException {
|
| + assertReadFrom(getTestBytes(0x100));
|
| + assertReadFrom(getTestBytes(0x101));
|
| + assertReadFrom(getTestBytes(0x110));
|
| + assertReadFrom(getTestBytes(0x1000));
|
| + assertReadFrom(getTestBytes(0x1001));
|
| + assertReadFrom(getTestBytes(0x1010));
|
| + assertReadFrom(getTestBytes(0x10000));
|
| + assertReadFrom(getTestBytes(0x10001));
|
| + assertReadFrom(getTestBytes(0x10010));
|
| + }
|
| +
|
| + // Tests sizes that are near the read buffer size.
|
| + public void testReadFrom_byteBoundaries() throws IOException {
|
| + final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
|
| + final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
|
| +
|
| + assertReadFrom(getTestBytes(min - 1));
|
| + assertReadFrom(getTestBytes(min));
|
| + assertReadFrom(getTestBytes(min + 1));
|
| +
|
| + assertReadFrom(getTestBytes(min * 2 - 1));
|
| + assertReadFrom(getTestBytes(min * 2));
|
| + assertReadFrom(getTestBytes(min * 2 + 1));
|
| +
|
| + assertReadFrom(getTestBytes(min * 4 - 1));
|
| + assertReadFrom(getTestBytes(min * 4));
|
| + assertReadFrom(getTestBytes(min * 4 + 1));
|
| +
|
| + assertReadFrom(getTestBytes(min * 8 - 1));
|
| + assertReadFrom(getTestBytes(min * 8));
|
| + assertReadFrom(getTestBytes(min * 8 + 1));
|
| +
|
| + assertReadFrom(getTestBytes(max - 1));
|
| + assertReadFrom(getTestBytes(max));
|
| + assertReadFrom(getTestBytes(max + 1));
|
| +
|
| + assertReadFrom(getTestBytes(max * 2 - 1));
|
| + assertReadFrom(getTestBytes(max * 2));
|
| + assertReadFrom(getTestBytes(max * 2 + 1));
|
| + }
|
| +
|
| + // Tests that IOExceptions propagate through ByteString.readFrom().
|
| + public void testReadFrom_IOExceptions() {
|
| + try {
|
| + ByteString.readFrom(new FailStream());
|
| + fail("readFrom must throw the underlying IOException");
|
| +
|
| + } catch (IOException e) {
|
| + assertEquals("readFrom must throw the expected exception",
|
| + "synthetic failure", e.getMessage());
|
| + }
|
| + }
|
| +
|
| + // Tests that ByteString.readFrom works with streams that don't
|
| + // always fill their buffers.
|
| + public void testReadFrom_reluctantStream() throws IOException {
|
| + final byte[] data = getTestBytes(0x1000);
|
| +
|
| + ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
|
| + assertTrue("readFrom byte stream must contain the expected bytes",
|
| + isArray(byteString.toByteArray(), data));
|
| +
|
| + // Same test as above, but with some specific chunk sizes.
|
| + assertReadFromReluctantStream(data, 100);
|
| + assertReadFromReluctantStream(data, 248);
|
| + assertReadFromReluctantStream(data, 249);
|
| + assertReadFromReluctantStream(data, 250);
|
| + assertReadFromReluctantStream(data, 251);
|
| + assertReadFromReluctantStream(data, 0x1000);
|
| + assertReadFromReluctantStream(data, 0x1001);
|
| + }
|
| +
|
| + // Fails unless ByteString.readFrom reads the bytes correctly from a
|
| + // reluctant stream with the given chunkSize parameter.
|
| + private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
|
| + throws IOException {
|
| + ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
|
| + assertTrue("readFrom byte stream must contain the expected bytes",
|
| + isArray(b.toByteArray(), bytes));
|
| + }
|
| +
|
| + // Tests that ByteString.readFrom works with streams that implement
|
| + // available().
|
| + public void testReadFrom_available() throws IOException {
|
| + final byte[] data = getTestBytes(0x1001);
|
| +
|
| + ByteString byteString = ByteString.readFrom(new AvailableStream(data));
|
| + assertTrue("readFrom byte stream must contain the expected bytes",
|
| + isArray(byteString.toByteArray(), data));
|
| + }
|
| +
|
| + // Fails unless ByteString.readFrom reads the bytes correctly.
|
| + private void assertReadFrom(byte[] bytes) throws IOException {
|
| + ByteString byteString =
|
| + ByteString.readFrom(new ByteArrayInputStream(bytes));
|
| + assertTrue("readFrom byte stream must contain the expected bytes",
|
| + isArray(byteString.toByteArray(), bytes));
|
| + }
|
| +
|
| + // A stream that fails when read.
|
| + private static final class FailStream extends InputStream {
|
| + @Override public int read() throws IOException {
|
| + throw new IOException("synthetic failure");
|
| + }
|
| + }
|
| +
|
| + // A stream that simulates blocking by only producing 250 characters
|
| + // per call to read(byte[]).
|
| + private static class ReluctantStream extends InputStream {
|
| + protected final byte[] data;
|
| + protected int pos = 0;
|
| +
|
| + public ReluctantStream(byte[] data) {
|
| + this.data = data;
|
| + }
|
| +
|
| + @Override public int read() {
|
| + if (pos == data.length) {
|
| + return -1;
|
| + } else {
|
| + return data[pos++];
|
| + }
|
| + }
|
| +
|
| + @Override public int read(byte[] buf) {
|
| + return read(buf, 0, buf.length);
|
| + }
|
| +
|
| + @Override public int read(byte[] buf, int offset, int size) {
|
| + if (pos == data.length) {
|
| + return -1;
|
| + }
|
| + int count = Math.min(Math.min(size, data.length - pos), 250);
|
| + System.arraycopy(data, pos, buf, offset, count);
|
| + pos += count;
|
| + return count;
|
| + }
|
| + }
|
| +
|
| + // Same as above, but also implements available().
|
| + private static final class AvailableStream extends ReluctantStream {
|
| + public AvailableStream(byte[] data) {
|
| + super(data);
|
| + }
|
| +
|
| + @Override public int available() {
|
| + return Math.min(250, data.length - pos);
|
| + }
|
| + }
|
| +
|
| + // A stream which exposes the byte array passed into read(byte[], int, int).
|
| + private static class EvilInputStream extends InputStream {
|
| + public byte[] capturedArray = null;
|
| +
|
| + @Override
|
| + public int read(byte[] buf, int off, int len) {
|
| + if (capturedArray != null) {
|
| + return -1;
|
| + } else {
|
| + capturedArray = buf;
|
| + for (int x = 0; x < len; ++x) {
|
| + buf[x] = (byte) x;
|
| + }
|
| + return len;
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public int read() {
|
| + // Purposefully do nothing.
|
| + return -1;
|
| + }
|
| + }
|
| +
|
| + // A stream which exposes the byte array passed into write(byte[], int, int).
|
| + private static class EvilOutputStream extends OutputStream {
|
| + public byte[] capturedArray = null;
|
| +
|
| + @Override
|
| + public void write(byte[] buf, int off, int len) {
|
| + if (capturedArray == null) {
|
| + capturedArray = buf;
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void write(int ignored) {
|
| + // Purposefully do nothing.
|
| + }
|
| + }
|
| +
|
| + public void testToStringUtf8() throws UnsupportedEncodingException {
|
| + String testString = "I love unicode \u1234\u5678 characters";
|
| + byte[] testBytes = testString.getBytes("UTF-8");
|
| + ByteString byteString = ByteString.copyFrom(testBytes);
|
| + assertEquals("copyToStringUtf8 must respect the charset",
|
| + testString, byteString.toStringUtf8());
|
| + }
|
| +
|
| + public void testNewOutput_InitialCapacity() throws IOException {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString.Output output = ByteString.newOutput(bytes.length + 100);
|
| + output.write(bytes);
|
| + ByteString byteString = output.toByteString();
|
| + assertTrue(
|
| + "String built from newOutput(int) must contain the expected bytes",
|
| + isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
| + }
|
| +
|
| + // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
|
| + // write sizes
|
| + public void testNewOutput_ArrayWrite() throws IOException {
|
| + byte[] bytes = getTestBytes();
|
| + int length = bytes.length;
|
| + int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
|
| + 2 * length, 3 * length};
|
| + int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
|
| +
|
| + for (int bufferSize : bufferSizes) {
|
| + for (int writeSize : writeSizes) {
|
| + // Test writing the entire output writeSize bytes at a time.
|
| + ByteString.Output output = ByteString.newOutput(bufferSize);
|
| + for (int i = 0; i < length; i += writeSize) {
|
| + output.write(bytes, i, Math.min(writeSize, length - i));
|
| + }
|
| + ByteString byteString = output.toByteString();
|
| + assertTrue("String built from newOutput() must contain the expected bytes",
|
| + isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Test newOutput() using a variety of buffer sizes, but writing all the
|
| + // characters using write(byte);
|
| + public void testNewOutput_WriteChar() throws IOException {
|
| + byte[] bytes = getTestBytes();
|
| + int length = bytes.length;
|
| + int[] bufferSizes = {0, 1, 128, 256, length / 2,
|
| + length - 1, length, length + 1,
|
| + 2 * length, 3 * length};
|
| + for (int bufferSize : bufferSizes) {
|
| + ByteString.Output output = ByteString.newOutput(bufferSize);
|
| + for (byte byteValue : bytes) {
|
| + output.write(byteValue);
|
| + }
|
| + ByteString byteString = output.toByteString();
|
| + assertTrue("String built from newOutput() must contain the expected bytes",
|
| + isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
| + }
|
| + }
|
| +
|
| + // Test newOutput() in which we write the bytes using a variety of methods
|
| + // and sizes, and in which we repeatedly call toByteString() in the middle.
|
| + public void testNewOutput_Mixed() throws IOException {
|
| + Random rng = new Random(1);
|
| + byte[] bytes = getTestBytes();
|
| + int length = bytes.length;
|
| + int[] bufferSizes = {0, 1, 128, 256, length / 2,
|
| + length - 1, length, length + 1,
|
| + 2 * length, 3 * length};
|
| +
|
| + for (int bufferSize : bufferSizes) {
|
| + // Test writing the entire output using a mixture of write sizes and
|
| + // methods;
|
| + ByteString.Output output = ByteString.newOutput(bufferSize);
|
| + int position = 0;
|
| + while (position < bytes.length) {
|
| + if (rng.nextBoolean()) {
|
| + int count = 1 + rng.nextInt(bytes.length - position);
|
| + output.write(bytes, position, count);
|
| + position += count;
|
| + } else {
|
| + output.write(bytes[position]);
|
| + position++;
|
| + }
|
| + assertEquals("size() returns the right value", position, output.size());
|
| + assertTrue("newOutput() substring must have correct bytes",
|
| + isArrayRange(output.toByteString().toByteArray(),
|
| + bytes, 0, position));
|
| + }
|
| + ByteString byteString = output.toByteString();
|
| + assertTrue("String built from newOutput() must contain the expected bytes",
|
| + isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
| + }
|
| + }
|
| +
|
| + public void testNewOutputEmpty() throws IOException {
|
| + // Make sure newOutput() correctly builds empty byte strings
|
| + ByteString byteString = ByteString.newOutput().toByteString();
|
| + assertEquals(ByteString.EMPTY, byteString);
|
| + }
|
| +
|
| + public void testNewOutput_Mutating() throws IOException {
|
| + Output os = ByteString.newOutput(5);
|
| + os.write(new byte[] {1, 2, 3, 4, 5});
|
| + EvilOutputStream eos = new EvilOutputStream();
|
| + os.writeTo(eos);
|
| + byte[] capturedArray = eos.capturedArray;
|
| + ByteString byteString = os.toByteString();
|
| + byte[] oldValue = byteString.toByteArray();
|
| + Arrays.fill(capturedArray, (byte) 0);
|
| + byte[] newValue = byteString.toByteArray();
|
| + assertTrue("Output must not provide access to the underlying byte array",
|
| + Arrays.equals(oldValue, newValue));
|
| + }
|
| +
|
| + public void testNewCodedBuilder() throws IOException {
|
| + byte[] bytes = getTestBytes();
|
| + ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
|
| + builder.getCodedOutput().writeRawBytes(bytes);
|
| + ByteString byteString = builder.build();
|
| + assertTrue("String built from newCodedBuilder() must contain the expected bytes",
|
| + isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
| + }
|
| +
|
| + public void testSubstringParity() {
|
| + byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
|
| + int start = 512 * 1024 - 3333;
|
| + int end = 512 * 1024 + 7777;
|
| + ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
|
| + boolean ok = true;
|
| + for (int i = start; ok && i < end; ++i) {
|
| + ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
|
| + }
|
| + assertTrue("Concrete substring didn't capture the right bytes", ok);
|
| +
|
| + ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
|
| + assertTrue("Substring must be equal to literal string",
|
| + concreteSubstring.equals(literalString));
|
| + assertEquals("Substring must have same hashcode as literal string",
|
| + literalString.hashCode(), concreteSubstring.hashCode());
|
| + }
|
| +
|
| + public void testCompositeSubstring() {
|
| + byte[] referenceBytes = getTestBytes(77748, 113344L);
|
| +
|
| + List<ByteString> pieces = makeConcretePieces(referenceBytes);
|
| + ByteString listString = ByteString.copyFrom(pieces);
|
| +
|
| + int from = 1000;
|
| + int to = 40000;
|
| + ByteString compositeSubstring = listString.substring(from, to);
|
| + byte[] substringBytes = compositeSubstring.toByteArray();
|
| + boolean stillEqual = true;
|
| + for (int i = 0; stillEqual && i < to - from; ++i) {
|
| + stillEqual = referenceBytes[from + i] == substringBytes[i];
|
| + }
|
| + assertTrue("Substring must return correct bytes", stillEqual);
|
| +
|
| + stillEqual = true;
|
| + for (int i = 0; stillEqual && i < to - from; ++i) {
|
| + stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
|
| + }
|
| + assertTrue("Substring must support byteAt() correctly", stillEqual);
|
| +
|
| + ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
|
| + assertTrue("Composite substring must equal a literal substring over the same bytes",
|
| + compositeSubstring.equals(literalSubstring));
|
| + assertTrue("Literal substring must equal a composite substring over the same bytes",
|
| + literalSubstring.equals(compositeSubstring));
|
| +
|
| + assertEquals("We must get the same hashcodes for composite and literal substrings",
|
| + literalSubstring.hashCode(), compositeSubstring.hashCode());
|
| +
|
| + assertFalse("We can't be equal to a proper substring",
|
| + compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
|
| + }
|
| +
|
| + public void testCopyFromList() {
|
| + byte[] referenceBytes = getTestBytes(77748, 113344L);
|
| + ByteString literalString = ByteString.copyFrom(referenceBytes);
|
| +
|
| + List<ByteString> pieces = makeConcretePieces(referenceBytes);
|
| + ByteString listString = ByteString.copyFrom(pieces);
|
| +
|
| + assertTrue("Composite string must be equal to literal string",
|
| + listString.equals(literalString));
|
| + assertEquals("Composite string must have same hashcode as literal string",
|
| + literalString.hashCode(), listString.hashCode());
|
| + }
|
| +
|
| + public void testConcat() {
|
| + byte[] referenceBytes = getTestBytes(77748, 113344L);
|
| + ByteString literalString = ByteString.copyFrom(referenceBytes);
|
| +
|
| + List<ByteString> pieces = makeConcretePieces(referenceBytes);
|
| +
|
| + Iterator<ByteString> iter = pieces.iterator();
|
| + ByteString concatenatedString = iter.next();
|
| + while (iter.hasNext()) {
|
| + concatenatedString = concatenatedString.concat(iter.next());
|
| + }
|
| +
|
| + assertTrue("Concatenated string must be equal to literal string",
|
| + concatenatedString.equals(literalString));
|
| + assertEquals("Concatenated string must have same hashcode as literal string",
|
| + literalString.hashCode(), concatenatedString.hashCode());
|
| + }
|
| +
|
| + /**
|
| + * Test the Rope implementation can deal with Empty nodes, even though we
|
| + * guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
|
| + */
|
| + public void testConcat_empty() {
|
| + byte[] referenceBytes = getTestBytes(7748, 113344L);
|
| + ByteString literalString = ByteString.copyFrom(referenceBytes);
|
| +
|
| + ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
|
| + ByteString temp = RopeByteString.newInstanceForTest(
|
| + RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
|
| + RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
|
| + ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
|
| +
|
| + assertTrue("String with concatenated nulls must equal simple concatenate",
|
| + duo.equals(quintet));
|
| + assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
|
| + duo.hashCode(), quintet.hashCode());
|
| +
|
| + ByteString.ByteIterator duoIter = duo.iterator();
|
| + ByteString.ByteIterator quintetIter = quintet.iterator();
|
| + boolean stillEqual = true;
|
| + while (stillEqual && quintetIter.hasNext()) {
|
| + stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
|
| + }
|
| + assertTrue("We must get the same characters by iterating", stillEqual);
|
| + assertFalse("Iterator must be exhausted", duoIter.hasNext());
|
| + try {
|
| + duoIter.nextByte();
|
| + fail("Should have thrown an exception.");
|
| + } catch (NoSuchElementException e) {
|
| + // This is success
|
| + }
|
| + try {
|
| + quintetIter.nextByte();
|
| + fail("Should have thrown an exception.");
|
| + } catch (NoSuchElementException e) {
|
| + // This is success
|
| + }
|
| +
|
| + // Test that even if we force empty strings in as rope leaves in this
|
| + // configuration, we always get a (possibly Bounded) LiteralByteString
|
| + // for a length 1 substring.
|
| + //
|
| + // It is possible, using the testing factory method to create deeply nested
|
| + // trees of empty leaves, to make a string that will fail this test.
|
| + for (int i = 1; i < duo.size(); ++i) {
|
| + assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
|
| + duo.substring(i - 1, i) instanceof LiteralByteString);
|
| + }
|
| + for (int i = 1; i < quintet.size(); ++i) {
|
| + assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
|
| + quintet.substring(i - 1, i) instanceof LiteralByteString);
|
| + }
|
| + }
|
| +
|
| + public void testStartsWith() {
|
| + byte[] bytes = getTestBytes(1000, 1234L);
|
| + ByteString string = ByteString.copyFrom(bytes);
|
| + ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
|
| + ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
|
| + assertTrue(string.startsWith(ByteString.EMPTY));
|
| + assertTrue(string.startsWith(string));
|
| + assertTrue(string.startsWith(prefix));
|
| + assertFalse(string.startsWith(suffix));
|
| + assertFalse(prefix.startsWith(suffix));
|
| + assertFalse(suffix.startsWith(prefix));
|
| + assertFalse(ByteString.EMPTY.startsWith(prefix));
|
| + assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
|
| + }
|
| +
|
| + static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
|
| + List<ByteString> pieces = new ArrayList<ByteString>();
|
| + // Starting length should be small enough that we'll do some concatenating by
|
| + // copying if we just concatenate all these pieces together.
|
| + for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
|
| + length = (length << 1) - 1;
|
| + if (start + length > referenceBytes.length) {
|
| + length = referenceBytes.length - start;
|
| + }
|
| + pieces.add(ByteString.copyFrom(referenceBytes, start, length));
|
| + }
|
| + return pieces;
|
| + }
|
| +}
|
|
|
| Property changes on: third_party/protobuf/java/src/test/java/com/google/protobuf/ByteStringTest.java
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|