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    *      http://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  package org.apache.commons.vfs2;
18  
19  import static org.junit.jupiter.api.Assertions.assertThrows;
20  
21  import org.junit.Test;
22  
23  /**
24   * Test cases for file naming.
25   * <p>
26   * TODO - Add tests for all FileName methods.
27   * </p>
28   */
29  public class NamingTests extends AbstractProviderTestCase {
30  
31      /**
32       * Asserts that a particular relative name is invalid for a particular scope.
33       */
34      private void assertBadName(final FileName name, final String relName, final NameScope scope) {
35          try {
36              getManager().resolveName(name, relName, scope);
37              fail("expected failure");
38          } catch (final FileSystemException e) {
39              // TODO - should check error message
40          }
41      }
42  
43      /**
44       * Checks that a relative name resolves to the expected absolute path. Tests both forward and back slashes.
45       */
46      private void assertSameName(final String expectedPath, final FileName baseName, final String relName)
47              throws Exception {
48          assertSameName(expectedPath, baseName, relName, NameScope.FILE_SYSTEM);
49      }
50  
51      /**
52       * Checks that a relative name resolves to the expected absolute path. Tests both forward and back slashes.
53       */
54      private void assertSameName(final String expectedPath, final FileName baseName, final String relName,
55              final NameScope scope) throws Exception {
56          // Try the supplied name
57          FileName name = getManager().resolveName(baseName, relName, scope);
58          assertEquals(expectedPath, name.getPath());
59  
60          String temp;
61  
62          // Replace the separators
63          temp = relName.replace('\\', '/');
64          name = getManager().resolveName(baseName, temp, scope);
65          assertEquals(expectedPath, name.getPath());
66  
67          // And again
68          temp = relName.replace('/', '\\');
69          name = getManager().resolveName(baseName, temp, scope);
70          assertEquals(expectedPath, name.getPath());
71      }
72  
73      /**
74       * Tests resolution of absolute names.
75       */
76      private void checkAbsoluteNames(final FileName name) throws Exception {
77          // Root
78          assertSameName("/", name, "/");
79          assertSameName("/", name, "//");
80          assertSameName("/", name, "/.");
81          assertSameName("/", name, "/some file/..");
82  
83          // Some absolute names
84          assertSameName("/a", name, "/a");
85          assertSameName("/a", name, "/./a");
86          assertSameName("/a", name, "/a/.");
87          assertSameName("/a/b", name, "/a/b");
88  
89          // Some bad names
90          assertBadName(name, "/..", NameScope.FILE_SYSTEM);
91          assertBadName(name, "/a/../..", NameScope.FILE_SYSTEM);
92      }
93  
94      /**
95       * Name resolution tests that are common for CHILD or DESCENDENT scope.
96       */
97      private void checkDescendentNames(final FileName name, final NameScope scope) throws Exception {
98          // Make some assumptions about the name
99          assertFalse(name.getPath().equals("/"));
100         assertFalse(name.getPath().endsWith("/a"));
101         assertFalse(name.getPath().endsWith("/a/b"));
102 
103         // Test names with the same prefix
104         final String path = name.getPath() + "/a";
105         assertSameName(path, name, path, scope);
106         assertSameName(path, name, "../" + name.getBaseName() + "/a", scope);
107         assertSameName(path, name, "./a", scope);
108         assertSameName(path, name, "./a/foo/..", scope);
109         assertSameName(path, name, "foo/../a", scope);
110         assertSameName(path, name, "foo%2f..%2fa", scope);
111         assertSameName(path, name, "foo%2f/..%2fa", scope);
112         assertSameName(path, name, "foo/%2f..%2fa", scope);
113 
114         // Test an empty name
115         assertBadName(name, "", scope);
116 
117         // Test . name
118         assertBadName(name, ".", scope);
119         assertBadName(name, "./", scope);
120 
121         // Test ancestor names
122         assertBadName(name, "..", scope);
123         assertBadName(name, "../a", scope);
124         assertBadName(name, "../" + name.getBaseName() + "a", scope);
125         assertBadName(name, "a/..", scope);
126         assertBadName(name, "%2e%2e/ab", scope);
127         assertBadName(name, "..%2f../ab", scope);
128         assertBadName(name, "foo%2f..%2f..%2fa", scope);
129         assertBadName(name, "foo%2f..%2f..%2fnone-child%2fa", scope);
130 
131         // Test absolute names
132         assertBadName(name, "/", scope);
133         assertBadName(name, "/a", scope);
134         assertBadName(name, "/a/b", scope);
135         assertBadName(name, name.getPath(), scope);
136         assertBadName(name, name.getPath() + "a", scope);
137     }
138 
139     /**
140      * Tests conversion from absolute to relative names.
141      */
142     @Test
143     public void testAbsoluteNameConvert() throws Exception {
144         final FileName baseName = getReadFolder().getName();
145 
146         String path = "/test1/test2";
147         FileName name = getManager().resolveName(baseName, path);
148         assertEquals(path, name.getPath());
149 
150         // Try child and descendent names
151         testRelName(name, "child");
152         testRelName(name, "child1/child2");
153 
154         // Try own name
155         testRelName(name, ".");
156 
157         // Try parent, and root
158         testRelName(name, "..");
159         testRelName(name, "../..");
160 
161         // Try sibling and descendent of sibling
162         testRelName(name, "../sibling");
163         testRelName(name, "../sibling/child");
164 
165         // Try siblings with similar names
166         testRelName(name, "../test2_not");
167         testRelName(name, "../test2_not/child");
168         testRelName(name, "../test");
169         testRelName(name, "../test/child");
170 
171         // Try unrelated
172         testRelName(name, "../../unrelated");
173         testRelName(name, "../../test");
174         testRelName(name, "../../test/child");
175 
176         // Test against root
177         path = "/";
178         name = getManager().resolveName(baseName, path);
179         assertEquals(path, name.getPath());
180 
181         // Try child and descendent names (against root)
182         testRelName(name, "child");
183         testRelName(name, "child1/child2");
184 
185         // Try own name (against root)
186         testRelName(name, ".");
187     }
188 
189     /**
190      * Tests resolution of absolute names.
191      */
192     @Test
193     public void testAbsoluteNames() throws Exception {
194         // Test against the base folder
195         FileName name = getReadFolder().getName();
196         checkAbsoluteNames(name);
197 
198         // Test against the root
199         name = getReadFolder().getFileSystem().getRoot().getName();
200         checkAbsoluteNames(name);
201 
202         // Test against some unknown file
203         name = getManager().resolveName(name, "a/b/unknown");
204         checkAbsoluteNames(name);
205     }
206 
207     /**
208      * Tests child file names.
209      */
210     @Test
211     public void testChildName() throws Exception {
212         final FileName baseName = getReadFolder().getName();
213         final String basePath = baseName.getPath();
214         final FileName name = getManager().resolveName(baseName, "some-child", NameScope.CHILD);
215 
216         // Test path is absolute
217         assertTrue("is absolute", basePath.startsWith("/"));
218 
219         // Test base name
220         assertEquals("base name", "some-child", name.getBaseName());
221 
222         // Test absolute path
223         assertEquals("absolute path", basePath + "/some-child", name.getPath());
224 
225         // Test parent path
226         assertEquals("parent absolute path", basePath, name.getParent().getPath());
227 
228         // Try using a compound name to find a child
229         assertBadName(name, "a/b", NameScope.CHILD);
230 
231         // Check other invalid names
232         checkDescendentNames(name, NameScope.CHILD);
233     }
234 
235     /**
236      * Tests descendent name resolution.
237      */
238     @Test
239     public void testDescendentName() throws Exception {
240         final FileName baseName = getReadFolder().getName();
241 
242         // Test direct child
243         String path = baseName.getPath() + "/some-child";
244         assertSameName(path, baseName, "some-child", NameScope.DESCENDENT);
245 
246         // Test compound name
247         path += "/grand-child";
248         assertSameName(path, baseName, "some-child/grand-child", NameScope.DESCENDENT);
249 
250         // Test relative names
251         assertSameName(path, baseName, "./some-child/grand-child", NameScope.DESCENDENT);
252         assertSameName(path, baseName, "./nada/../some-child/grand-child", NameScope.DESCENDENT);
253         assertSameName(path, baseName, "some-child/./grand-child", NameScope.DESCENDENT);
254 
255         // Test badly formed descendent names
256         checkDescendentNames(baseName, NameScope.DESCENDENT);
257     }
258 
259     /**
260      * Tests relative name resolution, relative to the base folder.
261      */
262     @Test
263     public void testNameResolution() throws Exception {
264         final FileName baseName = getReadFolder().getName();
265         final String parentPath = baseName.getParent().getPath();
266         final String path = baseName.getPath();
267         final String childPath = path + "/some-child";
268 
269         // Test empty relative path
270         assertSameName(path, baseName, "");
271 
272         // Test . relative path
273         assertSameName(path, baseName, ".");
274 
275         // Test ./ relative path
276         assertSameName(path, baseName, "./");
277 
278         // Test .// relative path
279         assertSameName(path, baseName, ".//");
280 
281         // Test .///.///. relative path
282         assertSameName(path, baseName, ".///.///.");
283         assertSameName(path, baseName, "./\\/.\\//.");
284 
285         // Test <elem>/.. relative path
286         assertSameName(path, baseName, "a/..");
287 
288         // Test .. relative path
289         assertSameName(parentPath, baseName, "..");
290 
291         // Test ../ relative path
292         assertSameName(parentPath, baseName, "../");
293 
294         // Test ..//./ relative path
295         assertSameName(parentPath, baseName, "..//./");
296         assertSameName(parentPath, baseName, "..//.\\");
297 
298         // Test <elem>/../.. relative path
299         assertSameName(parentPath, baseName, "a/../..");
300 
301         // Test <elem> relative path
302         assertSameName(childPath, baseName, "some-child");
303 
304         // Test ./<elem> relative path
305         assertSameName(childPath, baseName, "./some-child");
306 
307         // Test ./<elem>/ relative path
308         assertSameName(childPath, baseName, "./some-child/");
309 
310         // Test <elem>/././././ relative path
311         assertSameName(childPath, baseName, "./some-child/././././");
312 
313         // Test <elem>/../<elem> relative path
314         assertSameName(childPath, baseName, "a/../some-child");
315 
316         // Test <elem>/<elem>/../../<elem> relative path
317         assertSameName(childPath, baseName, "a/b/../../some-child");
318     }
319 
320     /**
321      * Tests resolution of relative file names via the FS manager.
322      */
323     @Test
324     public void testRelativeURI() throws Exception {
325         // Build base dir
326         getManager().setBaseFile(getReadFolder());
327 
328         // Locate the base dir
329         FileObject file = getManager().resolveFile(".");
330         assertSame("file object", getReadFolder(), file);
331 
332         // Locate a child
333         file = getManager().resolveFile("some-child");
334         assertSame("file object", getReadFolder(), file.getParent());
335 
336         // Locate a descendent
337         file = getManager().resolveFile("some-folder/some-file");
338         assertSame("file object", getReadFolder(), file.getParent().getParent());
339 
340         // Locate parent
341         file = getManager().resolveFile("..");
342         assertSame("file object", getReadFolder().getParent(), file);
343 
344         // free basefile
345         getManager().setBaseFile((FileObject) null);
346     }
347 
348     /**
349      * Tests encoding of relative URI.
350      */
351     @Test
352     public void testRelativeUriEncoding() throws Exception {
353         // Build base dir
354         getManager().setBaseFile(getReadFolder());
355         final String path = getReadFolder().getName().getPath();
356 
357         // §1 Encode "some file"
358         FileObject file = getManager().resolveFile("%73%6f%6d%65%20%66%69%6c%65");
359         assertEquals(path + "/some file", file.getName().getPathDecoded());
360 
361         // §2 Encode "."
362         file = getManager().resolveFile("%2e");
363         // 18-6-2005 imario@apache.org: no need to keep the "current directory"
364         // assertEquals(path + "/.", file.getName().getPathDecoded());
365         assertEquals(path, file.getName().getPathDecoded());
366 
367         // §3 Encode '%'
368         file = getManager().resolveFile("a%25");
369         assertEquals(path + "/a%", file.getName().getPathDecoded());
370 
371         // §4 Encode /
372         file = getManager().resolveFile("dir%2fchild");
373         assertEquals(path + "/dir/child", file.getName().getPathDecoded());
374 
375         // §5 Encode \
376         file = getManager().resolveFile("dir%5cchild");
377         // 18-6-2005 imario@apache.org: all file separators normalized to "/"
378         // decided to do this to get the same behavior as in §4 on Windows
379         // platforms
380         // assertEquals(path + "/dir\\child", file.getName().getPathDecoded());
381         assertEquals(path + "/dir/child", file.getName().getPathDecoded());
382 
383         // §6 Use "%" literal
384         assertThrows(FileSystemException.class, () -> getManager().resolveFile("%"));
385 
386         // §7 Not enough digits in encoded char
387         assertThrows(FileSystemException.class, () -> getManager().resolveFile("%5"));
388 
389         // §8 Invalid digit in encoded char
390         assertThrows(FileSystemException.class, () -> getManager().resolveFile("%q"));
391 
392         // free basefile
393         getManager().setBaseFile((FileObject) null);
394     }
395 
396     /**
397      * Checks that a file name converts to an expected relative path
398      */
399     private void testRelName(final FileName baseName, final String relPath) throws Exception {
400         final FileName expectedName = getManager().resolveName(baseName, relPath);
401 
402         // Convert to relative path, and check
403         final String actualRelPath = baseName.getRelativeName(expectedName);
404         assertEquals(relPath, actualRelPath);
405     }
406 
407     /**
408      * Tests the root file name.
409      */
410     @Test
411     public void testRootFileName() throws Exception {
412         // Locate the root file
413         final FileName rootName = getReadFolder().getFileSystem().getRoot().getName();
414 
415         // Test that the root path is "/"
416         assertEquals("root path", "/", rootName.getPath());
417 
418         // Test that the root base name is ""
419         assertEquals("root base name", "", rootName.getBaseName());
420 
421         // Test that the root name has no parent
422         assertNull("root parent", rootName.getParent());
423     }
424 
425 }