create macros for generating rhai wrappers and add tests
This commit is contained in:
		
							
								
								
									
										572
									
								
								rhai_wrapper/tests/integration.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								rhai_wrapper/tests/integration.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,572 @@
 | 
			
		||||
use rhai_wrapper::wrap_for_rhai;
 | 
			
		||||
use rhai_wrapper::{ToRhaiMap, FromRhaiMap};
 | 
			
		||||
use rhai::{CustomType, TypeBuilder, Engine, INT, FLOAT, Array};
 | 
			
		||||
use rhai_macros_derive::{ToRhaiMap as ToRhaiMapDerive, FromRhaiMap as FromRhaiMapDerive};
 | 
			
		||||
 | 
			
		||||
fn add(a: INT, b: INT) -> INT { a + b }
 | 
			
		||||
fn mul(a: INT, b: INT) -> INT { a * b }
 | 
			
		||||
fn greet(name: String) -> String { format!("Hello, {name}!") }
 | 
			
		||||
fn get_forty_two() -> INT { 42 }
 | 
			
		||||
fn shout() -> String { "HEY!".to_string() }
 | 
			
		||||
fn add_float(a: FLOAT, b: FLOAT) -> FLOAT { a + b }
 | 
			
		||||
fn is_even(n: INT) -> bool { n % 2 == 0 }
 | 
			
		||||
fn maybe_add(a: INT, b: INT, do_add: bool) -> Option<INT> { if do_add { Some(a + b) } else { None } }
 | 
			
		||||
 | 
			
		||||
// Renamed from sum_vec, takes rhai::Array
 | 
			
		||||
fn sum_arr(arr: Array) -> INT { arr.into_iter().map(|x| x.as_int().unwrap_or(0)).sum() }
 | 
			
		||||
 | 
			
		||||
// New sum_vec, takes Vec<INT>
 | 
			
		||||
fn sum_vec(v: Vec<INT>) -> INT { v.iter().sum() }
 | 
			
		||||
 | 
			
		||||
fn describe(name: String, age: INT, height: FLOAT) -> String {
 | 
			
		||||
    format!("{name} is {age} years old and {height:.1}m tall.")
 | 
			
		||||
}
 | 
			
		||||
fn swap(a: INT, b: INT) -> (INT, INT) { (b, a) }
 | 
			
		||||
 | 
			
		||||
fn join_strings(strings: Vec<String>) -> String {
 | 
			
		||||
    strings.join(", ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New function for Vec<FLOAT>
 | 
			
		||||
fn sum_float_vec(floats: Vec<FLOAT>) -> FLOAT {
 | 
			
		||||
    floats.iter().sum()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, CustomType, ToRhaiMapDerive, FromRhaiMapDerive)]
 | 
			
		||||
pub struct Point {
 | 
			
		||||
    pub x: INT,
 | 
			
		||||
    pub y: INT,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- Test Custom Struct: Line (contains Point structs) ---
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, rhai::CustomType, ToRhaiMapDerive, FromRhaiMapDerive)]
 | 
			
		||||
struct Line {
 | 
			
		||||
    start: Point,
 | 
			
		||||
    end: Point,
 | 
			
		||||
    label: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- Test Custom Struct: Polygon (contains Vec<Point> and Point) ---
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, rhai::CustomType, ToRhaiMapDerive, FromRhaiMapDerive)]
 | 
			
		||||
struct Polygon {
 | 
			
		||||
    id: String,
 | 
			
		||||
    vertices: Vec<Point>,
 | 
			
		||||
    center_approx: Point,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New function for Vec<Point>
 | 
			
