use bao_engine::context::JsContext;
use mozjs::jsapi::OnNewGlobalHookOption;
use mozjs::jsval::UndefinedValue;
use mozjs::realm::AutoRealm;
use mozjs::rooted;
use mozjs::rust::wrappers2::{JS_DefineDebuggerObject, JS_NewGlobalObject};
use mozjs::rust::{SIMPLE_GLOBAL_CLASS, evaluate_script};
use mozjs::rust::CompileOptionsWrapper;
fn eval_bool_in_debugger_realm(
cx: &mut mozjs::context::JSContext,
source: &str,
filename: &str,
) -> bool {
let options = bun_sm::node_realm_options();
rooted!(&in(cx) let global = unsafe {
JS_NewGlobalObject(
cx,
&SIMPLE_GLOBAL_CLASS,
std::ptr::null_mut(),
OnNewGlobalHookOption::FireOnNewGlobalHook,
&*options,
)
});
assert!(
!global.get().is_null(),
"debugger-realm global creation must succeed"
);
let c_filename = std::ffi::CString::new(filename)
.unwrap_or_else(|_| std::ffi::CString::new("<debugger-native>").unwrap());
let compile_opts = CompileOptionsWrapper::new(cx, c_filename, 1);
rooted!(&in(cx) let mut rval = UndefinedValue());
{
let mut realm = AutoRealm::new_from_handle(cx, global.handle());
let defined = unsafe { JS_DefineDebuggerObject(&mut realm, global.handle()) };
assert!(
defined,
"JS_DefineDebuggerObject must succeed on the fresh realm global"
);
let realm_cx: &mut mozjs::context::JSContext = &mut realm;
let result = evaluate_script(
realm_cx,
global.handle(),
source,
rval.handle_mut(),
compile_opts,
);
assert!(
result.is_ok(),
"evaluating in debugger realm must not error: {:?}",
result.err()
);
}
let jsval = unsafe { bun_sm::value::jsval_to_jsvalue(cx.raw_cx_no_gc(), rval.get()) };
jsval
.as_bool()
.expect("script result must be a boolean === comparison")
}
#[test]
fn test_debugger_object_native_install() {
let ctx = JsContext::for_test().expect("Failed to create JsContext");
let mut cx = ctx.cx();
assert!(
eval_bool_in_debugger_realm(
&mut cx,
r#"typeof Debugger === "function""#,
"dbg_typeof.js",
),
"JS_DefineDebuggerObject must install a callable Debugger constructor"
);
assert!(
eval_bool_in_debugger_realm(
&mut cx,
r#"["onNewScript", "onDebuggerStatement", "onEnterFrame",
"onExceptionUnwind", "onPromiseSettled"]
.every(function(n) { return n in Debugger.prototype; })"#,
"dbg_hooks.js",
),
"Debugger.prototype must expose the onNewScript/onDebuggerStatement/\
onEnterFrame/onExceptionUnwind/onPromiseSettled hooks"
);
assert!(
eval_bool_in_debugger_realm(
&mut cx,
r#"(function() {
var d = new Debugger();
return typeof d.findScripts === "function"
&& typeof d.addDebuggee === "function"
&& typeof d.removeAllDebuggees === "function";
})()"#,
"dbg_instance.js",
),
"new Debugger() must be constructible with findScripts/addDebuggee/\
removeAllDebuggees methods"
);
bao_engine::context::JsContext::shutdown_thread_sm();
}