1/*
2 * Copyright (C) 2009 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.  You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.google.common.io;
18
19import static com.google.common.base.Charsets.UTF_8;
20import static com.google.common.io.Files.simplifyPath;
21
22import com.google.common.base.CharMatcher;
23import com.google.common.base.Splitter;
24
25import junit.framework.TestCase;
26
27import java.io.IOException;
28import java.net.URL;
29import java.util.Iterator;
30
31/**
32 * Unit tests for {@link Files#simplifyPath}.
33 *
34 * @author Pablo Bellver
35 */
36public class FilesSimplifyPathTest extends TestCase {
37
38  public void testSimplifyEmptyString() {
39    assertEquals(".", simplifyPath(""));
40  }
41
42  public void testSimplifyDot() {
43    assertEquals(".", simplifyPath("."));
44  }
45
46  public void testSimplifyWhiteSpace() {
47    assertEquals(" ", simplifyPath(" "));
48  }
49
50  public void testSimplify2() {
51    assertEquals("x", simplifyPath("x"));
52  }
53
54  public void testSimplify3() {
55    assertEquals("/a/b/c/d", simplifyPath("/a/b/c/d"));
56  }
57
58  public void testSimplify4() {
59    assertEquals("/a/b/c/d", simplifyPath("/a/b/c/d/"));
60  }
61
62  public void testSimplify5() {
63    assertEquals("/a/b", simplifyPath("/a//b"));
64  }
65
66  public void testSimplify6() {
67    assertEquals("/a/b", simplifyPath("//a//b/"));
68  }
69
70  public void testSimplify7() {
71    assertEquals("/", simplifyPath("/.."));
72  }
73
74  public void testSimplify8() {
75    assertEquals("/", simplifyPath("/././././"));
76  }
77
78  public void testSimplify9() {
79    assertEquals("/a", simplifyPath("/a/b/.."));
80  }
81
82  public void testSimplify10() {
83    assertEquals("/", simplifyPath("/a/b/../../.."));
84  }
85
86  public void testSimplify11() {
87    assertEquals("/", simplifyPath("//a//b/..////../..//"));
88  }
89
90  public void testSimplify12() {
91    assertEquals("/x", simplifyPath("//a//../x//"));
92  }
93
94  public void testSimplify13() {
95    assertEquals("../c", simplifyPath("a/b/../../../c"));
96  }
97
98  public void testSimplifyDotDot() {
99    assertEquals("..", simplifyPath(".."));
100  }
101
102  public void testSimplifyDotDotSlash() {
103    assertEquals("..", simplifyPath("../"));
104    assertEquals("..", simplifyPath("a/../.."));
105    assertEquals("..", simplifyPath("a/../../"));
106  }
107
108  public void testSimplifyDotDots() {
109    assertEquals("../..", simplifyPath("a/../../.."));
110    assertEquals("../../..", simplifyPath("a/../../../.."));
111  }
112
113  public void testSimplifyRootedDotDots() {
114    assertEquals("/", simplifyPath("/../../.."));
115    assertEquals("/", simplifyPath("/../../../"));
116  }
117
118  // b/4558855
119  public void testMadbotsBug() {
120    assertEquals("../this", simplifyPath("../this"));
121    assertEquals("../this/is/ok", simplifyPath("../this/is/ok"));
122    assertEquals("../ok", simplifyPath("../this/../ok"));
123  }
124
125  // https://code.google.com/p/guava-libraries/issues/detail?id=705
126  public void test705() {
127    assertEquals("../b", simplifyPath("x/../../b"));
128    assertEquals("b", simplifyPath("x/../b"));
129  }
130
131  // https://code.google.com/p/guava-libraries/issues/detail?id=716
132  public void test716() {
133    assertEquals("b", simplifyPath("./b"));
134    assertEquals("b", simplifyPath("./b/."));
135    assertEquals("b", simplifyPath("././b/./."));
136    assertEquals("b", simplifyPath("././b"));
137    assertEquals("a/b", simplifyPath("./a/b"));
138  }
139
140  public void testHiddenFiles() {
141    assertEquals(".b", simplifyPath(".b"));
142    assertEquals(".b", simplifyPath("./.b"));
143    assertEquals(".metadata/b", simplifyPath(".metadata/b"));
144    assertEquals(".metadata/b", simplifyPath("./.metadata/b"));
145  }
146
147  // https://code.google.com/p/guava-libraries/issues/detail?id=716
148  public void testMultipleDotFilenames() {
149    assertEquals("..a", simplifyPath("..a"));
150    assertEquals("/..a", simplifyPath("/..a"));
151    assertEquals("/..a/..b", simplifyPath("/..a/..b"));
152    assertEquals("/.....a/..b", simplifyPath("/.....a/..b"));
153    assertEquals("..../....", simplifyPath("..../...."));
154    assertEquals("..a../..b..", simplifyPath("..a../..b.."));
155  }
156
157  public void testSlashDot() {
158    assertEquals("/", simplifyPath("/."));
159  }
160
161  // http://code.google.com/p/guava-libraries/issues/detail?id=722
162  public void testInitialSlashDotDot() {
163    assertEquals("/c", simplifyPath("/../c"));
164  }
165
166  // http://code.google.com/p/guava-libraries/issues/detail?id=722
167  public void testInitialSlashDot() {
168    assertEquals("/a", simplifyPath("/./a"));
169    assertEquals("/.a", simplifyPath("/.a/a/.."));
170  }
171
172  // http://code.google.com/p/guava-libraries/issues/detail?id=722
173  public void testConsecutiveParentsAfterPresent() {
174    assertEquals("../..", simplifyPath("./../../"));
175    assertEquals("../..", simplifyPath("./.././../"));
176  }
177
178  /*
179   * We co-opt some URI resolution tests for our purposes.
180   * Some of the tests have queries and anchors that are a little silly here.
181   */
182
183  /** http://gbiv.com/protocols/uri/rfc/rfc2396.html#rfc.section.C.1 */
184  public void testRfc2396Normal() {
185    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/g"));
186    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/./g"));
187    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/g/"));
188
189    assertEquals("/a/b/c/g?y", simplifyPath("/a/b/c/g?y"));
190    assertEquals("/a/b/c/g#s", simplifyPath("/a/b/c/g#s"));
191    assertEquals("/a/b/c/g?y#s", simplifyPath("/a/b/c/g?y#s"));
192    assertEquals("/a/b/c/;x", simplifyPath("/a/b/c/;x"));
193    assertEquals("/a/b/c/g;x", simplifyPath("/a/b/c/g;x"));
194    assertEquals("/a/b/c/g;x?y#s", simplifyPath("/a/b/c/g;x?y#s"));
195    assertEquals("/a/b/c", simplifyPath("/a/b/c/."));
196    assertEquals("/a/b/c", simplifyPath("/a/b/c/./"));
197    assertEquals("/a/b", simplifyPath("/a/b/c/.."));
198    assertEquals("/a/b", simplifyPath("/a/b/c/../"));
199    assertEquals("/a/b/g", simplifyPath("/a/b/c/../g"));
200    assertEquals("/a", simplifyPath("/a/b/c/../.."));
201    assertEquals("/a", simplifyPath("/a/b/c/../../"));
202    assertEquals("/a/g", simplifyPath("/a/b/c/../../g"));
203  }
204
205  /** http://gbiv.com/protocols/uri/rfc/rfc2396.html#rfc.section.C.2 */
206  public void testRfc2396Abnormal() {
207    assertEquals("/a/b/c/g.", simplifyPath("/a/b/c/g."));
208    assertEquals("/a/b/c/.g", simplifyPath("/a/b/c/.g"));
209    assertEquals("/a/b/c/g..", simplifyPath("/a/b/c/g.."));
210    assertEquals("/a/b/c/..g", simplifyPath("/a/b/c/..g"));
211    assertEquals("/a/b/g", simplifyPath("/a/b/c/./../g"));
212    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/./g/."));
213    assertEquals("/a/b/c/g/h", simplifyPath("/a/b/c/g/./h"));
214    assertEquals("/a/b/c/h", simplifyPath("/a/b/c/g/../h"));
215    assertEquals("/a/b/c/g;x=1/y", simplifyPath("/a/b/c/g;x=1/./y"));
216    assertEquals("/a/b/c/y", simplifyPath("/a/b/c/g;x=1/../y"));
217  }
218
219  /** http://gbiv.com/protocols/uri/rfc/rfc3986.html#relative-normal */
220  public void testRfc3986Normal() {
221    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/g"));
222    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/./g"));
223    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/g/"));
224
225    assertEquals("/a/b/c/g?y", simplifyPath("/a/b/c/g?y"));
226    assertEquals("/a/b/c/g#s", simplifyPath("/a/b/c/g#s"));
227    assertEquals("/a/b/c/g?y#s", simplifyPath("/a/b/c/g?y#s"));
228    assertEquals("/a/b/c/;x", simplifyPath("/a/b/c/;x"));
229    assertEquals("/a/b/c/g;x", simplifyPath("/a/b/c/g;x"));
230    assertEquals("/a/b/c/g;x?y#s", simplifyPath("/a/b/c/g;x?y#s"));
231
232    assertEquals("/a/b/c", simplifyPath("/a/b/c/."));
233    assertEquals("/a/b/c", simplifyPath("/a/b/c/./"));
234    assertEquals("/a/b", simplifyPath("/a/b/c/.."));
235    assertEquals("/a/b", simplifyPath("/a/b/c/../"));
236    assertEquals("/a/b/g", simplifyPath("/a/b/c/../g"));
237    assertEquals("/a", simplifyPath("/a/b/c/../.."));
238    assertEquals("/a", simplifyPath("/a/b/c/../../"));
239    assertEquals("/a/g", simplifyPath("/a/b/c/../../g"));
240  }
241
242  /** http://gbiv.com/protocols/uri/rfc/rfc3986.html#relative-abnormal */
243  public void testRfc3986Abnormal() {
244    assertEquals("/g", simplifyPath("/a/b/c/../../../g"));
245    assertEquals("/g", simplifyPath("/a/b/c/../../../../g"));
246
247    assertEquals("/a/b/c/g.", simplifyPath("/a/b/c/g."));
248    assertEquals("/a/b/c/.g", simplifyPath("/a/b/c/.g"));
249    assertEquals("/a/b/c/g..", simplifyPath("/a/b/c/g.."));
250    assertEquals("/a/b/c/..g", simplifyPath("/a/b/c/..g"));
251    assertEquals("/a/b/g", simplifyPath("/a/b/c/./../g"));
252    assertEquals("/a/b/c/g", simplifyPath("/a/b/c/./g/."));
253    assertEquals("/a/b/c/g/h", simplifyPath("/a/b/c/g/./h"));
254    assertEquals("/a/b/c/h", simplifyPath("/a/b/c/g/../h"));
255    assertEquals("/a/b/c/g;x=1/y", simplifyPath("/a/b/c/g;x=1/./y"));
256    assertEquals("/a/b/c/y", simplifyPath("/a/b/c/g;x=1/../y"));
257  }
258
259  public void testExtensiveWithAbsolutePrefix() throws IOException {
260    // Inputs are /b/c/<every possible 10-character string of characters "a./">
261    // Expected outputs are from realpath -s.
262    doExtensiveTest("testdata/simplifypathwithabsoluteprefixtests.txt");
263  }
264
265  public void testExtensiveNoPrefix() throws IOException {
266    /*
267     * Inputs are <every possible 10-character string of characters "a./">
268     *
269     * Expected outputs are generated by the code itself, but they've been
270     * checked against the inputs under Bash in order to confirm that the two
271     * forms are equivalent (though not necessarily minimal, though we hope this
272     * to be the case). Thus, this test is more of a regression test.
273     *
274     * Rough instructions to regenerate the test outputs and verify correctness:
275     * - Temporarily change this test:
276     * --- Comment out assertEquals.
277     * --- System.out.println(input + " " + simplifyPath(input));
278     * --- fail(). (If the test were to pass, its output would be hidden.)
279     * - Run the test.
280     * - Pull the relevant lines of output from the test into a testcases file.
281     * - Test the output:
282     * --- cat testcases | while read L; do
283     *       X=($L)
284     *       A=$( cd /b/c && sudo mkdir -p ${X[0]} && cd ${X[0]} && pwd |
285     *           sed -e 's#^//*#/#' )
286     *       B=$( cd /b/c && cd ${X[1]} && pwd )
287     *       cmp -s <(echo $A) <(echo $B) || echo "$X[0] -> $A vs. $B"
288     *     done | tee testoutput
289     * - Move that testcases file to the appropriate name under testdata.
290     *
291     * The last test will take hours, and if it passes, the output will be empty.
292     */
293    doExtensiveTest("testdata/simplifypathnoprefixtests.txt");
294  }
295
296  private void doExtensiveTest(String resourceName) throws IOException {
297    Splitter splitter = Splitter.on(CharMatcher.WHITESPACE);
298    URL url = getClass().getResource(resourceName);
299    for (String line : Resources.readLines(url, UTF_8)) {
300      Iterator<String> iterator = splitter.split(line).iterator();
301      String input = iterator.next();
302      String expectedOutput = iterator.next();
303      assertFalse(iterator.hasNext());
304      assertEquals(expectedOutput, simplifyPath(input));
305    }
306  }
307}
308