mod common; #[test] fn self_messages_clone_synchronously_and_dispatch_in_fifo_tasks() { let output = common::run( r#" const seen = []; if (postMessage.name !== 'postMessage' || postMessage.length !== 1) throw Error('Function surface'); try {new postMessage(1); throw Error('Constructible postMessage');} catch (error) {if (!(error instanceof TypeError)) throw error;} onmessage = function (event) { if (this !== self || event.target !== self || !event.isTrusted || !(event instanceof MessageEvent) || event.source !== null || event.origin !== '' || !Object.isFrozen(event.ports)) throw Error('Message event'); seen.push(event.data.value); queueMicrotask(() => seen.push('microtask')); }; const value = {value: 1}; postMessage(value); value.value = 9; postMessage({value: 2}, {}); queueMicrotask(() => seen.push('before')); addEventListener('message', event => { if (event.data.value === 2) { if (seen.join() !== 'before,1,microtask,2') throw Error(seen.join()); console.log('self messages'); } }); try { postMessage(() => {}); throw Error('Clone accepted'); } catch (error) { if (error.name !== 'DataCloneError') throw error; } try { postMessage(); throw Error('Missing argument'); } catch (error) { if (!(error instanceof TypeError)) throw error; } "#, &[], ); assert_eq!(output.stdout, b"self messages\n"); } #[test] fn self_messages_transfer_buffers_ports_and_streams() { let output = common::run( r#" const channel = new MessageChannel(), buffer = new Uint8Array([4, 5]).buffer; const stream = new ReadableStream({start(controller) {controller.enqueue('stream'); controller.close();}}); const portPost = MessagePort.prototype.postMessage; const answer = new Promise((resolve, reject) => { onmessage = async event => { try { if (event.data.port !== event.ports[0] || event.data.again !== event.data.port || new Uint8Array(event.data.buffer).join() !== '4,5') throw Error('Transfer graph'); const reply = new Promise(resolve => channel.port1.onmessage = e => resolve(e.data)); portPost.call(event.data.port, 'reply'); if (await reply !== 'reply' || (await event.data.stream.getReader().read()).value !== 'stream') throw Error('Transferred value'); event.data.port.close(); channel.port1.close(); resolve(); } catch (error) {reject(error);} }; }); const post = postMessage; globalThis.structuredClone = () => {throw Error('Guest clone');}; MessagePort.prototype.postMessage = () => {throw Error('Guest port');}; post({buffer, port: channel.port2, again: channel.port2, stream}, {transfer: [buffer, channel.port2, stream]}); if (buffer.byteLength !== 0 || !stream.locked) throw Error('Transfer not synchronous'); await answer; onmessage = null; if (onmessage !== null || onmessageerror !== null) throw Error('Handlers'); console.log('transfers'); "#, &[], ); assert_eq!(output.stdout, b"transfers\n"); }