1 /*
   2  * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.IOException;
  25 import java.nio.file.FileSystem;
  26 import java.nio.file.FileSystems;
  27 import java.nio.file.Files;
  28 import java.nio.file.InvalidPathException;
  29 import java.nio.file.Path;
  30 import java.nio.file.Paths;
  31 import java.nio.file.ProviderMismatchException;
  32 
  33 /**
  34  *
  35  * @test
  36  * @bug 8038500 8040059 8139956 8146754 8172921 8186142
  37  * @summary Tests path operations for zip provider.
  38  *
  39  * @modules jdk.zipfs
  40  * @run main PathOps
  41  * @run main/othervm/java.security.policy=test.policy PathOps
  42  */
  43 
  44 public class PathOps {
  45 
  46     static final java.io.PrintStream out = System.out;
  47     static FileSystem fs;
  48 
  49     private String input;
  50     private Path path;
  51     private Exception exc;
  52 
  53     private PathOps(String first, String... more) {
  54         out.println();
  55         input = first;
  56         try {
  57             path = fs.getPath(first, more);
  58             out.format("%s -> %s", first, path);
  59         } catch (Exception x) {
  60             exc = x;
  61             out.format("%s -> %s", first, x);
  62         }
  63         out.println();
  64     }
  65 
  66     Path path() {
  67         return path;
  68     }
  69 
  70     void fail() {
  71         throw new RuntimeException("PathOps failed");
  72     }
  73 
  74     void checkPath() {
  75         if (path == null) {
  76             throw new InternalError("path is null");
  77         }
  78     }
  79 
  80     void check(Object result, String expected) {
  81         out.format("\tExpected: %s\n", expected);
  82         out.format("\tActual: %s\n",  result);
  83         if (result == null) {
  84             if (expected == null) return;
  85         } else {
  86             // compare string representations
  87             if (expected != null && result.toString().equals(expected.toString()))
  88                 return;
  89         }
  90         fail();
  91     }
  92 
  93     void check(Object result, boolean expected) {
  94         check(result, Boolean.toString(expected));
  95     }
  96 
  97     PathOps root(String expected) {
  98         out.println("check root");
  99         checkPath();
 100         check(path.getRoot(), expected);
 101         return this;
 102     }
 103 
 104     PathOps parent(String expected) {
 105         out.println("check parent");
 106         checkPath();
 107         check(path.getParent(), expected);
 108         return this;
 109     }
 110 
 111     PathOps name(String expected) {
 112         out.println("check name");
 113         checkPath();
 114         check(path.getFileName(), expected);
 115         return this;
 116     }
 117 
 118     PathOps element(int index, String expected) {
 119         out.format("check element %d\n", index);
 120         checkPath();
 121         check(path.getName(index), expected);
 122         return this;
 123     }
 124 
 125     PathOps subpath(int startIndex, int endIndex, String expected) {
 126         out.format("test subpath(%d,%d)\n", startIndex, endIndex);
 127         checkPath();
 128         check(path.subpath(startIndex, endIndex), expected);
 129         return this;
 130     }
 131 
 132     PathOps starts(String prefix) {
 133         out.format("test startsWith with %s\n", prefix);
 134         checkPath();
 135         Path s = fs.getPath(prefix);
 136         check(path.startsWith(s), true);
 137         return this;
 138     }
 139 
 140     PathOps notStarts(String prefix) {
 141         out.format("test not startsWith with %s\n", prefix);
 142         checkPath();
 143         Path s = fs.getPath(prefix);
 144         check(path.startsWith(s), false);
 145         return this;
 146     }
 147 
 148     PathOps ends(String suffix) {
 149         out.format("test endsWith %s\n", suffix);
 150         checkPath();
 151         Path s = fs.getPath(suffix);
 152         check(path.endsWith(s), true);
 153         return this;
 154     }
 155 
 156     PathOps notEnds(String suffix) {
 157         out.format("test not endsWith %s\n", suffix);
 158         checkPath();
 159         Path s = fs.getPath(suffix);
 160         check(path.endsWith(s), false);
 161         return this;
 162     }
 163 
 164     PathOps absolute() {
 165         out.println("check path is absolute");
 166         checkPath();
 167         check(path.isAbsolute(), true);
 168         return this;
 169     }
 170 
 171     PathOps notAbsolute() {
 172         out.println("check path is not absolute");
 173         checkPath();
 174         check(path.isAbsolute(), false);
 175         return this;
 176     }
 177 
 178     PathOps resolve(String other, String expected) {
 179         out.format("test resolve %s\n", other);
 180         checkPath();
 181         check(path.resolve(other), expected);
 182         return this;
 183     }
 184 
 185     PathOps resolvePath(String other, String expected) {
 186         out.format("test resolve %s\n", other);
 187         checkPath();
 188         check(path.resolve(fs.getPath(other)), expected);
 189         return this;
 190     }
 191 
 192     PathOps resolveSibling(String other, String expected) {
 193         out.format("test resolveSibling %s\n", other);
 194         checkPath();
 195         check(path.resolveSibling(other), expected);
 196         return this;
 197     }
 198 
 199     PathOps relativize(String other, String expected) {
 200         out.format("test relativize %s\n", other);
 201         checkPath();
 202         Path that = fs.getPath(other);
 203         check(path.relativize(that), expected);
 204         return this;
 205     }
 206 
 207     PathOps normalize(String expected) {
 208         out.println("check normalized path");
 209         checkPath();
 210         check(path.normalize(), expected);
 211         return this;
 212     }
 213 
 214     PathOps string(String expected) {
 215         out.println("check string representation");
 216         checkPath();
 217         check(path, expected);
 218         return this;
 219     }
 220 
 221     PathOps isSameFile(String target) {
 222         try {
 223             out.println("check two paths are same");
 224             checkPath();
 225             check(Files.isSameFile(path, test(target).path()), true);
 226         } catch (IOException ioe) {
 227             fail();
 228         }
 229         return this;
 230     }
 231 
 232     PathOps invalid() {
 233         if (!(exc instanceof InvalidPathException)) {
 234             out.println("InvalidPathException not thrown as expected");
 235             fail();
 236         }
 237         return this;
 238     }
 239 
 240     static PathOps test(String s) {
 241         return new PathOps(s);
 242     }
 243 
 244     static PathOps test(String first, String... more) {
 245         return new PathOps(first, more);
 246     }
 247 
 248     // -- PathOpss --
 249 
 250     static void header(String s) {
 251         out.println();
 252         out.println();
 253         out.println("-- " + s + " --");
 254     }
 255 
 256     static void doPathOpTests() {
 257         header("Path operations");
 258 
 259         // construction
 260         test("/")
 261             .string("/");
 262         test("/", "")
 263             .string("/");
 264         test("/", "foo")
 265             .string("/foo");
 266         test("/", "/foo")
 267             .string("/foo");
 268         test("/", "foo/")
 269             .string("/foo");
 270         test("foo", "bar", "gus")
 271             .string("foo/bar/gus");
 272         test("")
 273             .string("");
 274         test("", "/")
 275             .string("/");
 276         test("", "foo", "", "bar", "", "/gus")
 277             .string("foo/bar/gus");
 278 
 279         // all components
 280         test("/a/b/c")
 281             .root("/")
 282             .parent("/a/b")
 283             .name("c");
 284 
 285         // root component only
 286         test("/")
 287             .root("/")
 288             .parent(null)
 289             .name(null);
 290 
 291         // no root component
 292         test("a/b")
 293             .root(null)
 294             .parent("a")
 295             .name("b");
 296 
 297         // name component only
 298         test("foo")
 299             .root(null)
 300             .parent(null)
 301             .name("foo");
 302 
 303         // startsWith
 304         test("")
 305             .starts("")
 306             .notStarts("/");
 307         test("/")
 308             .starts("/")
 309             .notStarts("/foo");
 310         test("/foo")
 311             .starts("/")
 312             .starts("/foo")
 313             .notStarts("/f")
 314             .notStarts("");
 315         test("/foo/bar")
 316             .starts("/")
 317             .starts("/foo")
 318             .starts("/foo/")
 319             .starts("/foo/bar")
 320             .notStarts("/f")
 321             .notStarts("foo")
 322             .notStarts("foo/bar")
 323             .notStarts("");
 324         test("foo")
 325             .starts("foo")
 326             .notStarts("f");
 327         test("foo/bar")
 328             .starts("foo")
 329             .starts("foo/")
 330             .starts("foo/bar")
 331             .notStarts("f")
 332             .notStarts("/foo")
 333             .notStarts("/foo/bar");
 334 
 335         // endsWith
 336         test("")
 337             .ends("")
 338             .notEnds("/");
 339         test("/")
 340             .ends("/")
 341             .notEnds("foo")
 342             .notEnds("/foo");
 343         test("/foo")
 344             .ends("foo")
 345             .ends("/foo")
 346             .notEnds("/");
 347         test("/foo/bar")
 348             .ends("bar")
 349             .ends("foo/bar")
 350             .ends("foo/bar/")
 351             .ends("/foo/bar")
 352             .notEnds("/bar");
 353         test("/foo/bar/")
 354             .ends("bar")
 355             .ends("foo/bar")
 356             .ends("foo/bar/")
 357             .ends("/foo/bar")
 358             .notEnds("/bar");
 359         test("foo")
 360             .ends("foo");
 361         test("foo/bar")
 362             .ends("bar")
 363             .ends("bar/")
 364             .ends("foo/bar/")
 365             .ends("foo/bar");
 366 
 367         // elements
 368         test("a/b/c")
 369             .element(0,"a")
 370             .element(1,"b")
 371             .element(2,"c");
 372 
 373         // isAbsolute
 374         test("/")
 375             .absolute();
 376         test("/tmp")
 377             .absolute();
 378         test("tmp")
 379             .notAbsolute();
 380         test("")
 381             .notAbsolute();
 382 
 383         // resolve
 384         test("/tmp")
 385             .resolve("foo", "/tmp/foo")
 386             .resolve("/foo", "/foo")
 387             .resolve("", "/tmp");
 388         test("tmp")
 389             .resolve("foo", "tmp/foo")
 390             .resolve("/foo", "/foo")
 391             .resolve("", "tmp");
 392         test("")
 393             .resolve("", "")
 394             .resolve("foo", "foo")
 395             .resolve("/foo", "/foo");
 396         test("/")
 397             .resolve("", "/")
 398             .resolve("foo", "/foo")
 399             .resolve("/foo", "/foo")
 400             .resolve("/foo/", "/foo");
 401 
 402         // resolve(Path)
 403         test("/tmp")
 404             .resolvePath("foo", "/tmp/foo")
 405             .resolvePath("/foo", "/foo")
 406             .resolvePath("", "/tmp");
 407         test("tmp")
 408             .resolvePath("foo", "tmp/foo")
 409             .resolvePath("/foo", "/foo")
 410             .resolvePath("", "tmp");
 411         test("")
 412             .resolvePath("", "")
 413             .resolvePath("foo", "foo")
 414             .resolvePath("/foo", "/foo");
 415         test("/")
 416             .resolvePath("", "/")
 417             .resolvePath("foo", "/foo")
 418             .resolvePath("/foo", "/foo")
 419             .resolvePath("/foo/", "/foo");
 420 
 421         // resolveSibling
 422         test("foo")
 423             .resolveSibling("bar", "bar")
 424             .resolveSibling("/bar", "/bar")
 425             .resolveSibling("", "");
 426         test("foo/bar")
 427             .resolveSibling("gus", "foo/gus")
 428             .resolveSibling("/gus", "/gus")
 429             .resolveSibling("", "foo");
 430         test("/foo")
 431             .resolveSibling("gus", "/gus")
 432             .resolveSibling("/gus", "/gus")
 433             .resolveSibling("", "/");
 434         test("/foo/bar")
 435             .resolveSibling("gus", "/foo/gus")
 436             .resolveSibling("/gus", "/gus")
 437             .resolveSibling("", "/foo");
 438         test("")
 439             .resolveSibling("foo", "foo")
 440             .resolveSibling("/foo", "/foo")
 441             .resolve("", "");
 442 
 443         // relativize
 444         test("/a/b/c")
 445             .relativize("/a/b/c", "")
 446             .relativize("/a/b/c/d/e", "d/e")
 447             .relativize("/a/x", "../../x")
 448             .relativize("/x", "../../../x");
 449         test("a/b/c")
 450             .relativize("a/b/c/d", "d")
 451             .relativize("a/x", "../../x")
 452             .relativize("x", "../../../x")
 453             .relativize("", "../../..");
 454         test("")
 455             .relativize("a", "a")
 456             .relativize("a/b/c", "a/b/c")
 457             .relativize("", "");
 458         test("/")
 459             .relativize("/a", "a")
 460             .relativize("/a/c", "a/c");
 461         // 8146754
 462         test("/tmp/path")
 463             .relativize("/tmp/path/a.txt", "a.txt");
 464         test("/tmp/path/")
 465             .relativize("/tmp/path/a.txt", "a.txt");
 466 
 467         // normalize
 468         test("/")
 469             .normalize("/");
 470         test("foo")
 471             .normalize("foo");
 472         test("/foo")
 473             .normalize("/foo");
 474         test(".")
 475             .normalize("");
 476         test("..")
 477             .normalize("..");
 478         test("/..")
 479             .normalize("/");
 480         test("/../..")
 481             .normalize("/");
 482         test("foo/.")
 483             .normalize("foo");
 484         test("./foo")
 485             .normalize("foo");
 486         test("foo/..")
 487             .normalize("");
 488         test("../foo")
 489             .normalize("../foo");
 490         test("../../foo")
 491             .normalize("../../foo");
 492         test("foo/bar/..")
 493             .normalize("foo");
 494         test("foo/bar/gus/../..")
 495             .normalize("foo");
 496         test("/foo/bar/gus/../..")
 497             .normalize("/foo");
 498         test("/./.")
 499             .normalize("/");
 500         test("/.")
 501             .normalize("/");
 502         test("/./abc")
 503             .normalize("/abc");
 504         // invalid
 505         test("foo\u0000bar")
 506             .invalid();
 507         test("\u0000foo")
 508             .invalid();
 509         test("bar\u0000")
 510             .invalid();
 511         test("//foo\u0000bar")
 512             .invalid();
 513         test("//\u0000foo")
 514             .invalid();
 515         test("//bar\u0000")
 516             .invalid();
 517 
 518         // normalization
 519         test("//foo//bar")
 520             .string("/foo/bar")
 521             .root("/")
 522             .parent("/foo")
 523             .name("bar");
 524 
 525         // isSameFile
 526         test("/fileDoesNotExist")
 527             .isSameFile("/fileDoesNotExist");
 528 
 529         // 8139956
 530         out.println("check getNameCount");
 531         int nc = fs.getPath("/").relativize(fs.getPath("/")).getNameCount();
 532         if (nc != 1) {
 533             out.format("\tExpected: 1\n");
 534             out.format("\tActual: %d\n",  nc);
 535             throw new RuntimeException("getNameCount of empty path failed");
 536         }
 537      }
 538 
 539     static void npes() {
 540         header("NullPointerException");
 541 
 542         Path path = fs.getPath("foo");
 543 
 544         try {
 545             path.resolve((String)null);
 546             throw new RuntimeException("NullPointerException not thrown");
 547         } catch (NullPointerException npe) {
 548         }
 549 
 550         try {
 551             path.relativize(null);
 552             throw new RuntimeException("NullPointerException not thrown");
 553         } catch (NullPointerException npe) {
 554         }
 555 
 556         try {
 557             path.compareTo(null);
 558             throw new RuntimeException("NullPointerException not thrown");
 559         } catch (NullPointerException npe) {
 560         }
 561 
 562         try {
 563             path.startsWith((Path)null);
 564             throw new RuntimeException("NullPointerException not thrown");
 565         } catch (NullPointerException npe) {
 566         }
 567 
 568         try {
 569             path.endsWith((Path)null);
 570             throw new RuntimeException("NullPointerException not thrown");
 571         } catch (NullPointerException npe) {
 572         }
 573 
 574     }
 575 
 576     static void mismatchedProviders() {
 577         header("ProviderMismatchException");
 578         Path path = fs.getPath("foo");
 579         Path other = Paths.get("foo");
 580         try {
 581             path.compareTo(other);
 582             throw new RuntimeException("ProviderMismatchException not thrown");
 583         } catch (ProviderMismatchException pme) {}
 584 
 585         try {
 586             path.resolve(other);
 587             throw new RuntimeException("ProviderMismatchException not thrown");
 588         } catch (ProviderMismatchException pme) {}
 589 
 590         try {
 591             path.relativize(other);
 592             throw new RuntimeException("ProviderMismatchException not thrown");
 593         } catch (ProviderMismatchException pme) {}
 594 
 595         try {
 596             if (path.startsWith(other))
 597                 throw new RuntimeException("providerMismatched startsWith() returns true ");
 598             if (path.endsWith(other))
 599                 throw new RuntimeException("providerMismatched endsWith() returns true ");
 600         } catch (ProviderMismatchException pme) {
 601             throw new RuntimeException("ProviderMismatchException is thrown for starts/endsWith()");
 602         }
 603     }
 604 
 605     public static void main(String[] args) throws IOException {
 606         // create empty JAR file, test doesn't require any contents
 607         Path emptyJar = Utils.createJarFile("empty.jar");
 608 
 609         fs = FileSystems.newFileSystem(emptyJar, (ClassLoader)null);
 610         try {
 611             npes();
 612             mismatchedProviders();
 613             doPathOpTests();
 614         } finally {
 615             fs.close();
 616         }
 617     }
 618 }