Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 Components.utils.import("resource://gre/modules/NetUtil.jsm");
4 var gIoService = Components.classes["@mozilla.org/network/io-service;1"]
5 .getService(Components.interfaces.nsIIOService);
8 // Run by: cd objdir; make -C netwerk/test/ xpcshell-tests
9 // or: cd objdir; make SOLO_FILE="test_URIs2.js" -C netwerk/test/ check-one
11 // This is a clone of test_URIs.js, with a different set of test data in gTests.
12 // The original test data in test_URIs.js was split between test_URIs and test_URIs2.js
13 // because test_URIs.js was running for too long on slow platforms, causing
14 // intermittent timeouts.
16 // Relevant RFCs: 1738, 1808, 2396, 3986 (newer than the code)
17 // http://greenbytes.de/tech/webdav/rfc3986.html#rfc.section.5.4
18 // http://greenbytes.de/tech/tc/uris/
20 // TEST DATA
21 // ---------
22 var gTests = [
23 // relative URL testcases from http://greenbytes.de/tech/webdav/rfc3986.html#rfc.section.5.4
24 { spec: "http://a/b/c/d;p?q",
25 relativeURI: "g:h",
26 scheme: "g",
27 prePath: "g:",
28 path: "h",
29 ref: "",
30 nsIURL: false, nsINestedURI: false },
31 { spec: "http://a/b/c/d;p?q",
32 relativeURI: "g",
33 scheme: "http",
34 prePath: "http://a",
35 path: "/b/c/g",
36 ref: "",
37 nsIURL: true, nsINestedURI: false },
38 { spec: "http://a/b/c/d;p?q",
39 relativeURI: "./g",
40 scheme: "http",
41 prePath: "http://a",
42 path: "/b/c/g",
43 ref: "",
44 nsIURL: true, nsINestedURI: false },
45 { spec: "http://a/b/c/d;p?q",
46 relativeURI: "g/",
47 scheme: "http",
48 prePath: "http://a",
49 path: "/b/c/g/",
50 ref: "",
51 nsIURL: true, nsINestedURI: false },
52 { spec: "http://a/b/c/d;p?q",
53 relativeURI: "/g",
54 scheme: "http",
55 prePath: "http://a",
56 path: "/g",
57 ref: "",
58 nsIURL: true, nsINestedURI: false },
59 { spec: "http://a/b/c/d;p?q",
60 relativeURI: "?y",
61 scheme: "http",
62 prePath: "http://a",
63 path: "/b/c/d;p?y",
64 ref: "",// fix
65 nsIURL: true, nsINestedURI: false },
66 { spec: "http://a/b/c/d;p?q",
67 relativeURI: "g?y",
68 scheme: "http",
69 prePath: "http://a",
70 path: "/b/c/g?y",
71 ref: "",// fix
72 specIgnoringRef: "http://a/b/c/g?y",
73 hasRef: false,
74 nsIURL: true, nsINestedURI: false },
75 { spec: "http://a/b/c/d;p?q",
76 relativeURI: "#s",
77 scheme: "http",
78 prePath: "http://a",
79 path: "/b/c/d;p?q#s",
80 ref: "s",// fix
81 specIgnoringRef: "http://a/b/c/d;p?q",
82 hasRef: true,
83 nsIURL: true, nsINestedURI: false },
84 { spec: "http://a/b/c/d;p?q",
85 relativeURI: "g#s",
86 scheme: "http",
87 prePath: "http://a",
88 path: "/b/c/g#s",
89 ref: "s",
90 nsIURL: true, nsINestedURI: false },
91 { spec: "http://a/b/c/d;p?q",
92 relativeURI: "g?y#s",
93 scheme: "http",
94 prePath: "http://a",
95 path: "/b/c/g?y#s",
96 ref: "s",
97 nsIURL: true, nsINestedURI: false },
98 /*
99 Bug xxxxxx - we return a path of b/c/;x
100 { spec: "http://a/b/c/d;p?q",
101 relativeURI: ";x",
102 scheme: "http",
103 prePath: "http://a",
104 path: "/b/c/d;x",
105 ref: "",
106 nsIURL: true, nsINestedURI: false },
107 */
108 { spec: "http://a/b/c/d;p?q",
109 relativeURI: "g;x",
110 scheme: "http",
111 prePath: "http://a",
112 path: "/b/c/g;x",
113 ref: "",
114 nsIURL: true, nsINestedURI: false },
115 { spec: "http://a/b/c/d;p?q",
116 relativeURI: "g;x?y#s",
117 scheme: "http",
118 prePath: "http://a",
119 path: "/b/c/g;x?y#s",
120 ref: "s",
121 nsIURL: true, nsINestedURI: false },
122 /*
123 Can't easily specify a relative URI of "" to the test code
124 { spec: "http://a/b/c/d;p?q",
125 relativeURI: "",
126 scheme: "http",
127 prePath: "http://a",
128 path: "/b/c/d",
129 ref: "",
130 nsIURL: true, nsINestedURI: false },
131 */
132 { spec: "http://a/b/c/d;p?q",
133 relativeURI: ".",
134 scheme: "http",
135 prePath: "http://a",
136 path: "/b/c/",
137 ref: "",
138 nsIURL: true, nsINestedURI: false },
139 { spec: "http://a/b/c/d;p?q",
140 relativeURI: "./",
141 scheme: "http",
142 prePath: "http://a",
143 path: "/b/c/",
144 ref: "",
145 nsIURL: true, nsINestedURI: false },
146 { spec: "http://a/b/c/d;p?q",
147 relativeURI: "..",
148 scheme: "http",
149 prePath: "http://a",
150 path: "/b/",
151 ref: "",
152 nsIURL: true, nsINestedURI: false },
153 { spec: "http://a/b/c/d;p?q",
154 relativeURI: "../",
155 scheme: "http",
156 prePath: "http://a",
157 path: "/b/",
158 ref: "",
159 nsIURL: true, nsINestedURI: false },
160 { spec: "http://a/b/c/d;p?q",
161 relativeURI: "../g",
162 scheme: "http",
163 prePath: "http://a",
164 path: "/b/g",
165 ref: "",
166 nsIURL: true, nsINestedURI: false },
167 { spec: "http://a/b/c/d;p?q",
168 relativeURI: "../..",
169 scheme: "http",
170 prePath: "http://a",
171 path: "/",
172 ref: "",
173 nsIURL: true, nsINestedURI: false },
174 { spec: "http://a/b/c/d;p?q",
175 relativeURI: "../../",
176 scheme: "http",
177 prePath: "http://a",
178 path: "/",
179 ref: "",
180 nsIURL: true, nsINestedURI: false },
181 { spec: "http://a/b/c/d;p?q",
182 relativeURI: "../../g",
183 scheme: "http",
184 prePath: "http://a",
185 path: "/g",
186 ref: "",
187 nsIURL: true, nsINestedURI: false },
189 // abnormal examples
190 { spec: "http://a/b/c/d;p?q",
191 relativeURI: "../../../g",
192 scheme: "http",
193 prePath: "http://a",
194 path: "/g",
195 ref: "",
196 nsIURL: true, nsINestedURI: false },
197 { spec: "http://a/b/c/d;p?q",
198 relativeURI: "../../../../g",
199 scheme: "http",
200 prePath: "http://a",
201 path: "/g",
202 ref: "",
203 nsIURL: true, nsINestedURI: false },
205 // coalesce
206 { spec: "http://a/b/c/d;p?q",
207 relativeURI: "/./g",
208 scheme: "http",
209 prePath: "http://a",
210 path: "/g",
211 ref: "",
212 nsIURL: true, nsINestedURI: false },
213 { spec: "http://a/b/c/d;p?q",
214 relativeURI: "/../g",
215 scheme: "http",
216 prePath: "http://a",
217 path: "/g",
218 ref: "",
219 nsIURL: true, nsINestedURI: false },
220 { spec: "http://a/b/c/d;p?q",
221 relativeURI: "g.",
222 scheme: "http",
223 prePath: "http://a",
224 path: "/b/c/g.",
225 ref: "",
226 nsIURL: true, nsINestedURI: false },
227 { spec: "http://a/b/c/d;p?q",
228 relativeURI: ".g",
229 scheme: "http",
230 prePath: "http://a",
231 path: "/b/c/.g",
232 ref: "",
233 nsIURL: true, nsINestedURI: false },
234 { spec: "http://a/b/c/d;p?q",
235 relativeURI: "g..",
236 scheme: "http",
237 prePath: "http://a",
238 path: "/b/c/g..",
239 ref: "",
240 nsIURL: true, nsINestedURI: false },
241 { spec: "http://a/b/c/d;p?q",
242 relativeURI: "..g",
243 scheme: "http",
244 prePath: "http://a",
245 path: "/b/c/..g",
246 ref: "",
247 nsIURL: true, nsINestedURI: false },
248 { spec: "http://a/b/c/d;p?q",
249 relativeURI: ".",
250 scheme: "http",
251 prePath: "http://a",
252 path: "/b/c/",
253 ref: "",
254 nsIURL: true, nsINestedURI: false },
255 { spec: "http://a/b/c/d;p?q",
256 relativeURI: "./../g",
257 scheme: "http",
258 prePath: "http://a",
259 path: "/b/g",
260 ref: "",
261 nsIURL: true, nsINestedURI: false },
262 { spec: "http://a/b/c/d;p?q",
263 relativeURI: "./g/.",
264 scheme: "http",
265 prePath: "http://a",
266 path: "/b/c/g/",
267 ref: "",
268 nsIURL: true, nsINestedURI: false },
269 { spec: "http://a/b/c/d;p?q",
270 relativeURI: "g/./h",
271 scheme: "http",
272 prePath: "http://a",
273 path: "/b/c/g/h",
274 ref: "",
275 nsIURL: true, nsINestedURI: false },
276 { spec: "http://a/b/c/d;p?q",
277 relativeURI: "g/../h",
278 scheme: "http",
279 prePath: "http://a",
280 path: "/b/c/h",
281 ref: "",// fix
282 nsIURL: true, nsINestedURI: false },
283 { spec: "http://a/b/c/d;p?q",
284 relativeURI: "g;x=1/./y",
285 scheme: "http",
286 prePath: "http://a",
287 path: "/b/c/g;x=1/y",
288 ref: "",
289 nsIURL: true, nsINestedURI: false },
290 { spec: "http://a/b/c/d;p?q",
291 relativeURI: "g;x=1/../y",
292 scheme: "http",
293 prePath: "http://a",
294 path: "/b/c/y",
295 ref: "",
296 nsIURL: true, nsINestedURI: false },
297 // protocol-relative http://tools.ietf.org/html/rfc3986#section-4.2
298 { spec: "http://www2.example.com/",
299 relativeURI: "//www3.example2.com/bar",
300 scheme: "http",
301 prePath: "http://www3.example2.com",
302 path: "/bar",
303 ref: "",
304 nsIURL: true, nsINestedURI: false },
305 { spec: "https://www2.example.com/",
306 relativeURI: "//www3.example2.com/bar",
307 scheme: "https",
308 prePath: "https://www3.example2.com",
309 path: "/bar",
310 ref: "",
311 nsIURL: true, nsINestedURI: false },
312 ];
314 var gHashSuffixes = [
315 "#",
316 "#myRef",
317 "#myRef?a=b",
318 "#myRef#",
319 "#myRef#x:yz"
320 ];
322 // TEST HELPER FUNCTIONS
323 // ---------------------
324 function do_info(text, stack) {
325 if (!stack)
326 stack = Components.stack.caller;
328 dump( "\n" +
329 "TEST-INFO | " + stack.filename + " | [" + stack.name + " : " +
330 stack.lineNumber + "] " + text + "\n");
331 }
333 // Checks that the URIs satisfy equals(), in both possible orderings.
334 // Also checks URI.equalsExceptRef(), because equal URIs should also be equal
335 // when we ignore the ref.
336 //
337 // The third argument is optional. If the client passes a third argument
338 // (e.g. todo_check_true), we'll use that in lieu of do_check_true.
339 function do_check_uri_eq(aURI1, aURI2, aCheckTrueFunc) {
340 if (!aCheckTrueFunc) {
341 aCheckTrueFunc = do_check_true;
342 }
344 do_info("(uri equals check: '" + aURI1.spec + "' == '" + aURI2.spec + "')");
345 aCheckTrueFunc(aURI1.equals(aURI2));
346 do_info("(uri equals check: '" + aURI2.spec + "' == '" + aURI1.spec + "')");
347 aCheckTrueFunc(aURI2.equals(aURI1));
349 // (Only take the extra step of testing 'equalsExceptRef' when we expect the
350 // URIs to really be equal. In 'todo' cases, the URIs may or may not be
351 // equal when refs are ignored - there's no way of knowing in general.)
352 if (aCheckTrueFunc == do_check_true) {
353 do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc);
354 }
355 }
357 // Checks that the URIs satisfy equalsExceptRef(), in both possible orderings.
358 //
359 // The third argument is optional. If the client passes a third argument
360 // (e.g. todo_check_true), we'll use that in lieu of do_check_true.
361 function do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc) {
362 if (!aCheckTrueFunc) {
363 aCheckTrueFunc = do_check_true;
364 }
366 do_info("(uri equalsExceptRef check: '" +
367 aURI1.spec + "' == '" + aURI2.spec + "')");
368 aCheckTrueFunc(aURI1.equalsExceptRef(aURI2));
369 do_info("(uri equalsExceptRef check: '" +
370 aURI2.spec + "' == '" + aURI1.spec + "')");
371 aCheckTrueFunc(aURI2.equalsExceptRef(aURI1));
372 }
374 // Checks that the given property on aURI matches the corresponding property
375 // in the test bundle (or matches some function of that corresponding property,
376 // if aTestFunctor is passed in).
377 function do_check_property(aTest, aURI, aPropertyName, aTestFunctor) {
378 if (aTest[aPropertyName]) {
379 var expectedVal = aTestFunctor ?
380 aTestFunctor(aTest[aPropertyName]) :
381 aTest[aPropertyName];
383 do_info("testing " + aPropertyName + " of " +
384 (aTestFunctor ? "modified '" : "'" ) + aTest.spec +
385 "' is '" + expectedVal + "'");
386 do_check_eq(aURI[aPropertyName], expectedVal);
387 }
388 }
390 // Test that a given URI parses correctly into its various components.
391 function do_test_uri_basic(aTest) {
392 var URI;
394 do_info("Basic tests for " + aTest.spec + " relative URI: " + aTest.relativeURI);
396 try {
397 URI = NetUtil.newURI(aTest.spec);
398 } catch(e) {
399 do_info("Caught error on parse of" + aTest.spec + " Error: " + e.result);
400 if (aTest.fail) {
401 do_check_eq(e.result, aTest.result);
402 return;
403 }
404 do_throw(e.result);
405 }
407 if (aTest.relativeURI) {
408 var relURI;
410 try {
411 relURI = gIoService.newURI(aTest.relativeURI, null, URI);
412 } catch (e) {
413 do_info("Caught error on Relative parse of " + aTest.spec + " + " + aTest.relativeURI +" Error: " + e.result);
414 if (aTest.relativeFail) {
415 do_check_eq(e.result, aTest.relativeFail);
416 return;
417 }
418 do_throw(e.result);
419 }
420 do_info("relURI.path = " + relURI.path + ", was " + URI.path);
421 URI = relURI;
422 do_info("URI.path now = " + URI.path);
423 }
425 // Sanity-check
426 do_info("testing " + aTest.spec + " equals a clone of itself");
427 do_check_uri_eq(URI, URI.clone());
428 do_check_uri_eqExceptRef(URI, URI.cloneIgnoringRef());
429 do_info("testing " + aTest.spec + " instanceof nsIURL");
430 do_check_eq(URI instanceof Ci.nsIURL, aTest.nsIURL);
431 do_info("testing " + aTest.spec + " instanceof nsINestedURI");
432 do_check_eq(URI instanceof Ci.nsINestedURI,
433 aTest.nsINestedURI);
435 do_info("testing that " + aTest.spec + " throws or returns false " +
436 "from equals(null)");
437 // XXXdholbert At some point it'd probably be worth making this behavior
438 // (throwing vs. returning false) consistent across URI implementations.
439 var threw = false;
440 var isEqualToNull;
441 try {
442 isEqualToNull = URI.equals(null);
443 } catch(e) {
444 threw = true;
445 }
446 do_check_true(threw || !isEqualToNull);
449 // Check the various components
450 do_check_property(aTest, URI, "scheme");
451 do_check_property(aTest, URI, "prePath");
452 do_check_property(aTest, URI, "path");
453 do_check_property(aTest, URI, "ref");
454 do_check_property(aTest, URI, "port");
455 do_check_property(aTest, URI, "username");
456 do_check_property(aTest, URI, "password");
457 do_check_property(aTest, URI, "host");
458 do_check_property(aTest, URI, "specIgnoringRef");
459 if ("hasRef" in aTest) {
460 do_info("testing hasref: " + aTest.hasRef + " vs " + URI.hasRef);
461 do_check_eq(aTest.hasRef, URI.hasRef);
462 }
463 }
465 // Test that a given URI parses correctly when we add a given ref to the end
466 function do_test_uri_with_hash_suffix(aTest, aSuffix) {
467 do_info("making sure caller is using suffix that starts with '#'");
468 do_check_eq(aSuffix[0], "#");
470 var origURI = NetUtil.newURI(aTest.spec);
471 var testURI;
473 if (aTest.relativeURI) {
474 try {
475 origURI = gIoService.newURI(aTest.relativeURI, null, origURI);
476 } catch (e) {
477 do_info("Caught error on Relative parse of " + aTest.spec + " + " + aTest.relativeURI +" Error: " + e.result);
478 return;
479 }
480 try {
481 testURI = gIoService.newURI(aSuffix, null, origURI);
482 } catch (e) {
483 do_info("Caught error adding suffix to " + aTest.spec + " + " + aTest.relativeURI + ", suffix " + aSuffix + " Error: " + e.result);
484 return;
485 }
486 } else {
487 testURI = NetUtil.newURI(aTest.spec + aSuffix);
488 }
490 do_info("testing " + aTest.spec + " with '" + aSuffix + "' appended " +
491 "equals a clone of itself");
492 do_check_uri_eq(testURI, testURI.clone());
494 do_info("testing " + aTest.spec +
495 " doesn't equal self with '" + aSuffix + "' appended");
497 do_check_false(origURI.equals(testURI));
499 do_info("testing " + aTest.spec +
500 " is equalExceptRef to self with '" + aSuffix + "' appended");
501 do_check_uri_eqExceptRef(origURI, testURI);
503 do_check_eq(testURI.hasRef, true);
505 if (!origURI.ref) {
506 // These tests fail if origURI has a ref
507 do_info("testing cloneIgnoringRef on " + testURI.spec +
508 " is equal to no-ref version but not equal to ref version");
509 var cloneNoRef = testURI.cloneIgnoringRef();
510 do_check_uri_eq(cloneNoRef, origURI);
511 do_check_false(cloneNoRef.equals(testURI));
512 }
514 do_check_property(aTest, testURI, "scheme");
515 do_check_property(aTest, testURI, "prePath");
516 if (!origURI.ref) {
517 // These don't work if it's a ref already because '+' doesn't give the right result
518 do_check_property(aTest, testURI, "path",
519 function(aStr) { return aStr + aSuffix; });
520 do_check_property(aTest, testURI, "ref",
521 function(aStr) { return aSuffix.substr(1); });
522 }
523 }
525 // Tests various ways of setting & clearing a ref on a URI.
526 function do_test_mutate_ref(aTest, aSuffix) {
527 do_info("making sure caller is using suffix that starts with '#'");
528 do_check_eq(aSuffix[0], "#");
530 var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix);
531 var refURIWithoutSuffix = NetUtil.newURI(aTest.spec);
533 var testURI = NetUtil.newURI(aTest.spec);
535 // First: Try setting .ref to our suffix
536 do_info("testing that setting .ref on " + aTest.spec +
537 " to '" + aSuffix + "' does what we expect");
538 testURI.ref = aSuffix;
539 do_check_uri_eq(testURI, refURIWithSuffix);
540 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
542 // Now try setting .ref but leave off the initial hash (expect same result)
543 var suffixLackingHash = aSuffix.substr(1);
544 if (suffixLackingHash) { // (skip this our suffix was *just* a #)
545 do_info("testing that setting .ref on " + aTest.spec +
546 " to '" + suffixLackingHash + "' does what we expect");
547 testURI.ref = suffixLackingHash;
548 do_check_uri_eq(testURI, refURIWithSuffix);
549 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
550 }
552 // Now, clear .ref (should get us back the original spec)
553 do_info("testing that clearing .ref on " + testURI.spec +
554 " does what we expect");
555 testURI.ref = "";
556 do_check_uri_eq(testURI, refURIWithoutSuffix);
557 do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
559 if (!aTest.relativeURI) {
560 // TODO: These tests don't work as-is for relative URIs.
562 // Now try setting .spec directly (including suffix) and then clearing .ref
563 var specWithSuffix = aTest.spec + aSuffix;
564 do_info("testing that setting spec to " +
565 specWithSuffix + " and then clearing ref does what we expect");
566 testURI.spec = specWithSuffix;
567 testURI.ref = "";
568 do_check_uri_eq(testURI, refURIWithoutSuffix);
569 do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
571 // XXX nsIJARURI throws an exception in SetPath(), so skip it for next part.
572 if (!(testURI instanceof Ci.nsIJARURI)) {
573 // Now try setting .path directly (including suffix) and then clearing .ref
574 // (same as above, but with now with .path instead of .spec)
575 testURI = NetUtil.newURI(aTest.spec);
577 var pathWithSuffix = aTest.path + aSuffix;
578 do_info("testing that setting path to " +
579 pathWithSuffix + " and then clearing ref does what we expect");
580 testURI.path = pathWithSuffix;
581 testURI.ref = "";
582 do_check_uri_eq(testURI, refURIWithoutSuffix);
583 do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
585 // Also: make sure that clearing .path also clears .ref
586 testURI.path = pathWithSuffix;
587 do_info("testing that clearing path from " +
588 pathWithSuffix + " also clears .ref");
589 testURI.path = "";
590 do_check_eq(testURI.ref, "");
591 }
592 }
593 }
595 // Tests that normally-mutable properties can't be modified on
596 // special URIs that are known to be immutable.
597 function do_test_immutable(aTest) {
598 do_check_true(aTest.immutable);
600 var URI = NetUtil.newURI(aTest.spec);
601 // All the non-readonly attributes on nsIURI.idl:
602 var propertiesToCheck = ["spec", "scheme", "userPass", "username", "password",
603 "hostPort", "host", "port", "path", "ref"];
605 propertiesToCheck.forEach(function(aProperty) {
606 var threw = false;
607 try {
608 URI[aProperty] = "anothervalue";
609 } catch(e) {
610 threw = true;
611 }
613 do_info("testing that setting '" + aProperty +
614 "' on immutable URI '" + aTest.spec + "' will throw");
615 do_check_true(threw);
616 });
617 }
620 // TEST MAIN FUNCTION
621 // ------------------
622 function run_test()
623 {
624 // UTF-8 check - From bug 622981
625 // ASCII
626 let base = gIoService.newURI("http://example.org/xenia?", null, null);
627 let resolved = gIoService.newURI("?x", null, base);
628 let expected = gIoService.newURI("http://example.org/xenia?x",
629 null, null);
630 do_info("Bug 662981: ACSII - comparing " + resolved.spec + " and " + expected.spec);
631 do_check_true(resolved.equals(expected));
633 // UTF-8 character "è"
634 // Bug 622981 was triggered by an empty query string
635 base = gIoService.newURI("http://example.org/xènia?", null, null);
636 resolved = gIoService.newURI("?x", null, base);
637 expected = gIoService.newURI("http://example.org/xènia?x",
638 null, null);
639 do_info("Bug 662981: UTF8 - comparing " + resolved.spec + " and " + expected.spec);
640 do_check_true(resolved.equals(expected));
642 gTests.forEach(function(aTest) {
643 // Check basic URI functionality
644 do_test_uri_basic(aTest);
646 if (!aTest.fail) {
647 // Try adding various #-prefixed strings to the ends of the URIs
648 gHashSuffixes.forEach(function(aSuffix) {
649 do_test_uri_with_hash_suffix(aTest, aSuffix);
650 if (!aTest.immutable) {
651 do_test_mutate_ref(aTest, aSuffix);
652 }
653 });
655 // For URIs that we couldn't mutate above due to them being immutable:
656 // Now we check that they're actually immutable.
657 if (aTest.immutable) {
658 do_test_immutable(aTest);
659 }
660 }
661 });
662 }