Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
"use strict";
// Run by: cd objdir; make -C netwerk/test/ xpcshell-tests
// or: cd objdir; make SOLO_FILE="test_URIs2.js" -C netwerk/test/ check-one
// This is a clone of test_URIs.js, with a different set of test data in gTests.
// The original test data in test_URIs.js was split between test_URIs and test_URIs2.js
// because test_URIs.js was running for too long on slow platforms, causing
// intermittent timeouts.
// Relevant RFCs: 1738, 1808, 2396, 3986 (newer than the code)
// TEST DATA
// ---------
var gTests = [
{
spec: "view-source:about:blank",
scheme: "view-source",
prePath: "view-source:",
pathQueryRef: "about:blank",
ref: "",
nsIURL: false,
nsINestedURI: true,
immutable: true,
},
{
spec: "view-source:http://www.mozilla.org/",
scheme: "view-source",
prePath: "view-source:",
pathQueryRef: "http://www.mozilla.org/",
ref: "",
nsIURL: false,
nsINestedURI: true,
immutable: true,
},
{
spec: "x-external:",
scheme: "x-external",
prePath: "x-external:",
pathQueryRef: "",
ref: "",
nsIURL: false,
nsINestedURI: false,
},
{
spec: "x-external:abc",
scheme: "x-external",
prePath: "x-external:",
pathQueryRef: "abc",
ref: "",
nsIURL: false,
nsINestedURI: false,
},
{
relativeURI: "a/b/c/d",
scheme: "http",
pathQueryRef: "/a/b/c/d",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g:h",
scheme: "g",
prePath: "g:",
pathQueryRef: "h",
ref: "",
nsIURL: false,
nsINestedURI: false,
},
{
relativeURI: "g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "./g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g/",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "/g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "?y",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/d;p?y",
ref: "", // fix
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g?y",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g?y",
ref: "", // fix
specIgnoringRef: "http://a/b/c/g?y",
hasRef: false,
hasQuery: true,
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "#s",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/d;p?q#s",
ref: "s", // fix
specIgnoringRef: "http://a/b/c/d;p?q",
hasRef: true,
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g#s",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g#s",
ref: "s",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g?y#s",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g?y#s",
ref: "s",
nsIURL: true,
nsINestedURI: false,
},
/*
Bug xxxxxx - we return a path of b/c/;x
{ spec: "http://a/b/c/d;p?q",
relativeURI: ";x",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/d;x",
ref: "",
nsIURL: true, nsINestedURI: false },
*/
{
relativeURI: "g;x",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g;x",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g;x?y#s",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g;x?y#s",
ref: "s",
nsIURL: true,
nsINestedURI: false,
},
/*
Can't easily specify a relative URI of "" to the test code
{ spec: "http://a/b/c/d;p?q",
relativeURI: "",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/d",
ref: "",
nsIURL: true, nsINestedURI: false },
*/
{
relativeURI: ".",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "./",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "..",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../..",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../../",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
// abnormal examples
{
relativeURI: "../../../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "../../../../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
// coalesce
{
relativeURI: "/./g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "/../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g.",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g.",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: ".g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/.g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g..",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g..",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "..g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/..g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: ".",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "./../g",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/g",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "./g/.",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g/",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g/./h",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g/h",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g/../h",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/h",
ref: "", // fix
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g;x=1/./y",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/g;x=1/y",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "g;x=1/../y",
scheme: "http",
prePath: "http://a",
pathQueryRef: "/b/c/y",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "//www3.example2.com/bar",
scheme: "http",
pathQueryRef: "/bar",
ref: "",
nsIURL: true,
nsINestedURI: false,
},
{
relativeURI: "//www3.example2.com/bar",
scheme: "https",
pathQueryRef: "/bar",
hasQuery: false,
ref: "",
nsIURL: true,
nsINestedURI: false,
},
];
var gHashSuffixes = ["#", "#myRef", "#myRef?a=b", "#myRef#", "#myRef#x:yz"];
// TEST HELPER FUNCTIONS
// ---------------------
function do_info(text, stack) {
if (!stack) {
stack = Components.stack.caller;
}
dump(
"\n" +
"TEST-INFO | " +
stack.filename +
" | [" +
stack.name +
" : " +
stack.lineNumber +
"] " +
text +
"\n"
);
}
// Checks that the URIs satisfy equals(), in both possible orderings.
// Also checks URI.equalsExceptRef(), because equal URIs should also be equal
// when we ignore the ref.
//
// The third argument is optional. If the client passes a third argument
// (e.g. todo_check_true), we'll use that in lieu of ok.
function do_check_uri_eq(aURI1, aURI2, aCheckTrueFunc = ok) {
do_info("(uri equals check: '" + aURI1.spec + "' == '" + aURI2.spec + "')");
aCheckTrueFunc(aURI1.equals(aURI2));
do_info("(uri equals check: '" + aURI2.spec + "' == '" + aURI1.spec + "')");
aCheckTrueFunc(aURI2.equals(aURI1));
// (Only take the extra step of testing 'equalsExceptRef' when we expect the
// URIs to really be equal. In 'todo' cases, the URIs may or may not be
// equal when refs are ignored - there's no way of knowing in general.)
if (aCheckTrueFunc == ok) {
do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc);
}
}
// Checks that the URIs satisfy equalsExceptRef(), in both possible orderings.
//
// The third argument is optional. If the client passes a third argument
// (e.g. todo_check_true), we'll use that in lieu of ok.
function do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc = ok) {
do_info(
"(uri equalsExceptRef check: '" + aURI1.spec + "' == '" + aURI2.spec + "')"
);
aCheckTrueFunc(aURI1.equalsExceptRef(aURI2));
do_info(
"(uri equalsExceptRef check: '" + aURI2.spec + "' == '" + aURI1.spec + "')"
);
aCheckTrueFunc(aURI2.equalsExceptRef(aURI1));
}
// Checks that the given property on aURI matches the corresponding property
// in the test bundle (or matches some function of that corresponding property,
// if aTestFunctor is passed in).
function do_check_property(aTest, aURI, aPropertyName, aTestFunctor) {
if (aTest[aPropertyName]) {
var expectedVal = aTestFunctor
? aTestFunctor(aTest[aPropertyName])
: aTest[aPropertyName];
do_info(
"testing " +
aPropertyName +
" of " +
(aTestFunctor ? "modified '" : "'") +
aTest.spec +
"' is '" +
expectedVal +
"'"
);
Assert.equal(aURI[aPropertyName], expectedVal);
}
}
// Test that a given URI parses correctly into its various components.
function do_test_uri_basic(aTest) {
var URI;
do_info(
"Basic tests for " + aTest.spec + " relative URI: " + aTest.relativeURI
);
try {
URI = NetUtil.newURI(aTest.spec);
} catch (e) {
do_info("Caught error on parse of" + aTest.spec + " Error: " + e.result);
if (aTest.fail) {
Assert.equal(e.result, aTest.result);
return;
}
do_throw(e.result);
}
if (aTest.relativeURI) {
var relURI;
try {
relURI = Services.io.newURI(aTest.relativeURI, null, URI);
} catch (e) {
do_info(
"Caught error on Relative parse of " +
aTest.spec +
" + " +
aTest.relativeURI +
" Error: " +
e.result
);
if (aTest.relativeFail) {
Assert.equal(e.result, aTest.relativeFail);
return;
}
do_throw(e.result);
}
do_info(
"relURI.pathQueryRef = " +
relURI.pathQueryRef +
", was " +
URI.pathQueryRef
);
URI = relURI;
do_info("URI.pathQueryRef now = " + URI.pathQueryRef);
}
// Sanity-check
do_info("testing " + aTest.spec + " equals a clone of itself");
do_check_uri_eq(URI, URI.mutate().finalize());
do_check_uri_eqExceptRef(URI, URI.mutate().setRef("").finalize());
do_info("testing " + aTest.spec + " instanceof nsIURL");
Assert.equal(URI instanceof Ci.nsIURL, aTest.nsIURL);
do_info("testing " + aTest.spec + " instanceof nsINestedURI");
Assert.equal(URI instanceof Ci.nsINestedURI, aTest.nsINestedURI);
do_info(
"testing that " +
aTest.spec +
" throws or returns false " +
"from equals(null)"
);
// XXXdholbert At some point it'd probably be worth making this behavior
// (throwing vs. returning false) consistent across URI implementations.
var threw = false;
var isEqualToNull;
try {
isEqualToNull = URI.equals(null);
} catch (e) {
threw = true;
}
Assert.ok(threw || !isEqualToNull);
// Check the various components
do_check_property(aTest, URI, "scheme");
do_check_property(aTest, URI, "prePath");
do_check_property(aTest, URI, "pathQueryRef");
do_check_property(aTest, URI, "query");
do_check_property(aTest, URI, "ref");
do_check_property(aTest, URI, "port");
do_check_property(aTest, URI, "username");
do_check_property(aTest, URI, "password");
do_check_property(aTest, URI, "host");
do_check_property(aTest, URI, "specIgnoringRef");
if ("hasRef" in aTest) {
do_info("testing hasref: " + aTest.hasRef + " vs " + URI.hasRef);
Assert.equal(aTest.hasRef, URI.hasRef);
}
if ("hasQuery" in aTest) {
do_info("testing hasQuery: " + aTest.hasQuery + " vs " + URI.hasQuery);
Assert.equal(aTest.hasQuery, URI.hasQuery);
}
}
// Test that a given URI parses correctly when we add a given ref to the end
function do_test_uri_with_hash_suffix(aTest, aSuffix) {
do_info("making sure caller is using suffix that starts with '#'");
Assert.equal(aSuffix[0], "#");
var origURI = NetUtil.newURI(aTest.spec);
var testURI;
if (aTest.relativeURI) {
try {
origURI = Services.io.newURI(aTest.relativeURI, null, origURI);
} catch (e) {
do_info(
"Caught error on Relative parse of " +
aTest.spec +
" + " +
aTest.relativeURI +
" Error: " +
e.result
);
return;
}
try {
testURI = Services.io.newURI(aSuffix, null, origURI);
} catch (e) {
do_info(
"Caught error adding suffix to " +
aTest.spec +
" + " +
aTest.relativeURI +
", suffix " +
aSuffix +
" Error: " +
e.result
);
return;
}
} else {
testURI = NetUtil.newURI(aTest.spec + aSuffix);
}
do_info(
"testing " +
aTest.spec +
" with '" +
aSuffix +
"' appended " +
"equals a clone of itself"
);
do_check_uri_eq(testURI, testURI.mutate().finalize());
do_info(
"testing " +
aTest.spec +
" doesn't equal self with '" +
aSuffix +
"' appended"
);
Assert.ok(!origURI.equals(testURI));
do_info(
"testing " +
aTest.spec +
" is equalExceptRef to self with '" +
aSuffix +
"' appended"
);
do_check_uri_eqExceptRef(origURI, testURI);
Assert.equal(testURI.hasRef, true);
if (!origURI.ref) {
// These tests fail if origURI has a ref
do_info(
"testing cloneIgnoringRef on " +
testURI.spec +
" is equal to no-ref version but not equal to ref version"
);
var cloneNoRef = testURI.mutate().setRef("").finalize();
do_check_uri_eq(cloneNoRef, origURI);
Assert.ok(!cloneNoRef.equals(testURI));
}
do_check_property(aTest, testURI, "scheme");
do_check_property(aTest, testURI, "prePath");
if (!origURI.ref) {
// These don't work if it's a ref already because '+' doesn't give the right result
do_check_property(aTest, testURI, "pathQueryRef", function (aStr) {
return aStr + aSuffix;
});
do_check_property(aTest, testURI, "ref", function () {
return aSuffix.substr(1);
});
}
}
// Tests various ways of setting & clearing a ref on a URI.
function do_test_mutate_ref(aTest, aSuffix) {
do_info("making sure caller is using suffix that starts with '#'");
Assert.equal(aSuffix[0], "#");
var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix);
var refURIWithoutSuffix = NetUtil.newURI(aTest.spec);
var testURI = NetUtil.newURI(aTest.spec);
// First: Try setting .ref to our suffix
do_info(
"testing that setting .ref on " +
aTest.spec +
" to '" +
aSuffix +
"' does what we expect"
);
testURI = testURI.mutate().setRef(aSuffix).finalize();
do_check_uri_eq(testURI, refURIWithSuffix);
do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
// Now try setting .ref but leave off the initial hash (expect same result)
var suffixLackingHash = aSuffix.substr(1);
if (suffixLackingHash) {
// (skip this our suffix was *just* a #)
do_info(
"testing that setting .ref on " +
aTest.spec +
" to '" +
suffixLackingHash +
"' does what we expect"
);
testURI = testURI.mutate().setRef(suffixLackingHash).finalize();
do_check_uri_eq(testURI, refURIWithSuffix);
do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
}
// Now, clear .ref (should get us back the original spec)
do_info(
"testing that clearing .ref on " + testURI.spec + " does what we expect"
);
testURI = testURI.mutate().setRef("").finalize();
do_check_uri_eq(testURI, refURIWithoutSuffix);
do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
if (!aTest.relativeURI) {
// TODO: These tests don't work as-is for relative URIs.
// Now try setting .spec directly (including suffix) and then clearing .ref
var specWithSuffix = aTest.spec + aSuffix;
do_info(
"testing that setting spec to " +
specWithSuffix +
" and then clearing ref does what we expect"
);
testURI = testURI.mutate().setSpec(specWithSuffix).setRef("").finalize();
do_check_uri_eq(testURI, refURIWithoutSuffix);
do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
// XXX nsIJARURI throws an exception in SetPath(), so skip it for next part.
if (!(testURI instanceof Ci.nsIJARURI)) {
// Now try setting .pathQueryRef directly (including suffix) and then clearing .ref
// (same as above, but with now with .pathQueryRef instead of .spec)
testURI = NetUtil.newURI(aTest.spec);
var pathWithSuffix = aTest.pathQueryRef + aSuffix;
do_info(
"testing that setting path to " +
pathWithSuffix +
" and then clearing ref does what we expect"
);
testURI = testURI
.mutate()
.setPathQueryRef(pathWithSuffix)
.setRef("")
.finalize();
do_check_uri_eq(testURI, refURIWithoutSuffix);
do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
// Also: make sure that clearing .pathQueryRef also clears .ref
testURI = testURI.mutate().setPathQueryRef(pathWithSuffix).finalize();
do_info(
"testing that clearing path from " +
pathWithSuffix +
" also clears .ref"
);
testURI = testURI.mutate().setPathQueryRef("").finalize();
Assert.equal(testURI.ref, "");
}
}
}
// TEST MAIN FUNCTION
// ------------------
function run_test() {
// UTF-8 check - From bug 622981
// ASCII
let base = Services.io.newURI("http://example.org/xenia?");
let resolved = Services.io.newURI("?x", null, base);
let expected = Services.io.newURI("http://example.org/xenia?x");
do_info(
"Bug 662981: ACSII - comparing " + resolved.spec + " and " + expected.spec
);
Assert.ok(resolved.equals(expected));
// UTF-8 character "è"
// Bug 622981 was triggered by an empty query string
base = Services.io.newURI("http://example.org/xènia?");
resolved = Services.io.newURI("?x", null, base);
expected = Services.io.newURI("http://example.org/xènia?x");
do_info(
"Bug 662981: UTF8 - comparing " + resolved.spec + " and " + expected.spec
);
Assert.ok(resolved.equals(expected));
gTests.forEach(function (aTest) {
// Check basic URI functionality
do_test_uri_basic(aTest);
if (!aTest.fail) {
// Try adding various #-prefixed strings to the ends of the URIs
gHashSuffixes.forEach(function (aSuffix) {
do_test_uri_with_hash_suffix(aTest, aSuffix);
if (!aTest.immutable) {
do_test_mutate_ref(aTest, aSuffix);
}
});
// For URIs that we couldn't mutate above due to them being immutable:
// Now we check that they're actually immutable.
if (aTest.immutable) {
Assert.ok(aTest.immutable);
}
}
});
}