• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package okio;
17 
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.Random;
21 import org.junit.Test;
22 
23 import static java.util.Arrays.asList;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 
29 public final class OkBufferTest {
readAndWriteUtf8()30   @Test public void readAndWriteUtf8() throws Exception {
31     OkBuffer buffer = new OkBuffer();
32     buffer.writeUtf8("ab");
33     assertEquals(2, buffer.size());
34     buffer.writeUtf8("cdef");
35     assertEquals(6, buffer.size());
36     assertEquals("abcd", buffer.readUtf8(4));
37     assertEquals(2, buffer.size());
38     assertEquals("ef", buffer.readUtf8(2));
39     assertEquals(0, buffer.size());
40     try {
41       buffer.readUtf8(1);
42       fail();
43     } catch (ArrayIndexOutOfBoundsException expected) {
44     }
45   }
46 
completeSegmentByteCountOnEmptyBuffer()47   @Test public void completeSegmentByteCountOnEmptyBuffer() throws Exception {
48     OkBuffer buffer = new OkBuffer();
49     assertEquals(0, buffer.completeSegmentByteCount());
50   }
51 
completeSegmentByteCountOnBufferWithFullSegments()52   @Test public void completeSegmentByteCountOnBufferWithFullSegments() throws Exception {
53     OkBuffer buffer = new OkBuffer();
54     buffer.writeUtf8(repeat('a', Segment.SIZE * 4));
55     assertEquals(Segment.SIZE * 4, buffer.completeSegmentByteCount());
56   }
57 
completeSegmentByteCountOnBufferWithIncompleteTailSegment()58   @Test public void completeSegmentByteCountOnBufferWithIncompleteTailSegment() throws Exception {
59     OkBuffer buffer = new OkBuffer();
60     buffer.writeUtf8(repeat('a', Segment.SIZE * 4 - 10));
61     assertEquals(Segment.SIZE * 3, buffer.completeSegmentByteCount());
62   }
63 
readUtf8SpansSegments()64   @Test public void readUtf8SpansSegments() throws Exception {
65     OkBuffer buffer = new OkBuffer();
66     buffer.writeUtf8(repeat('a', Segment.SIZE * 2));
67     buffer.readUtf8(Segment.SIZE - 1);
68     assertEquals("aa", buffer.readUtf8(2));
69   }
70 
readUtf8EntireBuffer()71   @Test public void readUtf8EntireBuffer() throws Exception {
72     OkBuffer buffer = new OkBuffer();
73     buffer.writeUtf8(repeat('a', Segment.SIZE));
74     assertEquals(repeat('a', Segment.SIZE), buffer.readUtf8(Segment.SIZE));
75   }
76 
toStringOnEmptyBuffer()77   @Test public void toStringOnEmptyBuffer() throws Exception {
78     OkBuffer buffer = new OkBuffer();
79     assertEquals("OkBuffer[size=0]", buffer.toString());
80   }
81 
toStringOnSmallBufferIncludesContents()82   @Test public void toStringOnSmallBufferIncludesContents() throws Exception {
83     OkBuffer buffer = new OkBuffer();
84     buffer.write(ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040"));
85     assertEquals("OkBuffer[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", buffer.toString());
86   }
87 
toStringOnLargeBufferIncludesMd5()88   @Test public void toStringOnLargeBufferIncludesMd5() throws Exception {
89     OkBuffer buffer = new OkBuffer();
90     buffer.write(ByteString.encodeUtf8("12345678901234567"));
91     assertEquals("OkBuffer[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", buffer.toString());
92   }
93 
toStringOnMultipleSegmentBuffer()94   @Test public void toStringOnMultipleSegmentBuffer() throws Exception {
95     OkBuffer buffer = new OkBuffer();
96     buffer.writeUtf8(repeat('a', 6144));
97     assertEquals("OkBuffer[size=6144 md5=d890021f28522533c1cc1b9b1f83ce73]", buffer.toString());
98   }
99 
multipleSegmentBuffers()100   @Test public void multipleSegmentBuffers() throws Exception {
101     OkBuffer buffer = new OkBuffer();
102     buffer.writeUtf8(repeat('a',  1000));
103     buffer.writeUtf8(repeat('b', 2500));
104     buffer.writeUtf8(repeat('c', 5000));
105     buffer.writeUtf8(repeat('d', 10000));
106     buffer.writeUtf8(repeat('e', 25000));
107     buffer.writeUtf8(repeat('f', 50000));
108 
109     assertEquals(repeat('a', 999), buffer.readUtf8(999)); // a...a
110     assertEquals("a" + repeat('b', 2500) + "c", buffer.readUtf8(2502)); // ab...bc
111     assertEquals(repeat('c', 4998), buffer.readUtf8(4998)); // c...c
112     assertEquals("c" + repeat('d', 10000) + "e", buffer.readUtf8(10002)); // cd...de
113     assertEquals(repeat('e', 24998), buffer.readUtf8(24998)); // e...e
114     assertEquals("e" + repeat('f', 50000), buffer.readUtf8(50001)); // ef...f
115     assertEquals(0, buffer.size());
116   }
117 
fillAndDrainPool()118   @Test public void fillAndDrainPool() throws Exception {
119     OkBuffer buffer = new OkBuffer();
120 
121     // Take 2 * MAX_SIZE segments. This will drain the pool, even if other tests filled it.
122     buffer.write(new byte[(int) SegmentPool.MAX_SIZE]);
123     buffer.write(new byte[(int) SegmentPool.MAX_SIZE]);
124     assertEquals(0, SegmentPool.INSTANCE.byteCount);
125 
126     // Recycle MAX_SIZE segments. They're all in the pool.
127     buffer.readByteString(SegmentPool.MAX_SIZE);
128     assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount);
129 
130     // Recycle MAX_SIZE more segments. The pool is full so they get garbage collected.
131     buffer.readByteString(SegmentPool.MAX_SIZE);
132     assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount);
133 
134     // Take MAX_SIZE segments to drain the pool.
135     buffer.write(new byte[(int) SegmentPool.MAX_SIZE]);
136     assertEquals(0, SegmentPool.INSTANCE.byteCount);
137 
138     // Take MAX_SIZE more segments. The pool is drained so these will need to be allocated.
139     buffer.write(new byte[(int) SegmentPool.MAX_SIZE]);
140     assertEquals(0, SegmentPool.INSTANCE.byteCount);
141   }
142 
moveBytesBetweenBuffersShareSegment()143   @Test public void moveBytesBetweenBuffersShareSegment() throws Exception {
144     int size = (Segment.SIZE / 2) - 1;
145     List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size));
146     assertEquals(asList(size * 2), segmentSizes);
147   }
148 
moveBytesBetweenBuffersReassignSegment()149   @Test public void moveBytesBetweenBuffersReassignSegment() throws Exception {
150     int size = (Segment.SIZE / 2) + 1;
151     List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size));
152     assertEquals(asList(size, size), segmentSizes);
153   }
154 
moveBytesBetweenBuffersMultipleSegments()155   @Test public void moveBytesBetweenBuffersMultipleSegments() throws Exception {
156     int size = 3 * Segment.SIZE + 1;
157     List<Integer> segmentSizes = moveBytesBetweenBuffers(repeat('a', size), repeat('b', size));
158     assertEquals(asList(Segment.SIZE, Segment.SIZE, Segment.SIZE, 1,
159         Segment.SIZE, Segment.SIZE, Segment.SIZE, 1), segmentSizes);
160   }
161 
moveBytesBetweenBuffers(String... contents)162   private List<Integer> moveBytesBetweenBuffers(String... contents) {
163     StringBuilder expected = new StringBuilder();
164     OkBuffer buffer = new OkBuffer();
165     for (String s : contents) {
166       OkBuffer source = new OkBuffer();
167       source.writeUtf8(s);
168       buffer.write(source, source.size());
169       expected.append(s);
170     }
171     List<Integer> segmentSizes = buffer.segmentSizes();
172     assertEquals(expected.toString(), buffer.readUtf8(expected.length()));
173     return segmentSizes;
174   }
175 
176   /** The big part of source's first segment is being moved. */
writeSplitSourceBufferLeft()177   @Test public void writeSplitSourceBufferLeft() throws Exception {
178     int writeSize = Segment.SIZE / 2 + 1;
179 
180     OkBuffer sink = new OkBuffer();
181     sink.writeUtf8(repeat('b', Segment.SIZE - 10));
182 
183     OkBuffer source = new OkBuffer();
184     source.writeUtf8(repeat('a', Segment.SIZE * 2));
185     sink.write(source, writeSize);
186 
187     assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes());
188     assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes());
189   }
190 
191   /** The big part of source's first segment is staying put. */
writeSplitSourceBufferRight()192   @Test public void writeSplitSourceBufferRight() throws Exception {
193     int writeSize = Segment.SIZE / 2 - 1;
194 
195     OkBuffer sink = new OkBuffer();
196     sink.writeUtf8(repeat('b', Segment.SIZE - 10));
197 
198     OkBuffer source = new OkBuffer();
199     source.writeUtf8(repeat('a', Segment.SIZE * 2));
200     sink.write(source, writeSize);
201 
202     assertEquals(asList(Segment.SIZE - 10, writeSize), sink.segmentSizes());
203     assertEquals(asList(Segment.SIZE - writeSize, Segment.SIZE), source.segmentSizes());
204   }
205 
writePrefixDoesntSplit()206   @Test public void writePrefixDoesntSplit() throws Exception {
207     OkBuffer sink = new OkBuffer();
208     sink.writeUtf8(repeat('b', 10));
209 
210     OkBuffer source = new OkBuffer();
211     source.writeUtf8(repeat('a', Segment.SIZE * 2));
212     sink.write(source, 20);
213 
214     assertEquals(asList(30), sink.segmentSizes());
215     assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes());
216     assertEquals(30, sink.size());
217     assertEquals(Segment.SIZE * 2 - 20, source.size());
218   }
219 
writePrefixDoesntSplitButRequiresCompact()220   @Test public void writePrefixDoesntSplitButRequiresCompact() throws Exception {
221     OkBuffer sink = new OkBuffer();
222     sink.writeUtf8(repeat('b', Segment.SIZE - 10)); // limit = size - 10
223     sink.readUtf8(Segment.SIZE - 20); // pos = size = 20
224 
225     OkBuffer source = new OkBuffer();
226     source.writeUtf8(repeat('a', Segment.SIZE * 2));
227     sink.write(source, 20);
228 
229     assertEquals(asList(30), sink.segmentSizes());
230     assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes());
231     assertEquals(30, sink.size());
232     assertEquals(Segment.SIZE * 2 - 20, source.size());
233   }
234 
readExhaustedSource()235   @Test public void readExhaustedSource() throws Exception {
236     OkBuffer sink = new OkBuffer();
237     sink.writeUtf8(repeat('a', 10));
238 
239     OkBuffer source = new OkBuffer();
240 
241     assertEquals(-1, source.read(sink, 10));
242     assertEquals(10, sink.size());
243     assertEquals(0, source.size());
244   }
245 
readZeroBytesFromSource()246   @Test public void readZeroBytesFromSource() throws Exception {
247     OkBuffer sink = new OkBuffer();
248     sink.writeUtf8(repeat('a', 10));
249 
250     OkBuffer source = new OkBuffer();
251 
252     // Either 0 or -1 is reasonable here. For consistency with Android's
253     // ByteArrayInputStream we return 0.
254     assertEquals(-1, source.read(sink, 0));
255     assertEquals(10, sink.size());
256     assertEquals(0, source.size());
257   }
258 
moveAllRequestedBytesWithRead()259   @Test public void moveAllRequestedBytesWithRead() throws Exception {
260     OkBuffer sink = new OkBuffer();
261     sink.writeUtf8(repeat('a', 10));
262 
263     OkBuffer source = new OkBuffer();
264     source.writeUtf8(repeat('b', 15));
265 
266     assertEquals(10, source.read(sink, 10));
267     assertEquals(20, sink.size());
268     assertEquals(5, source.size());
269     assertEquals(repeat('a', 10) + repeat('b', 10), sink.readUtf8(20));
270   }
271 
moveFewerThanRequestedBytesWithRead()272   @Test public void moveFewerThanRequestedBytesWithRead() throws Exception {
273     OkBuffer sink = new OkBuffer();
274     sink.writeUtf8(repeat('a', 10));
275 
276     OkBuffer source = new OkBuffer();
277     source.writeUtf8(repeat('b', 20));
278 
279     assertEquals(20, source.read(sink, 25));
280     assertEquals(30, sink.size());
281     assertEquals(0, source.size());
282     assertEquals(repeat('a', 10) + repeat('b', 20), sink.readUtf8(30));
283   }
284 
indexOf()285   @Test public void indexOf() throws Exception {
286     OkBuffer buffer = new OkBuffer();
287 
288     // The segment is empty.
289     assertEquals(-1, buffer.indexOf((byte) 'a'));
290 
291     // The segment has one value.
292     buffer.writeUtf8("a"); // a
293     assertEquals(0, buffer.indexOf((byte) 'a'));
294     assertEquals(-1, buffer.indexOf((byte) 'b'));
295 
296     // The segment has lots of data.
297     buffer.writeUtf8(repeat('b', Segment.SIZE - 2)); // ab...b
298     assertEquals(0, buffer.indexOf((byte) 'a'));
299     assertEquals(1, buffer.indexOf((byte) 'b'));
300     assertEquals(-1, buffer.indexOf((byte) 'c'));
301 
302     // The segment doesn't start at 0, it starts at 2.
303     buffer.readUtf8(2); // b...b
304     assertEquals(-1, buffer.indexOf((byte) 'a'));
305     assertEquals(0, buffer.indexOf((byte) 'b'));
306     assertEquals(-1, buffer.indexOf((byte) 'c'));
307 
308     // The segment is full.
309     buffer.writeUtf8("c"); // b...bc
310     assertEquals(-1, buffer.indexOf((byte) 'a'));
311     assertEquals(0, buffer.indexOf((byte) 'b'));
312     assertEquals(Segment.SIZE - 3, buffer.indexOf((byte) 'c'));
313 
314     // The segment doesn't start at 2, it starts at 4.
315     buffer.readUtf8(2); // b...bc
316     assertEquals(-1, buffer.indexOf((byte) 'a'));
317     assertEquals(0, buffer.indexOf((byte) 'b'));
318     assertEquals(Segment.SIZE - 5, buffer.indexOf((byte) 'c'));
319 
320     // Two segments.
321     buffer.writeUtf8("d"); // b...bcd, d is in the 2nd segment.
322     assertEquals(asList(Segment.SIZE - 4, 1), buffer.segmentSizes());
323     assertEquals(Segment.SIZE - 4, buffer.indexOf((byte) 'd'));
324     assertEquals(-1, buffer.indexOf((byte) 'e'));
325   }
326 
indexOfWithOffset()327   @Test public void indexOfWithOffset() throws Exception {
328     OkBuffer buffer = new OkBuffer();
329     int halfSegment = Segment.SIZE / 2;
330     buffer.writeUtf8(repeat('a', halfSegment));
331     buffer.writeUtf8(repeat('b', halfSegment));
332     buffer.writeUtf8(repeat('c', halfSegment));
333     buffer.writeUtf8(repeat('d', halfSegment));
334     assertEquals(0, buffer.indexOf((byte) 'a', 0));
335     assertEquals(halfSegment - 1, buffer.indexOf((byte) 'a', halfSegment - 1));
336     assertEquals(halfSegment, buffer.indexOf((byte) 'b', halfSegment - 1));
337     assertEquals(halfSegment * 2, buffer.indexOf((byte) 'c', halfSegment - 1));
338     assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment - 1));
339     assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 2));
340     assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 3));
341     assertEquals(halfSegment * 4 - 1, buffer.indexOf((byte) 'd', halfSegment * 4 - 1));
342   }
343 
writeBytes()344   @Test public void writeBytes() throws Exception {
345     OkBuffer data = new OkBuffer();
346     data.writeByte(0xab);
347     data.writeByte(0xcd);
348     assertEquals("OkBuffer[size=2 data=abcd]", data.toString());
349   }
350 
writeLastByteInSegment()351   @Test public void writeLastByteInSegment() throws Exception {
352     OkBuffer data = new OkBuffer();
353     data.writeUtf8(repeat('a', Segment.SIZE - 1));
354     data.writeByte(0x20);
355     data.writeByte(0x21);
356     assertEquals(asList(Segment.SIZE, 1), data.segmentSizes());
357     assertEquals(repeat('a', Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1));
358     assertEquals("OkBuffer[size=2 data=2021]", data.toString());
359   }
360 
writeShort()361   @Test public void writeShort() throws Exception {
362     OkBuffer data = new OkBuffer();
363     data.writeShort(0xabcd);
364     data.writeShort(0x4321);
365     assertEquals("OkBuffer[size=4 data=abcd4321]", data.toString());
366   }
367 
writeShortLe()368   @Test public void writeShortLe() throws Exception {
369     OkBuffer data = new OkBuffer();
370     data.writeShortLe(0xabcd);
371     data.writeShortLe(0x4321);
372     assertEquals("OkBuffer[size=4 data=cdab2143]", data.toString());
373   }
374 
writeInt()375   @Test public void writeInt() throws Exception {
376     OkBuffer data = new OkBuffer();
377     data.writeInt(0xabcdef01);
378     data.writeInt(0x87654321);
379     assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
380   }
381 
writeLastIntegerInSegment()382   @Test public void writeLastIntegerInSegment() throws Exception {
383     OkBuffer data = new OkBuffer();
384     data.writeUtf8(repeat('a', Segment.SIZE - 4));
385     data.writeInt(0xabcdef01);
386     data.writeInt(0x87654321);
387     assertEquals(asList(Segment.SIZE, 4), data.segmentSizes());
388     assertEquals(repeat('a', Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4));
389     assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
390   }
391 
writeIntegerDoesntQuiteFitInSegment()392   @Test public void writeIntegerDoesntQuiteFitInSegment() throws Exception {
393     OkBuffer data = new OkBuffer();
394     data.writeUtf8(repeat('a', Segment.SIZE - 3));
395     data.writeInt(0xabcdef01);
396     data.writeInt(0x87654321);
397     assertEquals(asList(Segment.SIZE - 3, 8), data.segmentSizes());
398     assertEquals(repeat('a', Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3));
399     assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
400   }
401 
writeIntLe()402   @Test public void writeIntLe() throws Exception {
403     OkBuffer data = new OkBuffer();
404     data.writeIntLe(0xabcdef01);
405     data.writeIntLe(0x87654321);
406     assertEquals("OkBuffer[size=8 data=01efcdab21436587]", data.toString());
407   }
408 
writeLong()409   @Test public void writeLong() throws Exception {
410     OkBuffer data = new OkBuffer();
411     data.writeLong(0xabcdef0187654321L);
412     data.writeLong(0xcafebabeb0b15c00L);
413     assertEquals("OkBuffer[size=16 data=abcdef0187654321cafebabeb0b15c00]", data.toString());
414   }
415 
writeLongLe()416   @Test public void writeLongLe() throws Exception {
417     OkBuffer data = new OkBuffer();
418     data.writeLongLe(0xabcdef0187654321L);
419     data.writeLongLe(0xcafebabeb0b15c00L);
420     assertEquals("OkBuffer[size=16 data=2143658701efcdab005cb1b0bebafeca]", data.toString());
421   }
422 
readByte()423   @Test public void readByte() throws Exception {
424     OkBuffer data = new OkBuffer();
425     data.write(new byte[] { (byte) 0xab, (byte) 0xcd });
426     assertEquals(0xab, data.readByte() & 0xff);
427     assertEquals(0xcd, data.readByte() & 0xff);
428     assertEquals(0, data.size());
429   }
430 
readShort()431   @Test public void readShort() throws Exception {
432     OkBuffer data = new OkBuffer();
433     data.write(new byte[] {
434         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01
435     });
436     assertEquals((short) 0xabcd, data.readShort());
437     assertEquals((short) 0xef01, data.readShort());
438     assertEquals(0, data.size());
439   }
440 
readShortLe()441   @Test public void readShortLe() throws Exception {
442     OkBuffer data = new OkBuffer();
443     data.write(new byte[] {
444         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10
445     });
446     assertEquals((short) 0xcdab, data.readShortLe());
447     assertEquals((short) 0x10ef, data.readShortLe());
448     assertEquals(0, data.size());
449   }
450 
readShortSplitAcrossMultipleSegments()451   @Test public void readShortSplitAcrossMultipleSegments() throws Exception {
452     OkBuffer data = new OkBuffer();
453     data.writeUtf8(repeat('a', Segment.SIZE - 1));
454     data.write(new byte[] { (byte) 0xab, (byte) 0xcd });
455     data.readUtf8(Segment.SIZE - 1);
456     assertEquals((short) 0xabcd, data.readShort());
457     assertEquals(0, data.size());
458   }
459 
readInt()460   @Test public void readInt() throws Exception {
461     OkBuffer data = new OkBuffer();
462     data.write(new byte[] {
463         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01,
464         (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21
465     });
466     assertEquals(0xabcdef01, data.readInt());
467     assertEquals(0x87654321, data.readInt());
468     assertEquals(0, data.size());
469   }
470 
readIntLe()471   @Test public void readIntLe() throws Exception {
472     OkBuffer data = new OkBuffer();
473     data.write(new byte[] {
474         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10,
475         (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21
476     });
477     assertEquals(0x10efcdab, data.readIntLe());
478     assertEquals(0x21436587, data.readIntLe());
479     assertEquals(0, data.size());
480   }
481 
readIntSplitAcrossMultipleSegments()482   @Test public void readIntSplitAcrossMultipleSegments() throws Exception {
483     OkBuffer data = new OkBuffer();
484     data.writeUtf8(repeat('a', Segment.SIZE - 3));
485     data.write(new byte[] {
486         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01
487     });
488     data.readUtf8(Segment.SIZE - 3);
489     assertEquals(0xabcdef01, data.readInt());
490     assertEquals(0, data.size());
491   }
492 
readLong()493   @Test public void readLong() throws Exception {
494     OkBuffer data = new OkBuffer();
495     data.write(new byte[] {
496         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10,
497         (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21,
498         (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69,
499         (byte) 0x12, (byte) 0x23, (byte) 0x34, (byte) 0x45
500     });
501     assertEquals(0xabcdef1087654321L, data.readLong());
502     assertEquals(0x3647586912233445L, data.readLong());
503     assertEquals(0, data.size());
504   }
505 
readLongLe()506   @Test public void readLongLe() throws Exception {
507     OkBuffer data = new OkBuffer();
508     data.write(new byte[] {
509         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10,
510         (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21,
511         (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69,
512         (byte) 0x12, (byte) 0x23, (byte) 0x34, (byte) 0x45
513     });
514     assertEquals(0x2143658710efcdabL, data.readLongLe());
515     assertEquals(0x4534231269584736L, data.readLongLe());
516     assertEquals(0, data.size());
517   }
518 
readLongSplitAcrossMultipleSegments()519   @Test public void readLongSplitAcrossMultipleSegments() throws Exception {
520     OkBuffer data = new OkBuffer();
521     data.writeUtf8(repeat('a', Segment.SIZE - 7));
522     data.write(new byte[] {
523         (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01,
524         (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21,
525     });
526     data.readUtf8(Segment.SIZE - 7);
527     assertEquals(0xabcdef0187654321L, data.readLong());
528     assertEquals(0, data.size());
529   }
530 
byteAt()531   @Test public void byteAt() throws Exception {
532     OkBuffer buffer = new OkBuffer();
533     buffer.writeUtf8("a");
534     buffer.writeUtf8(repeat('b', Segment.SIZE));
535     buffer.writeUtf8("c");
536     assertEquals('a', buffer.getByte(0));
537     assertEquals('a', buffer.getByte(0)); // getByte doesn't mutate!
538     assertEquals('c', buffer.getByte(buffer.size - 1));
539     assertEquals('b', buffer.getByte(buffer.size - 2));
540     assertEquals('b', buffer.getByte(buffer.size - 3));
541   }
542 
getByteOfEmptyBuffer()543   @Test public void getByteOfEmptyBuffer() throws Exception {
544     OkBuffer buffer = new OkBuffer();
545     try {
546       buffer.getByte(0);
547       fail();
548     } catch (IndexOutOfBoundsException expected) {
549     }
550   }
551 
skip()552   @Test public void skip() throws Exception {
553     OkBuffer buffer = new OkBuffer();
554     buffer.writeUtf8("a");
555     buffer.writeUtf8(repeat('b', Segment.SIZE));
556     buffer.writeUtf8("c");
557     buffer.skip(1);
558     assertEquals('b', buffer.readByte() & 0xff);
559     buffer.skip(Segment.SIZE - 2);
560     assertEquals('b', buffer.readByte() & 0xff);
561     buffer.skip(1);
562     assertEquals(0, buffer.size());
563   }
564 
testWritePrefixToEmptyBuffer()565   @Test public void testWritePrefixToEmptyBuffer() {
566     OkBuffer sink = new OkBuffer();
567     OkBuffer source = new OkBuffer();
568     source.writeUtf8("abcd");
569     sink.write(source, 2);
570     assertEquals("ab", sink.readUtf8(2));
571   }
572 
cloneDoesNotObserveWritesToOriginal()573   @Test public void cloneDoesNotObserveWritesToOriginal() throws Exception {
574     OkBuffer original = new OkBuffer();
575     OkBuffer clone = original.clone();
576     original.writeUtf8("abc");
577     assertEquals(0, clone.size());
578   }
579 
cloneDoesNotObserveReadsFromOriginal()580   @Test public void cloneDoesNotObserveReadsFromOriginal() throws Exception {
581     OkBuffer original = new OkBuffer();
582     original.writeUtf8("abc");
583     OkBuffer clone = original.clone();
584     assertEquals("abc", original.readUtf8(3));
585     assertEquals(3, clone.size());
586     assertEquals("ab", clone.readUtf8(2));
587   }
588 
originalDoesNotObserveWritesToClone()589   @Test public void originalDoesNotObserveWritesToClone() throws Exception {
590     OkBuffer original = new OkBuffer();
591     OkBuffer clone = original.clone();
592     clone.writeUtf8("abc");
593     assertEquals(0, original.size());
594   }
595 
originalDoesNotObserveReadsFromClone()596   @Test public void originalDoesNotObserveReadsFromClone() throws Exception {
597     OkBuffer original = new OkBuffer();
598     original.writeUtf8("abc");
599     OkBuffer clone = original.clone();
600     assertEquals("abc", clone.readUtf8(3));
601     assertEquals(3, original.size());
602     assertEquals("ab", original.readUtf8(2));
603   }
604 
cloneMultipleSegments()605   @Test public void cloneMultipleSegments() throws Exception {
606     OkBuffer original = new OkBuffer();
607     original.writeUtf8(repeat('a', Segment.SIZE * 3));
608     OkBuffer clone = original.clone();
609     original.writeUtf8(repeat('b', Segment.SIZE * 3));
610     clone.writeUtf8(repeat('c', Segment.SIZE * 3));
611 
612     assertEquals(repeat('a', Segment.SIZE * 3) + repeat('b', Segment.SIZE * 3),
613         original.readUtf8(Segment.SIZE * 6));
614     assertEquals(repeat('a', Segment.SIZE * 3) + repeat('c', Segment.SIZE * 3),
615         clone.readUtf8(Segment.SIZE * 6));
616   }
617 
testEqualsAndHashCodeEmpty()618   @Test public void testEqualsAndHashCodeEmpty() throws Exception {
619     OkBuffer a = new OkBuffer();
620     OkBuffer b = new OkBuffer();
621     assertTrue(a.equals(b));
622     assertTrue(a.hashCode() == b.hashCode());
623   }
624 
testEqualsAndHashCode()625   @Test public void testEqualsAndHashCode() throws Exception {
626     OkBuffer a = new OkBuffer().writeUtf8("dog");
627     OkBuffer b = new OkBuffer().writeUtf8("hotdog");
628     assertFalse(a.equals(b));
629     assertFalse(a.hashCode() == b.hashCode());
630 
631     b.readUtf8(3); // Leaves b containing 'dog'.
632     assertTrue(a.equals(b));
633     assertTrue(a.hashCode() == b.hashCode());
634   }
635 
testEqualsAndHashCodeSpanningSegments()636   @Test public void testEqualsAndHashCodeSpanningSegments() throws Exception {
637     byte[] data = new byte[1024 * 1024];
638     Random dice = new Random(0);
639     dice.nextBytes(data);
640 
641     OkBuffer a = bufferWithRandomSegmentLayout(dice, data);
642     OkBuffer b = bufferWithRandomSegmentLayout(dice, data);
643     assertTrue(a.equals(b));
644     assertTrue(a.hashCode() == b.hashCode());
645 
646     data[data.length / 2]++; // Change a single byte.
647     OkBuffer c = bufferWithRandomSegmentLayout(dice, data);
648     assertFalse(a.equals(c));
649     assertFalse(a.hashCode() == c.hashCode());
650   }
651 
652   /**
653    * Returns a new buffer containing the data in {@code data}, and a segment
654    * layout determined by {@code dice}.
655    */
bufferWithRandomSegmentLayout(Random dice, byte[] data)656   private OkBuffer bufferWithRandomSegmentLayout(Random dice, byte[] data) {
657     OkBuffer result = new OkBuffer();
658 
659     // Writing to result directly will yield packed segments. Instead, write to
660     // other buffers, then write those buffers to result.
661     for (int pos = 0, byteCount; pos < data.length; pos += byteCount) {
662       byteCount = (Segment.SIZE / 2) + dice.nextInt(Segment.SIZE / 2);
663       if (byteCount > data.length - pos) byteCount = data.length - pos;
664       int offset = dice.nextInt(Segment.SIZE - byteCount);
665 
666       OkBuffer segment = new OkBuffer();
667       segment.write(new byte[offset]);
668       segment.write(data, pos, byteCount);
669       segment.skip(offset);
670 
671       result.write(segment, byteCount);
672     }
673 
674     return result;
675   }
676 
repeat(char c, int count)677   private String repeat(char c, int count) {
678     char[] array = new char[count];
679     Arrays.fill(array, c);
680     return new String(array);
681   }
682 }
683