1 /*
   2  * Copyright (c) 2000, 2014, 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  * @summary Unit test for java.net.URI
  26  * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800
  27  *      7171415
  28  * @author Mark Reinhold
  29  */
  30 
  31 import java.io.ByteArrayInputStream;
  32 import java.io.ByteArrayOutputStream;
  33 import java.io.IOException;
  34 import java.io.ObjectInputStream;
  35 import java.io.ObjectOutputStream;
  36 import java.io.PrintStream;
  37 import java.net.URI;
  38 import java.net.URISyntaxException;
  39 import java.net.URL;
  40 import java.net.MalformedURLException;
  41 
  42 
  43 public class Test {
  44 
  45     static PrintStream out = System.out;
  46     static int testCount = 0;
  47 
  48     // Properties that we check
  49     static final int PARSEFAIL   = 1 << 0;
  50     static final int SCHEME      = 1 << 1;
  51     static final int SSP         = 1 << 2;
  52     static final int SSP_D       = 1 << 3;      // Decoded form
  53     static final int OPAQUEPART  = 1 << 4;      // SSP, and URI is opaque
  54     static final int USERINFO    = 1 << 5;
  55     static final int USERINFO_D  = 1 << 6;      // Decoded form
  56     static final int HOST        = 1 << 7;
  57     static final int PORT        = 1 << 8;
  58     static final int REGISTRY    = 1 << 9;
  59     static final int REGISTRY_D  = 1 << 10;     // Decoded form
  60     static final int PATH        = 1 << 11;
  61     static final int PATH_D      = 1 << 12;     // Decoded form
  62     static final int QUERY       = 1 << 13;
  63     static final int QUERY_D     = 1 << 14;     // Decoded form
  64     static final int FRAGMENT    = 1 << 15;
  65     static final int FRAGMENT_D  = 1 << 16;     // Decoded form
  66     static final int TOASCII     = 1 << 17;
  67     static final int IDENT_STR   = 1 << 18;     // Identities
  68     static final int IDENT_URI1  = 1 << 19;
  69     static final int IDENT_URI3  = 1 << 20;
  70     static final int IDENT_URI5  = 1 << 21;
  71     static final int IDENT_URI7  = 1 << 22;
  72     static final int TOSTRING    = 1 << 23;
  73 
  74     String input;
  75     URI uri = null;
  76     URI originalURI;
  77     URI base = null;                    // Base for resolution/relativization
  78     String op = null;                   // Op performed if uri != originalURI
  79     int checked = 0;                    // Mask for checked properties
  80     int failed = 0;                     // Mask for failed properties
  81     Exception exc = null;
  82 
  83     private Test(String s) {
  84         testCount++;
  85         input = s;
  86         try {
  87             uri = new URI(s);
  88         } catch (URISyntaxException x) {
  89             exc = x;
  90         }
  91         originalURI = uri;
  92     }
  93 
  94     static Test test(String s) {
  95         return new Test(s);
  96     }
  97 
  98     private Test(String s, String u, String h, int n,
  99                  String p, String q, String f)
 100     {
 101         testCount++;
 102         try {
 103             uri = new URI(s, u, h, n, p, q, f);
 104         } catch (URISyntaxException x) {
 105             exc = x;
 106             input = x.getInput();
 107         }
 108         if (uri != null)
 109             input = uri.toString();
 110         originalURI = uri;
 111     }
 112 
 113     static Test test(String s, String u, String h, int n,
 114                      String p, String q, String f) {
 115         return new Test(s, u, h, n, p, q, f);
 116     }
 117 
 118     private Test(String s, String a,
 119                  String p, String q, String f)
 120     {
 121         testCount++;
 122         try {
 123             uri = new URI(s, a, p, q, f);
 124         } catch (URISyntaxException x) {
 125             exc = x;
 126             input = x.getInput();
 127         }
 128         if (uri != null)
 129             input = uri.toString();
 130         originalURI = uri;
 131     }
 132 
 133     static Test test(String s, String a,
 134                      String p, String q, String f) {
 135         return new Test(s, a, p, q, f);
 136     }
 137 
 138     private Test(String s, String h, String p, String f) {
 139         testCount++;
 140         try {
 141             uri = new URI(s, h, p, f);
 142         } catch (URISyntaxException x) {
 143             exc = x;
 144             input = x.getInput();
 145         }
 146         if (uri != null)
 147             input = uri.toString();
 148         originalURI = uri;
 149     }
 150 
 151     static Test test(String s, String h, String p, String f) {
 152         return new Test(s, h, p, f);
 153     }
 154 
 155     private Test(String s, String ssp, String f) {
 156         testCount++;
 157         try {
 158             uri = new URI(s, ssp, f);
 159         } catch (URISyntaxException x) {
 160             exc = x;
 161             input = x.getInput();
 162         }
 163         if (uri != null)
 164             input = uri.toString();
 165         originalURI = uri;
 166     }
 167 
 168     static Test test(String s, String ssp, String f) {
 169         return new Test(s, ssp, f);
 170     }
 171 
 172     private Test(String s, boolean xxx) {
 173         testCount++;
 174         try {
 175             uri = URI.create(s);
 176         } catch (IllegalArgumentException x) {
 177             exc = x;
 178         }
 179         if (uri != null)
 180             input = uri.toString();
 181         originalURI = uri;
 182     }
 183 
 184     static Test testCreate(String s) {
 185         return new Test(s, false);
 186     }
 187 
 188     boolean parsed() {
 189         return uri != null;
 190     }
 191 
 192     boolean resolved() {
 193         return base != null;
 194     }
 195 
 196     URI uri() {
 197         return uri;
 198     }
 199 
 200 
 201     // Operations on Test instances
 202     //
 203     // These are short so as to make test cases compact.
 204     //
 205     //    s      Scheme
 206     //    sp     Scheme-specific part
 207     //    spd    Scheme-specific part, decoded
 208     //    o      Opaque part (isOpaque() && ssp matches)
 209     //    g      reGistry (authority matches, and host is not defined)
 210     //    gd     reGistry, decoded
 211     //    u      User info
 212     //    ud     User info, decoded
 213     //    h      Host
 214     //    n      port Number
 215     //    p      Path
 216     //    pd     Path, decoded
 217     //    q      Query
 218     //    qd     Query, decoded
 219     //    f      Fragment
 220     //    fd     Fragment, decoded
 221     //
 222     //    rslv   Resolve against given base
 223     //    rtvz   Relativize
 224     //    psa    Parse server Authority
 225     //    norm   Normalize
 226     //    ta     ASCII form
 227     //
 228     //    x      Check that parse failed as expected
 229     //    z      End -- ensure that unchecked components are null
 230 
 231     private boolean check1(int prop) {
 232         checked |= prop;
 233         if (!parsed()) {
 234             failed |= prop;
 235             return false;
 236         }
 237         return true;
 238     }
 239 
 240     private void check2(String s, String ans, int prop) {
 241         if ((s == null) || !s.equals(ans))
 242             failed |= prop;
 243     }
 244 
 245     Test s(String s) {
 246         if (check1(SCHEME)) check2(uri.getScheme(), s, SCHEME);
 247         return this;
 248     }
 249 
 250     Test u(String s) {
 251         if (check1(USERINFO)) check2(uri.getRawUserInfo(), s, USERINFO);
 252         return this;
 253     }
 254 
 255     Test ud(String s) {
 256         if (check1(USERINFO_D)) {
 257             check2(uri.getUserInfo(), s, USERINFO_D);
 258         }
 259         return this;
 260     }
 261 
 262     Test h(String s) {
 263         if (check1(HOST)) check2(uri.getHost(), s, HOST);
 264         return this;
 265     }
 266 
 267     Test g(String s) {
 268         if (check1(REGISTRY)) {
 269             if (uri.getHost() != null)
 270                 failed |= REGISTRY;
 271             else
 272                 check2(uri.getRawAuthority(), s, REGISTRY);
 273         }
 274         return this;
 275     }
 276 
 277     Test gd(String s) {
 278         if (check1(REGISTRY_D)) {
 279             if (uri.getHost() != null)
 280                 failed |= REGISTRY_D;
 281             else
 282                 check2(uri.getAuthority(), s, REGISTRY_D);
 283         }
 284         return this;
 285     }
 286 
 287     Test n(int n) {
 288         checked |= PORT;
 289         if (!parsed() || (uri.getPort() != n))
 290             failed |= PORT;
 291         return this;
 292     }
 293 
 294     Test p(String s) {
 295         if (check1(PATH)) check2(uri.getRawPath(), s, PATH);
 296         return this;
 297     }
 298 
 299     Test pd(String s) {
 300         if (check1(PATH_D)) check2(uri.getPath(), s, PATH_D);
 301         return this;
 302     }
 303 
 304     Test o(String s) {
 305         if (check1(OPAQUEPART)) {
 306             if (!uri.isOpaque())
 307                 failed |= OPAQUEPART;
 308             else
 309                 check2(uri.getSchemeSpecificPart(), s, OPAQUEPART);
 310         }
 311         return this;
 312     }
 313 
 314     Test sp(String s) {
 315         if (check1(SSP)) check2(uri.getRawSchemeSpecificPart(), s, SSP);
 316         return this;
 317     }
 318 
 319     Test spd(String s) {
 320         if (check1(SSP_D)) check2(uri.getSchemeSpecificPart(), s, SSP_D);
 321         return this;
 322     }
 323 
 324     Test q(String s) {
 325         if (check1(QUERY)) check2(uri.getRawQuery(), s, QUERY);
 326         return this;
 327     }
 328 
 329     Test qd(String s) {
 330         if (check1(QUERY_D)) check2(uri.getQuery(), s, QUERY_D);
 331         return this;
 332     }
 333 
 334     Test f(String s) {
 335         if (check1(FRAGMENT)) check2(uri.getRawFragment(), s, FRAGMENT);
 336         return this;
 337     }
 338 
 339     Test fd(String s) {
 340         if (check1(FRAGMENT_D)) check2(uri.getFragment(), s, FRAGMENT_D);
 341         return this;
 342     }
 343 
 344     Test ta(String s) {
 345         if (check1(TOASCII))
 346             check2(uri.toASCIIString(), s, TOASCII);
 347         return this;
 348     }
 349 
 350     Test ts(String s) {
 351         if (check1(TOSTRING))
 352             check2(uri.toString(), s, TOSTRING);
 353         return this;
 354     }
 355 
 356     Test x() {
 357         checked |= PARSEFAIL;
 358         if (parsed())
 359             failed |= PARSEFAIL;
 360         return this;
 361     }
 362 
 363     Test rslv(URI base) {
 364         if (!parsed())
 365             return this;
 366         this.base = base;
 367         op = "rslv";
 368         URI u = uri;
 369         uri = null;
 370         try {
 371             this.uri = base.resolve(u);
 372         } catch (IllegalArgumentException x) {
 373             exc = x;
 374         }
 375         checked = 0;
 376         failed = 0;
 377         return this;
 378     }
 379 
 380     Test norm() {
 381         if (!parsed())
 382             return this;
 383         op = "norm";
 384         uri = uri.normalize();
 385         return this;
 386     }
 387 
 388     Test rtvz(URI base) {
 389         if (!parsed())
 390             return this;
 391         this.base = base;
 392         op = "rtvz";
 393         uri = base.relativize(uri);
 394         checked = 0;
 395         failed = 0;
 396         return this;
 397     }
 398 
 399     Test psa() {
 400         try {
 401             uri.parseServerAuthority();
 402         } catch (URISyntaxException x) {
 403             exc = x;
 404             uri = null;
 405         }
 406         checked = 0;
 407         failed = 0;
 408         return this;
 409     }
 410 
 411     private void checkEmpty(String s, int prop) {
 412         if (((checked & prop) == 0) && (s != null))
 413             failed |= prop;
 414     }
 415 
 416     // Check identity for the seven-argument URI constructor
 417     //
 418     void checkURI7() {
 419         // Only works on hierarchical URIs
 420         if (uri.isOpaque())
 421             return;
 422         // Only works with server-based authorities
 423         if ((uri.getAuthority() == null)
 424             != ((uri.getUserInfo() == null) && (uri.getHost() == null)))
 425             return;
 426         // Not true if non-US-ASCII chars are encoded unnecessarily
 427         if (uri.getPath().indexOf('\u20AC') >= 0)
 428             return;
 429         try {
 430             URI u2 = new URI(uri.getScheme(), uri.getUserInfo(),
 431                              uri.getHost(), uri.getPort(), uri.getPath(),
 432                              uri.getQuery(), uri.getFragment());
 433             if (!uri.equals(u2))
 434                 failed |= IDENT_URI7;
 435         } catch (URISyntaxException x) {
 436             failed |= IDENT_URI7;
 437         }
 438     }
 439 
 440     // Check identity for the five-argument URI constructor
 441     //
 442     void checkURI5() {
 443         // Only works on hierarchical URIs
 444         if (uri.isOpaque())
 445             return;
 446         try {
 447             URI u2 = new URI(uri.getScheme(), uri.getAuthority(),
 448                              uri.getPath(), uri.getQuery(), uri.getFragment());
 449             if (!uri.equals(u2))
 450                 failed |= IDENT_URI5;
 451         } catch (URISyntaxException x) {
 452             failed |= IDENT_URI5;
 453         }
 454     }
 455 
 456     // Check identity for the three-argument URI constructor
 457     //
 458     void checkURI3() {
 459         try {
 460             URI u2 = new URI(uri.getScheme(),
 461                              uri.getSchemeSpecificPart(),
 462                              uri.getFragment());
 463             if (!uri.equals(u2))
 464                 failed |= IDENT_URI3;
 465         } catch (URISyntaxException x) {
 466             failed |= IDENT_URI3;
 467         }
 468     }
 469 
 470     // Check all identities mentioned in the URI class specification
 471     //
 472     void checkIdentities() {
 473         if (input != null) {
 474             if (!uri.toString().equals(input))
 475                 failed |= IDENT_STR;
 476         }
 477         try {
 478             if (!(new URI(uri.toString())).equals(uri))
 479                 failed |= IDENT_URI1;
 480         } catch (URISyntaxException x) {
 481             failed |= IDENT_URI1;
 482         }
 483 
 484         // Remaining identities fail if "//" given but authority is undefined
 485         if ((uri.getAuthority() == null)
 486             && (uri.getSchemeSpecificPart() != null)
 487             && (uri.getSchemeSpecificPart().startsWith("///")
 488                 || uri.getSchemeSpecificPart().startsWith("//?")
 489                 || uri.getSchemeSpecificPart().equals("//")))
 490             return;
 491 
 492         // Remaining identities fail if ":" given but port is undefined
 493         if ((uri.getHost() != null)
 494             && (uri.getAuthority() != null)
 495             && (uri.getAuthority().equals(uri.getHost() + ":")))
 496             return;
 497 
 498         // Remaining identities fail if non-US-ASCII chars are encoded
 499         // unnecessarily
 500         if ((uri.getPath() != null) && uri.getPath().indexOf('\u20AC') >= 0)
 501             return;
 502 
 503         checkURI3();
 504         checkURI5();
 505         checkURI7();
 506     }
 507 
 508     // Check identities, check that unchecked component properties are not
 509     // defined, and report any failures
 510     //
 511     Test z() {
 512         if (!parsed()) {
 513             report();
 514             return this;
 515         }
 516 
 517         if (op == null)
 518             checkIdentities();
 519 
 520         // Check that unchecked components are undefined
 521         checkEmpty(uri.getScheme(), SCHEME);
 522         checkEmpty(uri.getUserInfo(), USERINFO);
 523         checkEmpty(uri.getHost(), HOST);
 524         if (((checked & PORT) == 0) && (uri.getPort() != -1)) failed |= PORT;
 525         checkEmpty(uri.getPath(), PATH);
 526         checkEmpty(uri.getQuery(), QUERY);
 527         checkEmpty(uri.getFragment(), FRAGMENT);
 528 
 529         // Report failures
 530         report();
 531         return this;
 532     }
 533 
 534 
 535     // Summarization and reporting
 536 
 537     static void header(String s) {
 538         out.println();
 539         out.println();
 540         out.println("-- " + s + " --");
 541     }
 542 
 543     static void show(String prefix, URISyntaxException x) {
 544         out.println(uquote(x.getInput()));
 545         if (x.getIndex() >= 0) {
 546             for (int i = 0; i < x.getIndex(); i++) {
 547                 if (x.getInput().charAt(i) >= '\u0080')
 548                     out.print("      ");        // Skip over \u1234
 549                 else
 550                     out.print(" ");
 551             }
 552             out.println("^");
 553         }
 554         out.println(prefix + ": " + x.getReason());
 555     }
 556 
 557     private void summarize() {
 558         out.println();
 559         StringBuffer sb = new StringBuffer();
 560         if (input.length() == 0)
 561             sb.append("\"\"");
 562         else
 563             sb.append(input);
 564         if (base != null) {
 565             sb.append(" ");
 566             sb.append(base);
 567         }
 568         if (!parsed()) {
 569             String s = (((checked & PARSEFAIL) != 0)
 570                         ? "Correct exception" : "UNEXPECTED EXCEPTION");
 571             if (exc instanceof URISyntaxException)
 572                 show(s, (URISyntaxException)exc);
 573             else {
 574                 out.println(uquote(sb.toString()));
 575                 out.print(s + ": ");
 576                 exc.printStackTrace(out);
 577             }
 578         } else {
 579             if (uri != originalURI) {
 580                 sb.append(" ");
 581                 sb.append(op);
 582                 sb.append(" --> ");
 583                 sb.append(uri);
 584             }
 585             out.println(uquote(sb.toString()));
 586         }
 587     }
 588 
 589     public static String uquote(String str) {
 590         if (str == null)
 591             return str;
 592         StringBuffer sb = new StringBuffer();
 593         int n = str.length();
 594         for (int i = 0; i < n; i++) {
 595             char c = str.charAt(i);
 596             if ((c >= ' ') && (c < 0x7f)) {
 597                 sb.append(c);
 598                 continue;
 599             }
 600             sb.append("\\u");
 601             String s = Integer.toHexString(c).toUpperCase();
 602             while (s.length() < 4)
 603                 s = "0" + s;
 604             sb.append(s);
 605         }
 606         return sb.toString();
 607     }
 608 
 609     static void show(String n, String v) {
 610         out.println("  " + n
 611                     + "          = ".substring(n.length())
 612                     + uquote(v));
 613     }
 614 
 615     static void show(String n, String v, String vd) {
 616         if ((v == null) || v.equals(vd))
 617             show(n, v);
 618         else {
 619             out.println("  " + n
 620                         + "          = ".substring(n.length())
 621                         + uquote(v)
 622                         + " = " + uquote(vd));
 623         }
 624     }
 625 
 626     public static void show(URI u) {
 627         show("opaque", "" + u.isOpaque());
 628         show("scheme", u.getScheme());
 629         show("ssp", u.getRawSchemeSpecificPart(), u.getSchemeSpecificPart());
 630         show("authority", u.getRawAuthority(), u.getAuthority());
 631         show("userinfo", u.getRawUserInfo(), u.getUserInfo());
 632         show("host", u.getHost());
 633         show("port", "" + u.getPort());
 634         show("path", u.getRawPath(), u.getPath());
 635         show("query", u.getRawQuery(), u.getQuery());
 636         show("fragment", u.getRawFragment(), u.getFragment());
 637         if (!u.toString().equals(u.toASCIIString()))
 638             show("toascii", u.toASCIIString());
 639     }
 640 
 641     private void report() {
 642         summarize();
 643         if (failed == 0) return;
 644         StringBuffer sb = new StringBuffer();
 645         sb.append("FAIL:");
 646         if ((failed & PARSEFAIL) != 0) sb.append(" parsefail");
 647         if ((failed & SCHEME) != 0) sb.append(" scheme");
 648         if ((failed & SSP) != 0) sb.append(" ssp");
 649         if ((failed & OPAQUEPART) != 0) sb.append(" opaquepart");
 650         if ((failed & USERINFO) != 0) sb.append(" userinfo");
 651         if ((failed & USERINFO_D) != 0) sb.append(" userinfod");
 652         if ((failed & HOST) != 0) sb.append(" host");
 653         if ((failed & PORT) != 0) sb.append(" port");
 654         if ((failed & REGISTRY) != 0) sb.append(" registry");
 655         if ((failed & PATH) != 0) sb.append(" path");
 656         if ((failed & PATH_D) != 0) sb.append(" pathd");
 657         if ((failed & QUERY) != 0) sb.append(" query");
 658         if ((failed & QUERY_D) != 0) sb.append(" queryd");
 659         if ((failed & FRAGMENT) != 0) sb.append(" fragment");
 660         if ((failed & FRAGMENT_D) != 0) sb.append(" fragmentd");
 661         if ((failed & TOASCII) != 0) sb.append(" toascii");
 662         if ((failed & IDENT_STR) != 0) sb.append(" ident-str");
 663         if ((failed & IDENT_URI1) != 0) sb.append(" ident-uri1");
 664         if ((failed & IDENT_URI3) != 0) sb.append(" ident-uri3");
 665         if ((failed & IDENT_URI5) != 0) sb.append(" ident-uri5");
 666         if ((failed & IDENT_URI7) != 0) sb.append(" ident-uri7");
 667         if ((failed & TOSTRING) != 0) sb.append(" tostring");
 668         out.println(sb.toString());
 669         if (uri != null) show(uri);
 670         throw new RuntimeException("Test failed");
 671     }
 672 
 673 
 674 
 675     // -- Tests --
 676 
 677     static void rfc2396() {
 678 
 679 
 680         header("RFC2396: Basic examples");
 681 
 682         test("ftp://ftp.is.co.za/rfc/rfc1808.txt")
 683             .s("ftp").h("ftp.is.co.za").p("/rfc/rfc1808.txt").z();
 684 
 685         test("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles")
 686             .s("gopher").h("spinaltap.micro.umn.edu")
 687             .p("/00/Weather/California/Los%20Angeles").z();
 688 
 689         test("http://www.math.uio.no/faq/compression-faq/part1.html")
 690             .s("http").h("www.math.uio.no").p("/faq/compression-faq/part1.html").z();
 691 
 692         test("mailto:mduerst@ifi.unizh.ch")
 693             .s("mailto").o("mduerst@ifi.unizh.ch").z();
 694 
 695         test("news:comp.infosystems.www.servers.unix")
 696             .s("news").o("comp.infosystems.www.servers.unix").z();
 697 
 698         test("telnet://melvyl.ucop.edu/")
 699             .s("telnet").h("melvyl.ucop.edu").p("/").z();
 700 
 701         test("http://www.w3.org/Addressing/")
 702             .s("http").h("www.w3.org").p("/Addressing/").z();
 703 
 704         test("ftp://ds.internic.net/rfc/")
 705             .s("ftp").h("ds.internic.net").p("/rfc/").z();
 706 
 707         test("http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING")
 708             .s("http").h("www.ics.uci.edu").p("/pub/ietf/uri/historical.html")
 709             .f("WARNING").z();
 710 
 711         test("http://www.ics.uci.edu/pub/ietf/uri/#Related")
 712             .s("http").h("www.ics.uci.edu").p("/pub/ietf/uri/")
 713             .f("Related").z();
 714 
 715 
 716         header("RFC2396: Normal relative-URI examples (appendix C)");
 717 
 718         URI base = (test("http://a/b/c/d;p?q")
 719                     .s("http").h("a").p("/b/c/d;p").q("q").z().uri());
 720 
 721         // g:h       g:h
 722         test("g:h")
 723             .s("g").o("h").z()
 724             .rslv(base).s("g").o("h").z();
 725 
 726         // g         http://a/b/c/g
 727         test("g")
 728             .p("g").z()
 729             .rslv(base).s("http").h("a").p("/b/c/g").z();
 730 
 731         // ./g       http://a/b/c/g
 732         test("./g")
 733             .p("./g").z()
 734             .rslv(base).s("http").h("a").p("/b/c/g").z();
 735 
 736         // g/        http://a/b/c/g/
 737         test("g/")
 738             .p("g/").z()
 739             .rslv(base).s("http").h("a").p("/b/c/g/").z();
 740 
 741         // /g        http://a/g
 742         test("/g")
 743             .p("/g").z()
 744             .rslv(base).s("http").h("a").p("/g").z();
 745 
 746         // //g       http://g
 747         test("//g")
 748             .h("g").p("").z()
 749             .rslv(base).s("http").h("g").p("").z();
 750 
 751         // ?y        http://a/b/c/?y
 752         test("?y")
 753             .p("").q("y").z()
 754             .rslv(base).s("http").h("a").p("/b/c/").q("y").z();
 755 
 756         // g?y       http://a/b/c/g?y
 757         test("g?y")
 758             .p("g").q("y").z()
 759             .rslv(base).s("http").h("a").p("/b/c/g").q("y").z();
 760 
 761         // #s        (current document)#s
 762         // DEVIATION: Lone fragment parses as relative URI with empty path
 763         test("#s")
 764             .p("").f("s").z()
 765             .rslv(base).s("http").h("a").p("/b/c/d;p").f("s").q("q").z();
 766 
 767         // g#s       http://a/b/c/g#s
 768         test("g#s")
 769             .p("g").f("s").z()
 770             .rslv(base).s("http").h("a").p("/b/c/g").f("s").z();
 771 
 772         // g?y#s     http://a/b/c/g?y#s
 773         test("g?y#s")
 774             .p("g").q("y").f("s").z()
 775             .rslv(base).s("http").h("a").p("/b/c/g").q("y").f("s").z();
 776 
 777         // ;x        http://a/b/c/;x
 778         test(";x")
 779             .p(";x").z()
 780             .rslv(base).s("http").h("a").p("/b/c/;x").z();
 781 
 782         // g;x       http://a/b/c/g;x
 783         test("g;x")
 784             .p("g;x").z()
 785             .rslv(base).s("http").h("a").p("/b/c/g;x").z();
 786 
 787         // g;x?y#s   http://a/b/c/g;x?y#s
 788         test("g;x?y#s")
 789             .p("g;x").q("y").f("s").z()
 790             .rslv(base).s("http").h("a").p("/b/c/g;x").q("y").f("s").z();
 791 
 792         // .         http://a/b/c/
 793         test(".")
 794             .p(".").z()
 795             .rslv(base).s("http").h("a").p("/b/c/").z();
 796 
 797         // ./        http://a/b/c/
 798         test("./")
 799             .p("./").z()
 800             .rslv(base).s("http").h("a").p("/b/c/").z();
 801 
 802         // ..        http://a/b/
 803         test("..")
 804             .p("..").z()
 805             .rslv(base).s("http").h("a").p("/b/").z();
 806 
 807         // ../       http://a/b/
 808         test("../")
 809             .p("../").z()
 810             .rslv(base).s("http").h("a").p("/b/").z();
 811 
 812         // ../g      http://a/b/g
 813         test("../g")
 814             .p("../g").z()
 815             .rslv(base).s("http").h("a").p("/b/g").z();
 816 
 817         // ../..     http://a/
 818         test("../..")
 819             .p("../..").z()
 820             .rslv(base).s("http").h("a").p("/").z();
 821 
 822         // ../../    http://a/
 823         test("../../")
 824             .p("../../").z()
 825             .rslv(base).s("http").h("a").p("/").z();
 826 
 827         // ../../g   http://a/g
 828         test("../../g")
 829             .p("../../g").z()
 830             .rslv(base).s("http").h("a").p("/g").z();
 831 
 832 
 833         header("RFC2396: Abnormal relative-URI examples (appendix C)");
 834 
 835         // ../../../g    =  http://a/../g
 836         test("../../../g")
 837             .p("../../../g").z()
 838             .rslv(base).s("http").h("a").p("/../g").z();
 839 
 840         // ../../../../g =  http://a/../../g
 841         test("../../../../g")
 842             .p("../../../../g").z()
 843             .rslv(base).s("http").h("a").p("/../../g").z();
 844 
 845 
 846         // /./g          =  http://a/./g
 847         test("/./g")
 848             .p("/./g").z()
 849             .rslv(base).s("http").h("a").p("/./g").z();
 850 
 851         // /../g         =  http://a/../g
 852         test("/../g")
 853             .p("/../g").z()
 854             .rslv(base).s("http").h("a").p("/../g").z();
 855 
 856         // g.            =  http://a/b/c/g.
 857         test("g.")
 858             .p("g.").z()
 859             .rslv(base).s("http").h("a").p("/b/c/g.").z();
 860 
 861         // .g            =  http://a/b/c/.g
 862         test(".g")
 863             .p(".g").z()
 864             .rslv(base).s("http").h("a").p("/b/c/.g").z();
 865 
 866         // g..           =  http://a/b/c/g..
 867         test("g..")
 868             .p("g..").z()
 869             .rslv(base).s("http").h("a").p("/b/c/g..").z();
 870 
 871         // ..g           =  http://a/b/c/..g
 872         test("..g")
 873             .p("..g").z()
 874             .rslv(base).s("http").h("a").p("/b/c/..g").z();
 875 
 876         // ./../g        =  http://a/b/g
 877         test("./../g")
 878             .p("./../g").z()
 879             .rslv(base).s("http").h("a").p("/b/g").z();
 880 
 881         // ./g/.         =  http://a/b/c/g/
 882         test("./g/.")
 883             .p("./g/.").z()
 884             .rslv(base).s("http").h("a").p("/b/c/g/").z();
 885 
 886         // g/./h         =  http://a/b/c/g/h
 887         test("g/./h")
 888             .p("g/./h").z()
 889             .rslv(base).s("http").h("a").p("/b/c/g/h").z();
 890 
 891         // g/../h        =  http://a/b/c/h
 892         test("g/../h")
 893             .p("g/../h").z()
 894             .rslv(base).s("http").h("a").p("/b/c/h").z();
 895 
 896         // g;x=1/./y     =  http://a/b/c/g;x=1/y
 897         test("g;x=1/./y")
 898             .p("g;x=1/./y").z()
 899             .rslv(base).s("http").h("a").p("/b/c/g;x=1/y").z();
 900 
 901         // g;x=1/../y    =  http://a/b/c/y
 902         test("g;x=1/../y")
 903             .p("g;x=1/../y").z()
 904             .rslv(base).s("http").h("a").p("/b/c/y").z();
 905 
 906         // g?y/./x       =  http://a/b/c/g?y/./x
 907         test("g?y/./x")
 908             .p("g").q("y/./x").z()
 909             .rslv(base).s("http").h("a").p("/b/c/g").q("y/./x").z();
 910 
 911         // g?y/../x      =  http://a/b/c/g?y/../x
 912         test("g?y/../x")
 913             .p("g").q("y/../x").z()
 914             .rslv(base).s("http").h("a").p("/b/c/g").q("y/../x").z();
 915 
 916         // g#s/./x       =  http://a/b/c/g#s/./x
 917         test("g#s/./x")
 918             .p("g").f("s/./x").z()
 919             .rslv(base).s("http").h("a").p("/b/c/g").f("s/./x").z();
 920 
 921         // g#s/../x      =  http://a/b/c/g#s/../x
 922         test("g#s/../x")
 923             .p("g").f("s/../x").z()
 924             .rslv(base).s("http").h("a").p("/b/c/g").f("s/../x").z();
 925 
 926         // http:g        =  http:g
 927         test("http:g")
 928             .s("http").o("g").z()
 929             .rslv(base).s("http").o("g").z();
 930 
 931     }
 932 
 933 
 934     static void ip() {
 935 
 936         header("IP addresses");
 937 
 938         test("http://1.2.3.4:5")
 939             .s("http").h("1.2.3.4").n(5).p("").z();
 940 
 941         // From RFC2732
 942 
 943         test("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")
 944             .s("http").h("[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]")
 945             .n(80).p("/index.html").z();
 946 
 947         test("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:10%12]:80/index.html")
 948             .s("http").h("[FEDC:BA98:7654:3210:FEDC:BA98:7654:10%12]")
 949             .n(80).p("/index.html").z();
 950 
 951         test("http://[1080:0:0:0:8:800:200C:417A]/index.html")
 952             .s("http").h("[1080:0:0:0:8:800:200C:417A]").p("/index.html").z();
 953 
 954         test("http://[1080:0:0:0:8:800:200C:417A%1]/index.html")
 955             .s("http").h("[1080:0:0:0:8:800:200C:417A%1]").p("/index.html").z();
 956 
 957         test("http://[3ffe:2a00:100:7031::1]")
 958             .s("http").h("[3ffe:2a00:100:7031::1]").p("").z();
 959 
 960         test("http://[1080::8:800:200C:417A]/foo")
 961             .s("http").h("[1080::8:800:200C:417A]").p("/foo").z();
 962 
 963         test("http://[::192.9.5.5]/ipng")
 964             .s("http").h("[::192.9.5.5]").p("/ipng").z();
 965 
 966         test("http://[::192.9.5.5%interface]/ipng")
 967             .s("http").h("[::192.9.5.5%interface]").p("/ipng").z();
 968 
 969         test("http://[::FFFF:129.144.52.38]:80/index.html")
 970             .s("http").h("[::FFFF:129.144.52.38]").n(80).p("/index.html").z();
 971 
 972         test("http://[2010:836B:4179::836B:4179]")
 973             .s("http").h("[2010:836B:4179::836B:4179]").p("").z();
 974 
 975         // From RFC2373
 976 
 977         test("http://[FF01::101]")
 978             .s("http").h("[FF01::101]").p("").z();
 979 
 980         test("http://[::1]")
 981             .s("http").h("[::1]").p("").z();
 982 
 983         test("http://[::]")
 984             .s("http").h("[::]").p("").z();
 985 
 986         test("http://[::%hme0]")
 987             .s("http").h("[::%hme0]").p("").z();
 988 
 989         test("http://[0:0:0:0:0:0:13.1.68.3]")
 990             .s("http").h("[0:0:0:0:0:0:13.1.68.3]").p("").z();
 991 
 992         test("http://[0:0:0:0:0:FFFF:129.144.52.38]")
 993             .s("http").h("[0:0:0:0:0:FFFF:129.144.52.38]").p("").z();
 994 
 995         test("http://[0:0:0:0:0:FFFF:129.144.52.38%33]")
 996             .s("http").h("[0:0:0:0:0:FFFF:129.144.52.38%33]").p("").z();
 997 
 998         test("http://[0:0:0:0:0:ffff:1.2.3.4]")
 999             .s("http").h("[0:0:0:0:0:ffff:1.2.3.4]").p("").z();
1000 
1001         test("http://[::13.1.68.3]")
1002             .s("http").h("[::13.1.68.3]").p("").z();
1003 
1004         // Optional IPv6 brackets in constructors
1005 
1006         test("s", null, "1:2:3:4:5:6:7:8", -1, null, null, null)
1007             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1008 
1009         test("s", null, "[1:2:3:4:5:6:7:8]", -1, null, null, null)
1010             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1011 
1012         test("s", null, "[1:2:3:4:5:6:7:8]", -1, null, null, null)
1013             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1014 
1015         test("s", "1:2:3:4:5:6:7:8", null, null)
1016             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1017 
1018         test("s", "1:2:3:4:5:6:7:8%hme0", null, null)
1019             .s("s").h("[1:2:3:4:5:6:7:8%hme0]").p("").z();
1020 
1021         test("s", "1:2:3:4:5:6:7:8%1", null, null)
1022             .s("s").h("[1:2:3:4:5:6:7:8%1]").p("").z();
1023 
1024         test("s", "[1:2:3:4:5:6:7:8]", null, null)
1025             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1026 
1027         test("s", "[1:2:3:4:5:6:7:8]", null, null, null)
1028             .s("s").h("[1:2:3:4:5:6:7:8]").p("").z();
1029 
1030         test("s", "1:2:3:4:5:6:7:8", null, null, null)
1031             .s("s").g("1:2:3:4:5:6:7:8").p("").z();
1032 
1033         // Error cases
1034 
1035         test("http://[ff01:234/foo").x().z();
1036         test("http://[ff01:234:zzz]/foo").x().z();
1037         test("http://[foo]").x().z();
1038         test("http://[]").x().z();
1039         test("http://[129.33.44.55]").x().z();
1040         test("http://[ff:ee:dd:cc:bb::aa:9:8]").x().z();
1041         test("http://[fffff::1]").x().z();
1042         test("http://[ff::ee::8]").x().z();
1043         test("http://[1:2:3:4::5:6:7:8]").x().z();
1044         test("http://[1:2]").x().z();
1045         test("http://[1:2:3:4:5:6:7:8:9]").x().z();
1046         test("http://[1:2:3:4:5:6:7:8%]").x().z();
1047         test("http://[1:2:3:4:5:6:7:8%!/]").x().z();
1048         test("http://[::1.2.3.300]").x().z();
1049         test("http://1.2.3").psa().x().z();
1050         test("http://1.2.3.300").psa().x().z();
1051         test("http://1.2.3.4.5").psa().x().z();
1052         test("http://[1.2.3.4:5]").x().z();
1053         test("http://1:2:3:4:5:6:7:8").psa().x().z();
1054         test("http://[1.2.3.4]/").x().z();
1055         test("http://[1.2.3.4/").x().z();
1056         test("http://[foo]/").x().z();
1057         test("http://[foo/").x().z();
1058         test("s", "[foo]", "/", null, null).x().z();
1059         test("s", "[foo", "/", null, null).x().z();
1060         test("s", "[::foo", "/", null, null).x().z();
1061 
1062         // Test hostnames that might initially look like IPv4 addresses
1063 
1064         test("s://1.2.3.com").psa().s("s").h("1.2.3.com").p("").z();
1065         test("s://1.2.3.4me.com").psa().s("s").h("1.2.3.4me.com").p("").z();
1066 
1067         test("s://7up.com").psa().s("s").h("7up.com").p("").z();
1068         test("s://7up.com/p").psa().s("s").h("7up.com").p("/p").z();
1069         test("s://7up").psa().s("s").h("7up").p("").z();
1070         test("s://7up/p").psa().s("s").h("7up").p("/p").z();
1071         test("s://7up.").psa().s("s").h("7up.").p("").z();
1072         test("s://7up./p").psa().s("s").h("7up.").p("/p").z();
1073     }
1074 
1075 
1076     static void misc() throws URISyntaxException {
1077 
1078         URI base = new URI("s://h/a/b");
1079         URI rbase = new URI("a/b/c/d");
1080 
1081 
1082         header("Corner cases");
1083 
1084         // The empty URI parses as a relative URI with an empty path
1085         test("").p("").z()
1086             .rslv(base).s("s").h("h").p("/a/").z();
1087 
1088         // Resolving solo queries and fragments
1089         test("#f").p("").f("f").z()
1090             .rslv(base).s("s").h("h").p("/a/b").f("f").z();
1091         test("?q").p("").q("q").z()
1092             .rslv(base).s("s").h("h").p("/a/").q("q").z();
1093 
1094         // Fragment is not part of ssp
1095         test("p#f").p("p").f("f").sp("p").z();
1096         test("s:p#f").s("s").o("p").f("f").z();
1097         test("p#f")
1098             .rslv(base).s("s").h("h").p("/a/p").f("f").sp("//h/a/p").z();
1099         test("").p("").sp("").z();
1100 
1101 
1102 
1103         header("Emptiness");
1104 
1105         // Components that may be empty
1106         test("///p").p("/p").z();                 // Authority (w/ path)
1107         test("//@h/p").u("").h("h").p("/p").z();  // User info
1108         test("//h:/p").h("h").p("/p").z();        // Port
1109         test("//h").h("h").p("").z();             // Path
1110         test("//h?q").h("h").p("").q("q").z();    // Path (w/query)
1111         test("//?q").p("").q("q").z();            // Authority (w/query)
1112         test("//#f").p("").f("f").z();            // Authority (w/fragment)
1113         test("p?#").p("p").q("").f("").z();       // Query & fragment
1114 
1115         // Components that may not be empty
1116         test(":").x().z();              // Scheme
1117         test("x:").x().z();             // Hier/opaque
1118         test("//").x().z();             // Authority (w/o path)
1119 
1120 
1121         header("Resolution, normalization, and relativization");
1122 
1123         // Resolving relative paths
1124         test("../e/f").p("../e/f").z()
1125             .rslv(rbase).p("a/b/e/f").z();
1126         test("../../../../d").p("../../../../d").z()
1127             .rslv(rbase).p("../d").z();
1128         test("../../../d:e").p("../../../d:e").z()
1129             .rslv(rbase).p("./d:e").z();
1130         test("../../../d:e/f").p("../../../d:e/f").z()
1131             .rslv(rbase).p("./d:e/f").z();
1132 
1133         // Normalization
1134         test("a/./c/../d/f").p("a/./c/../d/f").z()
1135             .norm().p("a/d/f").z();
1136         test("http://a/./b/c/../d?q#f")
1137             .s("http").h("a").p("/./b/c/../d").q("q").f("f").z()
1138             .norm().s("http").h("a").p("/b/d").q("q").f("f").z();
1139         test("a/../b").p("a/../b").z().
1140             norm().p("b");
1141         test("a/../b:c").p("a/../b:c").z()
1142             .norm().p("./b:c").z();
1143 
1144         // Normalization of already normalized URI should yield the
1145         // same URI
1146         URI u1 = URI.create("s://h/../p");
1147         URI u2 = u1.normalize();
1148         eq(u1, u2);
1149         eqeq(u1, u2);
1150 
1151         // Relativization
1152         test("/a/b").p("/a/b").z()
1153             .rtvz(new URI("/a")).p("b").z();
1154         test("/a/b").p("/a/b").z()
1155             .rtvz(new URI("/a/")).p("b").z();
1156         test("a/b").p("a/b").z()
1157             .rtvz(new URI("a")).p("b").z();
1158         test("/a/b").p("/a/b").z()
1159             .rtvz(new URI("/a/b")).p("").z();   // Result is empty path
1160         test("a/../b:c/d").p("a/../b:c/d").z()
1161             .rtvz(new URI("./b:c/")).p("d").z();
1162 
1163         test("http://a/b/d/e?q#f")
1164             .s("http").h("a").p("/b/d/e").q("q").f("f").z()
1165             .rtvz(new URI("http://a/b/?r#g"))
1166             .p("d/e").q("q").f("f").z();
1167 
1168         // parseServerAuthority
1169         test("/a/b").psa().p("/a/b").z();
1170         test("s://u@h:1/p")
1171             .psa().s("s").u("u").h("h").n(1).p("/p").z();
1172         test("s://u@h:-foo/p").s("s").g("u@h:-foo").p("/p").z()
1173             .psa().x().z();
1174         test("s://h:999999999999999999999999").psa().x().z();
1175         test("s://:/b").psa().x().z();
1176 
1177 
1178         header("Constructors and factories");
1179 
1180         test("s", null, null, -1, "p", null, null).x().z();
1181         test(null, null, null, -1, null, null, null).p("").z();
1182         test(null, null, null, -1, "p", null, null).p("p").z();
1183         test(null, null, "foo%20bar", -1, null, null, null).x().z();
1184         test(null, null, "foo", -100, null, null, null).x().z();
1185         test("s", null, null, -1, "", null, null).x().z();
1186         test("s", null, null, -1, "/p", null, null).s("s").p("/p").z();
1187         test("s", "u", "h", 10, "/p", "q", "f")
1188             .s("s").u("u").h("h").n(10).p("/p").q("q").f("f").z();
1189         test("s", "a:b", "/p", "q", "f")
1190             .s("s").g("a:b").p("/p").q("q").f("f").z();
1191         test("s", "h", "/p", "f")
1192             .s("s").h("h").p("/p").f("f").z();
1193         test("s", "p", "f").s("s").o("p").f("f").z();
1194         test("s", "/p", "f").s("s").p("/p").f("f").z();
1195         testCreate("s://u@h/p?q#f")
1196             .s("s").u("u").h("h").p("/p").q("q").f("f").z();
1197     }
1198 
1199     static void npes() throws URISyntaxException {
1200 
1201         header("NullPointerException");
1202 
1203         URI base = URI.create("mailto:root@foobar.com");
1204 
1205         out.println();
1206 
1207         try {
1208             base.resolve((URI)null);
1209             throw new RuntimeException("NullPointerException not thrown");
1210         } catch (NullPointerException x) {
1211             out.println("resolve((URI)null) -->");
1212             out.println("Correct exception: " + x);
1213         }
1214 
1215         out.println();
1216 
1217         try {
1218             base.resolve((String)null);
1219             throw new RuntimeException("NullPointerException not thrown");
1220         } catch (NullPointerException x) {
1221             out.println("resolve((String)null) -->");
1222             out.println("Correct exception: " + x);
1223         }
1224 
1225         out.println();
1226 
1227         try {
1228             base.relativize((URI)null);
1229             throw new RuntimeException("NullPointerException not thrown");
1230         } catch (NullPointerException x) {
1231             out.println("relativize((String)null) -->");
1232             out.println("Correct exception: " + x);
1233         }
1234 
1235         testCount += 3;
1236     }
1237 
1238 
1239     static void chars() throws URISyntaxException {
1240 
1241         header("Escapes and non-US-ASCII characters");
1242 
1243         URI uri;
1244 
1245         // Escape pairs
1246         test("%0a%0A%0f%0F%01%09zz")
1247             .p("%0a%0A%0f%0F%01%09zz").z();
1248         test("foo%1").x().z();
1249         test("foo%z").x().z();
1250         test("foo%9z").x().z();
1251 
1252         // Escapes not permitted in scheme, host
1253         test("s%20t://a").x().z();
1254         test("//a%20b").g("a%20b").p("").z();         // Parses as registry
1255 
1256         // Escapes permitted in opaque part, userInfo, registry, path,
1257         // query, and fragment
1258         test("//u%20v@a").u("u%20v").h("a").p("").z();
1259         test("/p%20q").p("/p%20q").z();
1260         test("/p?q%20").p("/p").q("q%20").z();
1261         test("/p#%20f").p("/p").f("%20f").z();
1262 
1263         // Non-US-ASCII chars
1264         test("s\u00a7t://a").x().z();
1265         test("//\u00a7/b").g("\u00a7").p("/b").z();     // Parses as registry
1266         test("//u\u00a7v@a").u("u\u00a7v").h("a").p("").z();
1267         test("/p\u00a7q").p("/p\u00a7q").z();
1268         test("/p?q\u00a7").p("/p").q("q\u00a7").z();
1269         test("/p#\u00a7f").p("/p").f("\u00a7f").z();
1270 
1271         // 4648111 - Escapes quoted by toString after resolution
1272         uri = new URI("http://a/b/c/d;p?q");
1273         test("/p%20p")
1274             .rslv(uri).s("http").h("a").p("/p%20p").ts("http://a/p%20p").z();
1275 
1276         // 4464135: Forbid unwise characters throughout opaque part
1277         test("foo:x{bar").x().z();
1278         test("foo:{bar").x().z();
1279 
1280         // 4438319: Single-argument constructor requires quotation,
1281         //          preserves escapes
1282         test("//u%01@h/a/b/%02/c?q%03#f%04")
1283             .u("u%01").ud("u\1")
1284             .h("h")
1285             .p("/a/b/%02/c").pd("/a/b/\2/c")
1286             .q("q%03").qd("q\3")
1287             .f("f%04").fd("f\4")
1288             .z();
1289         test("/a/b c").x().z();
1290 
1291         // 4438319: Multi-argument constructors quote illegal chars and
1292         //          preserve legal non-ASCII chars
1293         // \uA001-\uA009 are visible characters, \u2000 is a space character
1294         test(null, "u\uA001\1", "h", -1,
1295              "/p% \uA002\2\u2000",
1296              "q% \uA003\3\u2000",
1297              "f% \uA004\4\u2000")
1298             .u("u\uA001%01").h("h")
1299             .p("/p%25%20\uA002%02%E2%80%80").pd("/p% \uA002\2\u2000")
1300             .q("q%25%20\uA003%03%E2%80%80").qd("q% \uA003\3\u2000")
1301             .f("f%25%20\uA004%04%E2%80%80").fd("f% \uA004\4\u2000").z();
1302         test(null, "g\uA001\1",
1303              "/p% \uA002\2\u2000",
1304              "q% \uA003\3\u2000",
1305              "f% \uA004\4\u2000")
1306             .g("g\uA001%01")
1307             .p("/p%25%20\uA002%02%E2%80%80").pd("/p% \uA002\2\u2000")
1308             .q("q%25%20\uA003%03%E2%80%80").qd("q% \uA003\3\u2000")
1309             .f("f%25%20\uA004%04%E2%80%80").fd("f% \uA004\4\u2000").z();
1310         test(null, null, "/p% \uA002\2\u2000", "f% \uA004\4\u2000")
1311             .p("/p%25%20\uA002%02%E2%80%80").pd("/p% \uA002\2\u2000")
1312             .f("f%25%20\uA004%04%E2%80%80").fd("f% \uA004\4\u2000").z();
1313         test(null, "/sp% \uA001\1\u2000", "f% \uA004\4\u2000")
1314             .sp("/sp%25%20\uA001%01%E2%80%80").spd("/sp% \uA001\1\u2000")
1315             .p("/sp%25%20\uA001%01%E2%80%80").pd("/sp% \uA001\1\u2000")
1316             .f("f%25%20\uA004%04%E2%80%80").fd("f% \uA004\4\u2000").z();
1317 
1318         // 4438319: Non-raw accessors decode all escaped octets
1319         test("/%25%20%E2%82%AC%E2%80%80")
1320             .p("/%25%20%E2%82%AC%E2%80%80").pd("/% \u20Ac\u2000").z();
1321 
1322         // 4438319: toASCIIString
1323         test("/\uCAFE\uBABE")
1324             .p("/\uCAFE\uBABE").ta("/%EC%AB%BE%EB%AA%BE").z();
1325 
1326         // 4991359 and 4866303: bad quoting by defineSchemeSpecificPart()
1327         URI base = new URI ("http://host/foo%20bar/a/b/c/d");
1328         test ("resolve")
1329             .rslv(base).spd("//host/foo bar/a/b/c/resolve")
1330             .sp("//host/foo%20bar/a/b/c/resolve").s("http")
1331             .pd("/foo bar/a/b/c/resolve").h("host")
1332             .p("/foo%20bar/a/b/c/resolve").z();
1333 
1334         // 6773270: java.net.URI fails to escape u0000
1335         test("s", "a", "/\u0000", null)
1336             .s("s").p("/%00").h("a")
1337             .ta("s://a/%00").z();
1338     }
1339 
1340 
1341     static void eq0(URI u, URI v) throws URISyntaxException {
1342         testCount++;
1343         if (!u.equals(v))
1344             throw new RuntimeException("Not equal: " + u + " " + v);
1345         int uh = u.hashCode();
1346         int vh = v.hashCode();
1347         if (uh != vh)
1348             throw new RuntimeException("Hash codes not equal: "
1349                                        + u + " " + Integer.toHexString(uh) + " "
1350                                        + v + " " + Integer.toHexString(vh));
1351         out.println();
1352         out.println(u + " == " + v
1353                     + "  [" + Integer.toHexString(uh) + "]");
1354     }
1355 
1356     static void cmp0(URI u, URI v, boolean same)
1357         throws URISyntaxException
1358     {
1359         int c = u.compareTo(v);
1360         if ((c == 0) != same)
1361             throw new RuntimeException("Comparison inconsistent: " + u + " " + v
1362                                        + " " + c);
1363     }
1364 
1365     static void eq(URI u, URI v) throws URISyntaxException {
1366         eq0(u, v);
1367         cmp0(u, v, true);
1368     }
1369 
1370     static void eq(String expected, String actual) {
1371         if (expected == null && actual == null) {
1372             return;
1373         }
1374         if (expected != null && expected.equals(actual)) {
1375             return;
1376         }
1377         throw new AssertionError(String.format(
1378                 "Strings are not equal: '%s', '%s'", expected, actual));
1379     }
1380 
1381     static void eqeq(URI u, URI v) {
1382         testCount++;
1383         if (u != v)
1384             throw new RuntimeException("Not ==: " + u + " " + v);
1385     }
1386 
1387     static void ne0(URI u, URI v) throws URISyntaxException {
1388         testCount++;
1389         if (u.equals(v))
1390             throw new RuntimeException("Equal: " + u + " " + v);
1391         out.println();
1392         out.println(u + " != " + v
1393                     + "  [" + Integer.toHexString(u.hashCode())
1394                     + " " + Integer.toHexString(v.hashCode())
1395                     + "]");
1396     }
1397 
1398     static void ne(URI u, URI v) throws URISyntaxException {
1399         ne0(u, v);
1400         cmp0(u, v, false);
1401     }
1402 
1403     static void lt(URI u, URI v) throws URISyntaxException {
1404         ne0(u, v);
1405         int c = u.compareTo(v);
1406         if (c >= 0) {
1407             show(u);
1408             show(v);
1409             throw new RuntimeException("Not less than: " + u + " " + v
1410                                        + " " + c);
1411         }
1412         out.println(u + " < " + v);
1413     }
1414 
1415     static void lt(String s, String t) throws URISyntaxException {
1416         lt(new URI(s), new URI(t));
1417     }
1418 
1419    static void gt(URI u, URI v) throws URISyntaxException {
1420         lt(v, u);
1421     }
1422 
1423     static void eqHashComp() throws URISyntaxException {
1424 
1425         header("Equality, hashing, and comparison");
1426 
1427         URI o = new URI("mailto:foo@bar.com");
1428         URI r = new URI("reg://some%20registry/b/c/d?q#f");
1429         URI s = new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#f");
1430         eq(o, o);
1431         lt(o, r);
1432         lt(s, o);
1433         lt(s, r);
1434         eq(o, new URI("MaILto:foo@bar.com"));
1435         gt(o, new URI("mailto:foo@bar.COM"));
1436         eq(r, new URI("rEg://some%20registry/b/c/d?q#f"));
1437         gt(r, new URI("reg://Some%20Registry/b/c/d?q#f"));
1438         gt(r, new URI("reg://some%20registry/b/c/D?q#f"));
1439         eq(s, new URI("hTtP://jag:cafebabe@Java.Sun.COM:94/b/c/d?q#f"));
1440         gt(s, new URI("http://jag:CafeBabe@java.sun.com:94/b/c/d?q#f"));
1441         lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?r#f"));
1442         lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#g"));
1443         eq(new URI("http://host/a%00bcd"), new URI("http://host/a%00bcd"));
1444         ne(new URI("http://host/a%00bcd"), new URI("http://host/aZ00bcd"));
1445         eq0(new URI("http://host/abc%e2def%C3ghi"),
1446             new URI("http://host/abc%E2def%c3ghi"));
1447 
1448         lt("p", "s:p");
1449         lt("s:p", "T:p");
1450         lt("S:p", "t:p");
1451         lt("s:/p", "s:p");
1452         lt("s:p", "s:q");
1453         lt("s:p#f", "s:p#g");
1454         lt("s://u@h:1", "s://v@h:1");
1455         lt("s://u@h:1", "s://u@i:1");
1456         lt("s://u@h:1", "s://v@h:2");
1457         lt("s://a%20b", "s://a%20c");
1458         lt("s://a%20b", "s://aab");
1459         lt("s://AA", "s://A_");
1460         lt("s:/p", "s:/q");
1461         lt("s:/p?q", "s:/p?r");
1462         lt("s:/p#f", "s:/p#g");
1463 
1464         lt("s://h", "s://h/p");
1465         lt("s://h/p", "s://h/p?q");
1466 
1467     }
1468 
1469 
1470     static void serial(URI u) throws IOException, URISyntaxException {
1471 
1472         ByteArrayOutputStream bo = new ByteArrayOutputStream();
1473         ObjectOutputStream oo = new ObjectOutputStream(bo);
1474 
1475         oo.writeObject(u);
1476         oo.close();
1477 
1478         ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
1479         ObjectInputStream oi = new ObjectInputStream(bi);
1480         try {
1481             Object o = oi.readObject();
1482             eq(u, (URI)o);
1483         } catch (ClassNotFoundException x) {
1484             x.printStackTrace();
1485             throw new RuntimeException(x.toString());
1486         }
1487 
1488         testCount++;
1489     }
1490 
1491     static void serial() throws IOException, URISyntaxException {
1492         header("Serialization");
1493 
1494         serial(URI.create("http://java.sun.com/jdk/1.4?release#beta"));
1495         serial(URI.create("s://h/p").resolve("/long%20path/"));
1496     }
1497 
1498 
1499     static void urls() throws URISyntaxException {
1500 
1501         header("URLs");
1502 
1503         URI uri;
1504         URL url;
1505         boolean caught = false;
1506 
1507         out.println();
1508         uri = new URI("http://a/p?q#f");
1509         try {
1510             url = uri.toURL();
1511         } catch (MalformedURLException x) {
1512             throw new RuntimeException(x.toString());
1513         }
1514         if (!url.toString().equals("http://a/p?q#f"))
1515             throw new RuntimeException("Incorrect URL: " + url);
1516         out.println(uri + " url --> " + url);
1517 
1518         out.println();
1519         uri = new URI("a/b");
1520         try {
1521             out.println(uri + " url --> ");
1522             url = uri.toURL();
1523         } catch (IllegalArgumentException x) {
1524             caught = true;
1525             out.println("Correct exception: " + x);
1526         } catch (MalformedURLException x) {
1527             caught = true;
1528             throw new RuntimeException("Incorrect exception: " + x);
1529         }
1530         if (!caught)
1531             throw new RuntimeException("Incorrect URL: " + url);
1532 
1533         out.println();
1534         uri = new URI("foo://bar/baz");
1535         caught = false;
1536         try {
1537             out.println(uri + " url --> ");
1538             url = uri.toURL();
1539         } catch (MalformedURLException x) {
1540             caught = true;
1541             out.println("Correct exception: " + x);
1542         } catch (IllegalArgumentException x) {
1543             caught = true;
1544             throw new RuntimeException("Incorrect exception: " + x);
1545         }
1546         if (!caught)
1547             throw new RuntimeException("Incorrect URL: " + url);
1548 
1549         testCount += 3;
1550     }
1551 
1552 
1553     static void tests() throws IOException, URISyntaxException {
1554         rfc2396();
1555         ip();
1556         misc();
1557         chars();
1558         eqHashComp();
1559         serial();
1560         urls();
1561         npes();
1562         bugs();
1563     }
1564 
1565 
1566     // -- Command-line invocation --
1567 
1568     static void usage() {
1569         out.println("Usage:");
1570         out.println("  java Test               --  Runs all tests in this file");
1571         out.println("  java Test <uri>         --  Parses uri, shows components");
1572         out.println("  java Test <base> <uri>  --  Parses uri and base, then resolves");
1573         out.println("                              uri against base");
1574     }
1575 
1576     static void clargs(String base, String uri) {
1577         URI b = null, u;
1578         try {
1579             if (base != null) {
1580                 b = new URI(base);
1581                 out.println(base);
1582                 show(b);
1583             }
1584             u = new URI(uri);
1585             out.println(uri);
1586             show(u);
1587             if (base != null) {
1588                 URI r = b.resolve(u);
1589                 out.println(r);
1590                 show(r);
1591             }
1592         } catch (URISyntaxException x) {
1593             show("ERROR", x);
1594             x.printStackTrace(out);
1595         }
1596     }
1597 
1598 
1599     // miscellaneous bugs/rfes that don't fit in with the test framework
1600 
1601     static void bugs() {
1602         b6339649();
1603         b8037396();
1604     }
1605 
1606     // 6339649 - include detail message from nested exception
1607     private static void b6339649() {
1608         try {
1609             URI uri = URI.create("http://nowhere.net/should not be permitted");
1610         } catch (IllegalArgumentException e) {
1611             if ("".equals(e.getMessage()) || e.getMessage() == null) {
1612                 throw new RuntimeException ("No detail message");
1613             }
1614         }
1615     }
1616 
1617     private static void b8037396() {
1618 
1619         // primary checks:
1620 
1621         URI u;
1622         try {
1623             u = new URI("http", "example.org", "/[a b]", "[a b]", "[a b]");
1624         } catch (URISyntaxException e) {
1625             throw new AssertionError("shouldn't ever happen", e);
1626         }
1627         eq("/[a b]", u.getPath());
1628         eq("[a b]", u.getQuery());
1629         eq("[a b]", u.getFragment());
1630 
1631         // additional checks:
1632         //  *   '%' symbols are still decoded outside square brackets
1633         //  *   the getRawXXX() functionality left intact
1634 
1635         try {
1636             u = new URI("http", "example.org", "/a b[c d]", "a b[c d]", "a b[c d]");
1637         } catch (URISyntaxException e) {
1638             throw new AssertionError("shouldn't ever happen", e);
1639         }
1640 
1641         eq("/a b[c d]", u.getPath());
1642         eq("a b[c d]", u.getQuery());
1643         eq("a b[c d]", u.getFragment());
1644 
1645         eq("/a%20b%5Bc%20d%5D", u.getRawPath());
1646         eq("a%20b[c%20d]", u.getRawQuery());
1647         eq("a%20b[c%20d]", u.getRawFragment());
1648     }
1649 
1650     public static void main(String[] args) throws Exception {
1651         switch (args.length) {
1652 
1653         case 0:
1654             tests();
1655             out.println();
1656             out.println("Test cases: " + testCount);
1657             break;
1658 
1659         case 1:
1660             if (args[0].equals("-help")) {
1661                 usage();
1662                 break;
1663             }
1664             clargs(null, args[0]);
1665             break;
1666 
1667         case 2:
1668             clargs(args[0], args[1]);
1669             break;
1670 
1671         default:
1672             usage();
1673             break;
1674 
1675         }
1676     }
1677 
1678 }