use solarsystems::Vec3;
use std::f64::consts::{FRAC_PI_2, FRAC_PI_4, PI};
#[test]
fn vec3_new_stores_components() {
let v = Vec3::new(1.0, 2.0, 3.0);
assert_eq!(v.x, 1.0);
assert_eq!(v.y, 2.0);
assert_eq!(v.z, 3.0);
}
#[test]
fn vec3_zero_is_origin() {
let v = Vec3::ZERO;
assert_eq!(v.x, 0.0);
assert_eq!(v.y, 0.0);
assert_eq!(v.z, 0.0);
}
#[test]
fn magnitude_of_unit_x() {
let v = Vec3::new(1.0, 0.0, 0.0);
assert!((v.magnitude() - 1.0).abs() < 1e-15);
}
#[test]
fn magnitude_pythagorean_triple() {
let v = Vec3::new(3.0, 4.0, 0.0);
assert!((v.magnitude() - 5.0).abs() < 1e-14);
}
#[test]
fn magnitude_3d() {
let v = Vec3::new(1.0, 2.0, 2.0);
assert!((v.magnitude() - 3.0).abs() < 1e-14);
}
#[test]
fn magnitude_zero_vector() {
assert_eq!(Vec3::ZERO.magnitude(), 0.0);
}
#[test]
fn magnitude_squared_avoids_sqrt() {
let v = Vec3::new(3.0, 4.0, 0.0);
assert!((v.magnitude_squared() - 25.0).abs() < 1e-14);
}
#[test]
fn magnitude_squared_consistent_with_magnitude() {
let v = Vec3::new(7.3, -2.1, 4.8);
let m = v.magnitude();
assert!((v.magnitude_squared() - m * m).abs() < 1e-10);
}
#[test]
fn normalize_unit_vector() {
let v = Vec3::new(5.0, 0.0, 0.0);
let n = v.normalize();
assert!((n.x - 1.0).abs() < 1e-15);
assert_eq!(n.y, 0.0);
assert_eq!(n.z, 0.0);
}
#[test]
fn normalize_arbitrary_vector() {
let v = Vec3::new(3.0, 4.0, 12.0);
let n = v.normalize();
assert!((n.magnitude() - 1.0).abs() < 1e-14);
}
#[test]
fn normalize_preserves_direction() {
let v = Vec3::new(-2.0, 3.0, -1.0);
let n = v.normalize();
let scale = v.magnitude();
assert!((n.x * scale - v.x).abs() < 1e-10);
assert!((n.y * scale - v.y).abs() < 1e-10);
assert!((n.z * scale - v.z).abs() < 1e-10);
}
#[test]
fn dot_product_orthogonal() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(0.0, 1.0, 0.0);
assert_eq!(a.dot(&b), 0.0);
}
#[test]
fn dot_product_parallel() {
let a = Vec3::new(2.0, 3.0, 4.0);
let expected = a.magnitude_squared();
assert!((a.dot(&a) - expected).abs() < 1e-10);
}
#[test]
fn dot_product_antiparallel() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(-1.0, 0.0, 0.0);
assert!((a.dot(&b) + 1.0).abs() < 1e-15);
}
#[test]
fn dot_product_general() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, -5.0, 6.0);
let expected = 1.0 * 4.0 + 2.0 * (-5.0) + 3.0 * 6.0;
assert!((a.dot(&b) - expected).abs() < 1e-14);
}
#[test]
fn cross_product_basis_vectors() {
let x = Vec3::new(1.0, 0.0, 0.0);
let y = Vec3::new(0.0, 1.0, 0.0);
let z = x.cross(&y);
assert!((z.x).abs() < 1e-15);
assert!((z.y).abs() < 1e-15);
assert!((z.z - 1.0).abs() < 1e-15);
}
#[test]
fn cross_product_anticommutative() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let ab = a.cross(&b);
let ba = b.cross(&a);
assert!((ab.x + ba.x).abs() < 1e-14);
assert!((ab.y + ba.y).abs() < 1e-14);
assert!((ab.z + ba.z).abs() < 1e-14);
}
#[test]
fn cross_product_parallel_is_zero() {
let a = Vec3::new(2.0, 4.0, 6.0);
let b = Vec3::new(1.0, 2.0, 3.0);
let c = a.cross(&b);
assert!(c.magnitude() < 1e-14);
}
#[test]
fn cross_product_perpendicular_to_both() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let c = a.cross(&b);
assert!(c.dot(&a).abs() < 1e-10);
assert!(c.dot(&b).abs() < 1e-10);
}
#[test]
fn distance_same_point() {
let a = Vec3::new(5.0, 3.0, 1.0);
assert_eq!(a.distance(&a), 0.0);
}
#[test]
fn distance_symmetric() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 6.0, 8.0);
assert!((a.distance(&b) - b.distance(&a)).abs() < 1e-14);
}
#[test]
fn distance_known_value() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(3.0, 4.0, 0.0);
assert!((a.distance(&b) - 5.0).abs() < 1e-14);
}
#[test]
fn angle_between_parallel() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(5.0, 0.0, 0.0);
assert!(a.angle_between(&b).abs() < 1e-14);
}
#[test]
fn angle_between_perpendicular() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(0.0, 1.0, 0.0);
assert!((a.angle_between(&b) - FRAC_PI_2).abs() < 1e-14);
}
#[test]
fn angle_between_opposite() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(-1.0, 0.0, 0.0);
assert!((a.angle_between(&b) - PI).abs() < 1e-14);
}
#[test]
fn angle_between_45_degrees() {
let a = Vec3::new(1.0, 0.0, 0.0);
let b = Vec3::new(1.0, 1.0, 0.0);
assert!((a.angle_between(&b) - FRAC_PI_4).abs() < 1e-14);
}
#[test]
fn rotate_x_90_degrees() {
let v = Vec3::new(0.0, 1.0, 0.0);
let r = v.rotate_x(FRAC_PI_2);
assert!(r.x.abs() < 1e-14);
assert!(r.y.abs() < 1e-14);
assert!((r.z - 1.0).abs() < 1e-14);
}
#[test]
fn rotate_x_preserves_x_component() {
let v = Vec3::new(7.0, 3.0, 4.0);
let r = v.rotate_x(1.23);
assert!((r.x - 7.0).abs() < 1e-14);
}
#[test]
fn rotate_y_90_degrees() {
let v = Vec3::new(1.0, 0.0, 0.0);
let r = v.rotate_y(FRAC_PI_2);
assert!(r.x.abs() < 1e-14);
assert!(r.y.abs() < 1e-14);
assert!((r.z + 1.0).abs() < 1e-14);
}
#[test]
fn rotate_y_preserves_y_component() {
let v = Vec3::new(3.0, 7.0, 4.0);
let r = v.rotate_y(1.23);
assert!((r.y - 7.0).abs() < 1e-14);
}
#[test]
fn rotate_z_90_degrees() {
let v = Vec3::new(1.0, 0.0, 0.0);
let r = v.rotate_z(FRAC_PI_2);
assert!(r.x.abs() < 1e-14);
assert!((r.y - 1.0).abs() < 1e-14);
assert!(r.z.abs() < 1e-14);
}
#[test]
fn rotate_z_preserves_z_component() {
let v = Vec3::new(3.0, 4.0, 7.0);
let r = v.rotate_z(1.23);
assert!((r.z - 7.0).abs() < 1e-14);
}
#[test]
fn rotation_preserves_magnitude() {
let v = Vec3::new(3.0, 4.0, 5.0);
let m = v.magnitude();
assert!((v.rotate_x(0.7).magnitude() - m).abs() < 1e-12);
assert!((v.rotate_y(1.3).magnitude() - m).abs() < 1e-12);
assert!((v.rotate_z(2.1).magnitude() - m).abs() < 1e-12);
}
#[test]
fn full_rotation_returns_to_start() {
let v = Vec3::new(3.0, 4.0, 5.0);
let r = v.rotate_x(2.0 * PI);
assert!((r.x - v.x).abs() < 1e-12);
assert!((r.y - v.y).abs() < 1e-12);
assert!((r.z - v.z).abs() < 1e-12);
}
#[test]
fn lerp_at_zero() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let l = a.lerp(&b, 0.0);
assert!((l.x - a.x).abs() < 1e-15);
assert!((l.y - a.y).abs() < 1e-15);
assert!((l.z - a.z).abs() < 1e-15);
}
#[test]
fn lerp_at_one() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let l = a.lerp(&b, 1.0);
assert!((l.x - b.x).abs() < 1e-15);
assert!((l.y - b.y).abs() < 1e-15);
assert!((l.z - b.z).abs() < 1e-15);
}
#[test]
fn lerp_at_half() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(10.0, 20.0, 30.0);
let l = a.lerp(&b, 0.5);
assert!((l.x - 5.0).abs() < 1e-14);
assert!((l.y - 10.0).abs() < 1e-14);
assert!((l.z - 15.0).abs() < 1e-14);
}
#[test]
fn lerp_at_quarter() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(100.0, 0.0, 0.0);
let l = a.lerp(&b, 0.25);
assert!((l.x - 25.0).abs() < 1e-12);
}
#[test]
fn add_vectors() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let c = a + b;
assert_eq!(c.x, 5.0);
assert_eq!(c.y, 7.0);
assert_eq!(c.z, 9.0);
}
#[test]
fn sub_vectors() {
let a = Vec3::new(5.0, 7.0, 9.0);
let b = Vec3::new(4.0, 5.0, 6.0);
let c = a - b;
assert_eq!(c.x, 1.0);
assert_eq!(c.y, 2.0);
assert_eq!(c.z, 3.0);
}
#[test]
fn mul_scalar() {
let v = Vec3::new(1.0, 2.0, 3.0);
let s = v * 3.0;
assert_eq!(s.x, 3.0);
assert_eq!(s.y, 6.0);
assert_eq!(s.z, 9.0);
}
#[test]
fn scalar_mul_vec() {
let v = Vec3::new(1.0, 2.0, 3.0);
let s = 3.0 * v;
assert_eq!(s.x, 3.0);
assert_eq!(s.y, 6.0);
assert_eq!(s.z, 9.0);
}
#[test]
fn div_scalar() {
let v = Vec3::new(6.0, 9.0, 12.0);
let d = v / 3.0;
assert_eq!(d.x, 2.0);
assert_eq!(d.y, 3.0);
assert_eq!(d.z, 4.0);
}
#[test]
fn neg_vector() {
let v = Vec3::new(1.0, -2.0, 3.0);
let n = -v;
assert_eq!(n.x, -1.0);
assert_eq!(n.y, 2.0);
assert_eq!(n.z, -3.0);
}
#[test]
fn add_assign() {
let mut v = Vec3::new(1.0, 2.0, 3.0);
v += Vec3::new(4.0, 5.0, 6.0);
assert_eq!(v.x, 5.0);
assert_eq!(v.y, 7.0);
assert_eq!(v.z, 9.0);
}
#[test]
fn sub_assign() {
let mut v = Vec3::new(5.0, 7.0, 9.0);
v -= Vec3::new(1.0, 2.0, 3.0);
assert_eq!(v.x, 4.0);
assert_eq!(v.y, 5.0);
assert_eq!(v.z, 6.0);
}
#[test]
fn mul_assign_scalar() {
let mut v = Vec3::new(1.0, 2.0, 3.0);
v *= 2.0;
assert_eq!(v.x, 2.0);
assert_eq!(v.y, 4.0);
assert_eq!(v.z, 6.0);
}
#[test]
fn display_format() {
let v = Vec3::new(1.5, 2.5, 3.5);
let s = format!("{}", v);
assert!(s.contains("1.5"));
assert!(s.contains("2.5"));
assert!(s.contains("3.5"));
}
#[test]
fn very_large_vector_magnitude() {
let v = Vec3::new(1e150, 1e150, 1e150);
assert!(v.magnitude().is_finite());
assert!(v.magnitude() > 0.0);
}
#[test]
fn very_small_vector_magnitude() {
let v = Vec3::new(1e-200, 1e-200, 1e-200);
assert!(v.magnitude() >= 0.0);
}
#[test]
fn negative_components() {
let v = Vec3::new(-3.0, -4.0, 0.0);
assert!((v.magnitude() - 5.0).abs() < 1e-14);
}