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