Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / fast / dom / Window / script-tests / postmessage-clone.js
blob645a85ce28fbcf400450166e29d81c3a7d9fa43a
1 document.getElementById("description").innerHTML = "Tests that we clone object hierarchies";
3 tryPostMessage('null');
4 tryPostMessage('undefined');
5 tryPostMessage('1');
6 tryPostMessage('true');
7 tryPostMessage('"1"');
8 tryPostMessage('({})');
9 tryPostMessage('({a:1})');
10 tryPostMessage('({a:"a"})');
11 tryPostMessage('({b:"a", a:"b"})');
12 tryPostMessage('({p0:"string0", p1:"string1", p2:"string2", p3:"string3", p4:"string4", p5:"string5", p6:"string6", p7:"string7", p8:"string8", p9:"string9", p10:"string10", p11:"string11", p12:"string12", p13:"string13", p14:"string14", p15:"string15", p16:"string16", p17:"string17", p18:"string18", p19:"string19"})');
13 tryPostMessage('({p0:"string1", p1:"string1", p2:"string2", p3:"string3", p4:"string4", p5:"string5", p6:"string6", p7:"string7", p8:"string8", p9:"string9", p10:"string10", p11:"string11", p12:"string12", p13:"string13", p14:"string14", p15:"string15", p16:"string16", p17:"string17", p18:"string18", p19:"string19"})');
14 tryPostMessage('({a:""})');
15 tryPostMessage('({a:0})');
16 tryPostMessage('({a:1})');
17 tryPostMessage('[]');
18 tryPostMessage('["a", "a", "b", "a", "b"]');
19 tryPostMessage('["a", "a", "b", {a:"b", b:"a"}]');
20 tryPostMessage('[1,2,3]');
21 tryPostMessage('[,,1]');
22 tryPostMessage('(function(){})', true, null, DOMException.DATA_CLONE_ERR);
23 tryPostMessage('var x = 0; try { eval("badref"); } catch(e) { x = e; } x', true, null, DOMException.DATA_CLONE_ERR);
24 var arrayBuffer = new ArrayBuffer(1);
25 tryPostMessage('"data"', false, null, 0, [arrayBuffer]);
26 tryPostMessage('arrayBuffer', true, null, DOMException.DATA_CLONE_ERR);
27 var duplicateArrayBuffer = new ArrayBuffer(1);
28 tryPostMessage('"data"', true, null, DOMException.DATA_CLONE_ERR, [duplicateArrayBuffer, duplicateArrayBuffer]);
29 var uint8Array = new Uint8Array([10]);
30 tryPostMessage('"data"', false, null, 0, [uint8Array.buffer]);
31 tryPostMessage('uint8Array', true, null, DOMException.DATA_CLONE_ERR);
32 tryPostMessage('new Date(1234567890000)');
33 tryPostMessage('new ConstructorWithPrototype("foo")', false, '({field:"foo"})');
34 tryPostMessage('new Boolean(true)');
35 tryPostMessage('new Boolean(false)');
36 tryPostMessage('new String("gnirts")');
37 tryPostMessage('new Number(42.0)');
38 cyclicObject={};
39 cyclicObject.self = cyclicObject;
40 tryPostMessage('cyclicObject', false, "cyclicObject");
41 cyclicArray=[];
42 cyclicArray[0] = cyclicArray;
43 tryPostMessage('cyclicArray', false, "cyclicArray");
44 var cyclicObjectGetter = {get self() { return cyclicObjectGetter; }};
45 tryPostMessage('cyclicObjectGetter', false, 'cyclicObject');
46 objectGraph = {};
47 object = {};
48 objectGraph.graph1 = object;
49 objectGraph.graph2 = object;
50 tryPostMessage('objectGraph', false, "objectGraph");
51 arrayGraph = [object, object];
52 tryPostMessage('arrayGraph', false, "arrayGraph");
53 tryPostMessage('window', true);
54 tryPostMessage('({get a() { throw "x" }})', true);
56 if (window.eventSender) {
57     var fileInput = document.getElementById("fileInput");
58     var fileRect = fileInput.getClientRects()[0];
59     var targetX = fileRect.left + fileRect.width / 2;
60     var targetY = fileRect.top + fileRect.height / 2;
61     eventSender.beginDragWithFiles(['resources/blank.html', 'resources/child.html']);
62     eventSender.mouseMoveTo(targetX, targetY);
63     eventSender.mouseUp();
65 var imageData = document.createElement("canvas").getContext("2d").createImageData(10,10);
66 for (var i = 0; i < imageData.data.length * 4; i++)
67     imageData.data[i] = i % 256;
68 var mutatedImageData = document.createElement("canvas").getContext("2d").createImageData(10,10);
69 for (var i = 0; i < imageData.data.length * 4; i++)
70     mutatedImageData.data[i] = i % 256;
71 tryPostMessage('imageData', false, imageData);
72 tryPostMessage('imageData.data', false, imageData.data)
73 tryPostMessage('mutatedImageData', false, imageData);
74 tryPostMessage('mutatedImageData.data', false, imageData.data)
75 for (var i = 0; i < imageData.data.length * 4; i++)
76     mutatedImageData.data[i] = 0;
78 // Test close() special case for Blob (and File.)
80 var blob = new Blob(["Hello"]);
81 var blobSize = blob.size;
82 tryPostMessage('blob', false, "evalThunk", function(v) { doPassFail(v.size === blobSize, "Cloned Blob size equal to the original size."); });
83 tryPostMessage('blob.close(); blob', true, null, DOMException.DATA_CLONE_ERR);
85 var constructedFile = new File(["Hello"], "test");
86 var fileSize = constructedFile.size;
87 tryPostMessage('constructedFile', false, "evalThunk", function(v) { doPassFail(v.size === fileSize, "Cloned File size equal to the original size."); });
88 tryPostMessage('constructedFile.close(); constructedFile', true, null, DOMException.DATA_CLONE_ERR);
90 function thunk(s) {
91     return "(function() {" + s + "})()";
93 tryPostMessage(thunk('return 42;'), false, '42');
94 tryPostMessage(thunk('return 42;'), false, thunk('return 40 + 2;'));
95 tryPostMessage(thunk('return 42;'), false, "evalThunk",
96                function(v) { doPassFail(v == 42, "evalThunk OK"); })
98 // Only enumerable properties should be serialized.
99 tryPostMessage(thunk('var o = {x:"hello"}; Object.defineProperty(o, "y", {value:"goodbye"}); return o;'), false, '({x:"hello"})');
101 // It's unclear what we should do if an accessor modifies an object out from under us
102 // while we're serializing it; the standard does mandate certain aspects about evaluation
103 // order, though, including that properties must be processed in their enumeration order.
104 tryPostMessage(thunk(
105         'var a = [0, 1, 2]; ' +
106         'var b = { get x() { a[0] = 40; a[2] = 42; a.push(43); return 41; }}; ' +
107         'a[1] = b; ' +
108         'return a;'
109     ), false, "evalThunk", function(v) {
110         doPassFail(v.length === 3, "length correct"); // undefined
111         doPassFail(v[0] === 0, "evaluation order OK"); // mandatory
112         doPassFail(v[1].x === 41, "evaluation order OK/accessor reached"); // mandatory
113         doPassFail(v[2] === 42, "evaluation order OK"); // mandatory
114     });
116 tryPostMessage(thunk(
117         'var a = [0, 1, 2]; ' +
118         'var b = { get x() { a.pop(); return 41; } }; ' +
119         'a[1] = b; ' +
120         'return a;'
121     ), false, "evalThunk", function(v) {
122         doPassFail(v.length === 3 || v.length === 2, "length correct"); // undefined
123         doPassFail(v[0] === 0, "index 0 OK"); // mandatory
124         doPassFail(v[1].x === 41, "accessor reached"); // mandatory
125         doPassFail(v[2] === undefined, "index 2 undefined"); // undefined
126     });
128 tryPostMessage(thunk(
129         'var a = [0, 1, 2]; ' +
130         'var b = { get x() { a.pop(); return 41; } }; ' +
131         'a[2] = b; ' +
132         'return a;'
133     ), false, "evalThunk", function(v) {
134         doPassFail(v.length === 3, "length correct"); // undefined
135         doPassFail(v[0] === 0, "index 0 OK"); // mandatory
136         doPassFail(v[1] === 1, "index 1 OK"); // mandatory
137         doPassFail(v[2].x === 41, "index 2 OK"); // undefined
138     });
140 // Now with objects! This is a little more tricky because the standard does not
141 // define an enumeration order.
142 tryPostMessage(thunk(
143         'var a = {p0: 0, p1: 1}; ' +
144         'Object.defineProperty(a, "p2", {get:function() {delete a.p3; return 42; }, enumerable: true, configurable: true}); ' +
145         'Object.defineProperty(a, "p3", {get:function() {delete a.p2; return 43; }, enumerable: true, configurable: true}); ' +
146         'Object.defineProperty(a, "p4", {get:function() { a.p5 = 45; return 44; }, enumerable: true, configurable: true}); ' +
147         'return a;'
148     ), false, "evalThunk", function(v) {
149         doPassFail(v.p0 === 0 && v.p1 === 1, "basic properties OK"); // mandatory
150         doPassFail(v.p2 === undefined && v.p3 !== undefined ||
151                    v.p2 !== undefined && v.p3 === undefined, "one accessor was run"); // mandatory
152         doPassFail(v.p2 !== undefined || Object.getOwnPropertyDescriptor(v, "p2") === undefined, "property was removed"); // undefined
153         doPassFail(v.p3 !== undefined || Object.getOwnPropertyDescriptor(v, "p3") === undefined, "property was removed"); // undefined
154         doPassFail(v.p4 === 44, "accessor was run"); // mandatory
155         doPassFail(Object.getOwnPropertyDescriptor(v, "p5") === undefined, "dynamic property not sent"); // undefined
156     });
158 // Objects returned from accessors should still be coalesced.
159 tryPostMessage(thunk(
160         'var obja = {get p() { return 42; }}; ' +
161         'var msg = {get a() { return obja; }, b: obja}; ' +
162         'return msg;'
163     ), false, "evalThunk", function(v) {
164         // Interestingly, the standard admits two answers here!
165         doPassFail(v.a === v.b, "reference equality preserved");
166         doPassFail((v.b.p === 42 && v.a.p === 42) ||
167             (v.b.p === null && v.a.p === null), "accessors used");
168     });
169 tryPostMessage(thunk(
170         'var obja = {get p() { return 42; }}; ' +
171         'var msg = {a: obja, get b() { return obja; }}; ' +
172         'return msg;'
173     ), false, "evalThunk", function(v) {
174         // Interestingly, the standard admits two answers here!
175         doPassFail(v.a === v.b, "reference equality preserved (opposite order)");
176         doPassFail((v.b.p === 42 && v.a.p === 42) ||
177                    (v.b.p === null && v.a.p === null), "accessors used (opposite order)");
178     });
180 // Tests to verify that accessor and non-accessor properties are
181 // treated equivalently.
182 tryPostMessage(thunk(
183         'var obja = {get p() { return 42; }, q: 43}; ' +
184         'return {get a() { return obja; }};'
185     ), false, "evalThunk", function(v) {
186         doPassFail(v.a.p === 42, "accessor value was not nullified");
187         doPassFail(v.a.q === 43, "non-accessor value was not nullified");
188     });
189 tryPostMessage(thunk(
190         'var objb = {get r() { return 44; }, t: 45}; ' +
191         'var obja = {get p() { return 42; }, q: 43, s: objb}; ' +
192         'return {get a() { return obja; }};'
193     ), false, "evalThunk", function(v) {
194         doPassFail(v.a.p === 42, "accessor value was not nullified");
195         doPassFail(v.a.q === 43, "non-accessor value was not nullified");
196         doPassFail(v.s !== null, "non-accessor value was not nullified");
197         doPassFail(v.a.s.r === 44, "accessor value was not nullified");
198         doPassFail(v.a.s.t === 45, "non-accessor value was not nullified");
199     });
200 tryPostMessage(thunk(
201         'var objb = {get r() { return 44; }, t: 45}; ' +
202         'var obja = {get p() { return 42; }, q: 43, s: [objb]}; ' +
203         'return {get c() { return 47; }, get a() { return obja; }, get b() { return 46; } };'
204     ), false, "evalThunk", function(v) {
205         doPassFail(v.b === 46, "accessor value was not nullified");
206         doPassFail(v.c === 47, "accessor value was not nullified");
207         doPassFail(v.a.p === 42, "accessor value was not nullified");
208         doPassFail(v.a.q === 43, "non-accessor value was not nullified");
209         doPassFail(v.a.s !== null, "non-accessor value was not nullified");
210         doPassFail(v.a.s !== undefined, "non-accessor value is defined");
211         doPassFail(v.a.s[0] !== null, "non-accessor value was not nullified");
212         doPassFail(v.a.s[0] !== undefined, "non-accessor value is defined");
213         doPassFail(v.a.s[0].r === 44, "accessor value was not nullified");
214         doPassFail(v.a.s[0].t === 45, "non-accessor value was not nullified");
215     });
217 // We need to pass out the exception raised from internal accessors.
218 tryPostMessage(thunk(
219         'return {get a() { throw "accessor-exn"; }};'
220     ), true, null, 'accessor-exn');
221 tryPostMessage(thunk(
222         'var obja = {get p() { throw "accessor-exn"; }}; ' +
223         'return {get a() { return obja; }};'
224     ), true, null, 'accessor-exn');
225 tryPostMessage(thunk(
226         'window.bcalled = undefined; ' +
227         'window.acalled = undefined; ' +
228         'window.pcalled = undefined; ' +
229         'var objb = {get b() { window.bcalled = true; return 42; }}; ' +
230         'var obja = {get a() { window.acalled = true; return objb; }}; ' +
231         'return { get p() { window.pcalled = true; return obja; }};'
232     ), false, "evalThunk", function(v) {
233         doPassFail(v.p.a.b === 42, "accessor value was not nullified");
234         doPassFail(window.pcalled === true, "window.pcalled === true");
235         doPassFail(window.acalled === true, "window.acalled === true");
236         doPassFail(window.bcalled === true, "window.bcalled === true");
237     });
239 // Reference equality between Boolean objects must be maintained.
240 tryPostMessage(thunk(
241         'var t1 = new Boolean(true); ' +
242         'var t2 = new Boolean(true); ' +
243         'var f1 = new Boolean(false); ' +
244         'var f2 = new Boolean(false); ' +
245         'return [t1, t1, t2, f1, f1, f2];'
246     ), false, "evalThunk", function(v) {
247         doPassFail(equal(v[0], new Boolean(true)), "Boolean values correct (0)");
248         doPassFail(equal(v[3], new Boolean(false)), "Boolean values correct (3)");
249         doPassFail(equal(v[1], v[2]), "Boolean values correct (1,2)");
250         doPassFail(equal(v[4], v[5]), "Boolean values correct (4,5)");
251         doPassFail(v[0] === v[1], "References to Booleans correct (0,1)");
252         doPassFail(v[3] === v[4], "References to Booleans correct (3,4)");
253         doPassFail(v[0] !== v[2], "References to Booleans correct (0,2)");
254         doPassFail(v[3] !== v[5], "References to Booleans correct (3,5)");
255     });
257 // Reference equality between Number objects must be maintained.
258 tryPostMessage(thunk(
259         'var n1 = new Number(42.0); ' +
260         'var n2 = new Number(42.0); ' +
261         'return [n1, n1, n2];'
262     ), false, "evalThunk", function(v) {
263         doPassFail(equal(v[0], new Number(42.0)), "Number values correct (0)");
264         doPassFail(equal(v[0], v[2]), "Number values correct (0,2)");
265         doPassFail(v[0] === v[1], "References to numbers correct (0,1)");
266         doPassFail(v[0] !== v[2], "References to numbers correct (0,2)");
267     });
269 // Reference equality between String objects must be maintained.
270 tryPostMessage(thunk(
271         'var s1 = new String("gnirts"); ' +
272         'var s2 = new String("gnirts"); ' +
273         'return [s1, s1, s2];'
274     ), false, "evalThunk", function(v) {
275         doPassFail(equal(v[0], new String("gnirts")), "String values correct (0)");
276         doPassFail(equal(v[0], v[2]), "String values correct (0,2)");
277         doPassFail(v[0] === v[1], "References to strings correct (0,1)");
278         doPassFail(v[0] !== v[2], "References to strings correct (0,2)");
279     });
281 // Properties added to String, Boolean and Number objects should not be serialized.
282 tryPostMessage(thunk(
283         'var s = new String("gnirts"); ' +
284         'var n = new Number(42.0); ' +
285         'var b = new Boolean(true); ' +
286         's.foo = 1; n.foo = 2; b.foo = 3; ' +
287         'return [s, n, b];'
288     ), false, "evalThunk", function(v) {
289         doPassFail(v[0].foo == undefined, "String object properties not serialized");
290         doPassFail(v[1].foo == undefined, "Number object properties not serialized");
291         doPassFail(v[2].foo == undefined, "Boolean object properties not serialized");
292     });
294 // Reference equality between dates must be maintained.
295 tryPostMessage(thunk(
296         'var d1 = new Date(1,2,3); ' +
297         'var d2 = new Date(1,2,3); ' +
298         'return [d1,d1,d2];'
299     ), false, "evalThunk", function(v) {
300         doPassFail(equal(v[0], new Date(1,2,3)), "Date values correct (0)");
301         doPassFail(equal(v[0], v[2]), "Date values correct (1)");
302         doPassFail(v[0] === v[1], "References to dates correct (0)");
303         doPassFail(v[0] !== v[2], "References to dates correct (1)");
304     });
306 // Reference equality between regexps must be preserved.
307 tryPostMessage(thunk(
308         'var rx1 = new RegExp("foo"); ' +
309         'var rx2 = new RegExp("foo"); ' +
310         'var rx3 = new RegExp("foo", "gim"); ' +
311         'rx3.exec("foofoofoo"); ' +
312         'doPassFail(rx3.lastIndex === 3, "lastIndex initially correct: was " + rx3.lastIndex); ' +
313         'return [rx1,rx1,rx2,rx3];'
314     ), false, "evalThunk", function(v) {
315         doPassFail(v[0].source === "foo", "Regexp value correct (0)");
316         doPassFail(v[0] === v[1], "References to regexps correct (0)");
317         doPassFail(v[0] !== v[2], "References to regexps correct (1)");
318         doPassFail(v[0].global === false, "global set (0)");
319         doPassFail(v[3].global === true, "global set (1)");
320         doPassFail(v[0].ignoreCase === false, "ignoreCase set (0)");
321         doPassFail(v[3].ignoreCase === true, "ignoreCase set (1)");
322         doPassFail(v[0].multiline === false, "multiline set (0)");
323         doPassFail(v[3].multiline === true, "multiline set (1)");
324         doPassFail(v[0].lastIndex === 0, "lastIndex correct (0)");
325         doPassFail(v[3].lastIndex === 0, "lastIndex correct (1)");
326     });
328 if (window.eventSender) {
329     tryPostMessage(thunk(
330         'window.fileList = fileInput.files; ' +
331         'window.file0 = fileList[0]; ' +
332         'window.file1 = fileList[1]; ' +
333         'return window.fileList.length'), false, 2);
334     doPassFail(window.fileList[0] === window.file0, "sanity on file reference equality")
335     // The standard mandates that we do _not_ maintain reference equality for files in a transferred FileList.
336     tryPostMessage(thunk('return [window.file0, window.file0];'
337         ), false, "evalThunk", function(v) { doPassFail(v[0] === v[1], "file references transfer")});
338     tryPostMessage(thunk('return [window.fileList, window.file0];'
339         ), false, "evalThunk", function(v) { doPassFail(v[0][0] !== v[1], "FileList should not respect reference equality")});
340     tryPostMessage(thunk('return [window.file0, window.fileList];'
341         ), false, "evalThunk", function(v) { doPassFail(v[1][0] !== v[0], "FileList should not respect reference equality")});
342     tryPostMessage(thunk('return [window.fileList, window.fileList];'
343         ), false, "evalThunk", function(v) { doPassFail(v[0] === v[1], "FileList respects self-reference equality")});
344     tryPostMessage(thunk('return [window.fileList, window.file0, window.file1]'
345         ), false, "evalThunk", function(v) {
346             doPassFail(v[0].length === window.fileList.length, "FileList length sent correctly");
347             doPassFail(v[0][0] !== v[1], "FileList should not respect reference equality (0)");
348             doPassFail(v[0][1] !== v[2], "FileList should not respect reference equality (1)");
349             doPassFail(v[0][0].name == window.file0.name, "FileList preserves order and data (name0)");
350             doPassFail(v[0][1].name == window.file1.name, "FileList preserves order and data (name1)");
351             doPassFail(equal(v[0][0].lastModifiedDate, window.file0.lastModifiedDate), "FileList preserves order and data (date0)");
352             doPassFail(equal(v[0][1].lastModifiedDate, window.file1.lastModifiedDate), "FileList preserves order and data (date1)");
353         });
355 tryPostMessage('"done"');