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