char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
711e4d5
main
1use std:: cell:: Cell ; 2use std:: io; 3use std:: rc:: Rc ; 4 5use avril_core::{ Error , Extension , Op , Runtime , RuntimeOptions }; 6 7# [ test ] 8fn live_initializers_run_after_all_static_entries_and_keep_export_identity () { 9let native =Rc :: new ( Cell :: new ( 10 )); 10let read = native. clone (); 11let mut runtime =Runtime :: new ( RuntimeOptions { 12extensions : vec! [ 13Extension { 14name : "ext:consumer" , 15dependencies : & [ "ext:producer" ], 16ops : vec! [ Op :: new ( "setNative" , move |value : u32 |{ 17 native. set ( value); 18Ok ::< _ , io:: Error >(()) 19})], 20modules : & [( 21"ext:consumer/main.js" , 22r#" 23import {onRuntimeStart, startRuntime} from 'ext:core/bootstrap'; 24import {setNative} from 'ext:core/ops'; 25import {value} from 'ext:producer/main.js'; 26if (value.native !== undefined) throw Error('Early initialization'); 27await Promise.resolve(); 28events.push('static consumer'); 29setNative(42); 30globalThis.captured = value; 31globalThis.startAgain = startRuntime; 32globalThis.registerLate = () => onRuntimeStart(() => {}); 33onRuntimeStart(() => { 34if (value.native !== 42) throw Error('Stale native state'); 35events.push('live consumer'); 36}); 37"# , 38)], 39entry_point : Some ( "ext:consumer/main.js" ), 40}, 41Extension { 42name : "ext:producer" , 43dependencies : & [], 44ops : vec! [ Op :: new ( "readNative" , move |(): () |{ 45Ok ::< _ , io:: Error >( read. get ()) 46})], 47modules : & [( 48"ext:producer/main.js" , 49r#" 50import {onRuntimeStart} from 'ext:core/bootstrap'; 51import {readNative} from 'ext:core/ops'; 52globalThis.events = ['static producer']; 53export const value = {native: undefined}; 54onRuntimeStart(() => { 55value.native = readNative(); 56Object.freeze(value); 57events.push('live producer'); 58}); 59"# , 60)], 61entry_point : Some ( "ext:producer/main.js" ), 62}, 63], 64 ..Default :: default () 65}) 66. unwrap (); 67assert_eq! ( 68 runtime 69. execute_script ::< Vec < String >>( "events.js" , "events" ) 70. unwrap (), 71[ 72"static producer" , 73"static consumer" , 74"live producer" , 75"live consumer" 76], 77); 78 runtime 79. register_extension_module ( "test:producer" , "ext:producer/main.js" ) 80. unwrap (); 81 runtime 82. execute_script ::<()>( 83"identity.js" , 84r#" 85import('test:producer').then(({value}) => { 86if (value !== captured || value.native !== 42 || !Object.isFrozen(value)) { 87throw Error('Export identity or descriptors changed'); 88} 89}); 90for (const action of [startAgain, registerLate]) { 91try { action(); throw Error('Expected rejection'); } 92catch (error) { if (error.message !== 'Runtime already started') throw error; } 93} 94"# , 95) 96. unwrap (); 97 runtime. run_event_loop (). unwrap (); 98} 99 100# [ test ] 101fn failing_live_initializers_abort_construction_without_running_later_initializers () { 102let called =Rc :: new ( Cell :: new ( false )); 103let observed = called. clone (); 104let result =Runtime :: new ( RuntimeOptions { 105extensions : vec! [ Extension { 106name : "ext:test" , 107dependencies : & [], 108ops : vec! [ Op :: new ( "later" , move |(): () |{ 109 called. set ( true ); 110Ok ::< _ , io:: Error >(()) 111})], 112modules : & [( 113"ext:test/main.js" , 114r#" 115import {onRuntimeStart} from 'ext:core/bootstrap'; 116import {later} from 'ext:core/ops'; 117onRuntimeStart(() => { throw Error('failed live initialization'); }); 118onRuntimeStart(() => { later(); }); 119"# , 120)], 121entry_point : Some ( "ext:test/main.js" ), 122}], 123 ..Default :: default () 124}); 125assert! ( 126matches! ( result, Err ( Error :: JavaScript ( message)) if message. contains ( "failed live initialization" )) 127); 128assert! ( !observed. get ()); 129} 130 131# [ test ] 132fn live_initializers_cannot_escape_the_startup_boundary_with_promises () { 133let result =Runtime :: new ( RuntimeOptions { 134extensions : vec! [ Extension { 135name : "ext:test" , 136dependencies : & [], 137ops : vec! [], 138modules : & [( 139"ext:test/main.js" , 140r#" 141import {onRuntimeStart} from 'ext:core/bootstrap'; 142onRuntimeStart(async () => {}); 143"# , 144)], 145entry_point : Some ( "ext:test/main.js" ), 146}], 147 ..Default :: default () 148}); 149assert! ( 150matches! ( result, Err ( Error :: JavaScript ( message)) if message. contains ( "Runtime initializers must return undefined" )) 151); 152} 153 154# [ test ] 155fn live_initializers_ignore_poisoned_array_protocols () { 156let mut runtime =Runtime :: new ( RuntimeOptions { 157extensions : vec! [ Extension { 158name : "ext:test" , 159dependencies : & [], 160ops : vec! [], 161modules : & [( 162"ext:test/main.js" , 163r#" 164import {onRuntimeStart} from 'ext:core/bootstrap'; 165const push = Array.prototype.push; 166const iterator = Array.prototype[Symbol.iterator]; 167let initialized = 0; 168onRuntimeStart(function () { 169if (this !== undefined) throw Error('Leaked initializer receiver'); 170initialized++; 171}); 172const poison = () => { throw Error('Mutable array protocol'); }; 173Array.prototype.push = poison; 174Array.prototype[Symbol.iterator] = poison; 175onRuntimeStart(() => { 176Array.prototype.push = push; 177Array.prototype[Symbol.iterator] = iterator; 178globalThis.initialized = initialized; 179}); 180"# , 181)], 182entry_point : Some ( "ext:test/main.js" ), 183}], 184 ..Default :: default () 185}) 186. unwrap (); 187assert_eq! ( 188 runtime 189. execute_script ::< u32 >( "initialized.js" , "initialized" ) 190. unwrap (), 1911 192); 193}