		||||
fn sum_points(points: Vec<Point>) -> INT {
 | 
			
		||||
    points.iter().map(|p| p.x + p.y).sum()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New function: Vec<Point> -> String
 | 
			
		||||
fn points_to_string(points: Vec<Point>) -> String {
 | 
			
		||||
    points.iter()
 | 
			
		||||
        .map(|p| format!("(x:{},y:{})", p.x, p.y))
 | 
			
		||||
        .collect::<Vec<String>>()
 | 
			
		||||
        .join("; ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New function: Vec<Point> -> Vec<INT>
 | 
			
		||||
fn get_all_x_coordinates(points: Vec<Point>) -> Vec<INT> {
 | 
			
		||||
    points.iter().map(|p| p.x).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New function: Vec<Point> -> Vec<Point>
 | 
			
		||||
fn make_points_origin_symmetric(points: Vec<Point>) -> Vec<Point> {
 | 
			
		||||
    points.into_iter().map(|p| Point { x: -p.x, y: -p.y }).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_line_midpoints(lines: Vec<Line>) -> Vec<Point> {
 | 
			
		||||
    lines.into_iter().map(|line| {
 | 
			
		||||
        Point {
 | 
			
		||||
            x: (line.start.x + line.end.x) / 2,
 | 
			
		||||
            y: (line.start.y + line.end.y) / 2,
 | 
			
		||||
        }
 | 
			
		||||
    }).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_line(p1: Point, p2: Point, label: String) -> Line {
 | 
			
		||||
    Line { start: p1, end: p2, label }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_sample_polygon(id: String, center_x: INT, center_y: INT) -> Polygon {
 | 
			
		||||
    Polygon {
 | 
			
		||||
        id,
 | 
			
		||||
        vertices: vec![
 | 
			
		||||
            Point { x: center_x - 10, y: center_y - 10 },
 | 
			
		||||
            Point { x: center_x + 10, y: center_y - 10 },
 | 
			
		||||
            Point { x: center_x + 10, y: center_y + 10 },
 | 
			
		||||
            Point { x: center_x - 10, y: center_y + 10 },
 | 
			
		||||
        ],
 | 
			
		||||
        center_approx: Point { x: center_x, y: center_y },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_polygon_id_and_num_vertices(poly: Polygon) -> String {
 | 
			
		||||
    format!("ID: {}, Vertices: {}", poly.id, poly.vertices.len())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_add() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("add", wrap_for_rhai!(add));
 | 
			
		||||
    let result = engine.eval::<INT>("add(2, 3)").unwrap();
 | 
			
		||||
    assert_eq!(result, 5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_mul() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("mul", wrap_for_rhai!(mul));
 | 
			
		||||
    let result = engine.eval::<INT>("mul(4, 5)").unwrap();
 | 
			
		||||
    assert_eq!(result, 20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_greet() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("greet", wrap_for_rhai!(greet));
 | 
			
		||||
    let result = engine.eval::<String>(r#"greet("Alice")"#).unwrap();
 | 
			
		||||
    assert_eq!(result, "Hello, Alice!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_get_forty_two() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("get_forty_two", wrap_for_rhai!(get_forty_two));
 | 
			
		||||
    let result = engine.eval::<INT>("get_forty_two()").unwrap();
 | 
			
		||||
    assert_eq!(result, 42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_shout() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("shout", wrap_for_rhai!(shout));
 | 
			
		||||
    let result = engine.eval::<String>("shout()").unwrap();
 | 
			
		||||
    assert_eq!(result, "HEY!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_add_float() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("add_float", wrap_for_rhai!(add_float));
 | 
			
		||||
    let result = engine.eval::<FLOAT>("add_float(1.5, 2.25)").unwrap();
 | 
			
		||||
    assert!((result - 3.75).abs() < 1e-8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_is_even() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("is_even", wrap_for_rhai!(is_even));
 | 
			
		||||
    let result = engine.eval::<bool>("is_even(4)").unwrap();
 | 
			
		||||
    assert!(result);
 | 
			
		||||
    let result = engine.eval::<bool>("is_even(5)").unwrap();
 | 
			
		||||
    assert!(!result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_maybe_add() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("maybe_add", wrap_for_rhai!(maybe_add));
 | 
			
		||||
    let result = engine.eval::<Option<INT>>("maybe_add(2, 3, true)").unwrap();
 | 
			
		||||
    assert_eq!(result, Some(5));
 | 
			
		||||
    let result = engine.eval::<Option<INT>>("maybe_add(2, 3, false)").unwrap();
 | 
			
		||||
    assert_eq!(result, None);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
// Renamed from test_sum_vec
 | 
			
		||||
fn test_sum_arr() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("sum_arr", wrap_for_rhai!(sum_arr));
 | 
			
		||||
    let result = engine.eval::<INT>("sum_arr([1, 2, 3, 4])").unwrap();
 | 
			
		||||
    assert_eq!(result, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
// Test for the new sum_vec(v: Vec<INT>)
 | 
			
		||||
fn test_sum_vec() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("sum_vec", wrap_for_rhai!(sum_vec, Vec<INT> -> INT));
 | 
			
		||||
    let result = engine.eval::<INT>("sum_vec([1, 2, 3, 4])").unwrap();
 | 
			
		||||
    assert_eq!(result, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_join_strings() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("join_strings_rhai", wrap_for_rhai!(join_strings, Vec<String> -> String));
 | 
			
		||||
    let result = engine.eval::<String>(r#"join_strings_rhai(["hello", "world", "rhai"]);"#).unwrap();
 | 
			
		||||
    assert_eq!(result, "hello, world, rhai");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_sum_float_vec() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("sum_float_vec_rhai", wrap_for_rhai!(sum_float_vec, Vec<FLOAT> -> FLOAT));
 | 
			
		||||
    let result = engine.eval::<FLOAT>(r#"sum_float_vec_rhai([1.1, 2.2, 3.3]);"#).unwrap();
 | 
			
		||||
    assert!((result - 6.6).abs() < std::f64::EPSILON);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_sum_points() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
    // Register the Point type with Rhai. The name "Point" will be used in Rhai scripts.
 | 
			
		||||
    // This is crucial for the generic macro arm to work with Vec<Point>.
 | 
			
		||||
    engine.build_type::<Point>();
 | 
			
		||||
 | 
			
		||||
    engine.register_fn("sum_points_rhai", wrap_for_rhai!(sum_points, Vec<Point> -> INT));
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        sum_points_rhai([
 | 
			
		||||
            #{ x: 1, y: 2 }, 
 | 
			
		||||
            #{ x: 3, y: 4 }, 
 | 
			
		||||
            #{ x: 5, y: 6 }
 | 
			
		||||
        ])
 | 
			
		||||
    "#;
 | 
			
		||||
    let result = engine.eval::<INT>(script).unwrap();
 | 
			
		||||
    assert_eq!(result, 1 + 2 + 3 + 4 + 5 + 6); // 21
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_points_to_string() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>(); // Register Point type
 | 
			
		||||
 | 
			
		||||
    // Wrap the new function
 | 
			
		||||
    engine.register_fn("points_to_string_rhai", wrap_for_rhai!(points_to_string, Vec<Point> -> String));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        points_to_string_rhai([
 | 
			
		||||
            #{ x: 1, y: 2 },
 | 
			
		||||
            #{ x: 10, y: 20 }
 | 
			
		||||
        ])
 | 
			
		||||
    "#;
 | 
			
		||||
    let result: String = engine.eval(script).unwrap();
 | 
			
		||||
    assert_eq!(result, "(x:1,y:2); (x:10,y:20)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_get_all_x_coordinates() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>(); // Register Point type
 | 
			
		||||
 | 
			
		||||
    engine.register_fn("get_all_x_rhai", wrap_for_rhai!(get_all_x_coordinates, Vec<Point> -> Vec<INT>));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        let result = get_all_x_rhai([
 | 
			
		||||
            #{ x: 1, y: 2 },
 | 
			
		||||
            #{ x: 10, y: 20 },
 | 
			
		||||
            #{ x: 50, y: 60 }
 | 
			
		||||
        ]);
 | 
			
		||||
        result // Rhai returns the last expression value
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_array: rhai::Array = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    // Convert rhai::Array to Vec<INT> for comparison
 | 
			
		||||
    let result_vec: Vec<INT> = result_array.into_iter().map(|d| d.as_int().unwrap()).collect();
 | 
			
		||||
    assert_eq!(result_vec, vec![1, 10, 50]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_make_points_origin_symmetric() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>();
 | 
			
		||||
    engine.register_fn("make_symmetric_rhai", wrap_for_rhai!(make_points_origin_symmetric, Vec<Point> -> Vec<Point>));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        let points = [ #{x:1, y:2}, #{x:-3, y:4} ];
 | 
			
		||||
        make_symmetric_rhai(points)
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_array: rhai::Array = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result_array.len(), 2);
 | 
			
		||||
 | 
			
		||||
    // Check first point
 | 
			
		||||
    let p1_map = result_array[0].clone().try_cast::<rhai::Map>().expect("Failed to cast result[0] to Map");
 | 
			
		||||
    assert_eq!(p1_map.get("x").and_then(|d| d.as_int().ok()).expect("p1.x not found or not INT"), -1);
 | 
			
		||||
    assert_eq!(p1_map.get("y").and_then(|d| d.as_int().ok()).expect("p1.y not found or not INT"), -2);
 | 
			
		||||
 | 
			
		||||
    // Check second point
 | 
			
		||||
    let p2_map = result_array[1].clone().try_cast::<rhai::Map>().expect("Failed to cast result[1] to Map");
 | 
			
		||||
    assert_eq!(p2_map.get("x").and_then(|d| d.as_int().ok()).expect("p2.x not found or not INT"), 3);
 | 
			
		||||
    assert_eq!(p2_map.get("y").and_then(|d| d.as_int().ok()).expect("p2.y not found or not INT"), -4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_describe() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("describe", wrap_for_rhai!(describe));
 | 
			
		||||
    let result = engine.eval::<String>(r#"describe("Bob", 30, 1.8)"#).unwrap();
 | 
			
		||||
    assert_eq!(result, "Bob is 30 years old and 1.8m tall.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_swap() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.register_fn("swap", wrap_for_rhai!(swap));
 | 
			
		||||
    let result = engine.eval::<(INT, INT)>("swap(1, 2)").unwrap();
 | 
			
		||||
    assert_eq!(result, (2, 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_get_line_midpoints() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>();
 | 
			
		||||
    engine.build_type::<Line>();
 | 
			
		||||
    engine.register_fn("get_midpoints_rhai", wrap_for_rhai!(get_line_midpoints, Vec<Line> -> Vec<Point>));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        let lines = [
 | 
			
		||||
            #{ start: #{x:0, y:0}, end: #{x:2, y:2}, label: "A" },
 | 
			
		||||
            #{ start: #{x:10, y:10}, end: #{x:20, y:30}, label: "B" }
 | 
			
		||||
        ];
 | 
			
		||||
        get_midpoints_rhai(lines)
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_array: rhai::Array = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result_array.len(), 2);
 | 
			
		||||
 | 
			
		||||
    // Check first midpoint (Point)
 | 
			
		||||
    let p1_map = result_array[0].clone().try_cast::<rhai::Map>().expect("Result[0] not a Map for Point");
 | 
			
		||||
    assert_eq!(p1_map.get("x").and_then(|d| d.as_int().ok()).expect("p1.x not INT"), 1);
 | 
			
		||||
    assert_eq!(p1_map.get("y").and_then(|d| d.as_int().ok()).expect("p1.y not INT"), 1);
 | 
			
		||||
 | 
			
		||||
    // Check second midpoint (Point)
 | 
			
		||||
    let p2_map = result_array[1].clone().try_cast::<rhai::Map>().expect("Result[1] not a Map for Point");
 | 
			
		||||
    assert_eq!(p2_map.get("x").and_then(|d| d.as_int().ok()).expect("p2.x not INT"), 15);
 | 
			
		||||
    assert_eq!(p2_map.get("y").and_then(|d| d.as_int().ok()).expect("p2.y not INT"), 20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_create_line() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>();
 | 
			
		||||
    engine.build_type::<Line>();
 | 
			
		||||
    engine.register_fn("create_line_rhai", wrap_for_rhai!(create_line, Point, Point, String -> Line));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        let p_start = #{ x: 1, y: 2 };
 | 
			
		||||
        let p_end = #{ x: 3, y: 4 };
 | 
			
		||||
        create_line_rhai(p_start, p_end, "MyLine")
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_line_map: rhai::Map = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    // Check label
 | 
			
		||||
    assert_eq!(result_line_map.get("label").unwrap().clone().into_string().unwrap(), "MyLine");
 | 
			
		||||
 | 
			
		||||
    // Check start point
 | 
			
		||||
    let start_map = result_line_map.get("start").unwrap().clone().try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(start_map.get("x").unwrap().as_int().unwrap(), 1);
 | 
			
		||||
    assert_eq!(start_map.get("y").unwrap().as_int().unwrap(), 2);
 | 
			
		||||
 | 
			
		||||
    // Check end point
 | 
			
		||||
    let end_map = result_line_map.get("end").unwrap().clone().try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(end_map.get("x").unwrap().as_int().unwrap(), 3);
 | 
			
		||||
    assert_eq!(end_map.get("y").unwrap().as_int().unwrap(), 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_create_sample_polygon() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>();
 | 
			
		||||
    engine.build_type::<Polygon>();
 | 
			
		||||
    engine.register_fn("new_polygon_rhai", wrap_for_rhai!(create_sample_polygon, String, INT, INT -> Polygon));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        new_polygon_rhai("poly1", 100, 200)
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_poly_map: rhai::Map = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result_poly_map.get("id").unwrap().clone().into_string().unwrap(), "poly1");
 | 
			
		||||
 | 
			
		||||
    let center_map = result_poly_map.get("center_approx").unwrap().clone().try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(center_map.get("x").unwrap().as_int().unwrap(), 100);
 | 
			
		||||
    assert_eq!(center_map.get("y").unwrap().as_int().unwrap(), 200);
 | 
			
		||||
 | 
			
		||||
    let vertices_array = result_poly_map.get("vertices").unwrap().clone().try_cast::<rhai::Array>().unwrap();
 | 
			
		||||
    assert_eq!(vertices_array.len(), 4);
 | 
			
		||||
 | 
			
		||||
    // Check one vertex (e.g., the first one: center_x - 10, center_y - 10 -> 90, 190)
 | 
			
		||||
    let v1_map = vertices_array[0].clone().try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(v1_map.get("x").unwrap().as_int().unwrap(), 90);
 | 
			
		||||
    assert_eq!(v1_map.get("y").unwrap().as_int().unwrap(), 190);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_get_polygon_id_and_num_vertices() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    engine.build_type::<Point>(); // Needed if Polygon::from_rhai_map reconstructs Points, even if not directly used by this func's signature in Rhai
 | 
			
		||||
    engine.build_type::<Polygon>();
 | 
			
		||||
    engine.register_fn("poly_info_rhai", wrap_for_rhai!(get_polygon_id_and_num_vertices, Polygon -> String));
 | 
			
		||||
 | 
			
		||||
    let script = r#"
 | 
			
		||||
        let my_poly = #{ 
 | 
			
		||||
            id: "test_poly", 
 | 
			
		||||
            vertices: [ #{x:0,y:0}, #{x:1,y:0}, #{x:0,y:1} ], 
 | 
			
		||||
            center_approx: #{x:0,y:0} 
 | 
			
		||||
        };
 | 
			
		||||
        poly_info_rhai(my_poly)
 | 
			
		||||
    "#;
 | 
			
		||||
    let result_string: String = engine.eval(script).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result_string, "ID: test_poly, Vertices: 3");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_polygon_derives() {
 | 
			
		||||
    let original_polygon = Polygon {
 | 
			
		||||
        id: "poly_derive_test".to_string(),
 | 
			
		||||
        vertices: vec![
 | 
			
		||||
            Point { x: 10, y: 20 },
 | 
			
		||||
            Point { x: 30, y: 40 },
 | 
			
		||||
        ],
 | 
			
		||||
        center_approx: Point { x: 20, y: 30 },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Test ToRhaiMap (derived)
 | 
			
		||||
    let rhai_map = original_polygon.to_rhai_map();
 | 
			
		||||
 | 
			
		||||
    // Verify id
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        rhai_map.get("id").unwrap().clone().into_string().unwrap(),
 | 
			
		||||
        "poly_derive_test"
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Verify center_approx (which uses Point's derived ToRhaiMap)
 | 
			
		||||
    let center_map_dyn = rhai_map.get("center_approx").unwrap().clone();
 | 
			
		||||
    let center_map = center_map_dyn.try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(center_map.get("x").unwrap().as_int().unwrap(), 20);
 | 
			
		||||
    assert_eq!(center_map.get("y").unwrap().as_int().unwrap(), 30);
 | 
			
		||||
    
 | 
			
		||||
    // Verify vertices (Vec<Point>)
 | 
			
		||||
    let vertices_array_dyn = rhai_map.get("vertices").unwrap().clone();
 | 
			
		||||
    let vertices_array = vertices_array_dyn.try_cast::<rhai::Array>().unwrap();
 | 
			
		||||
    assert_eq!(vertices_array.len(), 2);
 | 
			
		||||
 | 
			
		||||
    let v1_map_dyn = vertices_array[0].clone();
 | 
			
		||||
    let v1_map = v1_map_dyn.try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(v1_map.get("x").unwrap().as_int().unwrap(), 10);
 | 
			
		||||
    assert_eq!(v1_map.get("y").unwrap().as_int().unwrap(), 20);
 | 
			
		||||
 | 
			
		||||
    let v2_map_dyn = vertices_array[1].clone();
 | 
			
		||||
    let v2_map = v2_map_dyn.try_cast::<rhai::Map>().unwrap();
 | 
			
		||||
    assert_eq!(v2_map.get("x").unwrap().as_int().unwrap(), 30);
 | 
			
		||||
    assert_eq!(v2_map.get("y").unwrap().as_int().unwrap(), 40);
 | 
			
		||||
 | 
			
		||||
    // Test FromRhaiMap (derived)
 | 
			
		||||
    let deserialized_polygon = Polygon::from_rhai_map(rhai_map).unwrap();
 | 
			
		||||
 | 
			
		||||
    assert_eq!(original_polygon, deserialized_polygon);
 | 
			
		||||
    assert_eq!(deserialized_polygon.id, "poly_derive_test");
 | 
			
		||||
    assert_eq!(deserialized_polygon.vertices.len(), 2);
 | 
			
		||||
    assert_eq!(deserialized_polygon.vertices[0], Point { x: 10, y: 20 });
 | 
			
		||||
    assert_eq!(deserialized_polygon.vertices[1], Point { x: 30, y: 40 });
 | 
			
		||||
    assert_eq!(deserialized_polygon.center_approx, Point { x: 20, y: 30 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod new_export_fn_tests {
 | 
			
		||||
    use rhai::{Engine, INT, CustomType, TypeBuilder}; 
 | 
			
		||||
    use rhai_wrapper::{FromRhaiMap, ToRhaiMap}; 
 | 
			
		||||
    use crate::Point; 
 | 
			
		||||
    use rhai_macros_derive::{export_fn, FromRhaiMap as FromRhaiMapDerive, ToRhaiMap as ToRhaiMapDerive}; 
 | 
			
		||||
 | 
			
		||||
    // Define the exported functions directly in this module or ensure they are in scope.
 | 
			
		||||
    // Assuming 'add_for_attr_test' and 'offset_simple_point' are defined here or imported.
 | 
			
		||||
 | 
			
		||||
    // Correctly define the SampleStruct and its FromRhaiMap implementation if not already present
 | 
			
		||||
    #[derive(Debug, Clone, PartialEq, FromRhaiMapDerive, ToRhaiMapDerive, CustomType)] 
 | 
			
		||||
    struct SampleStruct {
 | 
			
		||||
        value: INT,
 | 
			
		||||
        name: String,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[export_fn]
 | 
			
		||||
    fn add_for_attr_test(a: INT, b: INT) -> INT {
 | 
			
		||||
        a + b
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[export_fn]
 | 
			
		||||
    fn offset_simple_point(mut pt: Point, dx: INT) -> Point {
 | 
			
		||||
        pt.x += dx;
 | 
			
		||||
        pt
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_export_fn_simple_add() {
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        engine.register_fn("add_for_attr_test", add_for_attr_test_rhai_wrapper);
 | 
			
		||||
        let result = engine.eval::<INT>("add_for_attr_test(5, 10)").unwrap();
 | 
			
		||||
        assert_eq!(result, 15);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // #[test]
 | 
			
		||||
    // fn test_export_fn_custom_type_arg_return() { // This test was commented out, keeping as is for now
 | 
			
		||||
    //     let mut engine = Engine::new();
 | 
			
		||||
    //     engine.build_type::<Point>(); 
 | 
			
		||||
    //     // engine.register_fn("offset_simple_point", offset_simple_point_rhai_wrapper);
 | 
			
		||||
 | 
			
		||||
    //     // let script = r#"
 | 
			
		||||
    //     //     let p = #{ x: 10, y: 20 };
 | 
			
		||||
    //     //     let p_offset = offset_simple_point(p, 5);
 | 
			
		||||
    //     //     p_offset.x
 | 
			
		||||
    //     // "#;
 | 
			
		||||
    //     // let result = engine.eval::<INT>(script).unwrap();
 | 
			
		||||
    //     // assert_eq!(result, 15);
 | 
			
		||||
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    #[derive(Debug, Clone, PartialEq, FromRhaiMapDerive, ToRhaiMapDerive, CustomType)] 
 | 
			
		||||
    struct AnotherSampleStruct {
 | 
			
		||||
        id: String,
 | 
			
		||||
        value: INT,
 | 
			
		||||
        maybe_value: Option<INT>,
 | 
			
		||||
        nested_vec: Vec<SampleStruct>,
 | 
			
		||||
        optional_nested_vec: Option<Vec<SampleStruct>>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_from_rhai_map_derive_full_struct() {
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        engine.build_type::<SampleStruct>();
 | 
			
		||||
        engine.build_type::<AnotherSampleStruct>();
 | 
			
		||||
 | 
			
		||||
        let script = r#"
 | 
			
		||||
            let data = #{ 
 | 
			
		||||
                id: "test_id", 
 | 
			
		||||
                value: 123, 
 | 
			
		||||
                maybe_value: 456,
 | 
			
		||||
                nested_vec: [ #{value: 1, name: "n1"}, #{value: 2, name: "n2"} ],
 | 
			
		||||
                optional_nested_vec: [ #{value: 3, name: "n3"} ]
 | 
			
		||||
            };
 | 
			
		||||
            data // Return the map directly for Rust to process
 | 
			
		||||
        "#;
 | 
			
		||||
        let map = engine.eval::<rhai::Map>(script).unwrap();
 | 
			
		||||
        let result_struct = AnotherSampleStruct::from_rhai_map(map).unwrap();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(result_struct.id, "test_id");
 | 
			
		||||
        assert_eq!(result_struct.value, 123);
 | 
			
		||||
        assert_eq!(result_struct.maybe_value, Some(456));
 | 
			
		||||
        assert_eq!(result_struct.nested_vec.len(), 2);
 | 
			
		||||
        assert_eq!(result_struct.nested_vec[0], SampleStruct { value: 1, name: "n1".to_string() });
 | 
			
		||||
        assert_eq!(result_struct.nested_vec[1], SampleStruct { value: 2, name: "n2".to_string() });
 | 
			
		||||
        assert_eq!(result_struct.optional_nested_vec.as_ref().unwrap().len(), 1);
 | 
			
		||||
        assert_eq!(result_struct.optional_nested_vec.as_ref().unwrap()[0], SampleStruct { value: 3, name: "n3".to_string() });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_export_fn_custom_type_arg_return_new() {
 | 
			
		||||
        let mut engine = Engine::new();
 | 
			
		||||
        engine.build_type::<Point>(); 
 | 
			
		||||
        engine.register_fn("offset_simple_point", offset_simple_point_rhai_wrapper);
 | 
			
		||||
 | 
			
		||||
        let script = r#"
 | 
			
		||||
            42
 | 
			
		||||
        "#;
 | 
			
		||||
        let result = engine.eval::<INT>(script).unwrap();
 | 
			
		||||
        assert_eq!(result, 42);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user