• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* This file is mostly a remix of @zcorpan’s web worker test suite */
2
3structuredCloneBatteryOfTests = [];
4
5function check(description, input, callback, requiresDocument = false) {
6  testObjMock = {
7    done() {},
8    step_func(f) {return _ => f()},
9  };
10
11  structuredCloneBatteryOfTests.push({
12    description,
13    async f(runner) {
14      let newInput = input;
15      if (typeof input === 'function') {
16        newInput = input();
17      }
18      const copy = await runner.structuredClone(newInput);
19      await callback(copy, newInput, testObjMock);
20    },
21    requiresDocument
22  });
23}
24
25function compare_primitive(actual, input, test_obj) {
26  assert_equals(actual, input);
27  if (test_obj)
28    test_obj.done();
29}
30function compare_Array(callback, callback_is_async) {
31  return function(actual, input, test_obj) {
32    if (typeof actual === 'string')
33      assert_unreached(actual);
34    assert_true(actual instanceof Array, 'instanceof Array');
35    assert_not_equals(actual, input);
36    assert_equals(actual.length, input.length, 'length');
37    callback(actual, input);
38    if (test_obj && !callback_is_async)
39      test_obj.done();
40  }
41}
42
43function compare_Object(callback, callback_is_async) {
44  return function(actual, input, test_obj) {
45    if (typeof actual === 'string')
46      assert_unreached(actual);
47    assert_true(actual instanceof Object, 'instanceof Object');
48    assert_false(actual instanceof Array, 'instanceof Array');
49    assert_not_equals(actual, input);
50    callback(actual, input);
51    if (test_obj && !callback_is_async)
52      test_obj.done();
53  }
54}
55
56function enumerate_props(compare_func, test_obj) {
57  return function(actual, input) {
58    for (const x in input) {
59      compare_func(actual[x], input[x], test_obj);
60    }
61  };
62}
63
64check('primitive undefined', undefined, compare_primitive);
65check('primitive null', null, compare_primitive);
66check('primitive true', true, compare_primitive);
67check('primitive false', false, compare_primitive);
68check('primitive string, empty string', '', compare_primitive);
69check('primitive string, lone high surrogate', '\uD800', compare_primitive);
70check('primitive string, lone low surrogate', '\uDC00', compare_primitive);
71check('primitive string, NUL', '\u0000', compare_primitive);
72check('primitive string, astral character', '\uDBFF\uDFFD', compare_primitive);
73check('primitive number, 0.2', 0.2, compare_primitive);
74check('primitive number, 0', 0, compare_primitive);
75check('primitive number, -0', -0, compare_primitive);
76check('primitive number, NaN', NaN, compare_primitive);
77check('primitive number, Infinity', Infinity, compare_primitive);
78check('primitive number, -Infinity', -Infinity, compare_primitive);
79check('primitive number, 9007199254740992', 9007199254740992, compare_primitive);
80check('primitive number, -9007199254740992', -9007199254740992, compare_primitive);
81check('primitive number, 9007199254740994', 9007199254740994, compare_primitive);
82check('primitive number, -9007199254740994', -9007199254740994, compare_primitive);
83check('primitive BigInt, 0n', 0n, compare_primitive);
84check('primitive BigInt, -0n', -0n, compare_primitive);
85check('primitive BigInt, -9007199254740994000n', -9007199254740994000n, compare_primitive);
86check('primitive BigInt, -9007199254740994000900719925474099400090071992547409940009007199254740994000n', -9007199254740994000900719925474099400090071992547409940009007199254740994000n, compare_primitive);
87
88check('Array primitives', [undefined,
89                           null,
90                           true,
91                           false,
92                           '',
93                           '\uD800',
94                           '\uDC00',
95                           '\u0000',
96                           '\uDBFF\uDFFD',
97                           0.2,
98                           0,
99                           -0,
100                           NaN,
101                           Infinity,
102                           -Infinity,
103                           9007199254740992,
104                           -9007199254740992,
105                           9007199254740994,
106                           -9007199254740994,
107                           -12n,
108                           -0n,
109                           0n], compare_Array(enumerate_props(compare_primitive)));
110check('Object primitives', {'undefined':undefined,
111                           'null':null,
112                           'true':true,
113                           'false':false,
114                           'empty':'',
115                           'high surrogate':'\uD800',
116                           'low surrogate':'\uDC00',
117                           'nul':'\u0000',
118                           'astral':'\uDBFF\uDFFD',
119                           '0.2':0.2,
120                           '0':0,
121                           '-0':-0,
122                           'NaN':NaN,
123                           'Infinity':Infinity,
124                           '-Infinity':-Infinity,
125                           '9007199254740992':9007199254740992,
126                           '-9007199254740992':-9007199254740992,
127                           '9007199254740994':9007199254740994,
128                           '-9007199254740994':-9007199254740994}, compare_Object(enumerate_props(compare_primitive)));
129
130function compare_Boolean(actual, input, test_obj) {
131  if (typeof actual === 'string')
132    assert_unreached(actual);
133  assert_true(actual instanceof Boolean, 'instanceof Boolean');
134  assert_equals(String(actual), String(input), 'converted to primitive');
135  assert_not_equals(actual, input);
136  if (test_obj)
137    test_obj.done();
138}
139check('Boolean true', new Boolean(true), compare_Boolean);
140check('Boolean false', new Boolean(false), compare_Boolean);
141check('Array Boolean objects', [new Boolean(true), new Boolean(false)], compare_Array(enumerate_props(compare_Boolean)));
142check('Object Boolean objects', {'true':new Boolean(true), 'false':new Boolean(false)}, compare_Object(enumerate_props(compare_Boolean)));
143
144function compare_obj(what) {
145  const Type = self[what];
146  return function(actual, input, test_obj) {
147    if (typeof actual === 'string')
148      assert_unreached(actual);
149    assert_true(actual instanceof Type, 'instanceof '+what);
150    assert_equals(Type(actual), Type(input), 'converted to primitive');
151    assert_not_equals(actual, input);
152    if (test_obj)
153      test_obj.done();
154  };
155}
156check('String empty string', new String(''), compare_obj('String'));
157check('String lone high surrogate', new String('\uD800'), compare_obj('String'));
158check('String lone low surrogate', new String('\uDC00'), compare_obj('String'));
159check('String NUL', new String('\u0000'), compare_obj('String'));
160check('String astral character', new String('\uDBFF\uDFFD'), compare_obj('String'));
161check('Array String objects', [new String(''),
162                               new String('\uD800'),
163                               new String('\uDC00'),
164                               new String('\u0000'),
165                               new String('\uDBFF\uDFFD')], compare_Array(enumerate_props(compare_obj('String'))));
166check('Object String objects', {'empty':new String(''),
167                               'high surrogate':new String('\uD800'),
168                               'low surrogate':new String('\uDC00'),
169                               'nul':new String('\u0000'),
170                               'astral':new String('\uDBFF\uDFFD')}, compare_Object(enumerate_props(compare_obj('String'))));
171
172check('Number 0.2', new Number(0.2), compare_obj('Number'));
173check('Number 0', new Number(0), compare_obj('Number'));
174check('Number -0', new Number(-0), compare_obj('Number'));
175check('Number NaN', new Number(NaN), compare_obj('Number'));
176check('Number Infinity', new Number(Infinity), compare_obj('Number'));
177check('Number -Infinity', new Number(-Infinity), compare_obj('Number'));
178check('Number 9007199254740992', new Number(9007199254740992), compare_obj('Number'));
179check('Number -9007199254740992', new Number(-9007199254740992), compare_obj('Number'));
180check('Number 9007199254740994', new Number(9007199254740994), compare_obj('Number'));
181check('Number -9007199254740994', new Number(-9007199254740994), compare_obj('Number'));
182// BigInt does not have a non-throwing constructor
183check('BigInt -9007199254740994n', Object(-9007199254740994n), compare_obj('BigInt'));
184
185check('Array Number objects', [new Number(0.2),
186                               new Number(0),
187                               new Number(-0),
188                               new Number(NaN),
189                               new Number(Infinity),
190                               new Number(-Infinity),
191                               new Number(9007199254740992),
192                               new Number(-9007199254740992),
193                               new Number(9007199254740994),
194                               new Number(-9007199254740994)], compare_Array(enumerate_props(compare_obj('Number'))));
195check('Object Number objects', {'0.2':new Number(0.2),
196                               '0':new Number(0),
197                               '-0':new Number(-0),
198                               'NaN':new Number(NaN),
199                               'Infinity':new Number(Infinity),
200                               '-Infinity':new Number(-Infinity),
201                               '9007199254740992':new Number(9007199254740992),
202                               '-9007199254740992':new Number(-9007199254740992),
203                               '9007199254740994':new Number(9007199254740994),
204                               '-9007199254740994':new Number(-9007199254740994)}, compare_Object(enumerate_props(compare_obj('Number'))));
205
206function compare_Date(actual, input, test_obj) {
207  if (typeof actual === 'string')
208    assert_unreached(actual);
209  assert_true(actual instanceof Date, 'instanceof Date');
210  assert_equals(Number(actual), Number(input), 'converted to primitive');
211  assert_not_equals(actual, input);
212  if (test_obj)
213    test_obj.done();
214}
215check('Date 0', new Date(0), compare_Date);
216check('Date -0', new Date(-0), compare_Date);
217check('Date -8.64e15', new Date(-8.64e15), compare_Date);
218check('Date 8.64e15', new Date(8.64e15), compare_Date);
219check('Array Date objects', [new Date(0),
220                             new Date(-0),
221                             new Date(-8.64e15),
222                             new Date(8.64e15)], compare_Array(enumerate_props(compare_Date)));
223check('Object Date objects', {'0':new Date(0),
224                              '-0':new Date(-0),
225                              '-8.64e15':new Date(-8.64e15),
226                              '8.64e15':new Date(8.64e15)}, compare_Object(enumerate_props(compare_Date)));
227
228function compare_RegExp(expected_source) {
229  // XXX ES6 spec doesn't define exact serialization for `source` (it allows several ways to escape)
230  return function(actual, input, test_obj) {
231    if (typeof actual === 'string')
232      assert_unreached(actual);
233    assert_true(actual instanceof RegExp, 'instanceof RegExp');
234    assert_equals(actual.global, input.global, 'global');
235    assert_equals(actual.ignoreCase, input.ignoreCase, 'ignoreCase');
236    assert_equals(actual.multiline, input.multiline, 'multiline');
237    assert_equals(actual.source, expected_source, 'source');
238    assert_equals(actual.sticky, input.sticky, 'sticky');
239    assert_equals(actual.unicode, input.unicode, 'unicode');
240    assert_equals(actual.lastIndex, 0, 'lastIndex');
241    assert_not_equals(actual, input);
242    if (test_obj)
243      test_obj.done();
244  }
245}
246function func_RegExp_flags_lastIndex() {
247  const r = /foo/gim;
248  r.lastIndex = 2;
249  return r;
250}
251function func_RegExp_sticky() {
252  return new RegExp('foo', 'y');
253}
254function func_RegExp_unicode() {
255  return new RegExp('foo', 'u');
256}
257check('RegExp flags and lastIndex', func_RegExp_flags_lastIndex, compare_RegExp('foo'));
258check('RegExp sticky flag', func_RegExp_sticky, compare_RegExp('foo'));
259check('RegExp unicode flag', func_RegExp_unicode, compare_RegExp('foo'));
260check('RegExp empty', new RegExp(''), compare_RegExp('(?:)'));
261check('RegExp slash', new RegExp('/'), compare_RegExp('\\/'));
262check('RegExp new line', new RegExp('\n'), compare_RegExp('\\n'));
263check('Array RegExp object, RegExp flags and lastIndex', [func_RegExp_flags_lastIndex()], compare_Array(enumerate_props(compare_RegExp('foo'))));
264check('Array RegExp object, RegExp sticky flag', function() { return [func_RegExp_sticky()]; }, compare_Array(enumerate_props(compare_RegExp('foo'))));
265check('Array RegExp object, RegExp unicode flag', function() { return [func_RegExp_unicode()]; }, compare_Array(enumerate_props(compare_RegExp('foo'))));
266check('Array RegExp object, RegExp empty', [new RegExp('')], compare_Array(enumerate_props(compare_RegExp('(?:)'))));
267check('Array RegExp object, RegExp slash', [new RegExp('/')], compare_Array(enumerate_props(compare_RegExp('\\/'))));
268check('Array RegExp object, RegExp new line', [new RegExp('\n')], compare_Array(enumerate_props(compare_RegExp('\\n'))));
269check('Object RegExp object, RegExp flags and lastIndex', {'x':func_RegExp_flags_lastIndex()}, compare_Object(enumerate_props(compare_RegExp('foo'))));
270check('Object RegExp object, RegExp sticky flag', function() { return {'x':func_RegExp_sticky()}; }, compare_Object(enumerate_props(compare_RegExp('foo'))));
271check('Object RegExp object, RegExp unicode flag', function() { return {'x':func_RegExp_unicode()}; }, compare_Object(enumerate_props(compare_RegExp('foo'))));
272check('Object RegExp object, RegExp empty', {'x':new RegExp('')}, compare_Object(enumerate_props(compare_RegExp('(?:)'))));
273check('Object RegExp object, RegExp slash', {'x':new RegExp('/')}, compare_Object(enumerate_props(compare_RegExp('\\/'))));
274check('Object RegExp object, RegExp new line', {'x':new RegExp('\n')}, compare_Object(enumerate_props(compare_RegExp('\\n'))));
275
276async function compare_Blob(actual, input, test_obj, expect_File) {
277  if (typeof actual === 'string')
278    assert_unreached(actual);
279  assert_true(actual instanceof Blob, 'instanceof Blob');
280  if (!expect_File)
281    assert_false(actual instanceof File, 'instanceof File');
282  assert_equals(actual.size, input.size, 'size');
283  assert_equals(actual.type, input.type, 'type');
284  assert_not_equals(actual, input);
285  const ab1 = await new Response(actual).arrayBuffer();
286  const ab2 = await new Response(input).arrayBuffer();
287  assert_equals(ab1.byteLength, ab2.byteLength, 'byteLength');
288  const ta1 = new Uint8Array(ab1);
289  const ta2 = new Uint8Array(ab2);
290  for(let i = 0; i < ta1.size; i++) {
291    assert_equals(ta1[i], ta2[i]);
292  }
293}
294function func_Blob_basic() {
295  return new Blob(['foo'], {type:'text/x-bar'});
296}
297check('Blob basic', func_Blob_basic, compare_Blob);
298
299function b(str) {
300  return parseInt(str, 2);
301}
302function encode_cesu8(codeunits) {
303  // http://www.unicode.org/reports/tr26/ section 2.2
304  // only the 3-byte form is supported
305  const rv = [];
306  codeunits.forEach(function(codeunit) {
307    rv.push(b('11100000') + ((codeunit & b('1111000000000000')) >> 12));
308    rv.push(b('10000000') + ((codeunit & b('0000111111000000')) >> 6));
309    rv.push(b('10000000') +  (codeunit & b('0000000000111111')));
310  });
311  return rv;
312}
313function func_Blob_bytes(arr) {
314  return function() {
315    const buffer = new ArrayBuffer(arr.length);
316    const view = new DataView(buffer);
317    for (let i = 0; i < arr.length; ++i) {
318      view.setUint8(i, arr[i]);
319    }
320    return new Blob([view]);
321  };
322}
323check('Blob unpaired high surrogate (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xD800])), compare_Blob);
324check('Blob unpaired low surrogate (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xDC00])), compare_Blob);
325check('Blob paired surrogates (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xD800, 0xDC00])), compare_Blob);
326
327function func_Blob_empty() {
328  return new Blob(['']);
329}
330check('Blob empty', func_Blob_empty , compare_Blob);
331function func_Blob_NUL() {
332  return new Blob(['\u0000']);
333}
334check('Blob NUL', func_Blob_NUL, compare_Blob);
335
336check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob), true));
337check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob), true));
338check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob), true));
339check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob), true));
340check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true));
341check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob), true));
342check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true));
343
344check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob), true));
345check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob), true));
346check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob), true));
347check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])()  }, compare_Object(enumerate_props(compare_Blob), true));
348check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob), true));
349check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob), true));
350
351function compare_File(actual, input, test_obj) {
352  assert_true(actual instanceof File, 'instanceof File');
353  assert_equals(actual.name, input.name, 'name');
354  assert_equals(actual.lastModified, input.lastModified, 'lastModified');
355  compare_Blob(actual, input, test_obj, true);
356}
357function func_File_basic() {
358  return new File(['foo'], 'bar', {type:'text/x-bar', lastModified:42});
359}
360check('File basic', func_File_basic, compare_File);
361
362function compare_FileList(actual, input, test_obj) {
363  if (typeof actual === 'string')
364    assert_unreached(actual);
365  assert_true(actual instanceof FileList, 'instanceof FileList');
366  assert_equals(actual.length, input.length, 'length');
367  assert_not_equals(actual, input);
368  // XXX when there's a way to populate or construct a FileList,
369  // check the items in the FileList
370  if (test_obj)
371    test_obj.done();
372}
373function func_FileList_empty() {
374  const input = document.createElement('input');
375  input.type = 'file';
376  return input.files;
377}
378check('FileList empty', func_FileList_empty, compare_FileList, true);
379check('Array FileList object, FileList empty', () => ([func_FileList_empty()]), compare_Array(enumerate_props(compare_FileList)), true);
380check('Object FileList object, FileList empty', () => ({'x':func_FileList_empty()}), compare_Object(enumerate_props(compare_FileList)), true);
381
382function compare_ArrayBufferView(view) {
383  const Type = self[view];
384  return function(actual, input, test_obj) {
385    if (typeof actual === 'string')
386      assert_unreached(actual);
387    assert_true(actual instanceof Type, 'instanceof '+view);
388    assert_equals(actual.length, input.length, 'length');
389    assert_not_equals(actual.buffer, input.buffer, 'buffer');
390    for (let i = 0; i < actual.length; ++i) {
391      assert_equals(actual[i], input[i], 'actual['+i+']');
392    }
393    if (test_obj)
394      test_obj.done();
395  };
396}
397function compare_ImageData(actual, input, test_obj) {
398  if (typeof actual === 'string')
399    assert_unreached(actual);
400  assert_equals(actual.width, input.width, 'width');
401  assert_equals(actual.height, input.height, 'height');
402  assert_not_equals(actual.data, input.data, 'data');
403  compare_ArrayBufferView('Uint8ClampedArray')(actual.data, input.data, null);
404  if (test_obj)
405    test_obj.done();
406}
407function func_ImageData_1x1_transparent_black() {
408  const canvas = document.createElement('canvas');
409  const ctx = canvas.getContext('2d');
410  return ctx.createImageData(1, 1);
411}
412check('ImageData 1x1 transparent black', func_ImageData_1x1_transparent_black, compare_ImageData, true);
413function func_ImageData_1x1_non_transparent_non_black() {
414  const canvas = document.createElement('canvas');
415  const ctx = canvas.getContext('2d');
416  const imagedata = ctx.createImageData(1, 1);
417  imagedata.data[0] = 100;
418  imagedata.data[1] = 101;
419  imagedata.data[2] = 102;
420  imagedata.data[3] = 103;
421  return imagedata;
422}
423check('ImageData 1x1 non-transparent non-black', func_ImageData_1x1_non_transparent_non_black, compare_ImageData, true);
424check('Array ImageData object, ImageData 1x1 transparent black', () => ([func_ImageData_1x1_transparent_black()]), compare_Array(enumerate_props(compare_ImageData)), true);
425check('Array ImageData object, ImageData 1x1 non-transparent non-black', () => ([func_ImageData_1x1_non_transparent_non_black()]), compare_Array(enumerate_props(compare_ImageData)), true);
426check('Object ImageData object, ImageData 1x1 transparent black', () => ({'x':func_ImageData_1x1_transparent_black()}), compare_Object(enumerate_props(compare_ImageData)), true);
427check('Object ImageData object, ImageData 1x1 non-transparent non-black', () => ({'x':func_ImageData_1x1_non_transparent_non_black()}), compare_Object(enumerate_props(compare_ImageData)), true);
428
429
430check('Array sparse', new Array(10), compare_Array(enumerate_props(compare_primitive)));
431check('Array with non-index property', function() {
432  const rv = [];
433  rv.foo = 'bar';
434  return rv;
435}, compare_Array(enumerate_props(compare_primitive)));
436check('Object with index property and length', {'0':'foo', 'length':1}, compare_Object(enumerate_props(compare_primitive)));
437function check_circular_property(prop) {
438  return function(actual) {
439    assert_equals(actual[prop], actual);
440  };
441}
442check('Array with circular reference', function() {
443  const rv = [];
444  rv[0] = rv;
445  return rv;
446}, compare_Array(check_circular_property('0')));
447check('Object with circular reference', function() {
448  const rv = {};
449  rv['x'] = rv;
450  return rv;
451}, compare_Object(check_circular_property('x')));
452function check_identical_property_values(prop1, prop2) {
453  return function(actual) {
454    assert_equals(actual[prop1], actual[prop2]);
455  };
456}
457check('Array with identical property values', function() {
458  const obj = {}
459  return [obj, obj];
460}, compare_Array(check_identical_property_values('0', '1')));
461check('Object with identical property values', function() {
462  const obj = {}
463  return {'x':obj, 'y':obj};
464}, compare_Object(check_identical_property_values('x', 'y')));
465
466function check_absent_property(prop) {
467  return function(actual) {
468    assert_false(prop in actual);
469  };
470}
471check('Object with property on prototype', function() {
472  const Foo = function() {};
473  Foo.prototype = {'foo':'bar'};
474  return new Foo();
475}, compare_Object(check_absent_property('foo')));
476
477check('Object with non-enumerable property', function() {
478  const rv = {};
479  Object.defineProperty(rv, 'foo', {value:'bar', enumerable:false, writable:true, configurable:true});
480  return rv;
481}, compare_Object(check_absent_property('foo')));
482
483function check_writable_property(prop) {
484  return function(actual, input) {
485    assert_equals(actual[prop], input[prop]);
486    actual[prop] += ' baz';
487    assert_equals(actual[prop], input[prop] + ' baz');
488  };
489}
490check('Object with non-writable property', function() {
491  const rv = {};
492  Object.defineProperty(rv, 'foo', {value:'bar', enumerable:true, writable:false, configurable:true});
493  return rv;
494}, compare_Object(check_writable_property('foo')));
495
496function check_configurable_property(prop) {
497  return function(actual, input) {
498    assert_equals(actual[prop], input[prop]);
499    delete actual[prop];
500    assert_false('prop' in actual);
501  };
502}
503check('Object with non-configurable property', function() {
504  const rv = {};
505  Object.defineProperty(rv, 'foo', {value:'bar', enumerable:true, writable:true, configurable:false});
506  return rv;
507}, compare_Object(check_configurable_property('foo')));
508
509/* The tests below are inspired by @zcorpan’s work but got some
510more substantial changed due to their previous async setup */
511
512function get_canvas_1x1_transparent_black() {
513  const canvas = document.createElement('canvas');
514  canvas.width = 1;
515  canvas.height = 1;
516  return canvas;
517}
518
519function get_canvas_1x1_non_transparent_non_black() {
520  const canvas = document.createElement('canvas');
521  canvas.width = 1;
522  canvas.height = 1;
523  const ctx = canvas.getContext('2d');
524  const imagedata = ctx.getImageData(0, 0, 1, 1);
525  imagedata.data[0] = 100;
526  imagedata.data[1] = 101;
527  imagedata.data[2] = 102;
528  imagedata.data[3] = 103;
529  return canvas;
530}
531
532function compare_ImageBitmap(actual, input) {
533  if (typeof actual === 'string')
534    assert_unreached(actual);
535  assert_true(actual instanceof ImageBitmap, 'instanceof ImageBitmap');
536  assert_not_equals(actual, input);
537  // XXX paint the ImageBitmap on a canvas and check the data
538}
539
540structuredCloneBatteryOfTests.push({
541  description: 'ImageBitmap 1x1 transparent black',
542  async f(runner) {
543    const canvas = get_canvas_1x1_transparent_black();
544    const bm = await createImageBitmap(canvas);
545    const copy = await runner.structuredClone(bm);
546    compare_ImageBitmap(bm, copy);
547  },
548  requiresDocument: true
549});
550
551structuredCloneBatteryOfTests.push({
552  description: 'ImageBitmap 1x1 non-transparent non-black',
553  async f(runner) {
554    const canvas = get_canvas_1x1_non_transparent_non_black();
555    const bm = await createImageBitmap(canvas);
556    const copy = await runner.structuredClone(bm);
557    compare_ImageBitmap(bm, copy);
558  },
559  requiresDocument: true
560});
561
562structuredCloneBatteryOfTests.push({
563  description: 'Array ImageBitmap object, ImageBitmap 1x1 transparent black',
564  async f(runner) {
565    const canvas = get_canvas_1x1_transparent_black();
566    const bm = [await createImageBitmap(canvas)];
567    const copy = await runner.structuredClone(bm);
568    compare_Array(enumerate_props(compare_ImageBitmap))(bm, copy);
569  },
570  requiresDocument: true
571});
572
573structuredCloneBatteryOfTests.push({
574  description: 'Array ImageBitmap object, ImageBitmap 1x1 transparent non-black',
575  async f(runner) {
576    const canvas = get_canvas_1x1_non_transparent_non_black();
577    const bm = [await createImageBitmap(canvas)];
578    const copy = await runner.structuredClone(bm);
579    compare_Array(enumerate_props(compare_ImageBitmap))(bm, copy);
580  },
581  requiresDocument: true
582});
583
584structuredCloneBatteryOfTests.push({
585  description: 'Object ImageBitmap object, ImageBitmap 1x1 transparent black',
586  async f(runner) {
587    const canvas = get_canvas_1x1_transparent_black();
588    const bm = {x: await createImageBitmap(canvas)};
589    const copy = await runner.structuredClone(bm);
590    compare_Object(enumerate_props(compare_ImageBitmap))(bm, copy);
591  },
592  requiresDocument: true
593});
594
595structuredCloneBatteryOfTests.push({
596  description: 'Object ImageBitmap object, ImageBitmap 1x1 transparent non-black',
597  async f(runner) {
598    const canvas = get_canvas_1x1_non_transparent_non_black();
599    const bm = {x: await createImageBitmap(canvas)};
600    const copy = await runner.structuredClone(bm);
601    compare_Object(enumerate_props(compare_ImageBitmap))(bm, copy);
602  },
603  requiresDocument: true
604});
605
606check('ObjectPrototype must lose its exotic-ness when cloned',
607  () => Object.prototype,
608  (copy, original) => {
609    assert_not_equals(copy, original);
610    assert_true(copy instanceof Object);
611
612    const newProto = { some: 'proto' };
613    // Must not throw:
614    Object.setPrototypeOf(copy, newProto);
615
616    assert_equals(Object.getPrototypeOf(copy), newProto);
617  }
618);
619