blob: f31c799b42d21621c5e374881e8caf6de98bd6b3 [file] [log] [blame]
if (this.importScripts) {
importScripts('../../../resources/js-test.js');
importScripts('shared.js');
}
description("Test structured clone permutations in IndexedDB. File/FileList tests require DumpRenderTree.");
if (self.eventSender) {
var fileInput = document.getElementById("fileInput");
var fileRect = fileInput.getClientRects()[0];
var targetX = fileRect.left + fileRect.width / 2;
var targetY = fileRect.top + fileRect.height / 2;
eventSender.beginDragWithFiles(['resources/test-data.html', 'resources/test-data.txt']);
eventSender.mouseMoveTo(targetX, targetY);
eventSender.mouseUp();
}
indexedDBTest(prepareDatabase, startTests);
function prepareDatabase()
{
db = event.target.result;
evalAndLog("store = db.createObjectStore('storeName')");
debug("This index is not used, but evaluating key path on each put() call will exercise (de)serialization:");
evalAndLog("store.createIndex('indexName', 'dummyKeyPath')");
}
function startTests()
{
debug("");
debug("Running tests...");
var tests_to_run = [
testUndefined,
testNull,
testBoolean,
testNumber,
testString,
testBooleanObject,
testNumberObject,
testStringObject,
testDateObject,
testRegExpObject,
testImageData,
testBlob,
testFile,
testFileList,
testArray,
testObject,
testTypedArray
];
function nextTest() {
debug("");
if (tests_to_run.length) {
var test = tests_to_run.shift();
test(nextTest); // When done, call this again.
} else {
testBadTypes();
}
}
nextTest();
}
function forEachWithCallback(testFunction, values, callback)
{
function nextValue() {
if (values.length) {
testFunction(values.shift(), nextValue);
} else {
callback();
}
}
nextValue();
}
function testValue(value, callback)
{
// One transaction per test, since some tests require asynchronous
// operations to verify the result (e.g. via FileReader)
evalAndLog("transaction = db.transaction('storeName', 'readwrite')");
transaction.onerror = unexpectedErrorCallback;
transaction.onabort = unexpectedAbortCallback;
evalAndLog("store = transaction.objectStore('storeName')");
self.value = value;
request = evalAndLog("store.put(value, 'key')");
request.onerror = unexpectedErrorCallback;
request.onsuccess = function(e) {
request = evalAndLog("store.get('key')");
request.onerror = unexpectedErrorCallback;
request.onsuccess = function(e) {
callback(request.result);
};
};
}
// Identity testing, sensitive to NaN and -0
function is(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y;
}
return x !== x && y !== y;
}
function arrayCompare(a, b) {
if (a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; ++i) {
if (!is(a[i], b[i])) {
return false;
}
}
return true;
}
function testPrimitiveValue(string, callback)
{
debug("Testing: " + string);
var value = eval("value = (" + string + ")");
test_data = value;
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("is(test_data, result)");
debug("");
callback();
});
}
function testObjectWithValue(string, callback)
{
debug("Testing: " + string);
var value = eval("value = (" + string + ")");
test_data = value;
testValue(test_data, function(result) {
self.result = result;
shouldBeEqualToString("typeof result", "object");
shouldBe("Object.prototype.toString.call(result)", "Object.prototype.toString.call(test_data)");
shouldBeTrue("test_data !== result");
shouldBe("result.toString()", "test_data.toString()");
shouldBeTrue("is(test_data.valueOf(), result.valueOf())");
debug("");
callback();
});
}
function testUndefined(callback)
{
testPrimitiveValue("undefined", callback);
}
function testNull(callback)
{
testPrimitiveValue("null", callback);
}
function testBoolean(callback)
{
debug("Testing boolean primitives");
debug("");
forEachWithCallback(testPrimitiveValue, ["true", "false"], callback);
}
function testBooleanObject(callback)
{
debug("Testing Boolean objects");
debug("");
forEachWithCallback(testObjectWithValue, [
"new Boolean(true)",
"new Boolean(false)"
], callback);
}
function testString(callback)
{
debug("Testing string primitives");
debug("");
forEachWithCallback(testPrimitiveValue, [
"''",
"'this is a sample string'",
"'null(\\0)'"
], callback);
}
function testStringObject(callback)
{
debug("Testing String objects");
debug("");
forEachWithCallback(testObjectWithValue, [
"new String()",
"new String('this is a sample string')",
"new String('null(\\0)')"
], callback);
}
function testNumber(callback)
{
debug("Testing number primitives");
debug("");
forEachWithCallback(testPrimitiveValue, [
"NaN",
"-Infinity",
"-Number.MAX_VALUE",
"-0xffffffff",
"-0x80000000",
"-0x7fffffff",
"-1",
"-Number.MIN_VALUE",
"-0",
"0",
"1",
"Number.MIN_VALUE",
"0x7fffffff",
"0x80000000",
"0xffffffff",
"Number.MAX_VALUE",
"Infinity"
], callback);
}
function testNumberObject(callback)
{
debug("Testing Number objects");
debug("");
forEachWithCallback(testObjectWithValue, [
"new Number(NaN)",
"new Number(-Infinity)",
"new Number(-Number.MAX_VALUE)",
"new Number(-Number.MIN_VALUE)",
"new Number(-0)",
"new Number(0)",
"new Number(Number.MIN_VALUE)",
"new Number(Number.MAX_VALUE)",
"new Number(Infinity)"
], callback);
}
function testDateObject(callback)
{
debug("Testing Date objects");
debug("");
forEachWithCallback(testObjectWithValue, [
"new Date(-1e13)",
"new Date(-1e12)",
"new Date(-1e9)",
"new Date(-1e6)",
"new Date(-1e3)",
"new Date(0)",
"new Date(1e3)",
"new Date(1e6)",
"new Date(1e9)",
"new Date(1e12)",
"new Date(1e13)"
], callback);
}
function testRegExpObject(callback)
{
debug("Testing RegExp objects");
debug("");
function testRegExp(string, callback) {
debug("Testing RegExp: " + string);
var value = eval("value = (" + string + ")");
test_data = value;
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeEqualToString("Object.prototype.toString.call(result)", "[object RegExp]");
shouldBe("result.toString()", "test_data.toString()");
debug("");
callback();
});
}
forEachWithCallback(testRegExp, [
"new RegExp()",
"/abc/",
"/abc/g",
"/abc/i",
"/abc/gi",
"/abc/m",
"/abc/mg",
"/abc/mi",
"/abc/mgi"
], callback);
}
function testImageData(callback)
{
debug("Testing ImageData");
evalAndLog("canvas = document.createElement('canvas')");
evalAndLog("canvas.width = 8");
evalAndLog("canvas.height = 8");
evalAndLog("test_data = canvas.getContext('2d').getImageData(0, 0, 8, 8)");
for (var i = 0; i < 256; ++i) {
test_data.data[i] = i;
}
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeEqualToString("Object.prototype.toString.call(result)", "[object ImageData]");
shouldBe("result.width", "test_data.width");
shouldBe("result.height", "test_data.height");
shouldBe("result.data.length", "test_data.data.length");
if (arrayCompare(test_data.data, result.data)) {
testPassed("result data matches");
} else {
testFailed("result data doesn't match");
}
callback();
});
}
function readBlobAsText(blob, callback)
{
var reader = new FileReader();
reader.onload = function(e) {
if (e.target.readyState === FileReader.DONE) {
callback(e.target.result);
}
};
reader.onerror = function(e) {
testFailed("Error reading blob as text: " + e);
finishJSTest();
};
reader.readAsText(blob);
}
function checkBlobContents(blob, expected, callback)
{
readBlobAsText(blob, function(text) {
self.text = text;
shouldBeEqualToString("text", expected);
callback();
});
}
function compareBlobs(blob1, blob2, callback)
{
readBlobAsText(blob1, function(text1) {
readBlobAsText(blob2, function(text2) {
self.text1 = text1;
self.text2 = text2;
shouldBeEqualToString("text2", text1);
callback();
});
});
}
function testBlob(callback)
{
debug("Testing Blob");
// FIXME: Blob, File, and FileList support is incomplete.
// http://crbug.com/108012
debug("Skipping test");
callback();
return;
shouldBeTrue("FileReader != null");
evalAndLog("test_content = 'This is a test. This is only a test.'");
evalAndLog("test_data = new Blob([test_content])");
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeEqualToString("Object.prototype.toString.call(result)", "[object Blob]");
shouldBe("result.size", "test_data.size");
shouldBe("result.type", "test_data.type");
checkBlobContents(result, test_content, callback);
});
}
function compareFiles(file1, file2, callback)
{
self.file1 = file1;
self.file2 = file2;
shouldBeTrue("file1 !== file2");
shouldBeEqualToString("Object.prototype.toString.call(file1)", "[object File]");
shouldBeEqualToString("Object.prototype.toString.call(file2)", "[object File]");
debug("file1.size: " + file1.size);
shouldBe("file1.size", "file2.size");
debug("file1.type: " + file1.type);
shouldBe("file1.type", "file2.type");
debug("file1.name: " + file1.name);
shouldBe("file1.name", "file2.name");
shouldBe("String(file1.lastModifiedDate)", "String(file2.lastModifiedDate)");
if (callback) {
compareBlobs(file1, file2, callback);
}
}
function testFile(callback)
{
debug("Testing File");
// FIXME: Blob, File, and FileList support is incomplete.
// http://crbug.com/108012
debug("Skipping test");
callback();
return;
evalAndLog("test_content = fileInput.files[0]");
self.test_data = test_content;
testValue(test_data, function(result) {
self.result = result;
compareFiles(result, test_data, callback);
});
}
function testFileList(callback)
{
debug("Testing FileList");
// FIXME: Blob, File, and FileList support is incomplete.
// http://crbug.com/108012
debug("Skipping test");
callback();
return;
evalAndLog("test_content = fileInput.files");
self.test_data = test_content;
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeEqualToString("Object.prototype.toString.call(result)", "[object FileList]");
shouldBe("result.length", "test_data.length");
i = 0;
function doNext() {
if (i >= test_data.length) {
callback();
} else {
debug("comparing file[" + i + "]");
compareFiles(result[i], test_data[i++], doNext);
}
}
doNext();
});
}
function testArray(callback) {
debug("Testing Array");
evalAndLog("test_data = []");
evalAndLog("test_data[0] = 'foo'");
evalAndLog("test_data[1] = 'bar'");
evalAndLog("test_data[10] = true");
evalAndLog("test_data[11] = false");
evalAndLog("test_data[20] = 123");
evalAndLog("test_data[21] = 456");
evalAndLog("test_data[30] = null");
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeTrue("test_data.length === result.length");
Object.keys(test_data).forEach(
function(key) {
shouldBe("test_data[" + key + "]", "result[" + key + "]");
});
callback();
});
}
function testObject(callback) {
debug("Testing Object");
evalAndLog("test_data = []");
evalAndLog("test_data[0] = 'foo'");
evalAndLog("test_data[1] = 'bar'");
evalAndLog("test_data['a'] = true");
evalAndLog("test_data['b'] = false");
evalAndLog("test_data['foo'] = 123");
evalAndLog("test_data['bar'] = 456");
evalAndLog("test_data[''] = null");
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBeTrue("arrayCompare(Object.keys(result).sort(), Object.keys(test_data).sort())");
Object.keys(test_data).forEach(
function(key) {
shouldBe("test_data[" + JSON.stringify(key) + "]", "result[" + JSON.stringify(key) + "]");
});
callback();
});
}
function testTypedArray(callback) {
debug("Testing TypedArray");
function testTypedArrayValue(string, callback) {
evalAndLog("value = " + string);
test_data = value;
testValue(test_data, function(result) {
self.result = result;
shouldBeTrue("test_data !== result");
shouldBe("Object.prototype.toString.call(result)", "Object.prototype.toString.call(test_data)");
shouldBeTrue("test_data.length === result.length");
for (i = 0; i < test_data.length; ++i) {
shouldBeTrue("is(test_data[" + i + "], result[" + i + "])");
}
debug("");
callback();
});
}
forEachWithCallback(testTypedArrayValue, [
"new Uint8Array([])",
"new Uint8Array([0, 1, 254, 255])",
"new Uint16Array([0x0000, 0x0001, 0xFFFE, 0xFFFF])",
"new Uint32Array([0x00000000, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF])",
"new Int8Array([0, 1, 254, 255])",
"new Int16Array([0x0000, 0x0001, 0xFFFE, 0xFFFF])",
"new Int32Array([0x00000000, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF])",
"new Uint8ClampedArray([0, 1, 254, 255])",
"new Float32Array([-Infinity, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, Infinity, NaN])",
"new Float64Array([-Infinity, -Number.MAX_VALUE, -Number.MIN_VALUE, 0, Number.MIN_VALUE, Number.MAX_VALUE, Infinity, NaN])"
], callback);
}
function testBadTypes()
{
debug("");
debug("Test types that can't be cloned:");
debug("");
evalAndLog("transaction = db.transaction('storeName', 'readwrite')");
evalAndLog("store = transaction.objectStore('storeName')");
transaction.onerror = unexpectedErrorCallback;
transaction.onabort = unexpectedAbortCallback;
transaction.oncomplete = finishJSTest;
debug("");
debug("Other JavaScript object types:");
evalAndExpectException("store.put(new Error, 'key')", "DOMException.DATA_CLONE_ERR");
evalAndExpectException("store.put(new Function, 'key')", "DOMException.DATA_CLONE_ERR");
debug("");
debug("Other host object types:");
evalAndExpectException("store.put(self, 'key')", "DOMException.DATA_CLONE_ERR");
evalAndExpectException("store.put(document, 'key')", "DOMException.DATA_CLONE_ERR");
evalAndExpectException("store.put(document.body, 'key')", "DOMException.DATA_CLONE_ERR");
}