use bao_engine::context::JsContext;
use bao_engine::error::JsError;
use bao_engine::value::JsValue;
fn eval_string(ctx: &mut JsContext, source: &str) -> String {
match ctx.eval(source, "<test>") {
Ok(JsValue::String(s)) => s,
Ok(JsValue::Number(n)) => format!("{}", n),
Ok(JsValue::Bool(b)) => if b { "true" } else { "false" }.to_string(),
_ => String::new(),
}
}
fn eval_number(ctx: &mut JsContext, source: &str) -> f64 {
match ctx.eval(source, "<test>") {
Ok(JsValue::Number(n)) => n,
_ => f64::NAN,
}
}
unsafe fn install_test_globals(
cx: &mut mozjs::context::JSContext,
global: mozjs::rust::Handle<*mut mozjs::jsapi::JSObject>,
) {
bao_engine::host_fn::install_console(cx, global);
}
#[test]
fn test_bao_engine_core_all() {
let mut ctx = JsContext::for_test().expect("Failed to create JsContext");
ctx.set_global_setup(install_test_globals);
assert!(true, "JsContext created successfully");
let result = eval_number(&mut ctx, "1 + 2");
assert_eq!(result, 3.0, "1 + 2 should equal 3");
let result = eval_string(&mut ctx, "'hello' + ' ' + 'world'");
assert_eq!(result, "hello world");
match ctx.eval("true", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool(true), got: {:?}", other),
}
match ctx.eval("false", "<test>") {
Ok(JsValue::Bool(b)) => assert!(!b),
other => panic!("expected bool(false), got: {:?}", other),
}
match ctx.eval("1 === 1", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool(true) for 1===1, got: {:?}", other),
}
match ctx.eval("1 === 2", "<test>") {
Ok(JsValue::Bool(b)) => assert!(!b),
other => panic!("expected bool(false) for 1===2, got: {:?}", other),
}
match ctx.eval("undefined", "<test>") {
Ok(JsValue::Undefined) => {}
other => panic!("expected undefined, got: {:?}", other),
}
match ctx.eval("null", "<test>") {
Ok(JsValue::Null) => {}
other => panic!("expected null, got: {:?}", other),
}
match ctx.eval("({a: 1})", "<test>") {
Ok(JsValue::Object(_)) => {}
other => panic!("expected object, got: {:?}", other),
}
let result = ctx.eval("throw new Error('test error')", "<test>");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.message.contains("test error"),
"error message should contain 'test error', got: {}",
err.message
);
let result = ctx.eval("function(", "<test>");
assert!(result.is_err(), "syntax error should return Err");
assert_eq!(eval_number(&mut ctx, "10 / 3"), 10.0 / 3.0);
assert_eq!(eval_number(&mut ctx, "2 ** 10"), 1024.0);
assert_eq!(
eval_number(&mut ctx, "Math.PI > 3.14 && Math.PI < 3.15 ? 1 : 0"),
1.0
);
let result = eval_string(&mut ctx, "JSON.stringify({x: 1, y: [2, 3]})");
assert!(result.contains("\"x\":1"), "JSON: {}", result);
let result = eval_number(&mut ctx, "JSON.parse('{\"a\":42}').a");
assert_eq!(result, 42.0);
assert_eq!(
eval_string(&mut ctx, "[1,2,3].map(x => x * 2).join(',')"),
"2,4,6"
);
assert_eq!(
eval_number(&mut ctx, "[1,2,3,4,5].filter(x => x > 3).length"),
2.0
);
assert_eq!(
eval_number(&mut ctx, "[10,20,30].reduce((a,b) => a+b, 0)"),
60.0
);
assert_eq!(eval_string(&mut ctx, "'hello'.toUpperCase()"), "HELLO");
assert_eq!(eval_string(&mut ctx, "'HELLO'.toLowerCase()"), "hello");
assert_eq!(
eval_string(&mut ctx, "'abc'.split('').reverse().join('')"),
"cba"
);
match ctx.eval("typeof console === 'object'", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b, "console should be object"),
other => panic!("expected bool for console check, got: {:?}", other),
}
match ctx.eval("typeof console.log === 'function'", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool for console.log, got: {:?}", other),
}
match ctx.eval("typeof Promise === 'function'", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool for Promise, got: {:?}", other),
}
match ctx.eval("/hello/.test('hello world')", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool for regex test, got: {:?}", other),
}
assert_eq!(
eval_string(&mut ctx, "'abc123def'.replace(/\\d+/, 'NUM')"),
"abcNUMdef"
);
match ctx.eval("new Date().getTime() > 0", "<test>") {
Ok(JsValue::Bool(b)) => assert!(b),
other => panic!("expected bool for date, got: {:?}", other),
}
let result = eval_string(
&mut ctx,
r#"
var m = new Map();
m.set('key', 'val');
var s = new Set([1,2,3]);
m.get('key') + ',' + s.size
"#,
);
assert_eq!(result, "val,3");
let err = JsError {
message: "test".into(),
filename: "file.js".into(),
line: 10,
column: 5,
stack: Some("at file.js:10:5".into()),
};
assert_eq!(err.message, "test");
assert_eq!(err.filename, "file.js");
assert_eq!(err.line, 10);
assert_eq!(err.column, 5);
assert!(err.stack.is_some());
bao_engine::context::JsContext::shutdown_thread_sm();
}