1 /*
2  * Copyright (C) 2016 The Android Open Source Project
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 
17 package libcore.libcore.io;
18 
19 import junit.framework.TestCase;
20 
21 import android.system.ErrnoException;
22 import android.system.OsConstants;
23 
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.nio.ByteBuffer;
27 import java.nio.ByteOrder;
28 import java.nio.IntBuffer;
29 import java.util.Arrays;
30 import java.util.function.Function;
31 import libcore.io.BufferIterator;
32 import libcore.io.MemoryMappedFile;
33 import libcore.testing.io.TestIoUtils;
34 
35 public class MemoryMappedFileTest extends TestCase {
36 
37     private File tempDir;
38 
39     @Override
setUp()40     public void setUp() throws Exception {
41         super.setUp();
42         tempDir = TestIoUtils.createTemporaryDirectory("MemoryMappedFileTest");
43     }
44 
testMmapRo_missingFile()45     public void testMmapRo_missingFile() throws Exception {
46         try {
47             MemoryMappedFile.mmapRO("doesNotExist");
48             fail();
49         } catch (ErrnoException e) {
50             assertEquals(OsConstants.ENOENT, e.errno);
51         }
52     }
53 
testMmapRo_emptyFile()54     public void testMmapRo_emptyFile() throws Exception {
55         byte[] bytes = new byte[0];
56         File file = createFile(bytes);
57         try {
58             MemoryMappedFile.mmapRO(file.getPath());
59             fail();
60         } catch (ErrnoException e) {
61             assertEquals(OsConstants.EINVAL, e.errno);
62         } finally {
63             file.delete();
64         }
65     }
66 
testMmapRo()67     public void testMmapRo() throws Exception {
68         byte[] bytes = createBytes(10);
69         File file = createFile(bytes);
70         try (MemoryMappedFile memoryMappedFile = MemoryMappedFile.mmapRO(file.getPath())) {
71             assertEquals(10, memoryMappedFile.size());
72         } finally {
73             file.delete();
74         }
75     }
76 
testMmapRo_close()77     public void testMmapRo_close() throws Exception {
78         byte[] bytes = createBytes(10);
79         File file = createFile(bytes);
80         MemoryMappedFile memoryMappedFile = MemoryMappedFile.mmapRO(file.getPath());
81         memoryMappedFile.close();
82 
83         try {
84             memoryMappedFile.bigEndianIterator();
85             fail();
86         } catch (IllegalStateException expected) {
87         }
88 
89         try {
90             memoryMappedFile.littleEndianIterator();
91             fail();
92         } catch (IllegalStateException expected) {
93         }
94 
95         // Should not have any effect.
96         memoryMappedFile.close();
97     }
98 
testReadAfterCloseFails()99     public void testReadAfterCloseFails() throws Exception {
100         byte[] bytes = createBytes(10);
101         File file = createFile(bytes);
102         MemoryMappedFile memoryMappedFile = MemoryMappedFile.mmapRO(file.getPath());
103         BufferIterator iterator = memoryMappedFile.bigEndianIterator();
104         memoryMappedFile.close();
105 
106         try {
107             iterator.readByte();
108             fail();
109         } catch (IllegalStateException expected) {}
110     }
111 
testReadByte()112     public void testReadByte() throws Exception {
113         checkReadByte(MemoryMappedFile::bigEndianIterator);
114         checkReadByte(MemoryMappedFile::littleEndianIterator);
115     }
116 
checkReadByte( Function<MemoryMappedFile, BufferIterator> iteratorFactory)117     private void checkReadByte(
118             Function<MemoryMappedFile, BufferIterator> iteratorFactory) throws Exception {
119 
120         byte[] bytes = createBytes(10);
121         File file = createFile(bytes);
122         try {
123             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
124             BufferIterator iterator = iteratorFactory.apply(mappedFile);
125             for (int i = 0; i < bytes.length; i++) {
126                 assertReadByteSucceeds(iterator, bytes[i]);
127             }
128 
129             // Check skip.
130             iterator.seek(0);
131             for (int i = 0; i < bytes.length; i += 2) {
132                 assertReadByteSucceeds(iterator, bytes[i]);
133                 iterator.skip(1);
134             }
135         } finally {
136             file.delete();
137         }
138     }
139 
testSeek()140     public void testSeek() throws Exception {
141         checkSeek(MemoryMappedFile::bigEndianIterator);
142         checkSeek(MemoryMappedFile::littleEndianIterator);
143     }
144 
checkSeek( Function<MemoryMappedFile, BufferIterator> iteratorFactory)145     private void checkSeek(
146             Function<MemoryMappedFile, BufferIterator> iteratorFactory) throws Exception {
147 
148         byte[] bytes = createBytes(10);
149         File file = createFile(bytes);
150         try {
151             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
152             BufferIterator iterator = iteratorFactory.apply(mappedFile);
153             seekRead(bytes, iterator, 2);
154 
155             seekRead(bytes, iterator, 0);
156 
157             seekRead(bytes, iterator, 1);
158 
159             seekRead(bytes, iterator, 9);
160 
161             seekReadExpectFailure(iterator, -1);
162 
163             seekRead(bytes, iterator, 1);
164 
165             seekReadExpectFailure(iterator, 10);
166             seekReadExpectFailure(iterator, Integer.MAX_VALUE);
167             seekReadExpectFailure(iterator, Integer.MIN_VALUE);
168         } finally {
169             file.delete();
170         }
171     }
172 
seekRead(byte[] bytes, BufferIterator iterator, int offset)173     private static void seekRead(byte[] bytes, BufferIterator iterator, int offset) {
174         iterator.seek(offset);
175         assertEquals(offset, iterator.pos());
176         assertReadByteSucceeds(iterator, bytes[offset]);
177     }
178 
seekReadExpectFailure(BufferIterator iterator, int offset)179     private static void seekReadExpectFailure(BufferIterator iterator, int offset) {
180         iterator.seek(offset);
181         assertReadByteFails(iterator);
182     }
183 
testSkip()184     public void testSkip() throws Exception {
185         checkSkip(MemoryMappedFile::bigEndianIterator);
186         checkSkip(MemoryMappedFile::littleEndianIterator);
187     }
188 
checkSkip( Function<MemoryMappedFile, BufferIterator> iteratorFactory)189     private void checkSkip(
190             Function<MemoryMappedFile, BufferIterator> iteratorFactory) throws Exception {
191 
192         byte[] bytes = createBytes(10);
193         File file = createFile(bytes);
194         try {
195             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
196             BufferIterator iterator = iteratorFactory.apply(mappedFile);
197             iterator.skip(1);
198             assertEquals(1, iterator.pos());
199             assertReadByteSucceeds(iterator, bytes[1]);
200 
201             iterator.skip(-1);
202             assertEquals(1, iterator.pos());
203             assertReadByteSucceeds(iterator, bytes[1]);
204 
205             iterator.skip(2);
206             assertEquals(4, iterator.pos());
207             assertReadByteSucceeds(iterator, bytes[4]);
208 
209             iterator.skip(-2);
210             assertEquals(3, iterator.pos());
211             assertReadByteSucceeds(iterator, bytes[3]);
212 
213             iterator.skip(3);
214             assertEquals(7, iterator.pos());
215             assertReadByteSucceeds(iterator, bytes[7]);
216 
217             iterator.skip(-3);
218             assertEquals(5, iterator.pos());
219             assertReadByteSucceeds(iterator, bytes[5]);
220 
221             iterator.skip(4);
222             assertEquals(10, iterator.pos());
223             assertReadByteFails(iterator);
224 
225             iterator.skip(-1);
226             assertEquals(9, iterator.pos());
227             assertReadByteSucceeds(iterator, bytes[9]);
228         } finally {
229             file.delete();
230         }
231     }
232 
testReadShort_bigEndian()233     public void testReadShort_bigEndian() throws Exception {
234         byte[] bytes = createBytes(10);
235         File file = createFile(bytes);
236         try {
237             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
238             BufferIterator iterator = mappedFile.bigEndianIterator();
239 
240             // Even offset
241             short expectedValue = (short) ((bytes[0] << 8) | bytes[1]);
242             assertReadShortSucceeds(iterator, expectedValue);
243 
244             checkShortFailureCases(iterator);
245 
246             // Odd offset.
247             iterator.seek(1);
248             expectedValue = (short) ((bytes[1] << 8) | bytes[2]);
249             assertReadShortSucceeds(iterator, expectedValue);
250         } finally {
251             file.delete();
252         }
253     }
254 
testReadShort_littleEndian()255     public void testReadShort_littleEndian() throws Exception {
256         byte[] bytes = createBytes(10);
257         File file = createFile(bytes);
258         try {
259             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
260             BufferIterator iterator = mappedFile.littleEndianIterator();
261 
262             // Even offset
263             short expectedValue = (short) ((bytes[1] << 8) | bytes[0]);
264             assertReadShortSucceeds(iterator, expectedValue);
265 
266             checkShortFailureCases(iterator);
267 
268             // Odd offset.
269             iterator.seek(1);
270             expectedValue = (short) ((bytes[2] << 8) | bytes[1]);
271             assertReadShortSucceeds(iterator, expectedValue);
272         } finally {
273             file.delete();
274         }
275     }
276 
checkShortFailureCases(BufferIterator iterator)277     private static void checkShortFailureCases(BufferIterator iterator) {
278         // Partly before bounds.
279         iterator.seek(-1);
280         assertReadShortFails(iterator);
281 
282         // Entirely before bounds.
283         iterator.seek(-2);
284         assertReadShortFails(iterator);
285 
286         // Partly after bounds.
287         iterator.seek(9);
288         assertReadShortFails(iterator);
289 
290         // Entirely after bounds.
291         iterator.seek(10);
292         assertReadShortFails(iterator);
293     }
294 
testReadInt_bigEndian()295     public void testReadInt_bigEndian() throws Exception {
296         byte[] bytes = createBytes(10);
297         File file = createFile(bytes);
298         try {
299             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
300             BufferIterator iterator = mappedFile.bigEndianIterator();
301 
302             // Even offset
303             int expectedValue = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
304             assertReadIntSucceeds(iterator, expectedValue);
305 
306             checkIntFailureCases(iterator);
307 
308             // Odd offset.
309             iterator.seek(1);
310             expectedValue = (bytes[1] << 24) | (bytes[2] << 16) | (bytes[3] << 8) | bytes[4];
311             assertReadIntSucceeds(iterator, expectedValue);
312         } finally {
313             file.delete();
314         }
315     }
316 
testReadInt_littleEndian()317     public void testReadInt_littleEndian() throws Exception {
318         byte[] bytes = createBytes(10);
319         File file = createFile(bytes);
320         try {
321             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
322             BufferIterator iterator = mappedFile.littleEndianIterator();
323 
324             // Even offset
325             int expectedValue = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
326             assertReadIntSucceeds(iterator, expectedValue);
327 
328             checkIntFailureCases(iterator);
329 
330             // Odd offset.
331             iterator.seek(1);
332             expectedValue = (bytes[4] << 24) | (bytes[3] << 16) | (bytes[2] << 8) | bytes[1];
333             assertReadIntSucceeds(iterator, expectedValue);
334         } finally {
335             file.delete();
336         }
337     }
338 
checkIntFailureCases(BufferIterator iterator)339     private static void checkIntFailureCases(BufferIterator iterator) {
340         // Partly before bounds.
341         iterator.seek(-1);
342         assertReadIntFails(iterator);
343 
344         // Entirely before bounds.
345         iterator.seek(-4);
346         assertReadIntFails(iterator);
347 
348         // Partly after bounds.
349         iterator.seek(7);
350         assertReadIntFails(iterator);
351 
352         // Entirely after bounds.
353         iterator.seek(10);
354         assertReadIntFails(iterator);
355     }
356 
testReadIntArray()357     public void testReadIntArray() throws Exception {
358         checkReadIntArray(MemoryMappedFile::bigEndianIterator, ByteOrder.BIG_ENDIAN);
359         checkReadIntArray(MemoryMappedFile::littleEndianIterator, ByteOrder.LITTLE_ENDIAN);
360     }
361 
checkReadIntArray( Function<MemoryMappedFile, BufferIterator> iteratorFactory, ByteOrder byteOrdering)362     private void checkReadIntArray(
363             Function<MemoryMappedFile, BufferIterator> iteratorFactory,
364             ByteOrder byteOrdering) throws Exception {
365 
366         byte[] testBytes = createBytes(12);
367         File file = createFile(testBytes);
368         try {
369             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
370             BufferIterator iterator = iteratorFactory.apply(mappedFile);
371 
372             // Even offsets.
373             iterator.seek(4);
374             assertReadIntArraySucceeds(iterator, testBytes, byteOrdering, 2 /* intCount */);
375 
376             iterator.seek(0);
377             assertReadIntArraySucceeds(iterator, testBytes, byteOrdering, 3 /* intCount */);
378 
379             checkIntArrayZeroReadCases(iterator);
380 
381             // Odd offsets.
382             iterator.seek(1);
383             assertReadIntArraySucceeds(iterator, testBytes, byteOrdering, 2 /* intCount */);
384             iterator.seek(3);
385             assertReadIntArraySucceeds(iterator, testBytes, byteOrdering, 2 /* intCount */);
386         } finally {
387             file.delete();
388         }
389     }
390 
checkIntArrayZeroReadCases(BufferIterator iterator)391     private static void checkIntArrayZeroReadCases(BufferIterator iterator) {
392         // Zero length reads do nothing.
393         int posBeforeRead = iterator.pos();
394         int[] dstWithExistingValues = new int[] { 111, 222 };
395         iterator.readIntArray(dstWithExistingValues, 0, 0);
396         assertEquals(posBeforeRead, iterator.pos());
397         assertArrayEquals(new int[] { 111, 222 }, dstWithExistingValues);
398 
399         try {
400             iterator.readIntArray(null, 0, 0);
401             fail();
402         } catch (NullPointerException expected) {
403         }
404         assertEquals(posBeforeRead, iterator.pos());
405 
406         int[] dst = new int[2];
407 
408         // Partly before bounds.
409         iterator.seek(-1);
410         assertReadIntArrayFails(iterator, dst, 0, 1);
411 
412         // Entirely before bounds.
413         iterator.seek(-2);
414         assertReadIntArrayFails(iterator, dst, 0, 1);
415 
416         // Partly after bounds.
417         iterator.seek(9);
418         assertReadIntArrayFails(iterator, dst, 0, 1);
419 
420         // Entirely after bounds.
421         iterator.seek(12);
422         assertReadIntArrayFails(iterator, dst, 0, 1);
423 
424         // dst too small.
425         assertReadIntArrayFails(iterator, dst, 0, 3); // dst can only hold 2 ints
426 
427         // offset leaves dst too small.
428         assertReadIntArrayFails(iterator, dst, 1, 2);
429 
430         // Invalid offset
431         assertReadIntArrayFails(iterator, dst, -1, 2);
432         assertReadIntArrayFails(iterator, dst, 2, 2);
433 
434         // Null dst
435         try {
436             iterator.readIntArray(null, 0, 1);
437             fail();
438         } catch (NullPointerException expected) {
439         }
440     }
441 
testReadByteArray()442     public void testReadByteArray() throws Exception {
443         checkReadByteArray(MemoryMappedFile::bigEndianIterator);
444         checkReadByteArray(MemoryMappedFile::littleEndianIterator);
445     }
446 
checkReadByteArray( Function<MemoryMappedFile, BufferIterator> iteratorFactory)447     private void checkReadByteArray(
448             Function<MemoryMappedFile, BufferIterator> iteratorFactory) throws Exception {
449 
450         byte[] testBytes = createBytes(12);
451         File file = createFile(testBytes);
452         try {
453             MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(file.getPath());
454             BufferIterator iterator = iteratorFactory.apply(mappedFile);
455 
456             // Even offsets.
457             iterator.seek(4);
458             assertReadByteArraySucceeds(iterator, testBytes, 2 /* intCount */);
459 
460             iterator.seek(0);
461             assertReadByteArraySucceeds(iterator, testBytes, 3 /* intCount */);
462 
463             checkByteArrayZeroReadCases(iterator);
464 
465             // Odd offsets.
466             iterator.seek(1);
467             assertReadByteArraySucceeds(iterator, testBytes, 2 /* intCount */);
468             iterator.seek(3);
469             assertReadByteArraySucceeds(iterator, testBytes, 2 /* intCount */);
470         } finally {
471             file.delete();
472         }
473     }
474 
checkByteArrayZeroReadCases(BufferIterator iterator)475     private static void checkByteArrayZeroReadCases(BufferIterator iterator) {
476         // Zero length reads do nothing.
477         int posBeforeRead = iterator.pos();
478         byte[] dstWithExistingValues = new byte[] { 11, 22, 33, 44, 55, 66, 77, 88 };
479         iterator.readByteArray(dstWithExistingValues, 0, 0);
480         assertEquals(posBeforeRead, iterator.pos());
481         assertArrayEquals(new byte[] { 11, 22, 33, 44, 55, 66, 77, 88 }, dstWithExistingValues);
482 
483         try {
484             iterator.readByteArray(null, 0, 0);
485             fail();
486         } catch (NullPointerException expected) {
487         }
488         assertEquals(posBeforeRead, iterator.pos());
489 
490         byte[] dst = new byte[10];
491 
492         // Before bounds.
493         iterator.seek(-1);
494         assertReadByteArrayFails(iterator, dst, 0, 1);
495 
496         // After bounds.
497         iterator.seek(12);
498         assertReadByteArrayFails(iterator, dst, 0, 1);
499 
500         // dst too small.
501         assertReadByteArrayFails(iterator, dst, 0, 11); // dst can only hold 10 bytes
502 
503         // offset leaves dst too small.
504         assertReadByteArrayFails(iterator, dst, 1, 10);
505 
506         // Invalid offset
507         assertReadByteArrayFails(iterator, dst, -1, 2);
508         assertReadByteArrayFails(iterator, dst, 2, 2);
509 
510         // Null dst
511         try {
512             iterator.readByteArray(null, 0, 1);
513             fail();
514         } catch (NullPointerException expected) {
515         }
516     }
517 
assertReadByteArrayFails( BufferIterator iterator, byte[] dst, int offset, int intCount)518     private static void assertReadByteArrayFails(
519             BufferIterator iterator, byte[] dst, int offset, int intCount) {
520 
521         int posBefore = iterator.pos();
522         try {
523             iterator.readByteArray(dst, offset, intCount);
524             fail();
525         } catch (IndexOutOfBoundsException expected) {
526         }
527         assertEquals(posBefore, iterator.pos());
528     }
529 
assertReadByteArraySucceeds( BufferIterator iterator, byte[] underlyingData, int byteCount)530     private static void assertReadByteArraySucceeds(
531             BufferIterator iterator, byte[] underlyingData, int byteCount) {
532 
533         int posBefore = iterator.pos();
534 
535         // Create a byte[] containing book-end bytes we don't expect to be touched:
536         // [Byte.MAX_VALUE, {the bytes we expect from underlyingData from posBefore onward},
537         // Byte.MIN_VALUE].
538         byte[] expectedBytes = new byte[byteCount + 2];
539         expectedBytes[0] = Byte.MAX_VALUE;
540         expectedBytes[byteCount - 1] = Byte.MIN_VALUE;
541         System.arraycopy(underlyingData, posBefore, expectedBytes, 1, byteCount);
542 
543         // Get the true data.
544         byte[] dst = new byte[byteCount + 2];
545         // Copy the two bytes we expect to be untouched.
546         dst[0] = expectedBytes[0];
547         dst[byteCount - 1] = expectedBytes[byteCount - 1];
548         // Do the read.
549         iterator.readByteArray(dst, 1, byteCount);
550 
551         assertArrayEquals(expectedBytes, dst);
552         assertEquals(posBefore + byteCount, iterator.pos());
553     }
554 
assertReadIntArrayFails( BufferIterator iterator, int[] dst, int offset, int intCount)555     private static void assertReadIntArrayFails(
556             BufferIterator iterator, int[] dst, int offset, int intCount) {
557 
558         int posBefore = iterator.pos();
559         try {
560             iterator.readIntArray(dst, offset, intCount);
561             fail();
562         } catch (IndexOutOfBoundsException expected) {
563         }
564         assertEquals(posBefore, iterator.pos());
565     }
566 
assertReadIntArraySucceeds( BufferIterator iterator, byte[] underlyingData, ByteOrder byteOrder, int intCount)567     private static void assertReadIntArraySucceeds(
568             BufferIterator iterator, byte[] underlyingData, ByteOrder byteOrder, int intCount) {
569 
570         int posBefore = iterator.pos();
571 
572         // Create an int[] containing book-end ints we don't expect to be touched:
573         // [Integer.MAX_VALUE, {the ints we expect from underlyingData from posBefore onward},
574         // Integer.MIN_VALUE].
575 
576         // Create an IntBuffer containing the ints we'd expect from underlyingData from posBefore
577         // onward.
578         ByteBuffer byteBuffer = ByteBuffer.wrap(underlyingData);
579         byteBuffer.position(posBefore);
580         IntBuffer expectedIntsBuffer = byteBuffer.slice().order(byteOrder).asIntBuffer();
581         assertEquals(byteOrder, expectedIntsBuffer.order());
582 
583         // Copy the ints we expect.
584         int[] expectedInts = new int[intCount + 2];
585         expectedInts[0] = Integer.MAX_VALUE;
586         expectedInts[intCount - 1] = Integer.MIN_VALUE;
587         expectedIntsBuffer.get(expectedInts, 1, intCount);
588 
589         // Get the true data.
590         int[] dst = new int[intCount + 2];
591         dst[0] = expectedInts[0];
592         dst[intCount - 1] = expectedInts[intCount - 1];
593         iterator.readIntArray(dst, 1, intCount);
594 
595         assertArrayEquals(expectedInts, dst);
596         assertEquals(posBefore + (intCount * Integer.BYTES), iterator.pos());
597     }
598 
assertReadIntFails(BufferIterator iterator)599     private static void assertReadIntFails(BufferIterator iterator) {
600         int posBefore = iterator.pos();
601         try {
602             iterator.readInt();
603             fail();
604         } catch (IndexOutOfBoundsException expected) {
605         }
606         assertEquals(posBefore, iterator.pos());
607     }
608 
assertReadIntSucceeds(BufferIterator iterator, int expectedValue)609     private static void assertReadIntSucceeds(BufferIterator iterator, int expectedValue) {
610         int posBefore = iterator.pos();
611         assertEquals(expectedValue, iterator.readInt());
612         assertEquals(posBefore + Integer.BYTES, iterator.pos());
613     }
614 
assertReadShortFails(BufferIterator iterator)615     private static void assertReadShortFails(BufferIterator iterator) {
616         int posBefore = iterator.pos();
617         try {
618             iterator.readShort();
619             fail();
620         } catch (IndexOutOfBoundsException expected) {
621         }
622         assertEquals(posBefore, iterator.pos());
623     }
624 
assertReadShortSucceeds(BufferIterator iterator, short expectedValue)625     private static void assertReadShortSucceeds(BufferIterator iterator, short expectedValue) {
626         int posBefore = iterator.pos();
627         assertEquals(expectedValue, iterator.readShort());
628         assertEquals(posBefore + Short.BYTES, iterator.pos());
629     }
630 
assertReadByteFails(BufferIterator iterator)631     private static void assertReadByteFails(BufferIterator iterator) {
632         int posBefore = iterator.pos();
633         try {
634             iterator.readByte();
635             fail();
636         } catch (IndexOutOfBoundsException expected) {
637         }
638         // Must not advance pos.
639         assertEquals(posBefore, iterator.pos());
640     }
641 
assertReadByteSucceeds(BufferIterator iterator, byte expectedValue)642     private static void assertReadByteSucceeds(BufferIterator iterator, byte expectedValue) {
643         int posBefore = iterator.pos();
644         assertEquals(expectedValue, iterator.readByte());
645         assertEquals(posBefore + 1, iterator.pos());
646     }
647 
assertArrayEquals(int[] expected, int[] actual)648     private static void assertArrayEquals(int[] expected, int[] actual) {
649         assertEquals(Arrays.toString(expected), Arrays.toString(actual));
650     }
651 
assertArrayEquals(byte[] expected, byte[] actual)652     private static void assertArrayEquals(byte[] expected, byte[] actual) {
653         assertEquals(Arrays.toString(expected), Arrays.toString(actual));
654     }
655 
createBytes(int byteCount)656     private static byte[] createBytes(int byteCount) {
657         byte[] bytes = new byte[byteCount];
658         for (int i = 0; i < byteCount; i++) {
659             bytes[i] = (byte) i;
660         }
661         return bytes;
662     }
663 
createFile(byte[] bytes)664     private File createFile(byte[] bytes) throws Exception {
665         File file = File.createTempFile("bytes", null, tempDir);
666         try (FileOutputStream fos = new FileOutputStream(file)) {
667             fos.write(bytes);
668         }
669         return file;
670     }
671 }
672