use expy::{Context, Error, ParseError, eval, eval_in};
use glam::*;
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);
}
}