rhai/tests/maps.rs

328 lines
7.7 KiB
Rust
Raw Normal View History

2020-03-29 17:53:35 +02:00
#![cfg(not(feature = "no_object"))]
use rhai::{Engine, EvalAltResult, Map, ParseErrorType, Scope, INT};
2020-03-29 17:53:35 +02:00
#[test]
fn test_map_indexing() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
2020-03-29 17:53:35 +02:00
2020-03-30 11:40:26 +02:00
#[cfg(not(feature = "no_index"))]
{
assert_eq!(
engine.eval::<INT>(r#"let x = #{a: 1, b: 2, c: 3}; x["b"]"#)?,
2
);
2020-06-16 16:14:46 +02:00
assert_eq!(
engine.eval::<INT>(r#"let x = #{a: 1, b: 2, c: 3,}; x["b"]"#)?,
2
);
assert_eq!(
engine.eval::<char>(
r#"
let y = #{d: 1, "e": #{a: 42, b: 88, "": "hello"}, " 123 xyz": 9};
y.e[""][4]
2020-07-09 13:54:28 +02:00
"#
)?,
'o'
);
assert_eq!(
engine.eval::<String>(r#"let a = [#{s:"hello"}]; a[0].s[2] = 'X'; a[0].s"#)?,
"heXlo"
);
}
2020-03-30 11:40:26 +02:00
2020-03-29 17:53:35 +02:00
assert_eq!(
2020-03-30 11:40:26 +02:00
engine.eval::<INT>("let y = #{a: 1, b: 2, c: 3}; y.a = 5; y.a")?,
2020-03-29 17:53:35 +02:00
5
);
2022-01-10 06:26:33 +01:00
engine.run("let y = #{a: 1, b: 2, c: 3}; y.z")?;
2020-03-29 17:53:35 +02:00
2021-04-05 12:32:20 +02:00
#[cfg(not(feature = "no_index"))]
assert_eq!(
2021-04-05 12:32:20 +02:00
engine.eval::<INT>(
r#"
let y = #{`a
b`: 1}; y["a\nb"]
"#
)?,
1
);
assert!(matches!(
*engine
.eval::<INT>("let y = #{`a${1}`: 1}; y.a1")
2023-04-10 17:23:59 +02:00
.unwrap_err(),
2022-02-08 02:02:15 +01:00
EvalAltResult::ErrorParsing(ParseErrorType::PropertyExpected, ..)
));
2020-04-06 11:47:34 +02:00
assert!(engine.eval::<bool>(r#"let y = #{a: 1, b: 2, c: 3}; "c" in y"#)?);
assert!(engine.eval::<bool>(r#"let y = #{a: 1, b: 2, c: 3}; "b" in y"#)?);
2020-04-06 11:47:34 +02:00
assert!(!engine.eval::<bool>(r#"let y = #{a: 1, b: 2, c: 3}; "z" in y"#)?);
2020-04-10 15:59:29 +02:00
assert_eq!(
engine.eval::<INT>(
r#"
let x = #{a: 1, b: 2, c: 3};
let c = x.remove("c");
x.len() + c
2020-07-09 13:54:28 +02:00
"#
2020-04-10 15:59:29 +02:00
)?,
5
);
assert_eq!(
engine.eval::<INT>(
2021-04-20 06:01:35 +02:00
"
let x = #{a: 1, b: 2, c: 3};
let y = #{b: 42, d: 9};
x.mixin(y);
x.len() + x.b
2020-07-09 13:54:28 +02:00
"
)?,
46
);
assert_eq!(
engine.eval::<INT>(
2021-04-20 06:01:35 +02:00
"
let x = #{a: 1, b: 2, c: 3};
x += #{b: 42, d: 9};
x.len() + x.b
2020-07-09 13:54:28 +02:00
"
)?,
46
);
assert_eq!(
engine
.eval::<Map>(
2021-04-20 06:01:35 +02:00
"
let x = #{a: 1, b: 2, c: 3};
let y = #{b: 42, d: 9};
x + y
2020-07-09 13:54:28 +02:00
"
)?
.len(),
4
);
2020-03-29 17:53:35 +02:00
Ok(())
}
2022-02-09 06:12:43 +01:00
#[test]
fn test_map_prop() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
2022-12-30 18:07:39 +01:00
engine.eval::<()>("let x = #{a: 42}; x.b").unwrap();
2022-02-09 06:12:43 +01:00
engine.set_fail_on_invalid_map_property(true);
assert!(
2023-04-10 17:23:59 +02:00
matches!(*engine.eval::<()>("let x = #{a: 42}; x.b").unwrap_err(),
2022-02-09 06:12:43 +01:00
EvalAltResult::ErrorPropertyNotFound(prop, _) if prop == "b"
)
);
Ok(())
}
2022-05-19 10:56:22 +02:00
#[cfg(not(feature = "no_index"))]
2022-05-17 09:20:32 +02:00
#[test]
fn test_map_index_types() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
engine.compile(r#"#{a:1, b:2, c:3}["a"]['x']"#)?;
assert!(matches!(
engine
2022-05-17 09:20:32 +02:00
.compile("#{a:1, b:2, c:3}['x']")
2023-04-10 17:23:59 +02:00
.unwrap_err()
.err_type(),
2022-05-17 09:20:32 +02:00
ParseErrorType::MalformedIndexExpr(..)
));
assert!(matches!(
engine
2022-05-17 09:20:32 +02:00
.compile("#{a:1, b:2, c:3}[1]")
2023-04-10 17:23:59 +02:00
.unwrap_err()
.err_type(),
2022-05-17 09:20:32 +02:00
ParseErrorType::MalformedIndexExpr(..)
));
#[cfg(not(feature = "no_float"))]
assert!(matches!(
engine
2022-05-17 09:20:32 +02:00
.compile("#{a:1, b:2, c:3}[123.456]")
2023-04-10 17:23:59 +02:00
.unwrap_err()
.err_type(),
2022-05-17 09:20:32 +02:00
ParseErrorType::MalformedIndexExpr(..)
));
assert!(matches!(
engine
2022-05-17 09:20:32 +02:00
.compile("#{a:1, b:2, c:3}[()]")
2023-04-10 17:23:59 +02:00
.unwrap_err()
.err_type(),
2022-05-17 09:20:32 +02:00
ParseErrorType::MalformedIndexExpr(..)
));
assert!(matches!(
engine
2022-05-17 09:20:32 +02:00
.compile("#{a:1, b:2, c:3}[true && false]")
2023-04-10 17:23:59 +02:00
.unwrap_err()
.err_type(),
2022-05-17 09:20:32 +02:00
ParseErrorType::MalformedIndexExpr(..)
));
Ok(())
}
2020-03-29 17:53:35 +02:00
#[test]
fn test_map_assign() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
2020-03-29 17:53:35 +02:00
let x = engine.eval::<Map>(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?;
2020-03-29 17:53:35 +02:00
2022-04-21 04:04:57 +02:00
assert_eq!(x["a"].as_int().unwrap(), 1);
2022-12-30 18:07:39 +01:00
assert!(x["b"].as_bool().unwrap());
2021-03-30 12:57:16 +02:00
assert_eq!(x["c$"].clone_cast::<String>(), "hello");
2020-03-29 17:53:35 +02:00
Ok(())
}
#[test]
fn test_map_return() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
2020-03-29 17:53:35 +02:00
let x = engine.eval::<Map>(r#"#{a: 1, b: true, "c$": "hello"}"#)?;
2020-03-29 17:53:35 +02:00
2022-04-21 04:04:57 +02:00
assert_eq!(x["a"].as_int().unwrap(), 1);
2022-12-30 18:07:39 +01:00
assert!(x["b"].as_bool().unwrap());
2021-03-30 12:57:16 +02:00
assert_eq!(x["c$"].clone_cast::<String>(), "hello");
2020-03-29 17:53:35 +02:00
Ok(())
}
#[test]
2020-04-28 13:39:28 +02:00
#[cfg(not(feature = "no_index"))]
fn test_map_for() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
assert_eq!(
2020-04-10 09:18:26 +02:00
engine
.eval::<String>(
r#"
let map = #{a: 1, b_x: true, "$c d e!": "hello"};
let s = "";
2020-04-10 09:18:26 +02:00
for key in keys(map) {
s += key;
}
2020-04-10 09:18:26 +02:00
s
2020-07-09 13:54:28 +02:00
"#
2020-04-10 09:18:26 +02:00
)?
.len(),
11
);
Ok(())
}
2020-04-10 09:18:26 +02:00
#[test]
/// Because a Rhai object map literal is almost the same as JSON,
/// it is possible to convert from JSON into a Rhai object map.
fn test_map_json() -> Result<(), Box<EvalAltResult>> {
2020-04-10 09:18:26 +02:00
let engine = Engine::new();
2022-04-21 04:04:57 +02:00
let json = r#"{"a":1, "b":true, "c":41+1, "$d e f!":"hello", "z":null}"#;
2020-04-10 09:18:26 +02:00
2020-04-10 11:14:07 +02:00
let map = engine.parse_json(json, true)?;
2020-04-10 09:18:26 +02:00
assert!(!map.contains_key("x"));
2022-04-21 04:04:57 +02:00
assert_eq!(map["a"].as_int().unwrap(), 1);
2022-12-30 18:07:39 +01:00
assert!(map["b"].as_bool().unwrap());
2022-04-21 04:04:57 +02:00
assert_eq!(map["c"].as_int().unwrap(), 42);
2021-03-30 12:57:16 +02:00
assert_eq!(map["$d e f!"].clone_cast::<String>(), "hello");
2022-12-30 18:07:39 +01:00
let _: () = map["z"].as_unit().unwrap();
2020-04-10 09:18:26 +02:00
#[cfg(not(feature = "no_index"))]
{
2020-04-10 11:14:07 +02:00
let mut scope = Scope::new();
2020-04-10 09:18:26 +02:00
scope.push_constant("map", map);
assert_eq!(
engine
.eval_with_scope::<String>(
&mut scope,
r#"
let s = "";
for key in keys(map) {
s += key;
}
s
2020-07-09 13:54:28 +02:00
"#
2020-04-10 09:18:26 +02:00
)?
.len(),
11
);
}
2022-04-21 04:04:57 +02:00
engine.parse_json(json, true)?;
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("123", true).unwrap_err(),
2022-04-21 04:04:57 +02:00
EvalAltResult::ErrorMismatchOutputType(..)
));
2022-09-29 16:46:59 +02:00
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("{a:42}", true).unwrap_err(),
2022-09-29 16:46:59 +02:00
EvalAltResult::ErrorParsing(..)
));
2022-04-21 04:04:57 +02:00
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("#{a:123}", true).unwrap_err(),
2022-04-21 04:04:57 +02:00
EvalAltResult::ErrorParsing(..)
));
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("{a:()}", true).unwrap_err(),
2022-04-21 04:04:57 +02:00
EvalAltResult::ErrorParsing(..)
));
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("#{a:123+456}", true).unwrap_err(),
2022-04-21 04:04:57 +02:00
EvalAltResult::ErrorParsing(..)
));
assert!(matches!(
2023-04-10 17:23:59 +02:00
*engine.parse_json("{a:`hello${world}`}", true).unwrap_err(),
2022-04-21 04:04:57 +02:00
EvalAltResult::ErrorParsing(..)
));
2020-04-10 09:18:26 +02:00
Ok(())
}
2020-06-26 04:39:18 +02:00
#[test]
#[cfg(not(feature = "no_function"))]
fn test_map_oop() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
assert_eq!(
engine.eval::<INT>(
r#"
let obj = #{ data: 40, action: Fn("abc") };
fn abc(x) { this.data += x; }
obj.action(2);
obj.data
2020-07-09 13:54:28 +02:00
"#,
2020-06-26 04:39:18 +02:00
)?,
42
);
Ok(())
}