OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // http://code.google.com/p/protobuf/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
11 // * Redistributions in binary form must reproduce the above | 11 // * Redistributions in binary form must reproduce the above |
12 // copyright notice, this list of conditions and the following disclaimer | 12 // copyright notice, this list of conditions and the following disclaimer |
13 // in the documentation and/or other materials provided with the | 13 // in the documentation and/or other materials provided with the |
14 // distribution. | 14 // distribution. |
15 // * Neither the name of Google Inc. nor the names of its | 15 // * Neither the name of Google Inc. nor the names of its |
16 // contributors may be used to endorse or promote products derived from | 16 // contributors may be used to endorse or promote products derived from |
17 // this software without specific prior written permission. | 17 // this software without specific prior written permission. |
18 // | 18 // |
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 package com.google.protobuf; | 31 package com.google.protobuf.test; |
| 32 import com.google.protobuf.*; |
32 | 33 |
33 import com.google.protobuf.ByteString.Output; | 34 import com.google.protobuf.ByteString.Output; |
34 | 35 |
35 import junit.framework.TestCase; | 36 import junit.framework.TestCase; |
36 | 37 |
37 import java.io.ByteArrayInputStream; | 38 import java.io.ByteArrayInputStream; |
38 import java.io.ByteArrayOutputStream; | |
39 import java.io.IOException; | 39 import java.io.IOException; |
40 import java.io.InputStream; | 40 import java.io.InputStream; |
41 import java.io.OutputStream; | 41 import java.io.OutputStream; |
42 import java.lang.reflect.Field; | 42 import java.io.UnsupportedEncodingException; |
43 import java.nio.ByteBuffer; | 43 import java.nio.ByteBuffer; |
44 import java.nio.charset.Charset; | |
45 import java.util.ArrayList; | 44 import java.util.ArrayList; |
46 import java.util.Arrays; | 45 import java.util.Arrays; |
47 import java.util.Iterator; | 46 import java.util.Iterator; |
48 import java.util.List; | 47 import java.util.List; |
49 import java.util.NoSuchElementException; | 48 import java.util.NoSuchElementException; |
50 import java.util.Random; | 49 import java.util.Random; |
51 | 50 |
52 /** | 51 /** |
53 * Test methods with implementations in {@link ByteString}, plus do some top-lev
el "integration" | 52 * Test methods with implementations in {@link ByteString}, plus do some top-lev
el "integration" |
54 * tests. | 53 * tests. |
55 * | 54 * |
56 * @author carlanton@google.com (Carl Haverl) | 55 * @author carlanton@google.com (Carl Haverl) |
57 */ | 56 */ |
58 public class ByteStringTest extends TestCase { | 57 public class ByteStringTest extends TestCase { |
59 | 58 |
60 private static final Charset UTF_16 = Charset.forName("UTF-16"); | 59 private static final String UTF_16 = "UTF-16"; |
61 | 60 |
62 static byte[] getTestBytes(int size, long seed) { | 61 static byte[] getTestBytes(int size, long seed) { |
63 Random random = new Random(seed); | 62 Random random = new Random(seed); |
64 byte[] result = new byte[size]; | 63 byte[] result = new byte[size]; |
65 random.nextBytes(result); | 64 random.nextBytes(result); |
66 return result; | 65 return result; |
67 } | 66 } |
68 | 67 |
69 private byte[] getTestBytes(int size) { | 68 private byte[] getTestBytes(int size) { |
70 return getTestBytes(size, 445566L); | 69 return getTestBytes(size, 445566L); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 public void testCopyFrom_ByteBuffer() { | 121 public void testCopyFrom_ByteBuffer() { |
123 byte[] bytes = getTestBytes(); | 122 byte[] bytes = getTestBytes(); |
124 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length); | 123 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length); |
125 byteBuffer.put(bytes); | 124 byteBuffer.put(bytes); |
126 byteBuffer.position(500); | 125 byteBuffer.position(500); |
127 ByteString byteString = ByteString.copyFrom(byteBuffer); | 126 ByteString byteString = ByteString.copyFrom(byteBuffer); |
128 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes", | 127 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes", |
129 isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500)); | 128 isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500)); |
130 } | 129 } |
131 | 130 |
132 public void testCopyFrom_StringEncoding() { | 131 public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException
{ |
133 String testString = "I love unicode \u1234\u5678 characters"; | 132 String testString = "I love unicode \u1234\u5678 characters"; |
134 ByteString byteString = ByteString.copyFrom(testString, UTF_16); | 133 ByteString byteString = ByteString.copyFrom(testString, UTF_16); |
135 byte[] testBytes = testString.getBytes(UTF_16); | 134 byte[] testBytes = testString.getBytes(UTF_16); |
136 assertTrue("copyFrom string must respect the charset", | 135 assertTrue("copyFrom string must respect the charset", |
137 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | 136 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); |
138 } | 137 } |
139 | 138 |
140 public void testCopyFrom_Utf8() { | 139 public void testCopyFrom_Utf8() throws UnsupportedEncodingException { |
141 String testString = "I love unicode \u1234\u5678 characters"; | 140 String testString = "I love unicode \u1234\u5678 characters"; |
142 ByteString byteString = ByteString.copyFromUtf8(testString); | 141 ByteString byteString = ByteString.copyFromUtf8(testString); |
143 byte[] testBytes = testString.getBytes(Internal.UTF_8); | 142 byte[] testBytes = testString.getBytes("UTF-8"); |
144 assertTrue("copyFromUtf8 string must respect the charset", | 143 assertTrue("copyFromUtf8 string must respect the charset", |
145 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | 144 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); |
146 } | 145 } |
147 | 146 |
148 public void testCopyFrom_Iterable() { | 147 public void testCopyFrom_Iterable() { |
149 byte[] testBytes = getTestBytes(77777, 113344L); | 148 byte[] testBytes = getTestBytes(77777, 113344L); |
150 final List<ByteString> pieces = makeConcretePieces(testBytes); | 149 final List<ByteString> pieces = makeConcretePieces(testBytes); |
151 // Call copyFrom() on a Collection | 150 // Call copyFrom() on a Collection |
152 ByteString byteString = ByteString.copyFrom(pieces); | 151 ByteString byteString = ByteString.copyFrom(pieces); |
153 assertTrue("copyFrom a List must contain the expected bytes", | 152 assertTrue("copyFrom a List must contain the expected bytes", |
154 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); | 153 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length)); |
155 // Call copyFrom on an iteration that's not a collection | 154 // Call copyFrom on an iteration that's not a collection |
156 ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() { | 155 ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() { |
157 @Override | |
158 public Iterator<ByteString> iterator() { | 156 public Iterator<ByteString> iterator() { |
159 return pieces.iterator(); | 157 return pieces.iterator(); |
160 } | 158 } |
161 }); | 159 }); |
162 assertEquals("copyFrom from an Iteration must contain the expected bytes", | 160 assertEquals("copyFrom from an Iteration must contain the expected bytes", |
163 byteString, byteStringAlt); | 161 byteString, byteStringAlt); |
164 } | 162 } |
165 | 163 |
166 public void testCopyTo_TargetOffset() { | 164 public void testCopyTo_TargetOffset() { |
167 byte[] bytes = getTestBytes(); | 165 byte[] bytes = getTestBytes(); |
(...skipping 24 matching lines...) Expand all Loading... |
192 byte[] originalValue = byteString.toByteArray(); | 190 byte[] originalValue = byteString.toByteArray(); |
193 for (int x = 0; x < capturedArray.length; ++x) { | 191 for (int x = 0; x < capturedArray.length; ++x) { |
194 capturedArray[x] = (byte) 0; | 192 capturedArray[x] = (byte) 0; |
195 } | 193 } |
196 | 194 |
197 byte[] newValue = byteString.toByteArray(); | 195 byte[] newValue = byteString.toByteArray(); |
198 assertTrue("copyFrom byteBuffer must not grant access to underlying array", | 196 assertTrue("copyFrom byteBuffer must not grant access to underlying array", |
199 Arrays.equals(originalValue, newValue)); | 197 Arrays.equals(originalValue, newValue)); |
200 } | 198 } |
201 | 199 |
202 // Tests sizes that are near the rope copy-out threshold. | |
203 public void testReadFrom_mediumStream() throws IOException { | |
204 assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1)); | |
205 assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE)); | |
206 assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1)); | |
207 assertReadFrom(getTestBytes(200)); | |
208 } | |
209 | |
210 // Tests sizes that are over multi-segment rope threshold. | 200 // Tests sizes that are over multi-segment rope threshold. |
211 public void testReadFrom_largeStream() throws IOException { | 201 public void testReadFrom_largeStream() throws IOException { |
212 assertReadFrom(getTestBytes(0x100)); | 202 assertReadFrom(getTestBytes(0x100)); |
213 assertReadFrom(getTestBytes(0x101)); | 203 assertReadFrom(getTestBytes(0x101)); |
214 assertReadFrom(getTestBytes(0x110)); | 204 assertReadFrom(getTestBytes(0x110)); |
215 assertReadFrom(getTestBytes(0x1000)); | 205 assertReadFrom(getTestBytes(0x1000)); |
216 assertReadFrom(getTestBytes(0x1001)); | 206 assertReadFrom(getTestBytes(0x1001)); |
217 assertReadFrom(getTestBytes(0x1010)); | 207 assertReadFrom(getTestBytes(0x1010)); |
218 assertReadFrom(getTestBytes(0x10000)); | 208 assertReadFrom(getTestBytes(0x10000)); |
219 assertReadFrom(getTestBytes(0x10001)); | 209 assertReadFrom(getTestBytes(0x10001)); |
220 assertReadFrom(getTestBytes(0x10010)); | 210 assertReadFrom(getTestBytes(0x10010)); |
221 } | 211 } |
222 | 212 |
223 // Tests sizes that are near the read buffer size. | |
224 public void testReadFrom_byteBoundaries() throws IOException { | |
225 final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE; | |
226 final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE; | |
227 | |
228 assertReadFrom(getTestBytes(min - 1)); | |
229 assertReadFrom(getTestBytes(min)); | |
230 assertReadFrom(getTestBytes(min + 1)); | |
231 | |
232 assertReadFrom(getTestBytes(min * 2 - 1)); | |
233 assertReadFrom(getTestBytes(min * 2)); | |
234 assertReadFrom(getTestBytes(min * 2 + 1)); | |
235 | |
236 assertReadFrom(getTestBytes(min * 4 - 1)); | |
237 assertReadFrom(getTestBytes(min * 4)); | |
238 assertReadFrom(getTestBytes(min * 4 + 1)); | |
239 | |
240 assertReadFrom(getTestBytes(min * 8 - 1)); | |
241 assertReadFrom(getTestBytes(min * 8)); | |
242 assertReadFrom(getTestBytes(min * 8 + 1)); | |
243 | |
244 assertReadFrom(getTestBytes(max - 1)); | |
245 assertReadFrom(getTestBytes(max)); | |
246 assertReadFrom(getTestBytes(max + 1)); | |
247 | |
248 assertReadFrom(getTestBytes(max * 2 - 1)); | |
249 assertReadFrom(getTestBytes(max * 2)); | |
250 assertReadFrom(getTestBytes(max * 2 + 1)); | |
251 } | |
252 | |
253 // Tests that IOExceptions propagate through ByteString.readFrom(). | 213 // Tests that IOExceptions propagate through ByteString.readFrom(). |
254 public void testReadFrom_IOExceptions() { | 214 public void testReadFrom_IOExceptions() { |
255 try { | 215 try { |
256 ByteString.readFrom(new FailStream()); | 216 ByteString.readFrom(new FailStream()); |
257 fail("readFrom must throw the underlying IOException"); | 217 fail("readFrom must throw the underlying IOException"); |
258 | 218 |
259 } catch (IOException e) { | 219 } catch (IOException e) { |
260 assertEquals("readFrom must throw the expected exception", | 220 assertEquals("readFrom must throw the expected exception", |
261 "synthetic failure", e.getMessage()); | 221 "synthetic failure", e.getMessage()); |
262 } | 222 } |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 return len; | 335 return len; |
376 } | 336 } |
377 } | 337 } |
378 | 338 |
379 @Override | 339 @Override |
380 public int read() { | 340 public int read() { |
381 // Purposefully do nothing. | 341 // Purposefully do nothing. |
382 return -1; | 342 return -1; |
383 } | 343 } |
384 } | 344 } |
385 | 345 |
386 // A stream which exposes the byte array passed into write(byte[], int, int). | 346 // A stream which exposes the byte array passed into write(byte[], int, int). |
387 private static class EvilOutputStream extends OutputStream { | 347 private static class EvilOutputStream extends OutputStream { |
388 public byte[] capturedArray = null; | 348 public byte[] capturedArray = null; |
389 | 349 |
390 @Override | 350 @Override |
391 public void write(byte[] buf, int off, int len) { | 351 public void write(byte[] buf, int off, int len) { |
392 if (capturedArray == null) { | 352 if (capturedArray == null) { |
393 capturedArray = buf; | 353 capturedArray = buf; |
394 } | 354 } |
395 } | 355 } |
396 | 356 |
397 @Override | 357 @Override |
398 public void write(int ignored) { | 358 public void write(int ignored) { |
399 // Purposefully do nothing. | 359 // Purposefully do nothing. |
400 } | 360 } |
401 } | 361 } |
402 | 362 |
403 public void testToStringUtf8() { | 363 public void testToStringUtf8() throws UnsupportedEncodingException { |
404 String testString = "I love unicode \u1234\u5678 characters"; | 364 String testString = "I love unicode \u1234\u5678 characters"; |
405 byte[] testBytes = testString.getBytes(Internal.UTF_8); | 365 byte[] testBytes = testString.getBytes("UTF-8"); |
406 ByteString byteString = ByteString.copyFrom(testBytes); | 366 ByteString byteString = ByteString.copyFrom(testBytes); |
407 assertEquals("copyToStringUtf8 must respect the charset", | 367 assertEquals("copyToStringUtf8 must respect the charset", |
408 testString, byteString.toStringUtf8()); | 368 testString, byteString.toStringUtf8()); |
409 } | 369 } |
410 | 370 |
411 public void testNewOutput_InitialCapacity() throws IOException { | 371 public void testNewOutput_InitialCapacity() throws IOException { |
412 byte[] bytes = getTestBytes(); | 372 byte[] bytes = getTestBytes(); |
413 ByteString.Output output = ByteString.newOutput(bytes.length + 100); | 373 ByteString.Output output = ByteString.newOutput(bytes.length + 100); |
414 output.write(bytes); | 374 output.write(bytes); |
415 ByteString byteString = output.toByteString(); | 375 ByteString byteString = output.toByteString(); |
416 assertTrue( | 376 assertTrue( |
417 "String built from newOutput(int) must contain the expected bytes", | 377 "String built from newOutput(int) must contain the expected bytes", |
418 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | 378 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); |
419 } | 379 } |
420 | 380 |
421 // Test newOutput() using a variety of buffer sizes and a variety of (fixed) | 381 // Test newOutput() using a variety of buffer sizes and a variety of (fixed) |
422 // write sizes | 382 // write sizes |
423 public void testNewOutput_ArrayWrite() { | 383 public void testNewOutput_ArrayWrite() throws IOException { |
424 byte[] bytes = getTestBytes(); | 384 byte[] bytes = getTestBytes(); |
425 int length = bytes.length; | 385 int length = bytes.length; |
426 int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1, | 386 int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1, |
427 2 * length, 3 * length}; | 387 2 * length, 3 * length}; |
428 int[] writeSizes = {1, 4, 5, 7, 23, bytes.length}; | 388 int[] writeSizes = {1, 4, 5, 7, 23, bytes.length}; |
429 | 389 |
430 for (int bufferSize : bufferSizes) { | 390 for (int bufferSize : bufferSizes) { |
431 for (int writeSize : writeSizes) { | 391 for (int writeSize : writeSizes) { |
432 // Test writing the entire output writeSize bytes at a time. | 392 // Test writing the entire output writeSize bytes at a time. |
433 ByteString.Output output = ByteString.newOutput(bufferSize); | 393 ByteString.Output output = ByteString.newOutput(bufferSize); |
434 for (int i = 0; i < length; i += writeSize) { | 394 for (int i = 0; i < length; i += writeSize) { |
435 output.write(bytes, i, Math.min(writeSize, length - i)); | 395 output.write(bytes, i, Math.min(writeSize, length - i)); |
436 } | 396 } |
437 ByteString byteString = output.toByteString(); | 397 ByteString byteString = output.toByteString(); |
438 assertTrue("String built from newOutput() must contain the expected byte
s", | 398 assertTrue("String built from newOutput() must contain the expected byte
s", |
439 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | 399 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); |
440 } | 400 } |
441 } | 401 } |
442 } | 402 } |
443 | 403 |
444 // Test newOutput() using a variety of buffer sizes, but writing all the | 404 // Test newOutput() using a variety of buffer sizes, but writing all the |
445 // characters using write(byte); | 405 // characters using write(byte); |
446 public void testNewOutput_WriteChar() { | 406 public void testNewOutput_WriteChar() throws IOException { |
447 byte[] bytes = getTestBytes(); | 407 byte[] bytes = getTestBytes(); |
448 int length = bytes.length; | 408 int length = bytes.length; |
449 int[] bufferSizes = {0, 1, 128, 256, length / 2, | 409 int[] bufferSizes = {0, 1, 128, 256, length / 2, |
450 length - 1, length, length + 1, | 410 length - 1, length, length + 1, |
451 2 * length, 3 * length}; | 411 2 * length, 3 * length}; |
452 for (int bufferSize : bufferSizes) { | 412 for (int bufferSize : bufferSizes) { |
453 ByteString.Output output = ByteString.newOutput(bufferSize); | 413 ByteString.Output output = ByteString.newOutput(bufferSize); |
454 for (byte byteValue : bytes) { | 414 for (byte byteValue : bytes) { |
455 output.write(byteValue); | 415 output.write(byteValue); |
456 } | 416 } |
457 ByteString byteString = output.toByteString(); | 417 ByteString byteString = output.toByteString(); |
458 assertTrue("String built from newOutput() must contain the expected bytes"
, | 418 assertTrue("String built from newOutput() must contain the expected bytes"
, |
459 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | 419 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); |
460 } | 420 } |
461 } | 421 } |
462 | 422 |
463 // Test newOutput() in which we write the bytes using a variety of methods | 423 // Test newOutput() in which we write the bytes using a variety of methods |
464 // and sizes, and in which we repeatedly call toByteString() in the middle. | 424 // and sizes, and in which we repeatedly call toByteString() in the middle. |
465 public void testNewOutput_Mixed() { | 425 public void testNewOutput_Mixed() throws IOException { |
466 Random rng = new Random(1); | 426 Random rng = new Random(1); |
467 byte[] bytes = getTestBytes(); | 427 byte[] bytes = getTestBytes(); |
468 int length = bytes.length; | 428 int length = bytes.length; |
469 int[] bufferSizes = {0, 1, 128, 256, length / 2, | 429 int[] bufferSizes = {0, 1, 128, 256, length / 2, |
470 length - 1, length, length + 1, | 430 length - 1, length, length + 1, |
471 2 * length, 3 * length}; | 431 2 * length, 3 * length}; |
472 | 432 |
473 for (int bufferSize : bufferSizes) { | 433 for (int bufferSize : bufferSizes) { |
474 // Test writing the entire output using a mixture of write sizes and | 434 // Test writing the entire output using a mixture of write sizes and |
475 // methods; | 435 // methods; |
(...skipping 11 matching lines...) Expand all Loading... |
487 assertEquals("size() returns the right value", position, output.size()); | 447 assertEquals("size() returns the right value", position, output.size()); |
488 assertTrue("newOutput() substring must have correct bytes", | 448 assertTrue("newOutput() substring must have correct bytes", |
489 isArrayRange(output.toByteString().toByteArray(), | 449 isArrayRange(output.toByteString().toByteArray(), |
490 bytes, 0, position)); | 450 bytes, 0, position)); |
491 } | 451 } |
492 ByteString byteString = output.toByteString(); | 452 ByteString byteString = output.toByteString(); |
493 assertTrue("String built from newOutput() must contain the expected bytes"
, | 453 assertTrue("String built from newOutput() must contain the expected bytes"
, |
494 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | 454 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); |
495 } | 455 } |
496 } | 456 } |
497 | 457 |
498 public void testNewOutputEmpty() { | 458 public void testNewOutputEmpty() throws IOException { |
499 // Make sure newOutput() correctly builds empty byte strings | 459 // Make sure newOutput() correctly builds empty byte strings |
500 ByteString byteString = ByteString.newOutput().toByteString(); | 460 ByteString byteString = ByteString.newOutput().toByteString(); |
501 assertEquals(ByteString.EMPTY, byteString); | 461 assertEquals(ByteString.EMPTY, byteString); |
502 } | 462 } |
503 | 463 |
504 public void testNewOutput_Mutating() throws IOException { | 464 public void testNewOutput_Mutating() throws IOException { |
505 Output os = ByteString.newOutput(5); | 465 Output os = ByteString.newOutput(5); |
506 os.write(new byte[] {1, 2, 3, 4, 5}); | 466 os.write(new byte[] {1, 2, 3, 4, 5}); |
507 EvilOutputStream eos = new EvilOutputStream(); | 467 EvilOutputStream eos = new EvilOutputStream(); |
508 os.writeTo(eos); | 468 os.writeTo(eos); |
509 byte[] capturedArray = eos.capturedArray; | 469 byte[] capturedArray = eos.capturedArray; |
510 ByteString byteString = os.toByteString(); | 470 ByteString byteString = os.toByteString(); |
511 byte[] oldValue = byteString.toByteArray(); | 471 byte[] oldValue = byteString.toByteArray(); |
512 Arrays.fill(capturedArray, (byte) 0); | 472 Arrays.fill(capturedArray, (byte) 0); |
513 byte[] newValue = byteString.toByteArray(); | 473 byte[] newValue = byteString.toByteArray(); |
514 assertTrue("Output must not provide access to the underlying byte array", | 474 assertTrue("Output must not provide access to the underlying byte array", |
515 Arrays.equals(oldValue, newValue)); | 475 Arrays.equals(oldValue, newValue)); |
516 } | 476 } |
517 | 477 |
518 public void testNewCodedBuilder() throws IOException { | |
519 byte[] bytes = getTestBytes(); | |
520 ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length); | |
521 builder.getCodedOutput().writeRawBytes(bytes); | |
522 ByteString byteString = builder.build(); | |
523 assertTrue("String built from newCodedBuilder() must contain the expected by
tes", | |
524 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length)); | |
525 } | |
526 | |
527 public void testSubstringParity() { | 478 public void testSubstringParity() { |
528 byte[] bigBytes = getTestBytes(2048 * 1024, 113344L); | 479 byte[] bigBytes = getTestBytes(2048 * 1024, 113344L); |
529 int start = 512 * 1024 - 3333; | 480 int start = 512 * 1024 - 3333; |
530 int end = 512 * 1024 + 7777; | 481 int end = 512 * 1024 + 7777; |
531 ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start
, end); | 482 ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start
, end); |
532 boolean ok = true; | 483 boolean ok = true; |
533 for (int i = start; ok && i < end; ++i) { | 484 for (int i = start; ok && i < end; ++i) { |
534 ok = (bigBytes[i] == concreteSubstring.byteAt(i - start)); | 485 ok = (bigBytes[i] == concreteSubstring.byteAt(i - start)); |
535 } | 486 } |
536 assertTrue("Concrete substring didn't capture the right bytes", ok); | 487 assertTrue("Concrete substring didn't capture the right bytes", ok); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 while (iter.hasNext()) { | 552 while (iter.hasNext()) { |
602 concatenatedString = concatenatedString.concat(iter.next()); | 553 concatenatedString = concatenatedString.concat(iter.next()); |
603 } | 554 } |
604 | 555 |
605 assertTrue("Concatenated string must be equal to literal string", | 556 assertTrue("Concatenated string must be equal to literal string", |
606 concatenatedString.equals(literalString)); | 557 concatenatedString.equals(literalString)); |
607 assertEquals("Concatenated string must have same hashcode as literal string"
, | 558 assertEquals("Concatenated string must have same hashcode as literal string"
, |
608 literalString.hashCode(), concatenatedString.hashCode()); | 559 literalString.hashCode(), concatenatedString.hashCode()); |
609 } | 560 } |
610 | 561 |
611 /** | |
612 * Test the Rope implementation can deal with Empty nodes, even though we | |
613 * guard against them. See also {@link LiteralByteStringTest#testConcat_empty(
)}. | |
614 */ | |
615 public void testConcat_empty() { | |
616 byte[] referenceBytes = getTestBytes(7748, 113344L); | |
617 ByteString literalString = ByteString.copyFrom(referenceBytes); | |
618 | |
619 ByteString duo = RopeByteString.newInstanceForTest(literalString, literalStr
ing); | |
620 ByteString temp = RopeByteString.newInstanceForTest( | |
621 RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY), | |
622 RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString)); | |
623 ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPT
Y); | |
624 | |
625 assertTrue("String with concatenated nulls must equal simple concatenate", | |
626 duo.equals(quintet)); | |
627 assertEquals("String with concatenated nulls have same hashcode as simple co
ncatenate", | |
628 duo.hashCode(), quintet.hashCode()); | |
629 | |
630 ByteString.ByteIterator duoIter = duo.iterator(); | |
631 ByteString.ByteIterator quintetIter = quintet.iterator(); | |
632 boolean stillEqual = true; | |
633 while (stillEqual && quintetIter.hasNext()) { | |
634 stillEqual = (duoIter.nextByte() == quintetIter.nextByte()); | |
635 } | |
636 assertTrue("We must get the same characters by iterating", stillEqual); | |
637 assertFalse("Iterator must be exhausted", duoIter.hasNext()); | |
638 try { | |
639 duoIter.nextByte(); | |
640 fail("Should have thrown an exception."); | |
641 } catch (NoSuchElementException e) { | |
642 // This is success | |
643 } | |
644 try { | |
645 quintetIter.nextByte(); | |
646 fail("Should have thrown an exception."); | |
647 } catch (NoSuchElementException e) { | |
648 // This is success | |
649 } | |
650 | |
651 // Test that even if we force empty strings in as rope leaves in this | |
652 // configuration, we always get a (possibly Bounded) LiteralByteString | |
653 // for a length 1 substring. | |
654 // | |
655 // It is possible, using the testing factory method to create deeply nested | |
656 // trees of empty leaves, to make a string that will fail this test. | |
657 for (int i = 1; i < duo.size(); ++i) { | |
658 assertTrue("Substrings of size() < 2 must not be RopeByteStrings", | |
659 duo.substring(i - 1, i) instanceof ByteString.LeafByteString); | |
660 } | |
661 for (int i = 1; i < quintet.size(); ++i) { | |
662 assertTrue("Substrings of size() < 2 must not be RopeByteStrings", | |
663 quintet.substring(i - 1, i) instanceof ByteString.LeafByteString); | |
664 } | |
665 } | |
666 | |
667 public void testStartsWith() { | 562 public void testStartsWith() { |
668 byte[] bytes = getTestBytes(1000, 1234L); | 563 byte[] bytes = getTestBytes(1000, 1234L); |
669 ByteString string = ByteString.copyFrom(bytes); | 564 ByteString string = ByteString.copyFrom(bytes); |
670 ByteString prefix = ByteString.copyFrom(bytes, 0, 500); | 565 ByteString prefix = ByteString.copyFrom(bytes, 0, 500); |
671 ByteString suffix = ByteString.copyFrom(bytes, 400, 600); | 566 ByteString suffix = ByteString.copyFrom(bytes, 400, 600); |
672 assertTrue(string.startsWith(ByteString.EMPTY)); | 567 assertTrue(string.startsWith(ByteString.EMPTY)); |
673 assertTrue(string.startsWith(string)); | 568 assertTrue(string.startsWith(string)); |
674 assertTrue(string.startsWith(prefix)); | 569 assertTrue(string.startsWith(prefix)); |
675 assertFalse(string.startsWith(suffix)); | 570 assertFalse(string.startsWith(suffix)); |
676 assertFalse(prefix.startsWith(suffix)); | 571 assertFalse(prefix.startsWith(suffix)); |
677 assertFalse(suffix.startsWith(prefix)); | 572 assertFalse(suffix.startsWith(prefix)); |
678 assertFalse(ByteString.EMPTY.startsWith(prefix)); | 573 assertFalse(ByteString.EMPTY.startsWith(prefix)); |
679 assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY)); | 574 assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY)); |
680 } | 575 } |
681 | 576 |
682 public void testEndsWith() { | |
683 byte[] bytes = getTestBytes(1000, 1234L); | |
684 ByteString string = ByteString.copyFrom(bytes); | |
685 ByteString prefix = ByteString.copyFrom(bytes, 0, 500); | |
686 ByteString suffix = ByteString.copyFrom(bytes, 400, 600); | |
687 assertTrue(string.endsWith(ByteString.EMPTY)); | |
688 assertTrue(string.endsWith(string)); | |
689 assertTrue(string.endsWith(suffix)); | |
690 assertFalse(string.endsWith(prefix)); | |
691 assertFalse(suffix.endsWith(prefix)); | |
692 assertFalse(prefix.endsWith(suffix)); | |
693 assertFalse(ByteString.EMPTY.endsWith(suffix)); | |
694 assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY)); | |
695 } | |
696 | |
697 static List<ByteString> makeConcretePieces(byte[] referenceBytes) { | 577 static List<ByteString> makeConcretePieces(byte[] referenceBytes) { |
698 List<ByteString> pieces = new ArrayList<ByteString>(); | 578 List<ByteString> pieces = new ArrayList<ByteString>(); |
699 // Starting length should be small enough that we'll do some concatenating b
y | 579 // Starting length should be small enough that we'll do some concatenating b
y |
700 // copying if we just concatenate all these pieces together. | 580 // copying if we just concatenate all these pieces together. |
701 for (int start = 0, length = 16; start < referenceBytes.length; start += len
gth) { | 581 for (int start = 0, length = 16; start < referenceBytes.length; start += len
gth) { |
702 length = (length << 1) - 1; | 582 length = (length << 1) - 1; |
703 if (start + length > referenceBytes.length) { | 583 if (start + length > referenceBytes.length) { |
704 length = referenceBytes.length - start; | 584 length = referenceBytes.length - start; |
705 } | 585 } |
706 pieces.add(ByteString.copyFrom(referenceBytes, start, length)); | 586 pieces.add(ByteString.copyFrom(referenceBytes, start, length)); |
707 } | 587 } |
708 return pieces; | 588 return pieces; |
709 } | 589 } |
710 | |
711 private byte[] substringUsingWriteTo( | |
712 ByteString data, int offset, int length) throws IOException { | |
713 ByteArrayOutputStream output = new ByteArrayOutputStream(); | |
714 data.writeTo(output, offset, length); | |
715 return output.toByteArray(); | |
716 } | |
717 | |
718 public void testWriteToOutputStream() throws Exception { | |
719 // Choose a size large enough so when two ByteStrings are concatenated they | |
720 // won't be merged into one byte array due to some optimizations. | |
721 final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1; | |
722 byte[] data1 = new byte[dataSize]; | |
723 for (int i = 0; i < data1.length; i++) { | |
724 data1[i] = (byte) 1; | |
725 } | |
726 data1[1] = (byte) 11; | |
727 // Test LiteralByteString.writeTo(OutputStream,int,int) | |
728 ByteString left = ByteString.wrap(data1); | |
729 byte[] result = substringUsingWriteTo(left, 1, 1); | |
730 assertEquals(1, result.length); | |
731 assertEquals((byte) 11, result[0]); | |
732 | |
733 byte[] data2 = new byte[dataSize]; | |
734 for (int i = 0; i < data1.length; i++) { | |
735 data2[i] = (byte) 2; | |
736 } | |
737 ByteString right = ByteString.wrap(data2); | |
738 // Concatenate two ByteStrings to create a RopeByteString. | |
739 ByteString root = left.concat(right); | |
740 // Make sure we are actually testing a RopeByteString with a simple tree | |
741 // structure. | |
742 assertEquals(1, root.getTreeDepth()); | |
743 // Write parts of the left node. | |
744 result = substringUsingWriteTo(root, 0, dataSize); | |
745 assertEquals(dataSize, result.length); | |
746 assertEquals((byte) 1, result[0]); | |
747 assertEquals((byte) 1, result[dataSize - 1]); | |
748 // Write parts of the right node. | |
749 result = substringUsingWriteTo(root, dataSize, dataSize); | |
750 assertEquals(dataSize, result.length); | |
751 assertEquals((byte) 2, result[0]); | |
752 assertEquals((byte) 2, result[dataSize - 1]); | |
753 // Write a segment of bytes that runs across both nodes. | |
754 result = substringUsingWriteTo(root, dataSize / 2, dataSize); | |
755 assertEquals(dataSize, result.length); | |
756 assertEquals((byte) 1, result[0]); | |
757 assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]); | |
758 assertEquals((byte) 2, result[dataSize - dataSize / 2]); | |
759 assertEquals((byte) 2, result[dataSize - 1]); | |
760 } | |
761 | |
762 /** | |
763 * Tests ByteString uses Arrays based byte copier when running under Hotstop V
M. | |
764 */ | |
765 public void testByteArrayCopier() throws Exception { | |
766 Field field = ByteString.class.getDeclaredField("byteArrayCopier"); | |
767 field.setAccessible(true); | |
768 Object byteArrayCopier = field.get(null); | |
769 assertNotNull(byteArrayCopier); | |
770 assertTrue( | |
771 byteArrayCopier.toString(), | |
772 byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopi
er")); | |
773 } | |
774 } | 590 } |
OLD | NEW |