char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somsnapshot: embed shared main and worker startup in the CLI688e96e

main
3.4 KiB72 linesraw
1mod common;
2
3#[test]
4fn self_messages_clone_synchronously_and_dispatch_in_fifo_tasks() {
5    let output = common::run(
6        r#"
7        const seen = [];
8        if (postMessage.name !== 'postMessage' || postMessage.length !== 1) throw Error('Function surface');
9        try {new postMessage(1); throw Error('Constructible postMessage');}
10        catch (error) {if (!(error instanceof TypeError)) throw error;}
11        onmessage = function (event) {
12            if (this !== self || event.target !== self || !event.isTrusted ||
13                !(event instanceof MessageEvent) || event.source !== null ||
14                event.origin !== '' || !Object.isFrozen(event.ports)) throw Error('Message event');
15            seen.push(event.data.value);
16            queueMicrotask(() => seen.push('microtask'));
17        };
18        const value = {value: 1};
19        postMessage(value);
20        value.value = 9;
21        postMessage({value: 2}, {});
22        queueMicrotask(() => seen.push('before'));
23        addEventListener('message', event => {
24            if (event.data.value === 2) {
25                if (seen.join() !== 'before,1,microtask,2') throw Error(seen.join());
26                console.log('self messages');
27            }
28        });
29        try { postMessage(() => {}); throw Error('Clone accepted'); }
30        catch (error) { if (error.name !== 'DataCloneError') throw error; }
31        try { postMessage(); throw Error('Missing argument'); }
32        catch (error) { if (!(error instanceof TypeError)) throw error; }
33    "#,
34        &[],
35    );
36    assert_eq!(output.stdout, b"self messages\n");
37}
38
39#[test]
40fn self_messages_transfer_buffers_ports_and_streams() {
41    let output = common::run(
42        r#"
43        const channel = new MessageChannel(), buffer = new Uint8Array([4, 5]).buffer;
44        const stream = new ReadableStream({start(controller) {controller.enqueue('stream'); controller.close();}});
45        const portPost = MessagePort.prototype.postMessage;
46        const answer = new Promise((resolve, reject) => {
47            onmessage = async event => {
48                try {
49                    if (event.data.port !== event.ports[0] || event.data.again !== event.data.port ||
50                        new Uint8Array(event.data.buffer).join() !== '4,5') throw Error('Transfer graph');
51                    const reply = new Promise(resolve => channel.port1.onmessage = e => resolve(e.data));
52                    portPost.call(event.data.port, 'reply');
53                    if (await reply !== 'reply' || (await event.data.stream.getReader().read()).value !== 'stream') throw Error('Transferred value');
54                    event.data.port.close(); channel.port1.close();
55                    resolve();
56                } catch (error) {reject(error);}
57            };
58        });
59        const post = postMessage;
60        globalThis.structuredClone = () => {throw Error('Guest clone');};
61        MessagePort.prototype.postMessage = () => {throw Error('Guest port');};
62        post({buffer, port: channel.port2, again: channel.port2, stream}, {transfer: [buffer, channel.port2, stream]});
63        if (buffer.byteLength !== 0 || !stream.locked) throw Error('Transfer not synchronous');
64        await answer;
65        onmessage = null;
66        if (onmessage !== null || onmessageerror !== null) throw Error('Handlers');
67        console.log('transfers');
68    "#,
69        &[],
70    );
71    assert_eq!(output.stdout, b"transfers\n");
72}