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