1 /*
   2  * Copyright (c) 2008, 2012, 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 /* @test
  25  * @bug 4313887 6838333 6925932 7006126 8037945 8072495
  26  * @summary Unit test for java.nio.file.Path path operations
  27  */
  28 
  29 import java.nio.file.*;
  30 
  31 public class PathOps {
  32 
  33     static final java.io.PrintStream out = System.out;
  34 
  35     private String input;
  36     private Path path;
  37     private Exception exc;
  38 
  39     private PathOps(String first, String... more) {
  40         out.println();
  41         input = first;
  42         try {
  43             path = FileSystems.getDefault().getPath(first, more);
  44             out.format("%s -> %s", first, path);
  45         } catch (Exception x) {
  46             exc = x;
  47             out.format("%s -> %s", first, x);
  48         }
  49         out.println();
  50     }
  51 
  52     Path path() {
  53         return path;
  54     }
  55 
  56     void fail() {
  57         throw new RuntimeException("PathOps failed");
  58     }
  59 
  60     void checkPath() {
  61         if (path == null) {
  62             throw new InternalError("path is null");
  63         }
  64     }
  65 
  66     void check(Object result, String expected) {
  67         out.format("\tExpected: %s\n", expected);
  68         out.format("\tActual: %s\n",  result);
  69         if (result == null) {
  70             if (expected == null) return;
  71         } else {
  72             // compare string representations
  73             if (expected != null && result.toString().equals(expected.toString()))
  74                 return;
  75         }
  76         fail();
  77     }
  78 
  79     void check(Object result, boolean expected) {
  80         check(result, Boolean.toString(expected));
  81     }
  82 
  83     PathOps root(String expected) {
  84         out.println("check root");
  85         checkPath();
  86         check(path.getRoot(), expected);
  87         return this;
  88     }
  89 
  90     PathOps parent(String expected) {
  91         out.println("check parent");
  92         checkPath();
  93         check(path.getParent(), expected);
  94         return this;
  95     }
  96 
  97     PathOps name(String expected) {
  98         out.println("check name");
  99         checkPath();
 100         check(path.getFileName(), expected);
 101         return this;
 102     }
 103 
 104     PathOps element(int index, String expected) {
 105         out.format("check element %d\n", index);
 106         checkPath();
 107         check(path.getName(index), expected);
 108         return this;
 109     }
 110 
 111     PathOps subpath(int startIndex, int endIndex, String expected) {
 112         out.format("test subpath(%d,%d)\n", startIndex, endIndex);
 113         checkPath();
 114         check(path.subpath(startIndex, endIndex), expected);
 115         return this;
 116     }
 117 
 118     PathOps starts(String prefix) {
 119         out.format("test startsWith with %s\n", prefix);
 120         checkPath();
 121         Path s = FileSystems.getDefault().getPath(prefix);
 122         check(path.startsWith(s), true);
 123         return this;
 124     }
 125 
 126     PathOps notStarts(String prefix) {
 127         out.format("test not startsWith with %s\n", prefix);
 128         checkPath();
 129         Path s = FileSystems.getDefault().getPath(prefix);
 130         check(path.startsWith(s), false);
 131         return this;
 132     }
 133 
 134     PathOps ends(String suffix) {
 135         out.format("test endsWith %s\n", suffix);
 136         checkPath();
 137         Path s = FileSystems.getDefault().getPath(suffix);
 138         check(path.endsWith(s), true);
 139         return this;
 140     }
 141 
 142     PathOps notEnds(String suffix) {
 143         out.format("test not endsWith %s\n", suffix);
 144         checkPath();
 145         Path s = FileSystems.getDefault().getPath(suffix);
 146         check(path.endsWith(s), false);
 147         return this;
 148     }
 149 
 150     PathOps absolute() {
 151         out.println("check path is absolute");
 152         checkPath();
 153         check(path.isAbsolute(), true);
 154         return this;
 155     }
 156 
 157     PathOps notAbsolute() {
 158         out.println("check path is not absolute");
 159         checkPath();
 160         check(path.isAbsolute(), false);
 161         return this;
 162     }
 163 
 164     PathOps resolve(String other, String expected) {
 165         out.format("test resolve %s\n", other);
 166         checkPath();
 167         check(path.resolve(other), expected);
 168         return this;
 169     }
 170 
 171     PathOps resolveSibling(String other, String expected) {
 172         out.format("test resolveSibling %s\n", other);
 173         checkPath();
 174         check(path.resolveSibling(other), expected);
 175         return this;
 176     }
 177 
 178     PathOps relativize(String other, String expected) {
 179         out.format("test relativize %s\n", other);
 180         checkPath();
 181         Path that = FileSystems.getDefault().getPath(other);
 182         check(path.relativize(that), expected);
 183         return this;
 184     }
 185 
 186     PathOps normalize(String expected) {
 187         out.println("check normalized path");
 188         checkPath();
 189         check(path.normalize(), expected);
 190         return this;
 191     }
 192 
 193     PathOps string(String expected) {
 194         out.println("check string representation");
 195         checkPath();
 196         check(path, expected);
 197         return this;
 198     }
 199 
 200     PathOps invalid() {
 201         if (!(exc instanceof InvalidPathException)) {
 202             out.println("InvalidPathException not thrown as expected");
 203             fail();
 204         }
 205         return this;
 206     }
 207 
 208     static PathOps test(String first, String... more) {
 209         return new PathOps(first, more);
 210     }
 211 
 212     // -- PathOpss --
 213 
 214     static void header(String s) {
 215         out.println();
 216         out.println();
 217         out.println("-- " + s + " --");
 218     }
 219 
 220     static void doWindowsTests() {
 221         header("Windows specific tests");
 222 
 223         // construction
 224         test("C:\\")
 225             .string("C:\\");
 226         test("C:\\", "")
 227             .string("C:\\");
 228         test("C:\\", "foo")
 229             .string("C:\\foo");
 230         test("C:\\", "\\foo")
 231             .string("C:\\foo");
 232         test("C:\\", "foo\\")
 233             .string("C:\\foo");
 234         test("foo", "bar", "gus")
 235             .string("foo\\bar\\gus");
 236         test("")
 237             .string("");
 238         test("", "C:\\")
 239             .string("C:\\");
 240         test("", "foo", "", "bar", "", "\\gus")
 241             .string("foo\\bar\\gus");
 242 
 243         // all components present
 244         test("C:\\a\\b\\c")
 245             .root("C:\\")
 246             .parent("C:\\a\\b")
 247             .name("c");
 248         test("C:a\\b\\c")
 249             .root("C:")
 250             .parent("C:a\\b")
 251             .name("c");
 252         test("\\\\server\\share\\a")
 253             .root("\\\\server\\share\\")
 254             .parent("\\\\server\\share\\")
 255             .name("a");
 256 
 257         // root component only
 258         test("C:\\")
 259             .root("C:\\")
 260             .parent(null)
 261             .name(null);
 262         test("C:")
 263             .root("C:")
 264             .parent(null)
 265             .name(null);
 266         test("\\\\server\\share\\")
 267             .root("\\\\server\\share\\")
 268             .parent(null)
 269             .name(null);
 270 
 271         // no root component
 272         test("a\\b")
 273             .root(null)
 274             .parent("a")
 275             .name("b");
 276 
 277         // name component only
 278         test("foo")
 279             .root(null)
 280             .parent(null)
 281             .name("foo");
 282         test("")
 283             .root(null)
 284             .parent(null)
 285             .name("");
 286 
 287         // startsWith
 288         test("C:\\")
 289             .starts("C:\\")
 290             .starts("c:\\")
 291             .notStarts("C")
 292             .notStarts("C:")
 293             .notStarts("");
 294         test("C:")
 295             .starts("C:")
 296             .starts("c:")
 297             .notStarts("C")
 298             .notStarts("");
 299         test("\\")
 300             .starts("\\");
 301         test("C:\\foo\\bar")
 302             .starts("C:\\")
 303             .starts("C:\\foo")
 304             .starts("C:\\FOO")
 305             .starts("C:\\foo\\bar")
 306             .starts("C:\\Foo\\Bar")
 307             .notStarts("C:")
 308             .notStarts("C")
 309             .notStarts("C:foo")
 310             .notStarts("");
 311         test("\\foo\\bar")
 312             .starts("\\")
 313             .starts("\\foo")
 314             .starts("\\foO")
 315             .starts("\\foo\\bar")
 316             .starts("\\fOo\\BaR")
 317             .notStarts("foo")
 318             .notStarts("foo\\bar")
 319             .notStarts("");
 320         test("foo\\bar")
 321             .starts("foo")
 322             .starts("foo\\bar")
 323             .notStarts("\\")
 324             .notStarts("");
 325         test("\\\\server\\share")
 326             .starts("\\\\server\\share")
 327             .starts("\\\\server\\share\\")
 328             .notStarts("\\")
 329             .notStarts("");
 330         test("")
 331             .starts("")
 332             .notStarts("\\");
 333 
 334         // endsWith
 335         test("C:\\")
 336             .ends("C:\\")
 337             .ends("c:\\")
 338             .notEnds("\\")
 339             .notEnds("");
 340         test("C:")
 341             .ends("C:")
 342             .ends("c:")
 343             .notEnds("");
 344         test("\\")
 345             .ends("\\")
 346             .notEnds("");
 347         test("C:\\foo\\bar")
 348             .ends("bar")
 349             .ends("BAR")
 350             .ends("foo\\bar")
 351             .ends("Foo\\Bar")
 352             .ends("C:\\foo\\bar")
 353             .ends("c:\\foO\\baR")
 354             .notEnds("r")
 355             .notEnds("\\foo\\bar")
 356             .notEnds("");
 357         test("\\foo\\bar")
 358             .ends("bar")
 359             .ends("BaR")
 360             .ends("foo\\bar")
 361             .ends("foO\\baR")
 362             .ends("\\foo\\bar")
 363             .ends("\\Foo\\Bar")
 364             .notEnds("oo\\bar")
 365             .notEnds("");
 366         test("foo\\bar")
 367             .ends("bar")
 368             .ends("BAR")
 369             .ends("foo\\bar")
 370             .ends("Foo\\Bar")
 371             .notEnds("ar")
 372             .notEnds("");
 373         test("\\\\server\\share")
 374             .ends("\\\\server\\share")
 375             .ends("\\\\server\\share\\")
 376             .notEnds("shared")
 377             .notEnds("\\")
 378             .notEnds("");
 379         test("")
 380             .ends("")
 381             .notEnds("\\");
 382 
 383         // elements
 384         test("C:\\a\\b\\c")
 385             .element(0, "a")
 386             .element(1, "b")
 387             .element(2, "c");
 388         test("foo.bar\\gus.alice")
 389             .element(0, "foo.bar")
 390             .element(1, "gus.alice");
 391         test("")
 392             .element(0, "");
 393 
 394         // subpath
 395         test("C:\\foo")
 396             .subpath(0, 1, "foo");
 397         test("C:foo")
 398             .subpath(0, 1, "foo");
 399         test("foo")
 400             .subpath(0, 1, "foo");
 401         test("C:\\foo\\bar\\gus")
 402             .subpath(0, 1, "foo")
 403             .subpath(0, 2, "foo\\bar")
 404             .subpath(0, 3, "foo\\bar\\gus")
 405             .subpath(1, 2, "bar")
 406             .subpath(1, 3, "bar\\gus")
 407             .subpath(2, 3, "gus");
 408         test("\\\\server\\share\\foo")
 409             .subpath(0, 1, "foo");
 410         test("")
 411             .subpath(0, 1, "");
 412 
 413         // isAbsolute
 414         test("foo").notAbsolute();
 415         test("C:").notAbsolute();
 416         test("C:\\").absolute();
 417         test("C:\\abc").absolute();
 418         test("\\\\server\\share\\").absolute();
 419         test("").notAbsolute();
 420 
 421         // resolve
 422         test("C:\\")
 423             .resolve("foo", "C:\\foo")
 424             .resolve("D:\\bar", "D:\\bar")
 425             .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 426             .resolve("C:foo", "C:\\foo")
 427             .resolve("D:foo", "D:foo")
 428             .resolve("", "C:\\");
 429         test("\\")
 430             .resolve("foo", "\\foo")
 431             .resolve("D:bar", "D:bar")
 432             .resolve("C:\\bar", "C:\\bar")
 433             .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 434             .resolve("\\foo", "\\foo")
 435             .resolve("", "\\");
 436         test("\\foo")
 437             .resolve("bar", "\\foo\\bar")
 438             .resolve("D:bar", "D:bar")
 439             .resolve("C:\\bar", "C:\\bar")
 440             .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 441             .resolve("\\bar", "\\bar")
 442             .resolve("", "\\foo");
 443         test("foo")
 444             .resolve("bar", "foo\\bar")
 445             .resolve("D:\\bar", "D:\\bar")
 446             .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 447             .resolve("C:bar", "C:bar")
 448             .resolve("D:foo", "D:foo")
 449             .resolve("", "foo");
 450         test("C:")
 451             .resolve("foo", "C:foo")
 452             .resolve("", "C:");
 453         test("\\\\server\\share\\foo")
 454             .resolve("bar", "\\\\server\\share\\foo\\bar")
 455             .resolve("\\bar", "\\\\server\\share\\bar")
 456             .resolve("D:\\bar", "D:\\bar")
 457             .resolve("\\\\other\\share\\bar", "\\\\other\\share\\bar")
 458             .resolve("D:bar", "D:bar")
 459             .resolve("", "\\\\server\\share\\foo");
 460         test("")
 461             .resolve("", "")
 462             .resolve("foo", "foo")
 463             .resolve("C:\\", "C:\\")
 464             .resolve("C:foo", "C:foo")
 465             .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar");
 466 
 467         // resolveSibling
 468         test("foo")
 469             .resolveSibling("bar", "bar")
 470             .resolveSibling("D:\\bar", "D:\\bar")
 471             .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 472             .resolveSibling("C:bar", "C:bar")
 473             .resolveSibling("D:foo", "D:foo")
 474             .resolveSibling("", "");
 475         test("foo\\bar")
 476             .resolveSibling("gus", "foo\\gus")
 477             .resolveSibling("D:\\bar", "D:\\bar")
 478             .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 479             .resolveSibling("C:bar", "C:bar")
 480             .resolveSibling("D:foo", "D:foo")
 481             .resolveSibling("", "foo");
 482         test("C:\\foo")
 483             .resolveSibling("gus", "C:\\gus")
 484             .resolveSibling("D:\\bar", "D:\\bar")
 485             .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 486             .resolveSibling("C:bar", "C:\\bar")
 487             .resolveSibling("D:foo", "D:foo")
 488             .resolveSibling("", "C:\\");
 489         test("C:\\foo\\bar")
 490             .resolveSibling("gus", "C:\\foo\\gus")
 491             .resolveSibling("D:\\bar", "D:\\bar")
 492             .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar")
 493             .resolveSibling("C:bar", "C:\\foo\\bar")
 494             .resolveSibling("D:foo", "D:foo")
 495             .resolveSibling("", "C:\\foo");
 496         test("\\\\server\\share\\foo")
 497             .resolveSibling("bar", "\\\\server\\share\\bar")
 498             .resolveSibling("\\bar", "\\\\server\\share\\bar")
 499             .resolveSibling("D:\\bar", "D:\\bar")
 500             .resolveSibling("\\\\other\\share\\bar", "\\\\other\\share\\bar")
 501             .resolveSibling("D:bar", "D:bar")
 502             .resolveSibling("", "\\\\server\\share\\");
 503         test("")
 504             .resolveSibling("", "")
 505             .resolveSibling("foo", "foo")
 506             .resolveSibling("C:\\", "C:\\");
 507 
 508         // relativize
 509         test("foo\\bar")
 510             .relativize("foo\\bar", "")
 511             .relativize("foo", "..");
 512         test("C:\\a\\b\\c")
 513             .relativize("C:\\a", "..\\..")
 514             .relativize("C:\\a\\b\\c", "");
 515         test("\\\\server\\share\\foo")
 516             .relativize("\\\\server\\share\\bar", "..\\bar")
 517             .relativize("\\\\server\\share\\foo", "");
 518         test("")
 519             .relativize("", "")
 520             .relativize("a", "a")
 521             .relativize("a\\b\\c", "a\\b\\c");
 522 
 523         // normalize
 524         test("C:\\")
 525             .normalize("C:\\");
 526         test("C:\\.")
 527             .normalize("C:\\");
 528         test("C:\\..")
 529             .normalize("C:\\");
 530         test("\\\\server\\share")
 531             .normalize("\\\\server\\share\\");
 532         test("\\\\server\\share\\.")
 533             .normalize("\\\\server\\share\\");
 534         test("\\\\server\\share\\..")
 535             .normalize("\\\\server\\share\\");
 536         test("C:")
 537             .normalize("C:");
 538         test("C:.")
 539             .normalize("C:");
 540         test("C:..")
 541             .normalize("C:..");
 542         test("\\")
 543             .normalize("\\");
 544         test("\\.")
 545             .normalize("\\");
 546         test("\\..")
 547             .normalize("\\");
 548         test("foo")
 549             .normalize("foo");
 550         test("foo\\.")
 551             .normalize("foo");
 552         test("foo\\..")
 553             .normalize("");
 554         test("C:\\foo")
 555             .normalize("C:\\foo");
 556         test("C:\\foo\\.")
 557             .normalize("C:\\foo");
 558         test("C:\\.\\foo")
 559             .normalize("C:\\foo");
 560         test("C:\\foo\\..")
 561             .normalize("C:\\");
 562         test("C:\\..\\foo")
 563             .normalize("C:\\foo");
 564         test("\\\\server\\share\\foo")
 565             .normalize("\\\\server\\share\\foo");
 566         test("\\\\server\\share\\foo\\.")
 567             .normalize("\\\\server\\share\\foo");
 568         test("\\\\server\\share\\.\\foo")
 569             .normalize("\\\\server\\share\\foo");
 570         test("\\\\server\\share\\foo\\..")
 571             .normalize("\\\\server\\share\\");
 572         test("\\\\server\\share\\..\\foo")
 573             .normalize("\\\\server\\share\\foo");
 574         test("C:foo")
 575             .normalize("C:foo");
 576         test("C:foo\\.")
 577             .normalize("C:foo");
 578         test("C:.\\foo")
 579             .normalize("C:foo");
 580         test("C:foo\\..")
 581             .normalize("C:");
 582         test("C:..\\foo")
 583             .normalize("C:..\\foo");
 584         test("\\foo")
 585             .normalize("\\foo");
 586         test("\\foo\\.")
 587             .normalize("\\foo");
 588         test("\\.\\foo")
 589             .normalize("\\foo");
 590         test("\\foo\\..")
 591             .normalize("\\");
 592         test("\\..\\foo")
 593             .normalize("\\foo");
 594         test(".")
 595             .normalize("");
 596         test("..")
 597             .normalize("..");
 598         test("\\..\\..")
 599             .normalize("\\");
 600         test("..\\..\\foo")
 601             .normalize("..\\..\\foo");
 602         test("foo\\bar\\..")
 603             .normalize("foo");
 604         test("foo\\bar\\.\\..")
 605             .normalize("foo");
 606         test("foo\\bar\\gus\\..\\..")
 607             .normalize("foo");
 608         test(".\\foo\\.\\bar\\.\\gus\\..\\.\\..")
 609             .normalize("foo");
 610         test("")
 611             .normalize("");
 612 
 613         // UNC corner cases
 614         test("\\\\server\\share\\")
 615             .root("\\\\server\\share\\")
 616             .parent(null)
 617             .name(null);
 618         test("\\\\server")
 619             .invalid();
 620         test("\\\\server\\")
 621             .invalid();
 622         test("\\\\server\\share")
 623             .root("\\\\server\\share\\")
 624             .parent(null)
 625             .name(null);
 626 
 627         // invalid
 628         test(":\\foo")
 629             .invalid();
 630         test("C::")
 631             .invalid();
 632         test("C:\\?")           // invalid character
 633             .invalid();
 634         test("C:\\*")           // invalid character
 635             .invalid();
 636         test("C:\\abc\u0001\\foo")
 637             .invalid();
 638         test("C:\\\u0019\\foo")
 639             .invalid();
 640         test("\\\\server\u0019\\share")
 641             .invalid();
 642         test("\\\\server\\share\u0019")
 643             .invalid();
 644         test("foo\u0000\bar")
 645             .invalid();
 646         test("C:\\foo ")                // trailing space
 647              .invalid();
 648         test("C:\\foo \\bar")
 649             .invalid();
 650         //test("C:\\foo.")              // trailing dot
 651             //.invalid();
 652         //test("C:\\foo...\\bar")
 653             //.invalid();
 654 
 655         // normalization at construction time (remove redundant and replace slashes)
 656         test("C:/a/b/c")
 657             .string("C:\\a\\b\\c")
 658             .root("C:\\")
 659             .parent("C:\\a\\b");
 660         test("C://a//b//c")
 661             .string("C:\\a\\b\\c")
 662             .root("C:\\")
 663             .parent("C:\\a\\b");
 664 
 665         // hashCode
 666         header("hashCode");
 667         int h1 = test("C:\\foo").path().hashCode();
 668         int h2 = test("c:\\FOO").path().hashCode();
 669         if (h1 != h2)
 670             throw new RuntimeException("PathOps failed");
 671     }
 672 
 673     static void doUnixTests() {
 674         header("Unix specific tests");
 675 
 676         // construction
 677         test("/")
 678             .string("/");
 679         test("/", "")
 680             .string("/");
 681         test("/", "foo")
 682             .string("/foo");
 683         test("/", "/foo")
 684             .string("/foo");
 685         test("/", "foo/")
 686             .string("/foo");
 687         test("foo", "bar", "gus")
 688             .string("foo/bar/gus");
 689         test("")
 690             .string("");
 691         test("", "/")
 692             .string("/");
 693         test("", "foo", "", "bar", "", "/gus")
 694             .string("foo/bar/gus");
 695 
 696         // all components
 697         test("/a/b/c")
 698             .root("/")
 699             .parent("/a/b")
 700             .name("c");
 701 
 702         // root component only
 703         test("/")
 704             .root("/")
 705             .parent(null)
 706             .name(null);
 707 
 708         // no root component
 709         test("a/b")
 710             .root(null)
 711             .parent("a")
 712             .name("b");
 713 
 714         // name component only
 715         test("foo")
 716             .root(null)
 717             .parent(null)
 718             .name("foo");
 719         test("")
 720              .root(null)
 721              .parent(null)
 722              .name("");
 723 
 724         // startsWith
 725         test("/")
 726             .starts("/")
 727             .notStarts("")
 728             .notStarts("/foo");
 729         test("/foo")
 730             .starts("/")
 731             .starts("/foo")
 732             .notStarts("/f");
 733         test("/foo/bar")
 734             .starts("/")
 735             .starts("/foo")
 736             .starts("/foo/bar")
 737             .notStarts("/f")
 738             .notStarts("foo")
 739             .notStarts("foo/bar");
 740         test("foo")
 741             .starts("foo")
 742             .notStarts("")
 743             .notStarts("f");
 744         test("foo/bar")
 745             .starts("foo")
 746             .starts("foo/bar")
 747             .notStarts("f")
 748             .notStarts("/foo")
 749             .notStarts("/foo/bar");
 750         test("")
 751              .starts("")
 752              .notStarts("/");
 753 
 754         // endsWith
 755         test("/")
 756             .ends("/")
 757             .notEnds("")
 758             .notEnds("foo")
 759             .notEnds("/foo");
 760         test("/foo")
 761             .ends("foo")
 762             .ends("/foo")
 763             .notEnds("fool");
 764         test("/foo/bar")
 765             .ends("bar")
 766             .ends("foo/bar")
 767             .ends("/foo/bar")
 768             .notEnds("ar")
 769             .notEnds("barack")
 770             .notEnds("/bar")
 771             .notEnds("o/bar");
 772         test("foo")
 773             .ends("foo")
 774             .notEnds("")
 775             .notEnds("oo")
 776             .notEnds("oola");
 777         test("foo/bar")
 778             .ends("bar")
 779             .ends("foo/bar")
 780             .notEnds("r")
 781             .notEnds("barmaid")
 782             .notEnds("/bar");
 783         test("foo/bar/gus")
 784             .ends("gus")
 785             .ends("bar/gus")
 786             .ends("foo/bar/gus")
 787             .notEnds("g")
 788             .notEnds("/gus")
 789             .notEnds("r/gus")
 790             .notEnds("barack/gus")
 791             .notEnds("bar/gust");
 792         test("")
 793             .ends("")
 794             .notEnds("/");
 795 
 796         // elements
 797         test("a/b/c")
 798             .element(0, "a")
 799             .element(1, "b")
 800             .element(2, "c");
 801         test("")
 802             .element(0, "");
 803 
 804         // subpath
 805         test("/foo")
 806             .subpath(0, 1, "foo");
 807         test("foo")
 808             .subpath(0, 1, "foo");
 809         test("/foo/bar")
 810             .subpath(0, 1, "foo")
 811             .subpath(1, 2, "bar")
 812             .subpath(0, 2, "foo/bar");
 813         test("foo/bar")
 814             .subpath(0, 1, "foo")
 815             .subpath(1, 2, "bar")
 816             .subpath(0, 2, "foo/bar");
 817         test("/foo/bar/gus")
 818             .subpath(0, 1, "foo")
 819             .subpath(1, 2, "bar")
 820             .subpath(2, 3, "gus")
 821             .subpath(0, 2, "foo/bar")
 822             .subpath(1, 3, "bar/gus")
 823             .subpath(0, 3, "foo/bar/gus");
 824         test("foo/bar/gus")
 825             .subpath(0, 1, "foo")
 826             .subpath(1, 2, "bar")
 827             .subpath(2, 3, "gus")
 828             .subpath(0, 2, "foo/bar")
 829             .subpath(1, 3, "bar/gus")
 830             .subpath(0, 3, "foo/bar/gus");
 831         test("")
 832             .subpath(0, 1, "");
 833 
 834         // isAbsolute
 835         test("/")
 836             .absolute();
 837         test("/tmp")
 838             .absolute();
 839         test("tmp")
 840             .notAbsolute();
 841         test("")
 842             .notAbsolute();
 843 
 844 
 845         // resolve
 846         test("/tmp")
 847             .resolve("foo", "/tmp/foo")
 848             .resolve("/foo", "/foo")
 849             .resolve("", "/tmp");
 850         test("tmp")
 851             .resolve("foo", "tmp/foo")
 852             .resolve("/foo", "/foo")
 853             .resolve("", "tmp");
 854         test("")
 855             .resolve("", "")
 856             .resolve("foo", "foo")
 857             .resolve("/foo", "/foo");
 858 
 859         // resolveSibling
 860         test("foo")
 861             .resolveSibling("bar", "bar")
 862             .resolveSibling("/bar", "/bar")
 863             .resolveSibling("", "");
 864         test("foo/bar")
 865             .resolveSibling("gus", "foo/gus")
 866             .resolveSibling("/gus", "/gus")
 867             .resolveSibling("", "foo");
 868         test("/foo")
 869             .resolveSibling("gus", "/gus")
 870             .resolveSibling("/gus", "/gus")
 871             .resolveSibling("", "/");
 872         test("/foo/bar")
 873             .resolveSibling("gus", "/foo/gus")
 874             .resolveSibling("/gus", "/gus")
 875             .resolveSibling("", "/foo");
 876         test("")
 877             .resolveSibling("foo", "foo")
 878             .resolveSibling("/foo", "/foo")
 879             .resolve("", "");
 880 
 881         // relativize
 882         test("/a/b/c")
 883             .relativize("/a/b/c", "")
 884             .relativize("/a/b/c/d/e", "d/e")
 885             .relativize("/a/x", "../../x")
 886             .relativize("/x", "../../../x");
 887         test("a/b/c")
 888             .relativize("a/b/c/d", "d")
 889             .relativize("a/x", "../../x")
 890             .relativize("x", "../../../x")
 891             .relativize("", "../../..");
 892         test("")
 893             .relativize("a", "a")
 894             .relativize("a/b/c", "a/b/c")
 895             .relativize("", "");
 896 
 897         // normalize
 898         test("/")
 899             .normalize("/");
 900         test("foo")
 901             .normalize("foo");
 902         test("/foo")
 903             .normalize("/foo");
 904         test("")
 905             .normalize("");
 906         test(".")
 907             .normalize("");
 908         test("..")
 909             .normalize("..");
 910         test("/..")
 911             .normalize("/");
 912         test("/../..")
 913             .normalize("/");
 914         test("foo/.")
 915             .normalize("foo");
 916         test("./foo")
 917             .normalize("foo");
 918         test("foo/..")
 919             .normalize("");
 920         test("../foo")
 921             .normalize("../foo");
 922         test("../../foo")
 923             .normalize("../../foo");
 924         test("foo/bar/..")
 925             .normalize("foo");
 926         test("foo/bar/gus/../..")
 927             .normalize("foo");
 928         test("/foo/bar/gus/../..")
 929             .normalize("/foo");
 930 
 931         // invalid
 932         test("foo\u0000bar")
 933             .invalid();
 934         test("\u0000foo")
 935             .invalid();
 936         test("bar\u0000")
 937             .invalid();
 938         test("//foo\u0000bar")
 939             .invalid();
 940         test("//\u0000foo")
 941             .invalid();
 942         test("//bar\u0000")
 943             .invalid();
 944 
 945         // normalization of input
 946         test("//foo//bar")
 947             .string("/foo/bar")
 948             .root("/")
 949             .parent("/foo")
 950             .name("bar");
 951     }
 952 
 953     static void npes() {
 954         header("NullPointerException");
 955 
 956         Path path = FileSystems.getDefault().getPath("foo");
 957 
 958         try {
 959             path.resolve((String)null);
 960             throw new RuntimeException("NullPointerException not thrown");
 961         } catch (NullPointerException npe) {
 962         }
 963 
 964         try {
 965             path.relativize(null);
 966             throw new RuntimeException("NullPointerException not thrown");
 967         } catch (NullPointerException npe) {
 968         }
 969 
 970         try {
 971             path.compareTo(null);
 972             throw new RuntimeException("NullPointerException not thrown");
 973         } catch (NullPointerException npe) {
 974         }
 975 
 976         try {
 977             path.startsWith((Path)null);
 978             throw new RuntimeException("NullPointerException not thrown");
 979         } catch (NullPointerException npe) {
 980         }
 981 
 982         try {
 983             path.endsWith((Path)null);
 984             throw new RuntimeException("NullPointerException not thrown");
 985         } catch (NullPointerException npe) {
 986         }
 987 
 988     }
 989 
 990     public static void main(String[] args) {
 991         // all platforms
 992         npes();
 993 
 994         // operating system specific
 995         String osname = System.getProperty("os.name");
 996         if (osname.startsWith("Windows")) {
 997             doWindowsTests();
 998         } else {
 999             doUnixTests();
1000         }
1001 
1002     }
1003 }