| OLD | NEW |
| (Empty) |
| 1 // Protocol Buffers - Google's data interchange format | |
| 2 // Copyright 2008 Google Inc. All rights reserved. | |
| 3 // http://code.google.com/p/protobuf/ | |
| 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.test; | |
| 32 import com.google.protobuf.*; | |
| 33 | |
| 34 import com.google.protobuf.ByteString.Output; | |
| 35 | |
| 36 import junit.framework.TestCase; | |
| 37 | |
| 38 import java.io.ByteArrayInputStream; | |
| 39 import java.io.IOException; | |
| 40 import java.io.InputStream; | |
| 41 import java.io.OutputStream; | |
| 42 import java.io.UnsupportedEncodingException; | |
| 43 import java.nio.ByteBuffer; | |
| 44 import java.util.ArrayList; | |
| 45 import java.util.Arrays; | |
| 46 import java.util.Iterator; | |
| 47 import java.util.List; | |
| 48 import java.util.NoSuchElementException; | |
| 49 import java.util.Random; | |
| 50 | |
| 51 /** | |
| 52 * Test methods with implementations in {@link ByteString}, plus do some top-lev
el "integration" | |
| 53 * tests. | |
| 54 * | |
| 55 * @author carlanton@google.com (Carl Haverl) | |
| 56 */ | |
| 57 public class ByteStringTest extends TestCase { | |
| 58 | |
| 59 private static final String UTF_16 = "UTF-16"; | |
| 60 | |
| 61 static byte[] getTestBytes(int size, long seed) { | |
| 62 Random random = new Random(seed); | |
| 63 byte[] result = new byte[size]; | |
| 64 random.nextBytes(result); | |
| 65 return result; | |
| 66 } | |
| 67 | |
| 68 private byte[] getTestBytes(int size) { | |
| 69 return getTestBytes(size, 445566L); | |
| 70 } | |
| 71 | |
| 72 private byte[] getTestBytes() { | |
| 73 return getTestBytes(1000); | |
| 74 } | |
| 75 | |
| 76 // Compare the entire left array with a subset of the right array. | |
| 77 private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int l
ength) { | |
| 78 boolean stillEqual = (left.length == length); | |
| 79 for (int i = 0; (stillEqual && i < length); ++i) { | |
| 80 stillEqual = (left[i] == right[rightOffset + i]); | |
| 81 } | |
| 82 return stillEqual; | |
| 83 } | |
| 84 | |
| 85 // Returns true only if the given two arrays have identical contents. | |
| 86 private boolean isArray(byte[] left, byte[] right) { | |
| 87 return left.length == right.length && isArrayRange(left, right, 0, left.leng
th); | |
| 88 } | |
| 89 | |
| 90 public void testSubstring_BeginIndex() { | |
| 91 byte[] bytes = getTestBytes(); | |
| 92 ByteString substring = ByteString.copyFrom(bytes).substring(500); | |
| 93 assertTrue("substring must contain the tail of the string", | |
| 94 isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500)); | |
| 95 } | |
| 96 | |
| 97 public void testCopyFrom_BytesOffsetSize() { | |
| 98 byte[] bytes = getTestBytes(); | |
| 99 ByteString byteString = ByteString.copyFrom(bytes, 500, 200); | |
| 100 assertTrue("copyFrom sub-range must contain the expected bytes", | |
| 101 isArrayRange(byteString.toByteArray(), bytes, 500, 200)); | |
| 102 } | |
| 103 | |
| 104 public void testCopyFrom_Bytes() { | |
| 105 byte[] bytes = getTestBytes(); | |
| 106 ByteString byteString = ByteString.copyFrom(bytes); | |
| 107 assertTrue("copyFrom must contain the expected bytes", | |
| 108 isArray(byteString.toByteArray(), bytes)); | |
| 109 } | |
| 110 | |
| 111 public void testCopyFrom_ByteBufferSize() { | |
| 112 byte[] bytes = getTestBytes(); | |
| 113 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length); | |
| 114 byteBuffer.put(bytes); | |
| 115 byteBuffer.position(500); | |
| 116 ByteString byteString = ByteString.copyFrom(byteBuffer, 200); | |
| 117 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes", | |
| 118 isArrayRange(byteString.toByteArray(), bytes, 500, 200)); | |
| 119 } | |
| 120 | |
| 121 public void testCopyFrom_ByteBuffer() { | |
| 122 byte[] bytes = getTestBytes(); | |
| 123 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length); | |
| 124 byteBuffer.put(bytes); | |
| 125 byteBuffer.position(500); | |
| 126 ByteString byteString = ByteString.copyFrom(byteBuffer); | |
| 127 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes", | |
| 128 isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500)); | |
| 129 } | |
| 130 | |
| 131 public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException
{ | |
| 132 String testString = "I love unicode \u1234\u5678 characters"; | |
| 133 ByteString byteString = ByteString.copyFrom(testString, UTF_16); | |
| 134 byte[] testBytes = testString.getBytes(UTF_16); | |
| 135 assertTrue("copyFrom string must respect the charset", | |
| 136 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | |
| 137 } | |
| 138 | |
| 139 public void testCopyFrom_Utf8() throws UnsupportedEncodingException { | |
| 140 String testString = "I love unicode \u1234\u5678 characters"; | |
| 141 ByteString byteString = ByteString.copyFromUtf8(testString); | |
| 142 byte[] testBytes = testString.getBytes("UTF-8"); | |
| 143 assertTrue("copyFromUtf8 string must respect the charset", | |
| 144 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | |
| 145 } | |
| 146 | |
| 147 public void testCopyFrom_Iterable() { | |
| 148 byte[] testBytes = getTestBytes(77777, 113344L); | |
| 149 final List<ByteString> pieces = makeConcretePieces(testBytes); | |
| 150 // Call copyFrom() on a Collection | |
| 151 ByteString byteString = ByteString.copyFrom(pieces); | |
| 152 assertTrue("copyFrom a List must contain the expected bytes", | |
| 153 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | |
| 154 // Call copyFrom on an iteration that's not a collection | |
| 155 ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() { | |
| 156 public Iterator<ByteString> iterator() { | |
| 157 return pieces.iterator(); | |
| 158 } | |
| 159 }); | |
| 160 assertEquals("copyFrom from an Iteration must contain the expected bytes", | |
| 161 byteString, byteStringAlt); | |
| 162 } | |
| 163 | |
| 164 public void testCopyTo_TargetOffset() { | |
| 165 byte[] bytes = getTestBytes(); | |
| 166 ByteString byteString = ByteString.copyFrom(bytes); | |
| 167 byte[] target = new byte[bytes.length + 1000]; | |
| 168 byteString.copyTo(target, 400); | |
| 169 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes", | |
| 170 isArrayRange(bytes, target, 400, bytes.length)); | |
| 171 } | |
| 172 | |
| 173 public void testReadFrom_emptyStream() throws IOException { | |
| 174 ByteString byteString = | |
| 175 ByteString.readFrom(new ByteArrayInputStream(new byte[0])); | |
| 176 assertSame("reading an empty stream must result in the EMPTY constant " | |
| 177 + "byte string", ByteString.EMPTY, byteString); | |
| 178 } | |
| 179 | |
| 180 public void testReadFrom_smallStream() throws IOException { | |
| 181 assertReadFrom(getTestBytes(10)); | |
| 182 } | |
| 183 | |
| 184 public void testReadFrom_mutating() throws IOException { | |
| 185 byte[] capturedArray = null; | |
| 186 EvilInputStream eis = new EvilInputStream(); | |
| 187 ByteString byteString = ByteString.readFrom(eis); | |
| 188 | |
| 189 capturedArray = eis.capturedArray; | |
| 190 byte[] originalValue = byteString.toByteArray(); | |
| 191 for (int x = 0; x < capturedArray.length; ++x) { | |
| 192 capturedArray[x] = (byte) 0; | |
| 193 } | |
| 194 | |
| 195 byte[] newValue = byteString.toByteArray(); | |
| 196 assertTrue("copyFrom byteBuffer must not grant access to underlying array", | |
| 197 Arrays.equals(originalValue, newValue)); | |
| 198 } | |
| 199 | |
| 200 // Tests sizes that are over multi-segment rope threshold. | |
| 201 public void testReadFrom_largeStream() throws IOException { | |
| 202 assertReadFrom(getTestBytes(0x100)); | |
| 203 assertReadFrom(getTestBytes(0x101)); | |
| 204 assertReadFrom(getTestBytes(0x110)); | |
| 205 assertReadFrom(getTestBytes(0x1000)); | |
| 206 assertReadFrom(getTestBytes(0x1001)); | |
| 207 assertReadFrom(getTestBytes(0x1010)); | |
| 208 assertReadFrom(getTestBytes(0x10000)); | |
| 209 assertReadFrom(getTestBytes(0x10001)); | |
| 210 assertReadFrom(getTestBytes(0x10010)); | |
| 211 } | |
| 212 | |
| 213 // Tests that IOExceptions propagate through ByteString.readFrom(). | |
| 214 public void testReadFrom_IOExceptions() { | |
| 215 try { | |
| 216 ByteString.readFrom(new FailStream()); | |
| 217 fail("readFrom must throw the underlying IOException"); | |
| 218 | |
| 219 } catch (IOException e) { | |
| 220 assertEquals("readFrom must throw the expected exception", | |
| 221 "synthetic failure", e.getMessage()); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 // Tests that ByteString.readFrom works with streams that don't | |
| 226 // always fill their buffers. | |
| 227 public void testReadFrom_reluctantStream() throws IOException { | |
| 228 final byte[] data = getTestBytes(0x1000); | |
| 229 | |
| 230 ByteString byteString = ByteString.readFrom(new ReluctantStream(data)); | |
| 231 assertTrue("readFrom byte stream must contain the expected bytes", | |
| 232 isArray(byteString.toByteArray(), data)); | |
| 233 | |
| 234 // Same test as above, but with some specific chunk sizes. | |
| 235 assertReadFromReluctantStream(data, 100); | |
| 236 assertReadFromReluctantStream(data, 248); | |
| 237 assertReadFromReluctantStream(data, 249); | |
| 238 assertReadFromReluctantStream(data, 250); | |
| 239 assertReadFromReluctantStream(data, 251); | |
| 240 assertReadFromReluctantStream(data, 0x1000); | |
| 241 assertReadFromReluctantStream(data, 0x1001); | |
| 242 } | |
| 243 | |
| 244 // Fails unless ByteString.readFrom reads the bytes correctly from a | |
| 245 // reluctant stream with the given chunkSize parameter. | |
| 246 private void assertReadFromReluctantStream(byte[] bytes, int chunkSize) | |
| 247 throws IOException { | |
| 248 ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize); | |
| 249 assertTrue("readFrom byte stream must contain the expected bytes", | |
| 250 isArray(b.toByteArray(), bytes)); | |
| 251 } | |
| 252 | |
| 253 // Tests that ByteString.readFrom works with streams that implement | |
| 254 // available(). | |
| 255 public void testReadFrom_available() throws IOException { | |
| 256 final byte[] data = getTestBytes(0x1001); | |
| 257 | |
| 258 ByteString byteString = ByteString.readFrom(new AvailableStream(data)); | |
| 259 assertTrue("readFrom byte stream must contain the expected bytes", | |
| 260 isArray(byteString.toByteArray(), data)); | |
| 261 } | |
| 262 | |
| 263 // Fails unless ByteString.readFrom reads the bytes correctly. | |
| 264 private void assertReadFrom(byte[] bytes) throws IOException { | |
| 265 ByteString byteString = | |
| 266 ByteString.readFrom(new ByteArrayInputStream(bytes)); | |
| 267 assertTrue("readFrom byte stream must contain the expected bytes", | |
| 268 isArray(byteString.toByteArray(), bytes)); | |
| 269 } | |
| 270 | |
| 271 // A stream that fails when read. | |
| 272 private static final class FailStream extends InputStream { | |
| 273 @Override public int read() throws IOException { | |
| 274 throw new IOException("synthetic failure"); | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 // A stream that simulates blocking by only producing 250 characters | |
| 279 // per call to read(byte[]). | |
| 280 private static class ReluctantStream extends InputStream { | |
| 281 protected final byte[] data; | |
| 282 protected int pos = 0; | |
| 283 | |
| 284 public ReluctantStream(byte[] data) { | |
| 285 this.data = data; | |
| 286 } | |
| 287 | |
| 288 @Override public int read() { | |
| 289 if (pos == data.length) { | |
| 290 return -1; | |
| 291 } else { | |
| 292 return data[pos++]; | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 @Override public int read(byte[] buf) { | |
| 297 return read(buf, 0, buf.length); | |
| 298 } | |
| 299 | |
| 300 @Override public int read(byte[] buf, int offset, int size) { | |
| 301 if (pos == data.length) { | |
| 302 return -1; | |
| 303 } | |
| 304 int count = Math.min(Math.min(size, data.length - pos), 250); | |
| 305 System.arraycopy(data, pos, buf, offset, count); | |
| 306 pos += count; | |
| 307 return count; | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 // Same as above, but also implements available(). | |
| 312 private static final class AvailableStream extends ReluctantStream { | |
| 313 public AvailableStream(byte[] data) { | |
| 314 super(data); | |
| 315 } | |
| 316 | |
| 317 @Override public int available() { | |
| 318 return Math.min(250, data.length - pos); | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 // A stream which exposes the byte array passed into read(byte[], int, int). | |
| 323 private static class EvilInputStream extends InputStream { | |
| 324 public byte[] capturedArray = null; | |
| 325 | |
| 326 @Override | |
| 327 public int read(byte[] buf, int off, int len) { | |
| 328 if (capturedArray != null) { | |
| 329 return -1; | |
| 330 } else { | |
| 331 capturedArray = buf; | |
| 332 for (int x = 0; x < len; ++x) { | |
| 333 buf[x] = (byte) x; | |
| 334 } | |
| 335 return len; | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 @Override | |
| 340 public int read() { | |
| 341 // Purposefully do nothing. | |
| 342 return -1; | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 // A stream which exposes the byte array passed into write(byte[], int, int). | |
| 347 private static class EvilOutputStream extends OutputStream { | |
| 348 public byte[] capturedArray = null; | |
| 349 | |
| 350 @Override | |
| 351 public void write(byte[] buf, int off, int len) { | |
| 352 if (capturedArray == null) { | |
| 353 capturedArray = buf; | |
| 354 } | |
| 355 } | |
| 356 | |
| 357 @Override | |
| 358 public void write(int ignored) { | |
| 359 // Purposefully do nothing. | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 public void testToStringUtf8() throws UnsupportedEncodingException { | |
| 364 String testString = "I love unicode \u1234\u5678 characters"; | |
| 365 byte[] testBytes = testString.getBytes("UTF-8"); | |
| 366 ByteString byteString = ByteString.copyFrom(testBytes); | |
| 367 assertEquals("copyToStringUtf8 must respect the charset", | |
| 368 testString, byteString.toStringUtf8()); | |
| 369 } | |
| 370 | |
| 371 public void testNewOutput_InitialCapacity() throws IOException { | |
| 372 byte[] bytes = getTestBytes(); | |
| 373 ByteString.Output output = ByteString.newOutput(bytes.length + 100); | |
| 374 output.write(bytes); | |
| 375 ByteString byteString = output.toByteString(); | |
| 376 assertTrue( | |
| 377 "String built from newOutput(int) must contain the expected bytes", | |
| 378 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | |
| 379 } | |
| 380 | |
| 381 // Test newOutput() using a variety of buffer sizes and a variety of (fixed) | |
| 382 // write sizes | |
| 383 public void testNewOutput_ArrayWrite() throws IOException { | |
| 384 byte[] bytes = getTestBytes(); | |
| 385 int length = bytes.length; | |
| 386 int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1, | |
| 387 2 * length, 3 * length}; | |
| 388 int[] writeSizes = {1, 4, 5, 7, 23, bytes.length}; | |
| 389 | |
| 390 for (int bufferSize : bufferSizes) { | |
| 391 for (int writeSize : writeSizes) { | |
| 392 // Test writing the entire output writeSize bytes at a time. | |
| 393 ByteString.Output output = ByteString.newOutput(bufferSize); | |
| 394 for (int i = 0; i < length; i += writeSize) { | |
| 395 output.write(bytes, i, Math.min(writeSize, length - i)); | |
| 396 } | |
| 397 ByteString byteString = output.toByteString(); | |
| 398 assertTrue("String built from newOutput() must contain the expected byte
s", | |
| 399 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | |
| 400 } | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 // Test newOutput() using a variety of buffer sizes, but writing all the | |
| 405 // characters using write(byte); | |
| 406 public void testNewOutput_WriteChar() throws IOException { | |
| 407 byte[] bytes = getTestBytes(); | |
| 408 int length = bytes.length; | |
| 409 int[] bufferSizes = {0, 1, 128, 256, length / 2, | |
| 410 length - 1, length, length + 1, | |
| 411 2 * length, 3 * length}; | |
| 412 for (int bufferSize : bufferSizes) { | |
| 413 ByteString.Output output = ByteString.newOutput(bufferSize); | |
| 414 for (byte byteValue : bytes) { | |
| 415 output.write(byteValue); | |
| 416 } | |
| 417 ByteString byteString = output.toByteString(); | |
| 418 assertTrue("String built from newOutput() must contain the expected bytes"
, | |
| 419 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 // Test newOutput() in which we write the bytes using a variety of methods | |
| 424 // and sizes, and in which we repeatedly call toByteString() in the middle. | |
| 425 public void testNewOutput_Mixed() throws IOException { | |
| 426 Random rng = new Random(1); | |
| 427 byte[] bytes = getTestBytes(); | |
| 428 int length = bytes.length; | |
| 429 int[] bufferSizes = {0, 1, 128, 256, length / 2, | |
| 430 length - 1, length, length + 1, | |
| 431 2 * length, 3 * length}; | |
| 432 | |
| 433 for (int bufferSize : bufferSizes) { | |
| 434 // Test writing the entire output using a mixture of write sizes and | |
| 435 // methods; | |
| 436 ByteString.Output output = ByteString.newOutput(bufferSize); | |
| 437 int position = 0; | |
| 438 while (position < bytes.length) { | |
| 439 if (rng.nextBoolean()) { | |
| 440 int count = 1 + rng.nextInt(bytes.length - position); | |
| 441 output.write(bytes, position, count); | |
| 442 position += count; | |
| 443 } else { | |
| 444 output.write(bytes[position]); | |
| 445 position++; | |
| 446 } | |
| 447 assertEquals("size() returns the right value", position, output.size()); | |
| 448 assertTrue("newOutput() substring must have correct bytes", | |
| 449 isArrayRange(output.toByteString().toByteArray(), | |
| 450 bytes, 0, position)); | |
| 451 } | |
| 452 ByteString byteString = output.toByteString(); | |
| 453 assertTrue("String built from newOutput() must contain the expected bytes"
, | |
| 454 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 public void testNewOutputEmpty() throws IOException { | |
| 459 // Make sure newOutput() correctly builds empty byte strings | |
| 460 ByteString byteString = ByteString.newOutput().toByteString(); | |
| 461 assertEquals(ByteString.EMPTY, byteString); | |
| 462 } | |
| 463 | |
| 464 public void testNewOutput_Mutating() throws IOException { | |
| 465 Output os = ByteString.newOutput(5); | |
| 466 os.write(new byte[] {1, 2, 3, 4, 5}); | |
| 467 EvilOutputStream eos = new EvilOutputStream(); | |
| 468 os.writeTo(eos); | |
| 469 byte[] capturedArray = eos.capturedArray; | |
| 470 ByteString byteString = os.toByteString(); | |
| 471 byte[] oldValue = byteString.toByteArray(); | |
| 472 Arrays.fill(capturedArray, (byte) 0); | |
| 473 byte[] newValue = byteString.toByteArray(); | |
| 474 assertTrue("Output must not provide access to the underlying byte array", | |
| 475 Arrays.equals(oldValue, newValue)); | |
| 476 } | |
| 477 | |
| 478 public void testSubstringParity() { | |
| 479 byte[] bigBytes = getTestBytes(2048 * 1024, 113344L); | |
| 480 int start = 512 * 1024 - 3333; | |
| 481 int end = 512 * 1024 + 7777; | |
| 482 ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start
, end); | |
| 483 boolean ok = true; | |
| 484 for (int i = start; ok && i < end; ++i) { | |
| 485 ok = (bigBytes[i] == concreteSubstring.byteAt(i - start)); | |
| 486 } | |
| 487 assertTrue("Concrete substring didn't capture the right bytes", ok); | |
| 488 | |
| 489 ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start)
; | |
| 490 assertTrue("Substring must be equal to literal string", | |
| 491 concreteSubstring.equals(literalString)); | |
| 492 assertEquals("Substring must have same hashcode as literal string", | |
| 493 literalString.hashCode(), concreteSubstring.hashCode()); | |
| 494 } | |
| 495 | |
| 496 public void testCompositeSubstring() { | |
| 497 byte[] referenceBytes = getTestBytes(77748, 113344L); | |
| 498 | |
| 499 List<ByteString> pieces = makeConcretePieces(referenceBytes); | |
| 500 ByteString listString = ByteString.copyFrom(pieces); | |
| 501 | |
| 502 int from = 1000; | |
| 503 int to = 40000; | |
| 504 ByteString compositeSubstring = listString.substring(from, to); | |
| 505 byte[] substringBytes = compositeSubstring.toByteArray(); | |
| 506 boolean stillEqual = true; | |
| 507 for (int i = 0; stillEqual && i < to - from; ++i) { | |
| 508 stillEqual = referenceBytes[from + i] == substringBytes[i]; | |
| 509 } | |
| 510 assertTrue("Substring must return correct bytes", stillEqual); | |
| 511 | |
| 512 stillEqual = true; | |
| 513 for (int i = 0; stillEqual && i < to - from; ++i) { | |
| 514 stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i); | |
| 515 } | |
| 516 assertTrue("Substring must support byteAt() correctly", stillEqual); | |
| 517 | |
| 518 ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to -
from); | |
| 519 assertTrue("Composite substring must equal a literal substring over the same
bytes", | |
| 520 compositeSubstring.equals(literalSubstring)); | |
| 521 assertTrue("Literal substring must equal a composite substring over the same
bytes", | |
| 522 literalSubstring.equals(compositeSubstring)); | |
| 523 | |
| 524 assertEquals("We must get the same hashcodes for composite and literal subst
rings", | |
| 525 literalSubstring.hashCode(), compositeSubstring.hashCode()); | |
| 526 | |
| 527 assertFalse("We can't be equal to a proper substring", | |
| 528 compositeSubstring.equals(literalSubstring.substring(0, literalSubstring
.size() - 1))); | |
| 529 } | |
| 530 | |
| 531 public void testCopyFromList() { | |
| 532 byte[] referenceBytes = getTestBytes(77748, 113344L); | |
| 533 ByteString literalString = ByteString.copyFrom(referenceBytes); | |
| 534 | |
| 535 List<ByteString> pieces = makeConcretePieces(referenceBytes); | |
| 536 ByteString listString = ByteString.copyFrom(pieces); | |
| 537 | |
| 538 assertTrue("Composite string must be equal to literal string", | |
| 539 listString.equals(literalString)); | |
| 540 assertEquals("Composite string must have same hashcode as literal string", | |
| 541 literalString.hashCode(), listString.hashCode()); | |
| 542 } | |
| 543 | |
| 544 public void testConcat() { | |
| 545 byte[] referenceBytes = getTestBytes(77748, 113344L); | |
| 546 ByteString literalString = ByteString.copyFrom(referenceBytes); | |
| 547 | |
| 548 List<ByteString> pieces = makeConcretePieces(referenceBytes); | |
| 549 | |
| 550 Iterator<ByteString> iter = pieces.iterator(); | |
| 551 ByteString concatenatedString = iter.next(); | |
| 552 while (iter.hasNext()) { | |
| 553 concatenatedString = concatenatedString.concat(iter.next()); | |
| 554 } | |
| 555 | |
| 556 assertTrue("Concatenated string must be equal to literal string", | |
| 557 concatenatedString.equals(literalString)); | |
| 558 assertEquals("Concatenated string must have same hashcode as literal string"
, | |
| 559 literalString.hashCode(), concatenatedString.hashCode()); | |
| 560 } | |
| 561 | |
| 562 public void testStartsWith() { | |
| 563 byte[] bytes = getTestBytes(1000, 1234L); | |
| 564 ByteString string = ByteString.copyFrom(bytes); | |
| 565 ByteString prefix = ByteString.copyFrom(bytes, 0, 500); | |
| 566 ByteString suffix = ByteString.copyFrom(bytes, 400, 600); | |
| 567 assertTrue(string.startsWith(ByteString.EMPTY)); | |
| 568 assertTrue(string.startsWith(string)); | |
| 569 assertTrue(string.startsWith(prefix)); | |
| 570 assertFalse(string.startsWith(suffix)); | |
| 571 assertFalse(prefix.startsWith(suffix)); | |
| 572 assertFalse(suffix.startsWith(prefix)); | |
| 573 assertFalse(ByteString.EMPTY.startsWith(prefix)); | |
| 574 assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY)); | |
| 575 } | |
| 576 | |
| 577 static List<ByteString> makeConcretePieces(byte[] referenceBytes) { | |
| 578 List<ByteString> pieces = new ArrayList<ByteString>(); | |
| 579 // Starting length should be small enough that we'll do some concatenating b
y | |
| 580 // copying if we just concatenate all these pieces together. | |
| 581 for (int start = 0, length = 16; start < referenceBytes.length; start += len
gth) { | |
| 582 length = (length << 1) - 1; | |
| 583 if (start + length > referenceBytes.length) { | |
| 584 length = referenceBytes.length - start; | |
| 585 } | |
| 586 pieces.add(ByteString.copyFrom(referenceBytes, start, length)); | |
| 587 } | |
| 588 return pieces; | |
| 589 } | |
| 590 } | |
| OLD | NEW |