feat: 添加数组和字符串的属性与方法支持,包括 length、push、pop、upper、lower、trim、contains、starts_with、ends_with、substring、replace 和 split
This commit is contained in:
@@ -1419,3 +1419,210 @@ fn error_trim_non_string() {
|
||||
let result = std::panic::catch_unwind(|| { eval_expr("trim(42)"); });
|
||||
assert!(result.is_err(), "Expected error for trim(42)");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Array properties & methods (dot notation)
|
||||
// =========================================================================
|
||||
|
||||
#[test]
|
||||
fn eval_array_length_property() {
|
||||
assert_num(&eval_expr("[1, 2, 3].length"), 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_empty_array_length() {
|
||||
assert_num(&eval_expr("[].length"), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_length_via_variable() {
|
||||
let interp = run("let arr = [10, 20, 30, 40]; let len = arr.length;");
|
||||
assert_num(&get_var(&interp, "len"), 4.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_push_method_returns_value() {
|
||||
let interp = run("let arr = [1, 2]; let result = arr.push(3);");
|
||||
assert_num(&get_var(&interp, "result"), 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_push_method_modifies_array() {
|
||||
let interp = run("let arr = [1, 2]; arr.push(3);");
|
||||
match get_var(&interp, "arr") {
|
||||
Value::Array(arr) => {
|
||||
let arr = arr.borrow();
|
||||
assert_eq!(arr.len(), 3);
|
||||
assert_num(&arr[2], 3.0);
|
||||
}
|
||||
v => panic!("Expected Array, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_push_method_chained() {
|
||||
// push returns the pushed value, so chaining .push().push() won't work
|
||||
// but push returns the pushed value, verify that independently
|
||||
let interp = run("let arr = []; let a = arr.push(1); let b = arr.push(2); let c = arr.push(3);");
|
||||
assert_num(&get_var(&interp, "a"), 1.0);
|
||||
assert_num(&get_var(&interp, "b"), 2.0);
|
||||
assert_num(&get_var(&interp, "c"), 3.0);
|
||||
match get_var(&interp, "arr") {
|
||||
Value::Array(arr) => {
|
||||
let arr = arr.borrow();
|
||||
assert_eq!(arr.len(), 3);
|
||||
}
|
||||
v => panic!("Expected Array, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_pop_method_returns_last() {
|
||||
assert_num(&eval_expr("[1, 2, 3].pop()"), 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_array_pop_method_modifies_array() {
|
||||
let interp = run("let arr = [1, 2, 3]; let popped = arr.pop();");
|
||||
assert_num(&get_var(&interp, "popped"), 3.0);
|
||||
match get_var(&interp, "arr") {
|
||||
Value::Array(arr) => {
|
||||
let arr = arr.borrow();
|
||||
assert_eq!(arr.len(), 2);
|
||||
}
|
||||
v => panic!("Expected Array, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_array_pop_empty() {
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
eval_expr("[].pop()");
|
||||
});
|
||||
assert!(result.is_err(), "Expected error for pop() on empty array");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_array_unknown_property() {
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
eval_expr("[1, 2].foo");
|
||||
});
|
||||
assert!(result.is_err(), "Expected error for unknown array property");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_non_array_push_method() {
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
eval_expr("42.push(1)");
|
||||
});
|
||||
assert!(result.is_err(), "Expected error for .push() on non-array");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// String properties & methods (dot notation)
|
||||
// =========================================================================
|
||||
|
||||
#[test]
|
||||
fn eval_string_length_property() {
|
||||
assert_num(&eval_expr("\"hello\".length"), 5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_empty_string_length() {
|
||||
assert_num(&eval_expr("\"\".length"), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_length_via_variable() {
|
||||
let interp = run("let s = \"hi there\"; let len = s.length;");
|
||||
assert_num(&get_var(&interp, "len"), 8.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_upper_method() {
|
||||
match eval_expr("\"hello\".upper()") {
|
||||
Value::String(s) => assert_eq!(s, "HELLO"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_lower_method() {
|
||||
match eval_expr("\"HELLO\".lower()") {
|
||||
Value::String(s) => assert_eq!(s, "hello"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_trim_method() {
|
||||
match eval_expr("\" hi \".trim()") {
|
||||
Value::String(s) => assert_eq!(s, "hi"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_contains_method_true() {
|
||||
assert_bool(&eval_expr("\"hello\".contains(\"ell\")"), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_contains_method_false() {
|
||||
assert_bool(&eval_expr("\"hello\".contains(\"xyz\")"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_starts_with_method() {
|
||||
assert_bool(&eval_expr("\"hello\".starts_with(\"he\")"), true);
|
||||
assert_bool(&eval_expr("\"hello\".starts_with(\"lo\")"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_ends_with_method() {
|
||||
assert_bool(&eval_expr("\"hello\".ends_with(\"lo\")"), true);
|
||||
assert_bool(&eval_expr("\"hello\".ends_with(\"he\")"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_substring_method() {
|
||||
match eval_expr("\"hello\".substring(1, 3)") {
|
||||
Value::String(s) => assert_eq!(s, "ell"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_replace_method() {
|
||||
match eval_expr("\"hello world\".replace(\"world\", \"aster\")") {
|
||||
Value::String(s) => assert_eq!(s, "hello aster"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_split_method() {
|
||||
match eval_expr("\"a,b,c\".split(\",\")") {
|
||||
Value::Array(arr) => {
|
||||
let arr = arr.borrow();
|
||||
assert_eq!(arr.len(), 3);
|
||||
}
|
||||
v => panic!("Expected Array, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_string_method_chaining() {
|
||||
match eval_expr("\" hello \".trim().upper()") {
|
||||
Value::String(s) => assert_eq!(s, "HELLO"),
|
||||
v => panic!("Expected String, got {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_string_unknown_property() {
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
eval_expr("\"hi\".foo");
|
||||
});
|
||||
assert!(result.is_err(), "Expected error for unknown string property");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user