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 |