tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_URIs2.js (22372B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 "use strict";
      3 
      4 // Run by: cd objdir;  make -C netwerk/test/ xpcshell-tests
      5 // or: cd objdir; make SOLO_FILE="test_URIs2.js" -C netwerk/test/ check-one
      6 
      7 // This is a clone of test_URIs.js, with a different set of test data in gTests.
      8 // The original test data in test_URIs.js was split between test_URIs and test_URIs2.js
      9 // because test_URIs.js was running for too long on slow platforms, causing
     10 // intermittent timeouts.
     11 
     12 // Relevant RFCs: 1738, 1808, 2396, 3986 (newer than the code)
     13 // http://greenbytes.de/tech/webdav/rfc3986.html#rfc.section.5.4
     14 // http://greenbytes.de/tech/tc/uris/
     15 
     16 // TEST DATA
     17 // ---------
     18 var gTests = [
     19  {
     20    spec: "view-source:about:blank",
     21    scheme: "view-source",
     22    prePath: "view-source:",
     23    pathQueryRef: "about:blank",
     24    ref: "",
     25    nsIURL: false,
     26    nsINestedURI: true,
     27    immutable: true,
     28  },
     29  {
     30    spec: "view-source:http://www.mozilla.org/",
     31    scheme: "view-source",
     32    prePath: "view-source:",
     33    pathQueryRef: "http://www.mozilla.org/",
     34    ref: "",
     35    nsIURL: false,
     36    nsINestedURI: true,
     37    immutable: true,
     38  },
     39  {
     40    spec: "x-external:",
     41    scheme: "x-external",
     42    prePath: "x-external:",
     43    pathQueryRef: "",
     44    ref: "",
     45    nsIURL: false,
     46    nsINestedURI: false,
     47  },
     48  {
     49    spec: "x-external:abc",
     50    scheme: "x-external",
     51    prePath: "x-external:",
     52    pathQueryRef: "abc",
     53    ref: "",
     54    nsIURL: false,
     55    nsINestedURI: false,
     56  },
     57  {
     58    spec: "http://www2.example.com/",
     59    relativeURI: "a/b/c/d",
     60    scheme: "http",
     61    prePath: "http://www2.example.com",
     62    pathQueryRef: "/a/b/c/d",
     63    ref: "",
     64    nsIURL: true,
     65    nsINestedURI: false,
     66  },
     67  // relative URL testcases from http://greenbytes.de/tech/webdav/rfc3986.html#rfc.section.5.4
     68  {
     69    spec: "http://a/b/c/d;p?q",
     70    relativeURI: "g:h",
     71    scheme: "g",
     72    prePath: "g:",
     73    pathQueryRef: "h",
     74    ref: "",
     75    nsIURL: false,
     76    nsINestedURI: false,
     77  },
     78  {
     79    spec: "http://a/b/c/d;p?q",
     80    relativeURI: "g",
     81    scheme: "http",
     82    prePath: "http://a",
     83    pathQueryRef: "/b/c/g",
     84    ref: "",
     85    nsIURL: true,
     86    nsINestedURI: false,
     87  },
     88  {
     89    spec: "http://a/b/c/d;p?q",
     90    relativeURI: "./g",
     91    scheme: "http",
     92    prePath: "http://a",
     93    pathQueryRef: "/b/c/g",
     94    ref: "",
     95    nsIURL: true,
     96    nsINestedURI: false,
     97  },
     98  {
     99    spec: "http://a/b/c/d;p?q",
    100    relativeURI: "g/",
    101    scheme: "http",
    102    prePath: "http://a",
    103    pathQueryRef: "/b/c/g/",
    104    ref: "",
    105    nsIURL: true,
    106    nsINestedURI: false,
    107  },
    108  {
    109    spec: "http://a/b/c/d;p?q",
    110    relativeURI: "/g",
    111    scheme: "http",
    112    prePath: "http://a",
    113    pathQueryRef: "/g",
    114    ref: "",
    115    nsIURL: true,
    116    nsINestedURI: false,
    117  },
    118  {
    119    spec: "http://a/b/c/d;p?q",
    120    relativeURI: "?y",
    121    scheme: "http",
    122    prePath: "http://a",
    123    pathQueryRef: "/b/c/d;p?y",
    124    ref: "", // fix
    125    nsIURL: true,
    126    nsINestedURI: false,
    127  },
    128  {
    129    spec: "http://a/b/c/d;p?q",
    130    relativeURI: "g?y",
    131    scheme: "http",
    132    prePath: "http://a",
    133    pathQueryRef: "/b/c/g?y",
    134    ref: "", // fix
    135    specIgnoringRef: "http://a/b/c/g?y",
    136    hasRef: false,
    137    hasQuery: true,
    138    nsIURL: true,
    139    nsINestedURI: false,
    140  },
    141  {
    142    spec: "http://a/b/c/d;p?q",
    143    relativeURI: "#s",
    144    scheme: "http",
    145    prePath: "http://a",
    146    pathQueryRef: "/b/c/d;p?q#s",
    147    ref: "s", // fix
    148    specIgnoringRef: "http://a/b/c/d;p?q",
    149    hasRef: true,
    150    nsIURL: true,
    151    nsINestedURI: false,
    152  },
    153  {
    154    spec: "http://a/b/c/d;p?q",
    155    relativeURI: "g#s",
    156    scheme: "http",
    157    prePath: "http://a",
    158    pathQueryRef: "/b/c/g#s",
    159    ref: "s",
    160    nsIURL: true,
    161    nsINestedURI: false,
    162  },
    163  {
    164    spec: "http://a/b/c/d;p?q",
    165    relativeURI: "g?y#s",
    166    scheme: "http",
    167    prePath: "http://a",
    168    pathQueryRef: "/b/c/g?y#s",
    169    ref: "s",
    170    nsIURL: true,
    171    nsINestedURI: false,
    172  },
    173  /*
    174    Bug xxxxxx - we return a path of b/c/;x
    175  { spec:    "http://a/b/c/d;p?q",
    176    relativeURI: ";x",
    177    scheme:  "http",
    178    prePath: "http://a",
    179    pathQueryRef: "/b/c/d;x",
    180    ref:     "",
    181    nsIURL:  true, nsINestedURI: false },
    182  */
    183  {
    184    spec: "http://a/b/c/d;p?q",
    185    relativeURI: "g;x",
    186    scheme: "http",
    187    prePath: "http://a",
    188    pathQueryRef: "/b/c/g;x",
    189    ref: "",
    190    nsIURL: true,
    191    nsINestedURI: false,
    192  },
    193  {
    194    spec: "http://a/b/c/d;p?q",
    195    relativeURI: "g;x?y#s",
    196    scheme: "http",
    197    prePath: "http://a",
    198    pathQueryRef: "/b/c/g;x?y#s",
    199    ref: "s",
    200    nsIURL: true,
    201    nsINestedURI: false,
    202  },
    203  /*
    204    Can't easily specify a relative URI of "" to the test code
    205  { spec:    "http://a/b/c/d;p?q",
    206    relativeURI: "",
    207    scheme:  "http",
    208    prePath: "http://a",
    209    pathQueryRef: "/b/c/d",
    210    ref:     "",
    211    nsIURL:  true, nsINestedURI: false },
    212  */
    213  {
    214    spec: "http://a/b/c/d;p?q",
    215    relativeURI: ".",
    216    scheme: "http",
    217    prePath: "http://a",
    218    pathQueryRef: "/b/c/",
    219    ref: "",
    220    nsIURL: true,
    221    nsINestedURI: false,
    222  },
    223  {
    224    spec: "http://a/b/c/d;p?q",
    225    relativeURI: "./",
    226    scheme: "http",
    227    prePath: "http://a",
    228    pathQueryRef: "/b/c/",
    229    ref: "",
    230    nsIURL: true,
    231    nsINestedURI: false,
    232  },
    233  {
    234    spec: "http://a/b/c/d;p?q",
    235    relativeURI: "..",
    236    scheme: "http",
    237    prePath: "http://a",
    238    pathQueryRef: "/b/",
    239    ref: "",
    240    nsIURL: true,
    241    nsINestedURI: false,
    242  },
    243  {
    244    spec: "http://a/b/c/d;p?q",
    245    relativeURI: "../",
    246    scheme: "http",
    247    prePath: "http://a",
    248    pathQueryRef: "/b/",
    249    ref: "",
    250    nsIURL: true,
    251    nsINestedURI: false,
    252  },
    253  {
    254    spec: "http://a/b/c/d;p?q",
    255    relativeURI: "../g",
    256    scheme: "http",
    257    prePath: "http://a",
    258    pathQueryRef: "/b/g",
    259    ref: "",
    260    nsIURL: true,
    261    nsINestedURI: false,
    262  },
    263  {
    264    spec: "http://a/b/c/d;p?q",
    265    relativeURI: "../..",
    266    scheme: "http",
    267    prePath: "http://a",
    268    pathQueryRef: "/",
    269    ref: "",
    270    nsIURL: true,
    271    nsINestedURI: false,
    272  },
    273  {
    274    spec: "http://a/b/c/d;p?q",
    275    relativeURI: "../../",
    276    scheme: "http",
    277    prePath: "http://a",
    278    pathQueryRef: "/",
    279    ref: "",
    280    nsIURL: true,
    281    nsINestedURI: false,
    282  },
    283  {
    284    spec: "http://a/b/c/d;p?q",
    285    relativeURI: "../../g",
    286    scheme: "http",
    287    prePath: "http://a",
    288    pathQueryRef: "/g",
    289    ref: "",
    290    nsIURL: true,
    291    nsINestedURI: false,
    292  },
    293 
    294  // abnormal examples
    295  {
    296    spec: "http://a/b/c/d;p?q",
    297    relativeURI: "../../../g",
    298    scheme: "http",
    299    prePath: "http://a",
    300    pathQueryRef: "/g",
    301    ref: "",
    302    nsIURL: true,
    303    nsINestedURI: false,
    304  },
    305  {
    306    spec: "http://a/b/c/d;p?q",
    307    relativeURI: "../../../../g",
    308    scheme: "http",
    309    prePath: "http://a",
    310    pathQueryRef: "/g",
    311    ref: "",
    312    nsIURL: true,
    313    nsINestedURI: false,
    314  },
    315 
    316  // coalesce
    317  {
    318    spec: "http://a/b/c/d;p?q",
    319    relativeURI: "/./g",
    320    scheme: "http",
    321    prePath: "http://a",
    322    pathQueryRef: "/g",
    323    ref: "",
    324    nsIURL: true,
    325    nsINestedURI: false,
    326  },
    327  {
    328    spec: "http://a/b/c/d;p?q",
    329    relativeURI: "/../g",
    330    scheme: "http",
    331    prePath: "http://a",
    332    pathQueryRef: "/g",
    333    ref: "",
    334    nsIURL: true,
    335    nsINestedURI: false,
    336  },
    337  {
    338    spec: "http://a/b/c/d;p?q",
    339    relativeURI: "g.",
    340    scheme: "http",
    341    prePath: "http://a",
    342    pathQueryRef: "/b/c/g.",
    343    ref: "",
    344    nsIURL: true,
    345    nsINestedURI: false,
    346  },
    347  {
    348    spec: "http://a/b/c/d;p?q",
    349    relativeURI: ".g",
    350    scheme: "http",
    351    prePath: "http://a",
    352    pathQueryRef: "/b/c/.g",
    353    ref: "",
    354    nsIURL: true,
    355    nsINestedURI: false,
    356  },
    357  {
    358    spec: "http://a/b/c/d;p?q",
    359    relativeURI: "g..",
    360    scheme: "http",
    361    prePath: "http://a",
    362    pathQueryRef: "/b/c/g..",
    363    ref: "",
    364    nsIURL: true,
    365    nsINestedURI: false,
    366  },
    367  {
    368    spec: "http://a/b/c/d;p?q",
    369    relativeURI: "..g",
    370    scheme: "http",
    371    prePath: "http://a",
    372    pathQueryRef: "/b/c/..g",
    373    ref: "",
    374    nsIURL: true,
    375    nsINestedURI: false,
    376  },
    377  {
    378    spec: "http://a/b/c/d;p?q",
    379    relativeURI: ".",
    380    scheme: "http",
    381    prePath: "http://a",
    382    pathQueryRef: "/b/c/",
    383    ref: "",
    384    nsIURL: true,
    385    nsINestedURI: false,
    386  },
    387  {
    388    spec: "http://a/b/c/d;p?q",
    389    relativeURI: "./../g",
    390    scheme: "http",
    391    prePath: "http://a",
    392    pathQueryRef: "/b/g",
    393    ref: "",
    394    nsIURL: true,
    395    nsINestedURI: false,
    396  },
    397  {
    398    spec: "http://a/b/c/d;p?q",
    399    relativeURI: "./g/.",
    400    scheme: "http",
    401    prePath: "http://a",
    402    pathQueryRef: "/b/c/g/",
    403    ref: "",
    404    nsIURL: true,
    405    nsINestedURI: false,
    406  },
    407  {
    408    spec: "http://a/b/c/d;p?q",
    409    relativeURI: "g/./h",
    410    scheme: "http",
    411    prePath: "http://a",
    412    pathQueryRef: "/b/c/g/h",
    413    ref: "",
    414    nsIURL: true,
    415    nsINestedURI: false,
    416  },
    417  {
    418    spec: "http://a/b/c/d;p?q",
    419    relativeURI: "g/../h",
    420    scheme: "http",
    421    prePath: "http://a",
    422    pathQueryRef: "/b/c/h",
    423    ref: "", // fix
    424    nsIURL: true,
    425    nsINestedURI: false,
    426  },
    427  {
    428    spec: "http://a/b/c/d;p?q",
    429    relativeURI: "g;x=1/./y",
    430    scheme: "http",
    431    prePath: "http://a",
    432    pathQueryRef: "/b/c/g;x=1/y",
    433    ref: "",
    434    nsIURL: true,
    435    nsINestedURI: false,
    436  },
    437  {
    438    spec: "http://a/b/c/d;p?q",
    439    relativeURI: "g;x=1/../y",
    440    scheme: "http",
    441    prePath: "http://a",
    442    pathQueryRef: "/b/c/y",
    443    ref: "",
    444    nsIURL: true,
    445    nsINestedURI: false,
    446  },
    447  // protocol-relative http://tools.ietf.org/html/rfc3986#section-4.2
    448  {
    449    spec: "http://www2.example.com/",
    450    relativeURI: "//www3.example2.com/bar",
    451    scheme: "http",
    452    prePath: "http://www3.example2.com",
    453    pathQueryRef: "/bar",
    454    ref: "",
    455    nsIURL: true,
    456    nsINestedURI: false,
    457  },
    458  {
    459    spec: "https://www2.example.com/",
    460    relativeURI: "//www3.example2.com/bar",
    461    scheme: "https",
    462    prePath: "https://www3.example2.com",
    463    pathQueryRef: "/bar",
    464    hasQuery: false,
    465    ref: "",
    466    nsIURL: true,
    467    nsINestedURI: false,
    468  },
    469 ];
    470 
    471 var gHashSuffixes = ["#", "#myRef", "#myRef?a=b", "#myRef#", "#myRef#x:yz"];
    472 
    473 // TEST HELPER FUNCTIONS
    474 // ---------------------
    475 function do_info(text, stack) {
    476  if (!stack) {
    477    stack = Components.stack.caller;
    478  }
    479 
    480  dump(
    481    "\n" +
    482      "TEST-INFO | " +
    483      stack.filename +
    484      " | [" +
    485      stack.name +
    486      " : " +
    487      stack.lineNumber +
    488      "] " +
    489      text +
    490      "\n"
    491  );
    492 }
    493 
    494 // Checks that the URIs satisfy equals(), in both possible orderings.
    495 // Also checks URI.equalsExceptRef(), because equal URIs should also be equal
    496 // when we ignore the ref.
    497 //
    498 // The third argument is optional. If the client passes a third argument
    499 // (e.g. todo_check_true), we'll use that in lieu of ok.
    500 function do_check_uri_eq(aURI1, aURI2, aCheckTrueFunc = ok) {
    501  do_info("(uri equals check: '" + aURI1.spec + "' == '" + aURI2.spec + "')");
    502  aCheckTrueFunc(aURI1.equals(aURI2));
    503  do_info("(uri equals check: '" + aURI2.spec + "' == '" + aURI1.spec + "')");
    504  aCheckTrueFunc(aURI2.equals(aURI1));
    505 
    506  // (Only take the extra step of testing 'equalsExceptRef' when we expect the
    507  // URIs to really be equal.  In 'todo' cases, the URIs may or may not be
    508  // equal when refs are ignored - there's no way of knowing in general.)
    509  if (aCheckTrueFunc == ok) {
    510    do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc);
    511  }
    512 }
    513 
    514 // Checks that the URIs satisfy equalsExceptRef(), in both possible orderings.
    515 //
    516 // The third argument is optional. If the client passes a third argument
    517 // (e.g. todo_check_true), we'll use that in lieu of ok.
    518 function do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc = ok) {
    519  do_info(
    520    "(uri equalsExceptRef check: '" + aURI1.spec + "' == '" + aURI2.spec + "')"
    521  );
    522  aCheckTrueFunc(aURI1.equalsExceptRef(aURI2));
    523  do_info(
    524    "(uri equalsExceptRef check: '" + aURI2.spec + "' == '" + aURI1.spec + "')"
    525  );
    526  aCheckTrueFunc(aURI2.equalsExceptRef(aURI1));
    527 }
    528 
    529 // Checks that the given property on aURI matches the corresponding property
    530 // in the test bundle (or matches some function of that corresponding property,
    531 // if aTestFunctor is passed in).
    532 function do_check_property(aTest, aURI, aPropertyName, aTestFunctor) {
    533  if (aTest[aPropertyName]) {
    534    var expectedVal = aTestFunctor
    535      ? aTestFunctor(aTest[aPropertyName])
    536      : aTest[aPropertyName];
    537 
    538    do_info(
    539      "testing " +
    540        aPropertyName +
    541        " of " +
    542        (aTestFunctor ? "modified '" : "'") +
    543        aTest.spec +
    544        "' is '" +
    545        expectedVal +
    546        "'"
    547    );
    548    Assert.equal(aURI[aPropertyName], expectedVal);
    549  }
    550 }
    551 
    552 // Test that a given URI parses correctly into its various components.
    553 function do_test_uri_basic(aTest) {
    554  var URI;
    555 
    556  do_info(
    557    "Basic tests for " + aTest.spec + " relative URI: " + aTest.relativeURI
    558  );
    559 
    560  try {
    561    URI = NetUtil.newURI(aTest.spec);
    562  } catch (e) {
    563    do_info("Caught error on parse of" + aTest.spec + " Error: " + e.result);
    564    if (aTest.fail) {
    565      Assert.equal(e.result, aTest.result);
    566      return;
    567    }
    568    do_throw(e.result);
    569  }
    570 
    571  if (aTest.relativeURI) {
    572    var relURI;
    573 
    574    try {
    575      relURI = Services.io.newURI(aTest.relativeURI, null, URI);
    576    } catch (e) {
    577      do_info(
    578        "Caught error on Relative parse of " +
    579          aTest.spec +
    580          " + " +
    581          aTest.relativeURI +
    582          " Error: " +
    583          e.result
    584      );
    585      if (aTest.relativeFail) {
    586        Assert.equal(e.result, aTest.relativeFail);
    587        return;
    588      }
    589      do_throw(e.result);
    590    }
    591    do_info(
    592      "relURI.pathQueryRef = " +
    593        relURI.pathQueryRef +
    594        ", was " +
    595        URI.pathQueryRef
    596    );
    597    URI = relURI;
    598    do_info("URI.pathQueryRef now = " + URI.pathQueryRef);
    599  }
    600 
    601  // Sanity-check
    602  do_info("testing " + aTest.spec + " equals a clone of itself");
    603  do_check_uri_eq(URI, URI.mutate().finalize());
    604  do_check_uri_eqExceptRef(URI, URI.mutate().setRef("").finalize());
    605  do_info("testing " + aTest.spec + " instanceof nsIURL");
    606  Assert.equal(URI instanceof Ci.nsIURL, aTest.nsIURL);
    607  do_info("testing " + aTest.spec + " instanceof nsINestedURI");
    608  Assert.equal(URI instanceof Ci.nsINestedURI, aTest.nsINestedURI);
    609 
    610  do_info(
    611    "testing that " +
    612      aTest.spec +
    613      " throws or returns false " +
    614      "from equals(null)"
    615  );
    616  // XXXdholbert At some point it'd probably be worth making this behavior
    617  // (throwing vs. returning false) consistent across URI implementations.
    618  var threw = false;
    619  var isEqualToNull;
    620  try {
    621    isEqualToNull = URI.equals(null);
    622  } catch (e) {
    623    threw = true;
    624  }
    625  Assert.ok(threw || !isEqualToNull);
    626 
    627  // Check the various components
    628  do_check_property(aTest, URI, "scheme");
    629  do_check_property(aTest, URI, "prePath");
    630  do_check_property(aTest, URI, "pathQueryRef");
    631  do_check_property(aTest, URI, "query");
    632  do_check_property(aTest, URI, "ref");
    633  do_check_property(aTest, URI, "port");
    634  do_check_property(aTest, URI, "username");
    635  do_check_property(aTest, URI, "password");
    636  do_check_property(aTest, URI, "host");
    637  do_check_property(aTest, URI, "specIgnoringRef");
    638  if ("hasRef" in aTest) {
    639    do_info("testing hasref: " + aTest.hasRef + " vs " + URI.hasRef);
    640    Assert.equal(aTest.hasRef, URI.hasRef);
    641  }
    642  if ("hasQuery" in aTest) {
    643    do_info("testing hasQuery: " + aTest.hasQuery + " vs " + URI.hasQuery);
    644    Assert.equal(aTest.hasQuery, URI.hasQuery);
    645  }
    646 }
    647 
    648 // Test that a given URI parses correctly when we add a given ref to the end
    649 function do_test_uri_with_hash_suffix(aTest, aSuffix) {
    650  do_info("making sure caller is using suffix that starts with '#'");
    651  Assert.equal(aSuffix[0], "#");
    652 
    653  var origURI = NetUtil.newURI(aTest.spec);
    654  var testURI;
    655 
    656  if (aTest.relativeURI) {
    657    try {
    658      origURI = Services.io.newURI(aTest.relativeURI, null, origURI);
    659    } catch (e) {
    660      do_info(
    661        "Caught error on Relative parse of " +
    662          aTest.spec +
    663          " + " +
    664          aTest.relativeURI +
    665          " Error: " +
    666          e.result
    667      );
    668      return;
    669    }
    670    try {
    671      testURI = Services.io.newURI(aSuffix, null, origURI);
    672    } catch (e) {
    673      do_info(
    674        "Caught error adding suffix to " +
    675          aTest.spec +
    676          " + " +
    677          aTest.relativeURI +
    678          ", suffix " +
    679          aSuffix +
    680          " Error: " +
    681          e.result
    682      );
    683      return;
    684    }
    685  } else {
    686    testURI = NetUtil.newURI(aTest.spec + aSuffix);
    687  }
    688 
    689  do_info(
    690    "testing " +
    691      aTest.spec +
    692      " with '" +
    693      aSuffix +
    694      "' appended " +
    695      "equals a clone of itself"
    696  );
    697  do_check_uri_eq(testURI, testURI.mutate().finalize());
    698 
    699  do_info(
    700    "testing " +
    701      aTest.spec +
    702      " doesn't equal self with '" +
    703      aSuffix +
    704      "' appended"
    705  );
    706 
    707  Assert.ok(!origURI.equals(testURI));
    708 
    709  do_info(
    710    "testing " +
    711      aTest.spec +
    712      " is equalExceptRef to self with '" +
    713      aSuffix +
    714      "' appended"
    715  );
    716  do_check_uri_eqExceptRef(origURI, testURI);
    717 
    718  Assert.equal(testURI.hasRef, true);
    719 
    720  if (!origURI.ref) {
    721    // These tests fail if origURI has a ref
    722    do_info(
    723      "testing cloneIgnoringRef on " +
    724        testURI.spec +
    725        " is equal to no-ref version but not equal to ref version"
    726    );
    727    var cloneNoRef = testURI.mutate().setRef("").finalize();
    728    do_check_uri_eq(cloneNoRef, origURI);
    729    Assert.ok(!cloneNoRef.equals(testURI));
    730  }
    731 
    732  do_check_property(aTest, testURI, "scheme");
    733  do_check_property(aTest, testURI, "prePath");
    734  if (!origURI.ref) {
    735    // These don't work if it's a ref already because '+' doesn't give the right result
    736    do_check_property(aTest, testURI, "pathQueryRef", function (aStr) {
    737      return aStr + aSuffix;
    738    });
    739    do_check_property(aTest, testURI, "ref", function () {
    740      return aSuffix.substr(1);
    741    });
    742  }
    743 }
    744 
    745 // Tests various ways of setting & clearing a ref on a URI.
    746 function do_test_mutate_ref(aTest, aSuffix) {
    747  do_info("making sure caller is using suffix that starts with '#'");
    748  Assert.equal(aSuffix[0], "#");
    749 
    750  var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix);
    751  var refURIWithoutSuffix = NetUtil.newURI(aTest.spec);
    752 
    753  var testURI = NetUtil.newURI(aTest.spec);
    754 
    755  // First: Try setting .ref to our suffix
    756  do_info(
    757    "testing that setting .ref on " +
    758      aTest.spec +
    759      " to '" +
    760      aSuffix +
    761      "' does what we expect"
    762  );
    763  testURI = testURI.mutate().setRef(aSuffix).finalize();
    764  do_check_uri_eq(testURI, refURIWithSuffix);
    765  do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
    766 
    767  // Now try setting .ref but leave off the initial hash (expect same result)
    768  var suffixLackingHash = aSuffix.substr(1);
    769  if (suffixLackingHash) {
    770    // (skip this our suffix was *just* a #)
    771    do_info(
    772      "testing that setting .ref on " +
    773        aTest.spec +
    774        " to '" +
    775        suffixLackingHash +
    776        "' does what we expect"
    777    );
    778    testURI = testURI.mutate().setRef(suffixLackingHash).finalize();
    779    do_check_uri_eq(testURI, refURIWithSuffix);
    780    do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
    781  }
    782 
    783  // Now, clear .ref (should get us back the original spec)
    784  do_info(
    785    "testing that clearing .ref on " + testURI.spec + " does what we expect"
    786  );
    787  testURI = testURI.mutate().setRef("").finalize();
    788  do_check_uri_eq(testURI, refURIWithoutSuffix);
    789  do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
    790 
    791  if (!aTest.relativeURI) {
    792    // TODO: These tests don't work as-is for relative URIs.
    793 
    794    // Now try setting .spec directly (including suffix) and then clearing .ref
    795    var specWithSuffix = aTest.spec + aSuffix;
    796    do_info(
    797      "testing that setting spec to " +
    798        specWithSuffix +
    799        " and then clearing ref does what we expect"
    800    );
    801    testURI = testURI.mutate().setSpec(specWithSuffix).setRef("").finalize();
    802    do_check_uri_eq(testURI, refURIWithoutSuffix);
    803    do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
    804 
    805    // XXX nsIJARURI throws an exception in SetPath(), so skip it for next part.
    806    if (!(testURI instanceof Ci.nsIJARURI)) {
    807      // Now try setting .pathQueryRef directly (including suffix) and then clearing .ref
    808      // (same as above, but with now with .pathQueryRef instead of .spec)
    809      testURI = NetUtil.newURI(aTest.spec);
    810 
    811      var pathWithSuffix = aTest.pathQueryRef + aSuffix;
    812      do_info(
    813        "testing that setting path to " +
    814          pathWithSuffix +
    815          " and then clearing ref does what we expect"
    816      );
    817      testURI = testURI
    818        .mutate()
    819        .setPathQueryRef(pathWithSuffix)
    820        .setRef("")
    821        .finalize();
    822      do_check_uri_eq(testURI, refURIWithoutSuffix);
    823      do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
    824 
    825      // Also: make sure that clearing .pathQueryRef also clears .ref
    826      testURI = testURI.mutate().setPathQueryRef(pathWithSuffix).finalize();
    827      do_info(
    828        "testing that clearing path from " +
    829          pathWithSuffix +
    830          " also clears .ref"
    831      );
    832      testURI = testURI.mutate().setPathQueryRef("").finalize();
    833      Assert.equal(testURI.ref, "");
    834    }
    835  }
    836 }
    837 
    838 // TEST MAIN FUNCTION
    839 // ------------------
    840 function run_test() {
    841  // UTF-8 check - From bug 622981
    842  // ASCII
    843  let base = Services.io.newURI("http://example.org/xenia?");
    844  let resolved = Services.io.newURI("?x", null, base);
    845  let expected = Services.io.newURI("http://example.org/xenia?x");
    846  do_info(
    847    "Bug 662981: ACSII - comparing " + resolved.spec + " and " + expected.spec
    848  );
    849  Assert.ok(resolved.equals(expected));
    850 
    851  // UTF-8 character "è"
    852  // Bug 622981 was triggered by an empty query string
    853  base = Services.io.newURI("http://example.org/xènia?");
    854  resolved = Services.io.newURI("?x", null, base);
    855  expected = Services.io.newURI("http://example.org/xènia?x");
    856  do_info(
    857    "Bug 662981: UTF8 - comparing " + resolved.spec + " and " + expected.spec
    858  );
    859  Assert.ok(resolved.equals(expected));
    860 
    861  gTests.forEach(function (aTest) {
    862    // Check basic URI functionality
    863    do_test_uri_basic(aTest);
    864 
    865    if (!aTest.fail) {
    866      // Try adding various #-prefixed strings to the ends of the URIs
    867      gHashSuffixes.forEach(function (aSuffix) {
    868        do_test_uri_with_hash_suffix(aTest, aSuffix);
    869        if (!aTest.immutable) {
    870          do_test_mutate_ref(aTest, aSuffix);
    871        }
    872      });
    873 
    874      // For URIs that we couldn't mutate above due to them being immutable:
    875      // Now we check that they're actually immutable.
    876      if (aTest.immutable) {
    877        Assert.ok(aTest.immutable);
    878      }
    879    }
    880  });
    881 }