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.file;
19  
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.nio.file.FileSystem;
27  import java.nio.file.FileSystems;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.nio.file.Paths;
31  import java.nio.file.StandardCopyOption;
32  
33  import org.apache.commons.io.file.Counters.PathCounters;
34  import org.junit.jupiter.api.Test;
35  import org.junit.jupiter.api.io.TempDir;
36  import org.junit.jupiter.params.ParameterizedTest;
37  import org.junit.jupiter.params.provider.MethodSource;
38  
39  import com.google.common.jimfs.Configuration;
40  import com.google.common.jimfs.Jimfs;
41  
42  /**
43   * Tests {@link PathUtils}.
44   */
45  class PathUtilsContentEqualsTest {
46  
47      static Configuration[] testConfigurations() {
48          // @formatter:off
49          return new Configuration[] {
50                  Configuration.osX().toBuilder().setWorkingDirectory("/").build(),
51                  Configuration.unix().toBuilder().setWorkingDirectory("/").build(),
52                  Configuration.windows().toBuilder().setWorkingDirectory("C:\\").build()
53          };
54          // @formatter:on
55      }
56  
57      @TempDir
58      public File temporaryFolder;
59  
60      private void assertContentEquals(final FileSystem fileSystem1, final FileSystem fileSystem2) throws IOException {
61          assertTrue(PathUtils.contentEquals(fileSystem1, fileSystem2));
62          assertTrue(PathUtils.contentEquals(fileSystem2, fileSystem1));
63          assertTrue(PathUtils.contentEquals(fileSystem1, fileSystem1));
64          assertTrue(PathUtils.contentEquals(fileSystem2, fileSystem2));
65      }
66  
67      private void assertContentNotEquals(final FileSystem fileSystem1, final FileSystem fileSystem2) throws IOException {
68          assertFalse(PathUtils.contentEquals(fileSystem1, fileSystem2));
69          assertFalse(PathUtils.contentEquals(fileSystem2, fileSystem1));
70          assertTrue(PathUtils.contentEquals(fileSystem1, fileSystem1));
71          assertTrue(PathUtils.contentEquals(fileSystem2, fileSystem2));
72      }
73  
74      private void assertDirectoryAndFileContentEquals(final Path dir1, final Path dir2) throws IOException {
75          assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
76          assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
77          assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
78          assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
79      }
80  
81      private void assertDirectoryAndFileContentNotEquals(final Path dir1, final Path dir2) throws IOException {
82          assertFalse(PathUtils.directoryAndFileContentEquals(dir1, dir2));
83          assertFalse(PathUtils.directoryAndFileContentEquals(dir2, dir1));
84          assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
85          assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
86      }
87  
88      private void assertFileContentEquals(final Path path1, final Path path2) throws IOException {
89          assertTrue(PathUtils.fileContentEquals(path1, path1));
90          assertTrue(PathUtils.fileContentEquals(path1, path2));
91          assertTrue(PathUtils.fileContentEquals(path2, path2));
92          assertTrue(PathUtils.fileContentEquals(path2, path1));
93      }
94  
95      private void assertFileContentNotEquals(final Path path1, final Path path2) throws IOException {
96          assertFalse(PathUtils.fileContentEquals(path1, path2));
97          assertFalse(PathUtils.fileContentEquals(path2, path1));
98          assertTrue(PathUtils.fileContentEquals(path1, path1));
99          assertTrue(PathUtils.fileContentEquals(path2, path2));
100     }
101 
102     private String getName() {
103         return this.getClass().getSimpleName();
104     }
105 
106     @ParameterizedTest
107     @MethodSource("testConfigurations")
108     void testContentEqualsFileSystemsMemVsMem(final Configuration configuration) throws Exception {
109         final Path refDir = Paths.get("src/test/resources/dir-equals-tests");
110         try (FileSystem fileSystem1 = Jimfs.newFileSystem(configuration);
111                 FileSystem fileSystem2 = Jimfs.newFileSystem(configuration)) {
112             final Path fsDir1 = fileSystem1.getPath(refDir.getFileName().toString());
113             final Path fsDir2 = fileSystem2.getPath(refDir.getFileName().toString());
114             assertTrue(PathUtils.copyDirectory(refDir, fsDir1).getByteCounter().get() > 0);
115             assertTrue(PathUtils.copyDirectory(refDir, fsDir2).getByteCounter().get() > 0);
116             assertContentEquals(fileSystem1, fileSystem2);
117         }
118     }
119 
120     @ParameterizedTest
121     @MethodSource("testConfigurations")
122     void testContentEqualsFileSystemsMemVsZip(final Configuration configuration) throws Exception {
123         final Path refDir = Paths.get("src/test/resources/dir-equals-tests");
124         try (FileSystem fileSystem1 = Jimfs.newFileSystem(configuration);
125                 FileSystem fileSystem2 = FileSystems.newFileSystem(refDir.resolveSibling(refDir.getFileName() + ".zip"), null)) {
126             final Path fsDir1 = fileSystem1.getPath(refDir.getFileName().toString());
127             final PathCounters copyDirectory = PathUtils.copyDirectory(refDir, fsDir1);
128             assertTrue(copyDirectory.getByteCounter().get() > 0);
129             assertContentEquals(fileSystem1, fileSystem2);
130         }
131     }
132 
133     @Test
134     void testContentEqualsFileSystemsZipVsZip() throws Exception {
135         final Path zipPath = Paths.get("src/test/resources/dir-equals-tests.zip");
136         final Path zipCopy = temporaryFolder.toPath().resolve("copy2.zip");
137         Files.copy(zipPath, zipCopy, StandardCopyOption.REPLACE_EXISTING);
138         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath, null); FileSystem fileSystem2 = FileSystems.newFileSystem(zipCopy, null)) {
139             assertContentEquals(fileSystem1, fileSystem2);
140         }
141         final Path emptyZip = Paths.get("src/test/resources/org/apache/commons/io/empty.zip");
142         try (FileSystem fileSystem1 = FileSystems.newFileSystem(emptyZip, null); FileSystem fileSystem2 = FileSystems.newFileSystem(emptyZip, null)) {
143             assertContentEquals(fileSystem1, fileSystem2);
144         }
145         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipCopy, null); FileSystem fileSystem2 = FileSystems.newFileSystem(emptyZip, null)) {
146             assertContentNotEquals(fileSystem1, fileSystem2);
147         }
148         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath, null); FileSystem fileSystem2 = FileSystems.newFileSystem(emptyZip, null)) {
149             assertContentNotEquals(fileSystem1, fileSystem2);
150         }
151     }
152 
153     @Test
154     void testDirectoryAndFileContentEquals() throws Exception {
155         // Non-existent files
156         final Path path1 = new File(temporaryFolder, getName()).toPath();
157         final Path path2 = new File(temporaryFolder, getName() + "2").toPath();
158         assertDirectoryAndFileContentEquals(null, null);
159         assertDirectoryAndFileContentNotEquals(path1, null);
160         // both don't exist
161         assertDirectoryAndFileContentEquals(path1, path2);
162         // Tree equals true tests
163         {
164             // Trees of files only that contain the same files.
165             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only1");
166             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only2");
167             assertDirectoryAndFileContentEquals(dir1, dir2);
168         }
169         {
170             // Trees of directories containing other directories.
171             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir1");
172             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir2");
173             assertDirectoryAndFileContentEquals(dir1, dir2);
174         }
175         {
176             // Trees of directories containing other directories and files.
177             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
178             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
179             assertDirectoryAndFileContentEquals(dir1, dir2);
180         }
181         // Tree equals false tests
182         {
183             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/directory-files-only1");
184             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/");
185             assertDirectoryAndFileContentNotEquals(dir1, dir2);
186         }
187         {
188             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files");
189             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files");
190             assertDirectoryAndFileContentNotEquals(dir1, dir2);
191         }
192     }
193 
194     /**
195      * Tests IO-872 PathUtils.directoryAndFileContentEquals doesn't work across FileSystems.
196      *
197      * @throws Exception on test failure.
198      */
199     @Test
200     void testDirectoryAndFileContentEqualsDifferentFileSystemsFileVsZip() throws Exception {
201         final Path dir1 = Paths.get("src/test/resources/dir-equals-tests");
202         try (FileSystem fileSystem = FileSystems.newFileSystem(dir1.resolveSibling(dir1.getFileName() + ".zip"), null)) {
203             final Path dir2 = fileSystem.getPath("/dir-equals-tests");
204             // WindowsPath, UnixPath, and ZipPath equals() methods always return false if the argument is not of the same instance as itself.
205             assertDirectoryAndFileContentEquals(dir1, dir2);
206         }
207     }
208 
209     /**
210      * Tests IO-872 PathUtils.directoryAndFileContentEquals doesn't work across FileSystems.
211      *
212      * @throws Exception on test failure.
213      */
214     @Test
215     void testDirectoryAndFileContentEqualsDifferentFileSystemsZipVsZip() throws Exception {
216         final Path zipPath = Paths.get("src/test/resources/dir-equals-tests.zip");
217         final Path zipCopy = temporaryFolder.toPath().resolve("copy1.zip");
218         Files.copy(zipPath, zipCopy, StandardCopyOption.REPLACE_EXISTING);
219         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath, null);
220                 FileSystem fileSystem2 = FileSystems.newFileSystem(zipCopy, null)) {
221             final Path dir1 = fileSystem1.getPath("/dir-equals-tests");
222             final Path dir2 = fileSystem2.getPath("/dir-equals-tests");
223             // WindowsPath, UnixPath, and ZipPath equals() methods always return false if the argument is not of the same instance as itself.
224             assertDirectoryAndFileContentEquals(dir1, dir2);
225         }
226     }
227 
228     /**
229      * Tests IO-872 PathUtils.directoryAndFileContentEquals doesn't work across FileSystems.
230      *
231      * @throws Exception on test failure.
232      */
233     @Test
234     void testDirectoryAndFileContentEqualsDifferentFileSystemsZipVsZipEmpty() throws Exception {
235         final Path zipPath = Paths.get("src/test/resources/dir-equals-tests.zip");
236         final Path zipCopy = temporaryFolder.toPath().resolve("copy1.zip");
237         final Path emptyZip = Paths.get("src/test/resources/org/apache/commons/io/empty.zip");
238         Files.copy(zipPath, zipCopy, StandardCopyOption.REPLACE_EXISTING);
239         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath, null);
240                 FileSystem fileSystem2 = FileSystems.newFileSystem(emptyZip, null)) {
241             final Path dir1 = fileSystem1.getPath("/dir-equals-tests");
242             final Path dir2 = fileSystem2.getPath("/");
243             // WindowsPath, UnixPath, and ZipPath equals() methods always return false if the argument is not of the same instance as itself.
244             assertDirectoryAndFileContentNotEquals(dir1, dir2);
245         }
246         try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath, null);
247                 FileSystem fileSystem2 = FileSystems.newFileSystem(emptyZip, null)) {
248             final Path dir1 = fileSystem1.getPath("/dir-equals-tests");
249             final Path dir2 = fileSystem2.getRootDirectories().iterator().next();
250             // WindowsPath, UnixPath, and ZipPath equals() methods always return false if the argument is not of the same instance as itself.
251             assertDirectoryAndFileContentNotEquals(dir1, dir2);
252         }
253         Files.copy(emptyZip, zipCopy, StandardCopyOption.REPLACE_EXISTING);
254         try (FileSystem fileSystem1 = FileSystems.newFileSystem(emptyZip, null);
255                 FileSystem fileSystem2 = FileSystems.newFileSystem(zipCopy, null)) {
256             final Path dir1 = fileSystem1.getPath("/");
257             final Path dir2 = fileSystem2.getPath("/");
258             // WindowsPath, UnixPath, and ZipPath equals() methods always return false if the argument is not of the same instance as itself.
259             assertDirectoryAndFileContentEquals(dir1, dir2);
260         }
261     }
262 
263     @Test
264     void testDirectoryContentEquals() throws Exception {
265         // Non-existent files
266         final Path path1 = new File(temporaryFolder, getName()).toPath();
267         final Path path2 = new File(temporaryFolder, getName() + "2").toPath();
268         assertTrue(PathUtils.directoryContentEquals(null, null));
269         assertFalse(PathUtils.directoryContentEquals(null, path1));
270         assertFalse(PathUtils.directoryContentEquals(path1, null));
271         // both don't exist
272         assertTrue(PathUtils.directoryContentEquals(path1, path1));
273         assertTrue(PathUtils.directoryContentEquals(path1, path2));
274         assertTrue(PathUtils.directoryContentEquals(path2, path2));
275         assertTrue(PathUtils.directoryContentEquals(path2, path1));
276         // Tree equals true tests
277         {
278             // Trees of files only that contain the same files.
279             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only1");
280             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only2");
281             assertTrue(PathUtils.directoryContentEquals(dir1, dir2));
282             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
283             assertTrue(PathUtils.directoryContentEquals(dir1, dir1));
284             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
285         }
286         {
287             // Trees of directories containing other directories.
288             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir1");
289             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir2");
290             assertTrue(PathUtils.directoryContentEquals(dir1, dir2));
291             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
292             assertTrue(PathUtils.directoryContentEquals(dir1, dir1));
293             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
294         }
295         {
296             // Trees of directories containing other directories and files.
297             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
298             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
299             assertTrue(PathUtils.directoryContentEquals(dir1, dir2));
300             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
301             assertTrue(PathUtils.directoryContentEquals(dir1, dir1));
302             assertTrue(PathUtils.directoryContentEquals(dir2, dir2));
303         }
304         // Tree equals false tests
305         {
306             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/directory-files-only1");
307             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/");
308             assertFalse(PathUtils.directoryContentEquals(dir1, dir2));
309             assertFalse(PathUtils.directoryContentEquals(dir2, dir1));
310         }
311         {
312             final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files");
313             final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files");
314             assertFalse(PathUtils.directoryContentEquals(dir1, dir2));
315             assertFalse(PathUtils.directoryContentEquals(dir2, dir1));
316         }
317     }
318 
319     @Test
320     void testFileContentEquals() throws Exception {
321         // Non-existent files
322         final Path path1 = new File(temporaryFolder, getName()).toPath();
323         final Path path2 = new File(temporaryFolder, getName() + "2").toPath();
324         assertTrue(PathUtils.fileContentEquals(null, null));
325         assertFileContentNotEquals(path1, null);
326         // both don't exist
327         assertFileContentEquals(path1, path2);
328         // Directories
329         assertThrows(IOException.class, () -> PathUtils.fileContentEquals(temporaryFolder.toPath(), temporaryFolder.toPath()));
330         // Different files
331         final Path objFile1 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object");
332         PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1);
333         final Path objFile1b = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object2");
334         PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1b);
335         final Path objFile2 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".collection");
336         PathUtils.copyFile(getClass().getResource("/java/util/Collection.class"), objFile2);
337         assertFalse(PathUtils.fileContentEquals(objFile1, objFile2));
338         assertFalse(PathUtils.fileContentEquals(objFile1b, objFile2));
339         assertTrue(PathUtils.fileContentEquals(objFile1, objFile1b));
340         assertTrue(PathUtils.fileContentEquals(objFile1, objFile1));
341         assertTrue(PathUtils.fileContentEquals(objFile1b, objFile1b));
342         assertTrue(PathUtils.fileContentEquals(objFile2, objFile2));
343         // Equal files
344         Files.createFile(path1);
345         Files.createFile(path2);
346         assertFileContentEquals(path1, path2);
347     }
348 
349     @Test
350     void testFileContentEqualsZip() throws Exception {
351         final Path path1 = Paths.get("src/test/resources/org/apache/commons/io/bla.zip");
352         final Path path2 = Paths.get("src/test/resources/org/apache/commons/io/bla-copy.zip");
353         // moby.zip is from https://issues.apache.org/jira/browse/COMPRESS-93
354         final Path path3 = Paths.get("src/test/resources/org/apache/commons/io/moby.zip");
355         assertFileContentEquals(path1, path2);
356         assertFileContentNotEquals(path1, path3);
357     }
358 
359     @Test
360     void testFileContentEqualsZipFileSystem() throws Exception {
361         try (FileSystem fileSystem = FileSystems.newFileSystem(Paths.get("src/test/resources/org/apache/commons/io/test-same-size-diff-contents.zip"),
362                 ClassLoader.getSystemClassLoader())) {
363             // Contains one char: A
364             final Path path1 = fileSystem.getPath("/test-same-size-diff-contents/A.txt");
365             // Contains one char: B
366             final Path path2 = fileSystem.getPath("/test-same-size-diff-contents/B.txt");
367             assertTrue(Files.exists(path1));
368             assertTrue(Files.exists(path2));
369             assertFileContentNotEquals(path1, path2);
370         }
371     }
372 
373 }