#![allow(clippy::result_large_err)]
#![allow(dead_code)]
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::rc::Rc;
use qlexpress::class_supplier::ClassSupplier;
use qlexpress::exception::error_codes;
use qlexpress::exception::ql_exception::{QLException, QLExceptionKind};
use qlexpress::init_options::InitOptions;
use qlexpress::ql_options::QLOptions;
use qlexpress::runtime::class_ref::ClassRef;
use qlexpress::runtime::native_object::NativeObject;
use qlexpress::runtime::native_type::{NativeConstructorCandidate, NativeType};
use qlexpress::runtime::opaque_native_object::OpaqueNativeObject;
use qlexpress::runtime::parameters::Parameters;
use qlexpress::runtime::qcontext::QContext;
use qlexpress::runtime::value::DataValue;
use qlexpress::security::ql_security_strategy::QLSecurityStrategy;
use qlexpress::Express4Runner;
pub struct JdkClassSupplier;
const JDK_CLASSES: &[(&str, &str)] = &[
("java.lang", "String"),
("java.lang", "Object"),
("java.lang", "Integer"),
("java.lang", "Long"),
("java.lang", "Double"),
("java.lang", "Float"),
("java.lang", "Short"),
("java.lang", "Byte"),
("java.lang", "Character"),
("java.lang", "Boolean"),
("java.lang", "Number"),
("java.lang", "Math"),
("java.lang", "StringBuilder"),
("java.lang", "StringBuffer"),
("java.lang", "Exception"),
("java.lang", "RuntimeException"),
("java.lang", "NullPointerException"),
("java.lang", "IllegalArgumentException"),
("java.lang", "IllegalStateException"),
("java.lang", "ClassCastException"),
("java.lang", "ArithmeticException"),
("java.lang", "IndexOutOfBoundsException"),
("java.lang", "ArrayIndexOutOfBoundsException"),
("java.lang", "UnsupportedOperationException"),
("java.lang", "Comparable"),
("java.lang", "Runnable"),
("java.io", "Serializable"),
("java.math", "BigDecimal"),
("java.math", "BigInteger"),
("java.util", "List"),
("java.util", "ArrayList"),
("java.util", "LinkedList"),
("java.util", "Map"),
("java.util", "HashMap"),
("java.util", "LinkedHashMap"),
("java.util", "TreeMap"),
("java.util", "Set"),
("java.util", "HashSet"),
("java.util", "LinkedHashSet"),
("java.util", "Arrays"),
("java.util", "Objects"),
("java.util", "Collections"),
("java.util", "Date"),
("java.util.stream", "Collectors"),
("java.util.stream", "Stream"),
("java.util.function", "Supplier"),
("java.util.function", "Consumer"),
("java.util.function", "Function"),
("java.util.function", "Predicate"),
("com.alibaba.qlexpress4.inport", "Person"),
("com.alibaba.qlexpress4.inport", "Sample"),
("com.alibaba.qlexpress4.inport", "Sample1"),
("com.alibaba.qlexpress4.inport", "MyHome"),
("com.alibaba.qlexpress4.inport", "MyDesk"),
(
"com.alibaba.qlexpress4.test.constructor",
"HelloConstructor",
),
("com.alibaba.qlexpress4.test.constructor", "HelloParent"),
("com.alibaba.qlexpress4.test.constructor", "HelloChild"),
(
"com.alibaba.qlexpress4.test.lambda",
"UserFunctionalInterface",
),
("com.alibaba.qlexpress4.test.property", "Sample"),
("com.alibaba.qlexpress4.test.property", "SampleEnum"),
("com.alibaba.qlexpress4.test.property", "SomeInter"),
("com.alibaba.qlexpress4.test.property", "Parent"),
("com.alibaba.qlexpress4.test.property", "SampleSet"),
("com.alibaba.qlexpress4.test.property", "SampleForPrivate"),
("com.alibaba.qlexpress4.test.property", "TestEnum"),
("com.alibaba.qlexpress4.test.method", "TestChild"),
("com.alibaba.qlexpress4.test.method", "TestParent"),
("com.alibaba.qlexpress4.test.method", "InterWithDefault"),
("com.alibaba.qlexpress4.test.stream", "STObject"),
("com.alibaba.fastjson2", "JSON"),
("com.alibaba.fastjson2", "JSONObject"),
];
impl ClassSupplier for JdkClassSupplier {
fn load_cls(&self, qualified_name: &str) -> Option<String> {
let (pack, simple) = qualified_name.rsplit_once('.')?;
if JDK_CLASSES.contains(&(pack, simple)) {
Some(qualified_name.to_string())
} else {
None
}
}
}
pub fn jdk_init_options() -> InitOptions {
InitOptions::builder()
.class_supplier(Rc::new(JdkClassSupplier))
.security_strategy(QLSecurityStrategy::open())
.build()
}
pub fn jdk_init_options_with_private_access() -> InitOptions {
InitOptions::builder()
.class_supplier(Rc::new(JdkClassSupplier))
.security_strategy(QLSecurityStrategy::open())
.allow_private_access(true)
.build()
}
pub fn biz_error(message: impl Into<String>) -> QLException {
QLException::for_test(
QLExceptionKind::Runtime,
message.into(),
error_codes::BIZ_EXCEPTION,
)
}
fn wrap_assert_message(q_context: &dyn QContext, message: &str) -> String {
let test_path = q_context
.attachment()
.get("TEST_PATH")
.map(DataValue::string_value_of)
.unwrap_or_else(|| "null".to_string());
format!("{test_path}: {message}")
}
fn assert_function(ctx: &mut dyn QContext, params: &Parameters) -> Result<DataValue, QLException> {
match params.size() {
1 => match params.get_value(0) {
DataValue::Bool(true) => Ok(DataValue::Null),
_ => Err(biz_error(wrap_assert_message(ctx, "assert fail"))),
},
2 => match params.get_value(0) {
DataValue::Bool(true) => Ok(DataValue::Null),
_ => match params.get_value(1) {
DataValue::Str(msg) => {
Err(biz_error(wrap_assert_message(ctx, &msg.to_string_lossy())))
}
_ => Err(biz_error(wrap_assert_message(ctx, "assert fail"))),
},
},
n => Err(biz_error(format!("invalid parameter size: {n}"))),
}
}
fn assert_false_function(
ctx: &mut dyn QContext,
params: &Parameters,
) -> Result<DataValue, QLException> {
match params.size() {
1 => match params.get_value(0) {
DataValue::Bool(false) => Ok(DataValue::Null),
_ => Err(biz_error(wrap_assert_message(ctx, "assert fail"))),
},
2 => match params.get_value(0) {
DataValue::Bool(false) => Ok(DataValue::Null),
_ => match params.get_value(1) {
DataValue::Str(msg) => {
Err(biz_error(wrap_assert_message(ctx, &msg.to_string_lossy())))
}
_ => Err(biz_error(wrap_assert_message(ctx, "assert fail"))),
},
},
n => Err(biz_error(format!("invalid parameter size: {n}"))),
}
}
fn assert_error_code_function(
_ctx: &mut dyn QContext,
params: &Parameters,
) -> Result<DataValue, QLException> {
if params.size() != 2 {
return Err(biz_error(format!(
"invalid pSize:{}, expected 2 parameters",
params.size()
)));
}
let lambda = match params.get_value(0) {
DataValue::Lambda(lambda) => lambda,
other => {
return Err(biz_error(format!(
"assertErrorCode 第一个参数必须是 lambda,实际为 {other:?}"
)))
}
};
let expected_code = match params.get_value(1) {
DataValue::Str(code) => code,
other => {
return Err(biz_error(format!(
"assertErrorCode 第二个参数必须是字符串错误码,实际为 {other:?}"
)))
}
};
match lambda.call(&[]) {
Ok(_) => Err(biz_error(format!(
"expect error codes:{expected_code}, but end normally"
))),
Err(err) if expected_code.as_str() == Some(err.error_code()) => Ok(DataValue::Null),
Err(err) => Err(biz_error(format!(
"expect error code {expected_code}, but got {}: {}",
err.error_code(),
err.reason()
))),
}
}
fn print_function(_ctx: &mut dyn QContext, _params: &Parameters) -> Result<DataValue, QLException> {
Ok(DataValue::Null)
}
include!("native_objects.rs");
include!("suite_runner.rs");
pub fn run_script(script: &str) -> Result<DataValue, QLException> {
suite_runner()
.execute(script, HashMap::new(), &QLOptions::builder().build())
.map(|r| r.into_result())
}
pub fn run_script_with(script: &str, options: &QLOptions) -> Result<DataValue, QLException> {
suite_runner()
.execute(script, HashMap::new(), options)
.map(|r| r.into_result())
}
pub fn expect_ok(script: &str) -> DataValue {
run_script(script).unwrap_or_else(|err| panic!("脚本应执行成功但失败: {err:?}"))
}
pub fn expect_null(script: &str) {
let value = expect_ok(script);
assert!(
value.is_null(),
"脚本应返回 null(noReturn),实际为 {value:?}"
);
}
pub fn expect_err_code(script: &str, expected_code: &str) {
match run_script(script) {
Ok(value) => panic!("期望错误码 {expected_code},但脚本正常结束: {value:?}"),
Err(err) => assert_eq!(
err.error_code(),
expected_code,
"错误码不一致,实际错误: {err:?}"
),
}
}
pub fn expect_err_code_with(script: &str, options: &QLOptions, expected_code: &str) {
match run_script_with(script, options) {
Ok(value) => panic!("期望错误码 {expected_code},但脚本正常结束: {value:?}"),
Err(err) => assert_eq!(
err.error_code(),
expected_code,
"错误码不一致,实际错误: {err:?}"
),
}
}
pub fn expect_ok_with(script: &str, options: &QLOptions) -> DataValue {
run_script_with(script, options).unwrap_or_else(|err| panic!("脚本应执行成功但失败: {err:?}"))
}