use avril_core::{Extension, Runtime, RuntimeOptions}; fn runtime() -> Runtime { Runtime::new(RuntimeOptions { extensions: vec![Extension { name: "ext:test", dependencies: &[], ops: vec![], modules: &[("ext:test/main.js", r#" import {clone} from 'ext:core/structured_clone'; const hosts=new WeakMap(); globalThis.hostCloneCount=0; globalThis.makeHost=value=>{const object={};hosts.set(object,value);return object;}; globalThis.hostValue=object=>hosts.get(object); const cloneHost=source=>{ if(hosts.get(source)==='fail')throw globalThis.reason; hostCloneCount++; return makeHost(hosts.get(source)); }; globalThis.cloneForTest=value=>clone(value,[],object=>hosts.has(object)?1:0,cloneHost,message=>new Error(message)); "#)], entry_point: Some("ext:test/main.js"), }], ..Default::default() }).unwrap() } #[test] fn native_clone_bridge_preserves_extension_host_identity_without_web_policy() { let mut runtime = runtime(); assert!(runtime.execute_script::("host graph",r#" const host=makeHost('value'), source={host,again:host};source.self=source; const copy=cloneForTest(source); copy!==source && copy.self===copy && copy.host===copy.again && copy.host!==host && hostValue(copy.host)==='value' && hostCloneCount===1 "#).unwrap()); } #[test] fn policy_and_getter_exceptions_preserve_identity_and_allow_reentrant_clones() { let mut runtime = runtime(); runtime .execute_script::<()>( "exceptions", r#" globalThis.reason={reason:true}; for(const source of [makeHost('fail'),{get x(){throw reason;}}]){ try{cloneForTest(source);throw Error('Accepted');}catch(e){if(e!==reason)throw e;} } "#, ) .unwrap(); assert!( runtime .execute_script::( "next turn", r#" const result=cloneForTest({get x(){return cloneForTest({value:3});}}); result.x.value===3 "# ) .unwrap() ); }