//! Vector math tests. use expy::{Context, Error, ParseError, eval, eval_in}; use glam::*; // (Used by randomized tests). const MAX: f32 = 16.; const TRIES: usize = 512; #[test] fn subscript() { let mut ctx = Context::new(); ctx.set("v", Vec2::new(1., 2.)); assert_eq!(eval_in(&mut ctx, "v[0]").unwrap().unwrap_float(), 1.); assert_eq!(eval_in(&mut ctx, "v[1]").unwrap().unwrap_float(), 2.); } #[test] fn member_access() { let mut ctx = Context::new(); ctx.set("v", Vec2::new(1., 2.)); assert_eq!(eval_in(&mut ctx, "v.x").unwrap().unwrap_float(), 1.); assert_eq!(eval_in(&mut ctx, "v.y").unwrap().unwrap_float(), 2.); } #[test] fn vector_literals() { assert_eq!(eval("[1., 2.]").unwrap().unwrap_vec2(), Vec2::new(1., 2.)); assert_eq!(eval("[1., 2., 3.]").unwrap().unwrap_vec3(), Vec3::new(1., 2., 3.)); assert_eq!(eval("[1., 2., 3., 4.]").unwrap().unwrap_vec4(), Vec4::new(1., 2., 3., 4.)); assert_eq!( eval("[1., 2., 3., 4., 5.]").unwrap_err(), Error::Parse(ParseError::Unsupported("vector of length 5".into()))); } #[test] fn subscripting_literal_vectors() { assert_eq!(eval("[1., 2.][0]").unwrap().unwrap_float(), 1.); assert_eq!(eval("[1., 2., 3.][1]").unwrap().unwrap_float(), 2.); assert_eq!(eval("[1., 2., 3., 4.][2]").unwrap().unwrap_float(), 3.); } #[test] fn accessing_members_of_literal_vectors() { assert_eq!(eval("[1., 2.].x").unwrap().unwrap_float(), 1.); assert_eq!(eval("[1., 2., 3.].y").unwrap().unwrap_float(), 2.); assert_eq!(eval("[1., 2., 3., 4.].z").unwrap().unwrap_float(), 3.); } #[test] fn arithmetic_with_scalars() { let mut ctx = Context::new(); for _ in 0..TRIES { let v = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); let c = fastrand::f32() * MAX; ctx.set("v", v); ctx.set("c", c); assert_eq!(eval_in(&mut ctx, "v * c").unwrap().unwrap_vec2(), v * c); assert_eq!(eval_in(&mut ctx, "c * v").unwrap().unwrap_vec2(), c * v); if c != 0. { assert_eq!(eval_in(&mut ctx, "v / c").unwrap().unwrap_vec2(), v / c); } } } #[test] fn arithmetic_on_just_vectors() { let mut ctx = Context::new(); for _ in 0..TRIES { let a = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); let b = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); ctx.set("a", a); ctx.set("b", b); assert_eq!(eval_in(&mut ctx, "a + b").unwrap().unwrap_vec2(), a + b); assert_eq!(eval_in(&mut ctx, "a - b").unwrap().unwrap_vec2(), a - b); assert_eq!(eval_in(&mut ctx, "a * b").unwrap().unwrap_vec2(), a * b); if b.cmpne(Vec2::ZERO).all() { assert_eq!(eval_in(&mut ctx, "a / b").unwrap().unwrap_vec2(), a / b); } } } #[test] fn power() { let mut ctx = Context::new(); for _ in 0..TRIES { let v = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); let x = fastrand::f32() * MAX; ctx.set("v", v); ctx.set("x", x); assert_eq!(eval_in(&mut ctx, "v ^ x").unwrap().unwrap_vec2(), v.powf(x)); } } #[test] fn abs() { let mut ctx = Context::new(); for _ in 0..TRIES { let v = Vec2::new(-MAX + fastrand::f32() * 2. * MAX, -MAX +fastrand::f32() * 2. * MAX); ctx.set("v", v); assert_eq!(eval_in(&mut ctx, "abs(v)").unwrap().unwrap_vec2(), v.abs()); } } #[test] fn rounding_functions() { let mut ctx = Context::new(); for _ in 0..TRIES { let v = Vec2::new(-MAX + fastrand::f32() * 2. * MAX, -MAX +fastrand::f32() * 2. * MAX); ctx.set("v", v); assert_eq!(eval_in(&mut ctx, "frac(v)").unwrap().unwrap_vec2(), v.fract()); assert_eq!(eval_in(&mut ctx, "trunc(v)").unwrap().unwrap_vec2(), v.trunc()); assert_eq!(eval_in(&mut ctx, "floor(v)").unwrap().unwrap_vec2(), v.floor()); assert_eq!(eval_in(&mut ctx, "ceil(v)").unwrap().unwrap_vec2(), v.ceil()); assert_eq!(eval_in(&mut ctx, "round(v)").unwrap().unwrap_vec2(), v.round()); } } #[test] fn length() { let mut ctx = Context::new(); ctx.set("x", Vec2::X); ctx.set("y", Vec2::Y); assert_eq!(eval_in(&mut ctx, "len(x)").unwrap().unwrap_float(), 1.); assert_eq!(eval_in(&mut ctx, "len(y)").unwrap().unwrap_float(), 1.); } #[test] fn length_alias() { let mut ctx = Context::new(); ctx.set("x", Vec2::X); ctx.set("y", Vec2::Y); ctx.set("z", Vec3::Z); assert_eq!(eval_in(&mut ctx, "length(x)").unwrap().unwrap_float(), 1.); assert_eq!(eval_in(&mut ctx, "mag(y)").unwrap().unwrap_float(), 1.); assert_eq!(eval_in(&mut ctx, "magnitude(z)").unwrap().unwrap_float(), 1.); } #[test] fn normalize() { let mut ctx = Context::new(); for _ in 0..TRIES { let v = Vec2::new(-MAX + fastrand::f32() * 2. * MAX, -MAX +fastrand::f32() * 2. * MAX); if v.try_normalize().is_some() { ctx.set("v", v); let n = eval_in(&mut ctx, "normalize(v)").unwrap().unwrap_vec2(); assert!(n.is_normalized()); } } } #[test] fn distance() { let mut ctx = Context::new(); ctx.set("a", Vec2::new(5., 4.)); ctx.set("b", Vec2::new(5., -3.)); assert_eq!(eval_in(&mut ctx, "dist(a, b)").unwrap().unwrap_float(), 7.); } #[test] fn distance_commutative() { let mut ctx = Context::new(); for _ in 0..TRIES { let a = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); let b = Vec2::new(fastrand::f32() * MAX, fastrand::f32() * MAX); ctx.set("a", a); ctx.set("b", b); assert!( eval_in(&mut ctx, "dist(a, b) == dist(b, a)").unwrap().unwrap_bool(), "Distance between v_a ({}) and v_b ({}) is different than from v_b to v_a?!", a, b); } }