View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.io;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.io.IOException;
27  import java.io.RandomAccessFile;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.nio.file.Paths;
31  
32  import org.apache.commons.lang3.ArrayUtils;
33  import org.junit.jupiter.params.ParameterizedTest;
34  import org.junit.jupiter.params.provider.EnumSource;
35  
36  /**
37   * Tests {@link RandomAccessFiles}.
38   */
39  class RandomAccessFilesTest {
40  
41      private static final Path PATH_RO_20 = Paths.get("src/test/resources/org/apache/commons/io/test-file-20byteslength.bin");
42      private static final Path PATH_RO_0 = Paths.get("src/test/resources/org/apache/commons/io/test-file-empty.bin");
43      private static final Path PATH_RO_0_BIS = Paths.get("src/test/resources/org/apache/commons/io/test-file-empty2.bin");
44  
45      private static byte reverse(final byte b) {
46          return (byte) (~b & 0xff);
47      }
48  
49      @ParameterizedTest()
50      @EnumSource(value = RandomAccessFileMode.class)
51      void testContentEquals(final RandomAccessFileMode mode) throws IOException {
52          mode.accept(PATH_RO_20, raf -> {
53              assertEquals(raf, raf);
54              assertTrue(RandomAccessFiles.contentEquals(raf, raf));
55          });
56          // as above, to make sure resources are OK
57          mode.accept(PATH_RO_20, raf -> {
58              assertEquals(raf, raf);
59              assertTrue(RandomAccessFiles.contentEquals(raf, raf));
60          });
61          // same 20 bytes, 2 RAFs
62          try (RandomAccessFile raf1 = mode.create(PATH_RO_20);
63                  RandomAccessFile raf2 = mode.create(PATH_RO_20)) {
64              assertTrue(RandomAccessFiles.contentEquals(raf1, raf2));
65          }
66          // as above, nested
67          mode.accept(PATH_RO_20, raf1 -> mode.accept(PATH_RO_20, raf2 -> assertTrue(RandomAccessFiles.contentEquals(raf1, raf2))));
68          // same empty file
69          try (RandomAccessFile raf1 = mode.create(PATH_RO_0);
70                  RandomAccessFile raf2 = mode.create(PATH_RO_0)) {
71              assertTrue(RandomAccessFiles.contentEquals(raf1, raf2));
72              assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1)));
73          }
74          // diff empty file
75          try (RandomAccessFile raf1 = mode.create(PATH_RO_0);
76                  RandomAccessFile raf2 = mode.create(PATH_RO_0_BIS)) {
77              assertTrue(RandomAccessFiles.contentEquals(raf1, raf2));
78              assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1)));
79          }
80          try (RandomAccessFile raf1 = mode.create(PATH_RO_0);
81                  RandomAccessFile raf2 = mode.create(PATH_RO_20)) {
82              assertFalse(RandomAccessFiles.contentEquals(raf1, raf2));
83              assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1)));
84          }
85          //
86          final Path bigFile1 = Files.createTempFile(getClass().getSimpleName(), "-1.bin");
87          final Path bigFile2 = Files.createTempFile(getClass().getSimpleName(), "-2.bin");
88          final Path bigFile3 = Files.createTempFile(getClass().getSimpleName(), "-3.bin");
89          try {
90              // This length must match any restriction from the Surefire configuration.
91              final int newLength = 2_000_000;
92              final byte[] bytes1 = new byte[newLength];
93              final byte[] bytes2 = new byte[newLength];
94              // Make sure bytes1 and bytes2 are different despite the shuffle
95              ArrayUtils.shuffle(bytes1);
96              bytes1[0] = 1;
97              ArrayUtils.shuffle(bytes2);
98              bytes2[0] = 2;
99              Files.write(bigFile1, bytes1);
100             Files.write(bigFile2, bytes2);
101             try (RandomAccessFile raf1 = mode.create(bigFile1);
102                     RandomAccessFile raf2 = mode.create(bigFile2)) {
103                 assertFalse(RandomAccessFiles.contentEquals(raf1, raf2));
104                 assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1)));
105                 assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf1), RandomAccessFiles.reset(raf1)));
106             }
107             // Make the LAST byte different.
108             byte[] bytes3 = bytes1.clone();
109             final int last = bytes3.length - 1;
110             bytes3[last] = reverse(bytes3[last]);
111             Files.write(bigFile3, bytes3);
112             try (RandomAccessFile raf1 = mode.create(bigFile1);
113                     RandomAccessFile raf3 = mode.create(bigFile3)) {
114                 assertFalse(RandomAccessFiles.contentEquals(raf1, raf3));
115                 assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf3), RandomAccessFiles.reset(raf1)));
116             }
117             // Make a byte in the middle different
118             bytes3 = bytes1.clone();
119             final int middle = bytes3.length / 2;
120             bytes3[middle] = reverse(bytes3[middle]);
121             Files.write(bigFile3, bytes3);
122             try (RandomAccessFile raf1 = mode.create(bigFile1);
123                     RandomAccessFile raf3 = mode.create(bigFile3)) {
124                 assertFalse(RandomAccessFiles.contentEquals(raf1, raf3));
125                 assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf3), RandomAccessFiles.reset(raf1)));
126             }
127         } finally {
128             // Delete ASAP
129             Files.deleteIfExists(bigFile1);
130             Files.deleteIfExists(bigFile2);
131             Files.deleteIfExists(bigFile3);
132         }
133     }
134 
135     @ParameterizedTest()
136     @EnumSource(value = RandomAccessFileMode.class)
137     void testRead(final RandomAccessFileMode mode) throws IOException {
138         mode.accept(PATH_RO_20, raf -> assertArrayEquals(new byte[] {}, RandomAccessFiles.read(raf, 0, 0)));
139         mode.accept(PATH_RO_20, raf -> assertArrayEquals(new byte[] {}, RandomAccessFiles.read(raf, 1, 0)));
140         mode.accept(PATH_RO_20, raf -> assertArrayEquals(new byte[] { '1' }, RandomAccessFiles.read(raf, 0, 1)));
141         mode.accept(PATH_RO_20, raf -> assertArrayEquals(new byte[] { '2' }, RandomAccessFiles.read(raf, 1, 1)));
142         mode.accept(PATH_RO_20, raf -> assertEquals(20, RandomAccessFiles.read(raf, 0, 20).length));
143         mode.accept(PATH_RO_20, raf -> assertThrows(IOException.class, () -> RandomAccessFiles.read(raf, 0, 21)));
144     }
145 }