var num_checks = 0;
var num_fail = 0;
var num_pass = 0;
var output; // A place to write results
var xhr;
var ua; // User-Agent
var err = false;
var state = -1; // 0 = completed running, 1 = running, -1 = not started
var data; // The JSON data
//++++++++++++++++++++
// Initialization
//++++++++++++++++++++
function init() {
state = 1;
output = document.getElementById("output");
ua = getUserAgent();
if(XMLHttpRequest === undefined) {
alert("Your browser does not support XMLHttpRequest which is required for testing.");
return;
}
var xhr = new XMLHttpRequest();
xhr.open("GET", "tests.json", false);
xhr.send(null);
// Get the test cases from tests.json
data = JSON.parse(xhr.responseText);
}
//++++++++++++++++++++
// Utilities
//++++++++++++++++++++
// Any function that needs to wait until the entire page
// is loaded should use this.
function afterOnload(func) {
if(window.attachEvent) {
window.attachEvent('onload', func);
} else {
if(window.onload) {
var curronload = window.onload;
var newonload = function() {
curronload();
func();
};
window.onload = newonload;
} else {
window.onload = func;
}
}
}
function getUserAgent() {
var agent;
// Chrome includes both Chrome and Safari in it's UA string
// so check it first.
if (/Chrome[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
agent = "Chrome";
}
else if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
agent = "Firefox";
}
else if (/MSIE[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
agent = "MSIE";
}
else if (/Opera[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
agent = "Opera";
}
else if (/Safari[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
agent = "Safari";
}
return agent;
}
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 4 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
//++++++++++++++++++++++
// Logging and reporting
//++++++++++++++++++++++
function log(message) {
var e = document.createElement("li");
e.setAttribute("class","result");
e.innerHTML = message;
output.appendChild(e);
}
// Some exceptions are not caught
window.onerror = function (message, url, line) {
err = true;
alert(message + url + line);
return true;
}
function pass(message, e) {
log("[+] PASS: " + message + "");
}
function fail(message, e) {
log("[-] FAIL: " + message + "");
}
function INFO(comment) {
log("[*] INFO: " + comment + "");
}
function DEBUG(error, comment, expect) {
if (comment === "" || comment === undefined) {
log("[!] DEBG: " + error + "");
}
else {
log("[!] DEBG: Test case \"" + comment + "\" returned error " + error + "");
}
}
//++++++++++++++++++++
// Test harness
//++++++++++++++++++++
// Register a custom handler
function register(scheme, uri, title, id, expect, comment) {
if (navigator.registerProtocolHandler === undefined) {
DEBUG("Your Web browser does not support navigator.registerProtocolHandler.")
return false;
}
err = false; // Reset the error state
var errmsg; // Capture the error message
try {
navigator.registerProtocolHandler(scheme,
uri,
title);
}
catch (e) {
err = true;
if (ua === "Firefox") {
errmsg = e;
}
else {
errmsg = e.message;
}
//DEBUG(e, comment, expect);
}
finally {
if (expect == 0 && err == true) {
DEBUG(errmsg, comment, expect);
}
if (expect == -1 && err == true) {
pass(comment + " was prohibited with error " + errmsg + "");
}
if (expect == 0 && err == false) {
pass(comment + " was allowed");
}
if (expect == -1 && err == false && ua == "Chrome") {
fail(comment + " seems to have worked without error, but Chrome may not throw one");
}
else if (expect == -1 && err == false) {
fail(comment + " was allowed");
}
}
}
// Unregister a custom handler
function unregister(scheme, uri, title, id, expect) {
if (navigator.unregisterProtocolHandler !== undefined) {
try {
navigator.unregisterProtocolHandler(scheme,
uri,
title);
pass("function navigator.unregisterProtocolHandler successfully unregistered a custom handler.");
}
catch (er)
{
fail("function navigator.unregisterProtocolHandler returned an error when trying to unregister a custom handler for scheme '" + scheme + "'.");
}
}
else {
fail("function navigator.unregisterProtocolHandler was undefined.")
}
}
//+++++++++++++++++++
// TEST CASES
//+++++++++++++++++++
function testAllowedChars(begin, end) {
// Bail if the method doesn't exist
if (navigator.registerProtocolHandler === undefined) {
DEBUG("Your Web browser does not support navigator.registerProtocolHandler.")
return false;
}
var errmsg;
var tcpass = [];
var tcfail = [];
var comment = "Testing which characters in the range 0 - 1024 are allowed in the web+ scheme name";
for (var i = begin; i < end; i ++) {
err = false; // Reset the error state
var tc = String.fromCharCode(i); // The test case character
var hex = decimalToHex(i);
try{
navigator.registerProtocolHandler("web+" + tc,
document.baseURI + "?char=%s",
"web+ allowed characters test");
tcpass += "U+" + hex + ", ";
}
catch(e) {
err = true;
tcfail += "U+" + hex + ", ";
if (ua === "Firefox") {
errmsg = e;
}
else {
errmsg = e.message;
}
}
}
INFO("Testing allowed the following Unicode code points (range 1 - 1024) in the web+ prefix scheme: " + tcpass);
// Uncomment the next line to display characters that were not allowed
// INFO("Testing disallowed the following Unicode code points (range 1 - 1024) in the web+ prefix scheme: " + tcfail);
}
// Apparently Firefox writes these registrations to an RDF file and
// best-fit maps some Unicode chars.
function registerUnicodeBestFit() {
navigator.registerProtocolHandler("web+unicode\uFF02test",
"http://" + document.domain + "/?unicode=%s",
"web+unicode\uFF02test");
}
// Can these be unregistered?
function unregister() {
if (navigator.unregisterProtocolHandler === undefined) {
fail("The function navigator.unregisterProtocolHandler does not exist to unregister handlers.");
}
else {
pass("The function navigator.unregisterProtocolHandler exists, presumably to unregister handlers.");
}
}
function runAllTestsFromJson() {
var id;
var uri;
var title;
var scheme;
var expect;
var comment;
var test;
for (var i = 0, len = data.length; i < len; i++) {
test = data[i];
id = test["id"];
uri = test["uri"];
title = test["title"];
scheme = test["scheme"];
expect = test["expect"];
comment = test["comment"];
register(scheme, uri, title, id, expect, comment);
}
}
function runSingleTestFromJson(n) {
var tc = data[n];
id = tc["id"];
if (id != n) {
alert("Error, id does not match.");
return;
}
var uri = tc["uri"];
var title = tc["title"];
var scheme = tc["scheme"];
var expect = tc["expect"];
var comment = tc["comment"];
register(scheme, uri, title, id, expect, comment);
}
function runAdHocTest(title, scheme, uri, expect) {
if (expect != 0 && expect != 1) {
expect = -1;
}
register(scheme, uri, title, null, expect, "ad hoc test of " + scheme + " scheme");
}
function main() {
// Run all tests stored in tests.json
runAllTestsFromJson(data);
// Test unregister
unregister();
// Run test of allowed characters
testAllowedChars(0, 1024);
// Is it done yet?
state = 0;
}
// Start your engines
afterOnload(init);