var kSerializedScriptValueVersion = 9; function forVersion(version, values) { var versionTag = 0xff; var versionPrefix = [ (version << 8) | versionTag ]; return versionPrefix.concat(values) } function expectBufferValue(bytesPerElement, expectedValues, buffer) { expectedBufferValues = expectedValues; var arrayClass; if (bytesPerElement == 1) arrayClass = Uint8Array; else arrayClass = Uint16Array; bufferView = new arrayClass(buffer); shouldBe("bufferView.length", "expectedBufferValues.length"); var success = (bufferView.length == expectedBufferValues.length); if (success) { for (var i = 0; i < expectedValues.length; i++) { if (expectedValues[i] != bufferView[i]) { testFailed("ArrayBufferViews differ at index " + i + ". Should be " + expectedValues[i] + ". Was " + bufferView[i]); success = false; break; } } } if (!success) { // output the full buffer for adding back into the test var output = []; for (i = 0; i < bufferView.length; i++) { var hexVal = bufferView[i].toString(16); if (hexVal.length < bytesPerElement * 2) { hexVal = "0000".slice(hexVal.length, bytesPerElement * 2) + hexVal; } output.push("0x" + hexVal); } debug("Actual buffer: [" + output.join(", ") + "]"); } } function makeBuffer(bytesPerElement, serializedValues) { var arrayClass; if (bytesPerElement == 1) arrayClass = Uint8Array; else arrayClass = Uint16Array; var bufferView = new arrayClass(new ArrayBuffer(serializedValues.length * bytesPerElement)); for (var i = 0; i < serializedValues.length; i++) { bufferView[i] = serializedValues[i]; } return bufferView.buffer; } function areValuesIdentical(a, b) { function sortObject(object) { if (typeof object != "object" || object === null) return object; return Object.keys(object).sort().map(function(key) { return { key: key, value: sortObject(object[key]) }; }); } var jsonA = JSON.stringify(sortObject(a)); var jsonB = JSON.stringify(sortObject(b)); if (jsonA != jsonB) { debug("areValuesIdentical will fail"); debug("object A: " + jsonA); debug("object B: " + jsonB); } return JSON.stringify(sortObject(a)) === JSON.stringify(sortObject(b)); } function _testSerialization(bytesPerElement, obj, values, oldFormat, serializeExceptionValue) { debug(""); values = forVersion(kSerializedScriptValueVersion, values); if (!serializeExceptionValue) { self.obj = obj; debug("Deserialize to " + JSON.stringify(obj) + ":"); self.newObj = internals.deserializeBuffer(makeBuffer(bytesPerElement, values)); shouldBe("JSON.stringify(newObj)", "JSON.stringify(obj)"); shouldBeTrue("areValuesIdentical(newObj, obj)"); if (oldFormat) { self.newObj = internals.deserializeBuffer(makeBuffer(bytesPerElement, oldFormat)); shouldBe("JSON.stringify(newObj)", "JSON.stringify(obj)"); shouldBeTrue("areValuesIdentical(newObj, obj)"); } } debug("Serialize " + JSON.stringify(obj) + ":"); try { var serialized = internals.serializeObject(obj); if (serializeExceptionValue) { testFailed("Should have thrown an exception of type ", serializeExceptionValue); } } catch(e) { if (!serializeExceptionValue) { testFailed("Threw exception " + e); return; } else { self.thrownException = e; self.expectedException = serializeExceptionValue; shouldBe("thrownException.code", "expectedException"); return; } } expectBufferValue(bytesPerElement, values, serialized); } function testBlobSerialization() { debug(""); self.blobObj1 = new Blob(['Hi'], {type: 'text/plain'}); self.blobObj2 = internals.deserializeBuffer(internals.serializeObject(blobObj1)); shouldBeTrue("areValuesIdentical(blobObj1, blobObj2)"); self.dictionaryWithBlob1 = {blob: blobObj1, string: 'stringValue'}; self.dictionaryWithBlob2 = internals.deserializeBuffer(internals.serializeObject(dictionaryWithBlob1)); shouldBeTrue("areValuesIdentical(dictionaryWithBlob1, dictionaryWithBlob2)"); // Compare contents too. var xhr1 = new XMLHttpRequest(); xhr1.open("GET", URL.createObjectURL(self.blobObj1), false); xhr1.send(); self.blobContent1 = xhr1.response; var xhr2 = new XMLHttpRequest(); xhr2.open("GET", URL.createObjectURL(self.blobObj2), false); xhr2.send(); self.blobContent2 = xhr2.response; shouldBe("self.blobContent1", "self.blobContent2"); } function _testFileSerialization(sourceFile, done) { function checkIfSameContent(file1, file2, continuation) { function step1() { var fileReader = new FileReader(); fileReader.onload = function () { self.fileContents1 = fileReader.result; step2(); }; fileReader.onerror = function () { testFailed("could not read file1. " + fileReader.error.message); done(); } fileReader.readAsText(file1); } function step2() { var fileReader = new FileReader(); fileReader.onload = function () { self.fileContents2 = fileReader.result; finish(); }; fileReader.onerror = function () { testFailed("could not read file2. " + fileReader.error.message); done(); } fileReader.readAsText(file2); } function finish() { shouldBe("self.fileContents1", "self.fileContents2"); continuation(); } step1(); } self.fileObj1 = sourceFile; self.fileObj2 = internals.deserializeBuffer(internals.serializeObject(self.fileObj1)); shouldBeTrue("areValuesIdentical(fileObj1, fileObj2)"); self.dictionaryWithFile1 = {file: fileObj1, string: 'stringValue'}; self.dictionaryWithFile2 = internals.deserializeBuffer(internals.serializeObject(dictionaryWithFile1)); shouldBeTrue("areValuesIdentical(dictionaryWithFile1, dictionaryWithFile2)"); // Read and compare actual contents. checkIfSameContent(self.fileObj1, self.fileObj2, done); } function testConstructedFileSerialization(done) { debug(""); debug("Files created using the File constructor"); self.sourceFile = new File(['The', ' contents'], 'testfile.txt', {type: 'text/plain', lastModified: 0}); _testFileSerialization(sourceFile, done); } function testUserSelectedFileSerialization(done) { debug(""); debug("Files selected by the user in an <input type='file'>"); var fileInput = document.getElementById("fileInput"); fileInput.addEventListener("change", function () { self.sourceFile = fileInput.files.item(0); _testFileSerialization(sourceFile, done); }); eventSender.beginDragWithFiles(["resources/file.txt"]); var centerX = fileInput.offsetLeft + fileInput.offsetWidth / 2; var centerY = fileInput.offsetTop + fileInput.offsetHeight / 2; eventSender.mouseMoveTo(centerX, centerY); eventSender.mouseUp(); } function testFileSerialization() { window.jsTestIsAsync = true; testConstructedFileSerialization(function () { testUserSelectedFileSerialization(function () { finishJSTest(); }); }); }