<html><head>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<link rel="stylesheet" href="test_page.css">
<script>
// Do a deep comparison of two values. Return true if their values are
// identical, false otherwise.
function deepCompare(left, right) {
if (typeof(left) !== typeof(right))
return false;
// If their identity is the same or they're basic types with the same value,
// they are equal.
if (left === right)
return true;
// If it's a basic type and we got here, we know they're not equal.
if (["undefined", "boolean", "number", "string", "function"].indexOf(
typeof(left)) > -1) {
return false;
}
// Use right_keys as a set containing all keys from |right| which we haven't
// yet compared.
var right_keys = {};
for (var key in right)
right_keys[key] = true;
for (var key in left) {
if (key in right_keys) {
if (!deepCompare(left[key], right[key]))
return false;
} else {
// |left| had a key that |right| didn't.
return false;
}
delete right_keys[key];
}
// If there are keys left in |right_keys|, it means they didn't exist in
// |left|, so the objects aren't equal.
if (Object.keys(right_keys).length > 0)
return false;
return true;
}
function AdjustHeight(frameWin) {
var div = frameWin.document.getElementsByTagName("div")[0];
var height = frameWin.getComputedStyle(div).height;
frameWin.frameElement.style.height = height;
}
// Called when the tests are completed. |result| should be "PASS" if the test(s)
// passed, or information about the failure if the test(s) did not pass.
function DidExecuteTests(result) {
var plugin = document.getElementById("plugin");
if (plugin.parentNode.removePlugin) {
plugin.parentNode.removeChild(plugin);
plugin = undefined;
}
if (CheckPostConditions())
sendAutomationMessage(result);
if (window == top)
return;
// Otherwise, we are in a subframe, so we can use this opportunity to resize
// ourselves. This can only be done if the parent frame has the same origin.
if (window.frameElement)
AdjustHeight(window);
}
function AppendFrame(testcase, i) {
var p = document.createElement("P");
p.setAttribute("class", "frame-container");
var title = document.createElement("H2");
title.appendChild(document.createTextNode(testcase));
p.appendChild(title);
var frame = document.createElement("IFRAME");
var mode = ExtractSearchParameter("mode");
var websocket_host = ExtractSearchParameter("websocket_host");
var websocket_port = ExtractSearchParameter("websocket_port");
var ssl_server_port = ExtractSearchParameter("ssl_server_port");
var src = "?testcase=" + testcase;
if (mode == "nacl")
src += "&mode=nacl";
if (websocket_host != "")
src += "&websocket_host=" + websocket_host;
if (websocket_port != "")
src += "&websocket_port=" + websocket_port;
if (ssl_server_port != "")
src += "&ssl_server_port=" + ssl_server_port;
frame.setAttribute("src", src);
frame.setAttribute("onload", "LoadNext(" + (i + 1) + ")");
p.appendChild(frame);
document.body.appendChild(p);
}
function LoadNext(i) {
var links = document.links;
if (links.length > i)
AppendFrame(links[i].firstChild.nodeValue, i);
}
function RunAll() {
// Remove any existing frames.
var existing = document.getElementsByClassName("frame-container");
while (existing.length)
existing[0].parentNode.removeChild(existing[0]);
// Add new frames for each test, but do so one frame at a time.
LoadNext(0);
}
function ExtractSearchParameter(name) {
var nameIndex = location.search.indexOf(name + "=");
if (nameIndex != -1) {
var value = location.search.substring(nameIndex + name.length + 1);
var endIndex = value.indexOf("&");
if (endIndex != -1)
value = value.substring(0, endIndex);
return value;
}
return "";
}
// Parses the message, looking for strings of the form:
// TESTING_MESSAGE:<message_type>:<message_contents>
//
// If the message_data is not a string or does not match the above format, then
// undefined is returned.
//
// Otherwise, returns an array containing 2 items. The 0th element is the
// message_type, one of:
// - AddPostCondition
// - ClearConsole
// - DidExecuteTests
// - EvalScript
// - LogHTML
// - RemovePluginWhenFinished
// - ReportProgress
// The second item is the verbatim message_contents.
function ParseTestingMessage(message_data) {
if (typeof(message_data) != "string")
return undefined;
var testing_message_prefix = "TESTING_MESSAGE";
var delim_str = ":";
var delim1 = message_data.indexOf(delim_str);
if (message_data.substring(0, delim1) !== testing_message_prefix)
return undefined;
var delim2 = message_data.indexOf(delim_str, delim1 + 1);
if (delim2 == -1)
delim2 = message_data.length;
var message_type = message_data.substring(delim1 + 1, delim2);
var message_contents = message_data.substring(delim2 + 1);
return [message_type, message_contents];
}
function ClearConsole() {
window.document.getElementById("console").innerHTML = "";
}
function LogHTML(html) {
window.document.getElementById("console").innerHTML += html;
}
function RemovePluginWhenFinished() {
window.document.getElementById("container").removePlugin = true;
}
function sendAutomationMessage(msg) {
if (window.domAutomationController)
window.domAutomationController.send(msg);
}
function LogTestTime(test_time) {
console.log(test_time);
}
// If something goes really wrong, the test running inside the plugin may not
// terminate. For example, if the plugin does not load, the test will never
// send "PASS" to the browser. In this case we should explicitly use the
// automation controller to terminate the test.
function InternalError(msg) {
LogHTML("<p>" + msg);
sendAutomationMessage(msg);
}
function EvalScript(script) {
try {
eval(script);
} catch(ex) {
}
}
var conditions = [];
// Add a "PostCondition". These are bits of script that are run after the plugin
// is destroyed. If they evaluate to false or throw an exception, it's
// considered a failure.
function AddPostCondition(script) {
conditions.push(script);
}
// Update the HTML to show the failure and update cookies so that ui_tests
// doesn't count this as a pass.
function ConditionFailed(error) {
error_string = "Post condition check failed: " + error;
InternalError(error_string);
}
// Iterate through the post conditions defined in |conditions| and check that
// they all pass.
function CheckPostConditions() {
var success = true;
for (var i = 0; i < conditions.length; ++i) {
var script = conditions[i];
try {
if (!eval(script)) {
ConditionFailed("\"" + script + "\"");
success = false;
}
} catch (ex) {
ConditionFailed("\"" + script + "\"" + " failed with exception: " +
"\"" + ex.toString() + "\"");
success = false;
}
}
return success;
}
function IsTestingMessage(message_data) {
return (ParseTestingMessage(message_data) != undefined);
}
function handleTestingMessage(message_event) {
var type_contents_tuple = ParseTestingMessage(message_event.data);
if (type_contents_tuple) {
var type = type_contents_tuple[0];
var contents = type_contents_tuple[1];
if (type === "AddPostCondition")
AddPostCondition(contents);
else if (type === "ClearConsole")
ClearConsole();
else if (type === "DidExecuteTests")
DidExecuteTests(contents);
else if (type === "EvalScript")
EvalScript(contents);
else if (type === "LogHTML")
LogHTML(contents);
else if (type === "RemovePluginWhenFinished")
RemovePluginWhenFinished();
else if (type === "ReportProgress")
sendAutomationMessage(contents);
else if (type === "LogTestTime")
LogTestTime(contents);
}
}
function sendProgress() {
// We send "..." to signal that we're still working. See
// ppapi/tests/testing_instance.h for how this works.
sendAutomationMessage("...");
}
onload = function() {
var testcase = ExtractSearchParameter("testcase");
var mode = ExtractSearchParameter("mode");
document.title = 'Test ' + testcase;
var obj;
if (mode == "nacl_newlib") {
obj = document.createElement("EMBED");
obj.setAttribute("src", "ppapi_nacl_tests_newlib.nmf");
obj.setAttribute("type", "application/x-nacl");
obj.setAttribute("mode", mode);
} else if (mode == "nacl_glibc") {
obj = document.createElement("EMBED");
obj.setAttribute("src", "ppapi_nacl_tests_glibc.nmf");
obj.setAttribute("type", "application/x-nacl");
obj.setAttribute("mode", mode);
} else if (mode == "nacl_pnacl") {
obj = document.createElement("EMBED");
obj.setAttribute("src", "ppapi_nacl_tests_pnacl.nmf");
obj.setAttribute("type", "application/x-nacl");
obj.setAttribute("mode", mode);
} else if (mode == "mojo") {
obj = document.createElement("EMBED");
obj.setAttribute("src",
"test_data/ppapi/tests/mojo/pnacl/ppapi_tests_mojo.nmf");
obj.setAttribute("type", "application/x-pnacl");
obj.setAttribute("mode", mode);
} else {
var mimeType = "application/x-ppapi-tests";
if (mimeType in navigator.mimeTypes) {
obj = document.createElement("EMBED");
obj.setAttribute("src", "http://a.b.c/test");
obj.setAttribute("type", mimeType);
} else {
document.getElementById("console").innerHTML =
'<span class="fail">FAIL</span>: ' +
'<span class="err_msg">Test plugin is not registered.</span>';
}
}
if (obj) {
obj.setAttribute("width", 80);
obj.setAttribute("height", 80);
obj.setAttribute("style",
"background-color:#AAAAAA;border:1px solid black;");
obj.setAttribute("id", "plugin");
obj.setAttribute("testcase", testcase);
obj.setAttribute("protocol", window.location.protocol);
var websocket_host = ExtractSearchParameter("websocket_host");
if (websocket_host != "")
obj.setAttribute("websocket_host", websocket_host);
var websocket_port = ExtractSearchParameter("websocket_port");
if (websocket_port != "")
obj.setAttribute("websocket_port", websocket_port);
var ssl_server_port = ExtractSearchParameter("ssl_server_port");
if (ssl_server_port != "")
obj.setAttribute("ssl_server_port", ssl_server_port);
var container = document.getElementById("container");
container.addEventListener("message", handleTestingMessage, true);
// "error" and "crash" events will only fire for NaCl, but adding these
// listeners doesn't hurt in the non-NaCl cases.
obj.addEventListener("error", function() {
InternalError("Plugin did not load. '" + obj.lastError + "'");
}, true);
obj.addEventListener("crash", function() {
InternalError("Plugin crashed. '" + obj.lastError + "'");
}, true);
// NaCl sends progress events while loading. When we get one, notify the
// domAutomationController so that it knows we're still working.
obj.addEventListener("loadstart", sendProgress, true);
obj.addEventListener("progress", sendProgress, true);
obj.addEventListener("load", sendProgress, true);
obj.addEventListener("loadend", sendProgress, true);
// Register a bad dispatchEvent to make sure it isn't used. See 'EVIL' note
// below.
var original = obj.dispatchEvent;
obj.dispatchEvent = function() {
InternalError("Bad dispatchEvent called!");
}
container.appendChild(obj);
}
}
// EVIL Note:
// This part of the script does some nefarious things to make sure that it
// doesn't affect the behavior of PostMessage (on which all the tests rely). In
// particular, we replace document.createEvent, MessageEvent.initMessageEvent,
// and the MessageEvent constructor. Previously, the NaCl integration
// implementation made use of these and would fail (http://crbug.com/82604
// and http://crbug.com/109775).
document.createEvent = function() {
InternalError("Bad document.createEvent called!");
}
function MessageEvent() {
InternalError("Bad MessageEvent constructor called!");
}
MessageEvent.prototype.initMessageEvent = function() {
InternalError("Bad MessageEvent.initMessageEvent called!");
}
</script>
</head><body>
<div>
<div id="container"></div>
<div id="console"><span class="load_msg">loading...</span></div>
</div>
</body></html>