use std::f32::consts::{FRAC_PI_2, PI};

use roofy::{Quat, Vec3, Vec4};

#[test]
fn const_nan() {
    let a: [f32; 4] = Quat::NAN.into();
    assert!(a.iter().all(|x| x.is_nan()))
}

#[test]
fn const_identity() {
    assert_eq!(Quat::IDENTITY, Quat::new(0.0, 0.0, 0.0, 1.0));
}

#[test]
fn new() {
    assert_eq!(
        Quat::new(1.0, 2.0, 3.0, 4.0),
        Quat {
            x: 1.0,
            y: 2.0,
            z: 3.0,
            w: 4.0
        }
    );
}

#[test]
fn from_array() {
    assert_eq!(Quat::from_array([0.0, 0.0, 0.0, 1.0]), Quat::IDENTITY);
}

#[test]
fn to_array() {
    assert_eq!(Quat::IDENTITY.to_array(), [0.0, 0.0, 0.0, 1.0]);
}

#[test]
fn from_slice() {
    assert_eq!(Quat::from_slice(&[0.0, 0.0, 0.0, 1.0]), Quat::IDENTITY);
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn from_slice_panics_if_too_short() {
    let _ = Quat::from_slice(&[0.0; 3]);
}

#[test]
fn write_to_slice() {
    let mut slice: [f32; 4] = [0.0; 4];
    Quat::IDENTITY.write_to_slice(&mut slice);
    assert_eq!(slice, [0.0, 0.0, 0.0, 1.0]);
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn write_to_slice_panics_if_to_short() {
    let mut slice: [f32; 3] = [0.0; 3];
    Quat::IDENTITY.write_to_slice(&mut slice);
}

#[test]
fn from_vec4() {
    assert_eq!(
        Quat::from_vec4(Vec4::new(1.0, 2.0, 3.0, 4.0)),
        Quat::new(1.0, 2.0, 3.0, 4.0)
    );
}

#[test]
fn from_rotation_x_matches_from_axis_angle() {
    assert_eq!(
        Quat::from_rotation_x(0.73),
        Quat::from_axis_angle(Vec3::X, 0.73)
    );
}

#[test]
fn from_rotation_x_degrees_matches() {
    assert_eq!(
        Quat::from_rotation_x_degrees(90.0),
        Quat::from_rotation_x(PI / 2.0)
    );
}

#[test]
fn from_rotation_y_matches_from_axis_angle() {
    assert_eq!(
        Quat::from_rotation_y(0.73),
        Quat::from_axis_angle(Vec3::Y, 0.73)
    );
}

#[test]
fn from_rotation_y_degrees_matches() {
    assert_eq!(
        Quat::from_rotation_y_degrees(90.0),
        Quat::from_rotation_y(PI / 2.0)
    );
}

#[test]
fn from_rotation_z_matches_from_axis_angle() {
    assert_eq!(
        Quat::from_rotation_z(0.73),
        Quat::from_axis_angle(Vec3::Z, 0.73)
    );
}

#[test]
fn from_rotation_z_degrees_matches() {
    assert_eq!(
        Quat::from_rotation_z_degrees(90.0),
        Quat::from_rotation_z(PI / 2.0)
    );
}

#[test]
fn from_axis_angle_zero_is_identity() {
    assert_eq!(Quat::from_axis_angle(Vec3::Y, 0.0), Quat::IDENTITY);
}

#[test]
fn from_axis_angle_x_90_rotates_y_to_z() {
    let q: Quat = Quat::from_axis_angle(Vec3::X, FRAC_PI_2);
    let v: Vec3 = q * Vec3::Y;

    assert!(v.approx_eq(Vec3::Z));
}

#[test]
fn from_axis_angle_degrees_x_matches() {
    assert_eq!(
        Quat::from_axis_angle_degrees(Vec3::X, 90.0),
        Quat::from_axis_angle(Vec3::X, FRAC_PI_2)
    );
}

#[test]
fn from_axis_angle_y_90_rotates_z_to_x() {
    let q: Quat = Quat::from_axis_angle(Vec3::Y, FRAC_PI_2);
    let v: Vec3 = q * Vec3::Z;

    assert!(v.approx_eq(Vec3::X));
}

#[test]
fn from_axis_angle_degrees_y_matches() {
    assert_eq!(
        Quat::from_axis_angle_degrees(Vec3::Y, 90.0),
        Quat::from_axis_angle(Vec3::Y, FRAC_PI_2)
    );
}

#[test]
fn from_axis_angle_z_90_rotates_x_to_y() {
    let q: Quat = Quat::from_axis_angle(Vec3::Z, FRAC_PI_2);
    let v: Vec3 = q * Vec3::X;

    assert!(v.approx_eq(Vec3::Y));
}

#[test]
fn from_axis_angle_degrees_z_90_matches() {
    assert_eq!(
        Quat::from_axis_angle_degrees(Vec3::Z, 90.0),
        Quat::from_axis_angle(Vec3::Z, FRAC_PI_2)
    );
}

#[test]
fn to_axis_angle_near_identity_returns_x_axis() {
    let (axis, angle): (Vec3, f32) = Quat::IDENTITY.to_axis_angle();

    assert_eq!(axis, Vec3::X);
    assert_eq!(angle, 0.0);
}

#[test]
fn to_axis_angle() {
    let q: Quat = Quat::from_axis_angle(Vec3::Y, FRAC_PI_2);
    let (axis, angle): (Vec3, f32) = q.to_axis_angle();

    assert!(axis.distance(Vec3::Y) < 1e-5);
    assert_eq!(angle, FRAC_PI_2);
}

#[test]
fn to_axis_angle_degrees() {
    let q: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);
    let (axis, angle): (Vec3, f32) = q.to_axis_angle_degrees();

    assert!(axis.distance(Vec3::Y) < 1e-5);
    assert_eq!(angle, 90.0);
}

#[test]
fn from_euler_zero_is_identity() {
    assert_eq!(Quat::from_euler_zyx(0.0, 0.0, 0.0), Quat::IDENTITY);
}

#[test]
fn from_euler_zyx_yaw() {
    let q: Quat = Quat::from_euler_zyx(FRAC_PI_2, 0.0, 0.0);
    let v: Vec3 = q * Vec3::X;

    assert!(v.approx_eq(Vec3::Y));
}

#[test]
fn from_euler_zyx_yaw_degrees_matches() {
    assert_eq!(
        Quat::from_euler_zyx(FRAC_PI_2, 0.0, 0.0),
        Quat::from_euler_zyx_degrees(90.0, 0.0, 0.0)
    );
}

#[test]
fn from_euler_zyx_pitch() {
    let q: Quat = Quat::from_euler_zyx(0.0, FRAC_PI_2, 0.0);
    let v: Vec3 = q * Vec3::X;

    assert!(v.approx_eq(-Vec3::Z));
}

#[test]
fn from_euler_zyx_pitch_degrees_matches() {
    assert_eq!(
        Quat::from_euler_zyx(0.0, FRAC_PI_2, 0.0),
        Quat::from_euler_zyx_degrees(0.0, 90.0, 0.0)
    );
}

#[test]
fn from_euler_zyx_roll() {
    let q: Quat = Quat::from_euler_zyx(0.0, 0.0, FRAC_PI_2);
    let v: Vec3 = q * Vec3::Z;

    assert!(v.approx_eq(-Vec3::Y));
}

#[test]
fn from_euler_zyx_roll_degrees_matches() {
    assert_eq!(
        Quat::from_euler_zyx(0.0, 0.0, FRAC_PI_2),
        Quat::from_euler_zyx_degrees(0.0, 0.0, 90.0)
    );
}

#[test]
fn to_euler_zyx() {
    let q: Quat = Quat::from_euler_zyx(0.3, 0.5, -0.8);
    let e: Vec3 = q.to_euler_zyx();
    let q2: Quat = Quat::from_euler_zyx(e.x, e.y, e.z);

    assert!(q.approx_eq(q2));
}

#[test]
fn to_euler_degrees_zyx() {
    let q: Quat = Quat::from_euler_zyx(0.3, 0.5, -0.8);
    let e: Vec3 = q.to_euler_degrees_zyx();
    let q2: Quat = Quat::from_euler_zyx_degrees(e.x, e.y, e.z);

    assert!(q.approx_eq(q2));
}

#[test]
fn look_to_rh_forward_is_z() {
    assert_eq!(Quat::look_to_rh(Vec3::Z, Vec3::Y) * Vec3::Z, Vec3::Z);
}

#[test]
fn look_to_rh_rotates_to_x() {
    let q: Quat = Quat::look_to_rh(Vec3::X, Vec3::Y);

    assert!((q * Vec3::Z).distance(Vec3::X) < 1e-5);
}

#[test]
fn look_to_rh_result_is_normalized() {
    assert!(Quat::look_to_rh(Vec3::ONE.normalized(), Vec3::Y).is_normalized());
}

#[test]
fn look_to_rh_reconstructs_basis() {
    let forward: Vec3 = Vec3::new(0.6, 0.0, 0.8).normalized();
    let up: Vec3 = Vec3::Y;
    let q: Quat = Quat::look_to_rh(forward, up);

    let rotated_z: Vec3 = q * Vec3::Z;
    assert!(rotated_z.approx_eq(forward));
}

#[test]
fn look_to_lh_forward_is_neg_z() {
    assert_eq!(
        Quat::look_to_lh(Vec3::NEG_Z, Vec3::Y) * Vec3::NEG_Z,
        Vec3::NEG_Z
    );
}

#[test]
fn look_at_rh() {
    let eye: Vec3 = Vec3::ZERO;
    let target: Vec3 = Vec3::new(3.0, 0.0, 0.0);

    assert_eq!(
        Quat::look_at_rh(eye, target, Vec3::Y),
        Quat::look_to_rh((target - eye).normalized(), Vec3::Y)
    );
}

#[test]
fn look_at_lh() {
    let eye: Vec3 = Vec3::ZERO;
    let target: Vec3 = Vec3::new(3.0, 0.0, 0.0);

    assert_eq!(
        Quat::look_at_lh(eye, target, Vec3::Y),
        Quat::look_to_lh((target - eye).normalized(), Vec3::Y)
    );
}

#[test]
fn from_to_rotation_same_vector_is_identity() {
    assert_eq!(Quat::from_to_rotation(Vec3::X, Vec3::X) * Vec3::X, Vec3::X);
}

#[test]
fn from_to_rotation_x_to_y() {
    let q: Quat = Quat::from_to_rotation(Vec3::X, Vec3::Y);

    assert!((q * Vec3::X).distance(Vec3::Y) < 1e-5);
}

#[test]
fn from_to_rotation_x_to_neg_x() {
    let q: Quat = Quat::from_to_rotation(Vec3::X, Vec3::NEG_X);

    assert!((q * Vec3::X).distance(Vec3::NEG_X) < 1e-5);
}

#[test]
fn from_to_rotation_opposite_vectors() {
    let q: Quat = Quat::from_to_rotation(Vec3::X, Vec3::NEG_X);

    assert!((q * Vec3::X).distance(Vec3::NEG_X) < 1e-5);
}

#[test]
fn from_to_rotation_preserves_length() {
    let q: Quat = Quat::from_to_rotation(Vec3::X, Vec3::ONE).normalized();
    let v: Vec3 = Vec3::splat(2.0);

    assert!((v.length() - (q * v).length()).abs() < 1e-5);
}

#[test]
fn from_to_rotation_result_is_normalized() {
    assert!(Quat::from_to_rotation(Vec3::X, Vec3::Y).is_normalized());
}

#[test]
fn dot() {
    assert_eq!(Quat::IDENTITY.dot(Quat::IDENTITY), 1.0);
}

#[test]
fn length_identity_is_1() {
    assert_eq!(Quat::IDENTITY.length(), 1.0);
}

#[test]
fn length_squared_identity_is_1() {
    assert_eq!(Quat::IDENTITY.length_squared(), 1.0);
}

#[test]
fn normalize_sets_length_approx_1() {
    let mut q: Quat = Quat::new(1.0, 2.0, 3.0, 4.0);
    q.normalize();
    assert!(q.is_normalized());
}

#[test]
fn normalized_sets_length_approx_1() {
    assert!(Quat::new(1.0, 2.0, 3.0, 4.0).normalized().is_normalized());
}

#[test]
fn try_normalize_matches() {
    let mut q1: Quat = Quat::new(1.0, 2.0, 3.0, 4.0);
    let mut q2: Quat = Quat::new(1.0, 2.0, 3.0, 4.0);
    let _ = q1.try_normalize();
    q2.normalize();
    assert_eq!(q1, q2);
}

#[test]
fn try_normalize_identity_is_true() {
    let mut q: Quat = Quat::IDENTITY;
    assert!(q.try_normalize());
}

#[test]
fn try_normalize_zero_is_false() {
    let mut q: Quat = Quat::new(0.0, 0.0, 0.0, 0.0);
    assert!(!q.try_normalize());
}

#[test]
fn try_normalize_infinity_is_false() {
    let mut q: Quat = Quat::new(f32::INFINITY, 0.0, 0.0, 0.0);
    assert!(!q.try_normalize());
}

#[test]
fn try_normalized_matches() {
    assert_eq!(
        Quat::new(1.0, 2.0, 3.0, 4.0).try_normalized().unwrap(),
        Quat::new(1.0, 2.0, 3.0, 4.0).normalized()
    );
}

#[test]
fn try_normalized_zero_is_none() {
    assert!(Quat::new(0.0, 0.0, 0.0, 0.0).try_normalized().is_none());
}

#[test]
fn try_normalized_infinity_is_none() {
    assert!(
        Quat::new(f32::INFINITY, 0.0, 0.0, 0.0)
            .try_normalized()
            .is_none()
    );
}

#[test]
fn normalize_or() {
    assert_eq!(
        Quat::new(0.0, 0.0, 0.0, 0.0).normalized_or(Quat::IDENTITY),
        Quat::IDENTITY
    );
}

#[test]
fn normalize_or_zero() {
    assert_eq!(
        Quat::new(0.0, 0.0, 0.0, 0.0).normalized_or_identity(),
        Quat::IDENTITY
    );
}

#[test]
fn is_normalized() {
    assert!(Quat::IDENTITY.is_normalized());
    assert!(!Quat::new(1.0, 1.0, 1.0, 1.0).is_normalized());
}

#[test]
fn conjugate() {
    assert_eq!(
        Quat::new(1.0, 2.0, 3.0, 4.0).conjugate(),
        Quat::new(-1.0, -2.0, -3.0, 4.0)
    );
}

#[test]
fn inverse_identity() {
    assert_eq!(Quat::IDENTITY.inverse(), Quat::IDENTITY);
}

#[test]
fn inverse_cancels_rotation() {
    let q: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);

    assert_eq!(q * q.inverse(), Quat::IDENTITY);
}

#[test]
fn inverse_near_zero_returns_identity() {
    assert_eq!(Quat::new(0.0, 0.0, 0.0, 0.0).inverse(), Quat::IDENTITY);
}

#[test]
fn angle_identity() {
    assert_eq!(Quat::IDENTITY.angle(), 0.0)
}

#[test]
fn angle_quarter_turn() {
    assert_eq!(
        Quat::from_axis_angle_degrees(Vec3::Y, 90.0).angle_degrees(),
        90.0
    );
}

#[test]
fn angle_half_turn() {
    let q: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 45.0);

    assert!((q.angle_degrees() - 45.0).abs() < 1e-5);
}

#[test]
fn angle_between() {
    let a: Quat = Quat::IDENTITY;
    let b: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);
    let angle: f32 = a.angle_between(b);
    assert_eq!(angle, PI / 2.0);
}

#[test]
fn angle_between_degrees() {
    let a: Quat = Quat::IDENTITY;
    let b: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);
    let angle: f32 = a.angle_between_degrees(b);
    assert_eq!(angle, 90.0);
}

#[test]
fn lerp_at_0_returns_start() {
    let a: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 0.0);
    let b: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);

    assert_eq!(a.lerp(b, 0.0), a);
}

#[test]
fn lerp_at_1_returns_end() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);

    assert!(from.lerp(to, 1.0).approx_eq(to));
}

#[test]
fn lerp_clamped_at_negative_returns_start() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);

    assert_eq!(from.lerp_clamped(to, -1.0), from);
}

#[test]
fn lerp_clamped_at_2_returns_end() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);

    assert!(from.lerp_clamped(to, 2.0).approx_eq(to));
}

#[test]
fn lerp_result_is_normalized() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::X, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::X, 90.0);

    assert!(from.lerp(to, 0.5).is_normalized());
}

#[test]
fn slerp_at_0_returns_start() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 90.0);

    assert_eq!(from.slerp(to, 0.0), from);
}

#[test]
fn slerp_at_1_returns_end() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 90.0);

    assert!(from.slerp(to, 1.0).approx_eq(to));
}

#[test]
fn slerp_midpoint_angle() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);
    let angle: f32 = from.slerp(to, 0.5).angle_degrees();

    assert!((angle - 90.0 * 0.5).abs() < 1e-4);
}

#[test]
fn slerp_clamped_at_negative_returns_start() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 90.0);

    assert_eq!(from.slerp_clamped(to, -1.0), from);
}

#[test]
fn slerp_clamped_at_2_returns_end() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 90.0);

    assert!(from.slerp_clamped(to, 2.0).approx_eq(to));
}

#[test]
fn slerp_result_is_normalized() {
    let from: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 0.0);
    let to: Quat = Quat::from_axis_angle_degrees(Vec3::Z, 90.0);

    assert!(from.slerp(to, 0.5).is_normalized());
}

#[test]
fn rotate_towards_does_not_overshoot() {
    let from: Quat = Quat::IDENTITY;
    let to: Quat = Quat::from_axis_angle(Vec3::Y, 30.0);
    assert_eq!(from.rotate_towards(to, 90.0), to);
}

#[test]
fn rotate_towards_zero_max_angle_does_not_move() {
    let from: Quat = Quat::IDENTITY;
    let to: Quat = Quat::from_axis_angle(Vec3::Y, 90.0);
    assert_eq!(from.rotate_towards(to, 0.0), from);
}

#[test]
fn rotate_towards_same_rotation_is_noop() {
    let q: Quat = Quat::from_axis_angle(Vec3::X, 1.234);
    assert_eq!(q.rotate_towards(q, 0.5), q);
}

#[test]
fn approx_eq_identity_is_equal() {
    assert!(Quat::IDENTITY.approx_eq(Quat::IDENTITY));
}

#[test]
fn approx_eq_zero_is_not_identity() {
    assert!(!Quat::new(0.0, 0.0, 0.0, 0.0).approx_eq(Quat::IDENTITY));
}

#[test]
fn approx_eq_tiny_difference_is_equal() {
    assert!(Quat::IDENTITY.approx_eq(Quat::new(1e-7, 0.0, 0.0, 1.0)));
}

#[test]
fn is_finite_identity_returns_true() {
    assert!(Quat::IDENTITY.is_finite());
}

#[test]
fn is_finite_infinity_returns_false() {
    assert!(!Quat::new(f32::INFINITY, 0.0, 0.0, 0.0).is_finite());
}

#[test]
fn is_nan_identity_returns_false() {
    assert!(!Quat::IDENTITY.is_nan());
}

#[test]
fn is_nan_nan_returns_true() {
    assert!(Quat::NAN.is_nan());
}

#[test]
fn mul() {
    assert_eq!(
        Quat::new(2.0, 3.0, 4.0, 1.0) * Quat::new(6.0, 7.0, 8.0, 5.0),
        Quat::new(12.0, 30.0, 24.0, -60.0)
    );
}

#[test]
fn mul_identity() {
    assert_eq!(
        Quat::new(2.0, 3.0, 4.0, 1.0) * Quat::IDENTITY,
        Quat::new(2.0, 3.0, 4.0, 1.0)
    );
}

#[test]
fn mul_vec3() {
    let q: Quat = Quat::from_axis_angle_degrees(Vec3::Y, 90.0);
    let result: Vec3 = q * Vec3::X;
    assert!(result.distance(Vec3::NEG_Z) < 1e-5);
}

#[test]
fn mul_vec3_identity() {
    assert_eq!(
        Quat::IDENTITY * Vec3::new(1.0, 2.0, 3.0),
        Vec3::new(1.0, 2.0, 3.0)
    );
}

#[test]
fn neg() {
    assert_eq!(
        -Quat::new(1.0, 2.0, 3.0, 4.0),
        Quat::new(-1.0, -2.0, -3.0, -4.0)
    );
}

#[test]
fn index() {
    assert_eq!(Quat::IDENTITY[0], 0.0);
    assert_eq!(Quat::IDENTITY[1], 0.0);
    assert_eq!(Quat::IDENTITY[2], 0.0);
    assert_eq!(Quat::IDENTITY[3], 1.0);
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn index_panics_out_of_bounds() {
    let _ = Quat::IDENTITY[4];
}

#[test]
fn index_mut() {
    let mut q: Quat = Quat::IDENTITY;
    q[0] = 10.0;
    assert_eq!(q, Quat::new(10.0, 0.0, 0.0, 1.0));
}

#[test]
fn as_ref_array() {
    let r: &[f32; 4] = Quat::IDENTITY.as_ref();
    assert_eq!(r, &[0.0, 0.0, 0.0, 1.0]);
}

#[test]
fn as_mut_array() {
    let mut q: Quat = Quat::IDENTITY;
    let r: &mut [f32; 4] = q.as_mut();

    r[0] = 10.0;

    assert_eq!(q, Quat::new(10.0, 0.0, 0.0, 1.0));
}

#[test]
fn display() {
    assert_eq!(format!("{}", Quat::IDENTITY), "(0, 0, 0, 1)");
}

#[test]
fn display_with_precision() {
    assert_eq!(format!("{:.2}", Quat::IDENTITY), "(0.00, 0.00, 0.00, 1.00)");
}

#[test]
fn default() {
    assert_eq!(Quat::default(), Quat::IDENTITY);
}

#[test]
fn from_array_trait() {
    assert_eq!(
        Quat::from([1.0, 2.0, 3.0, 4.0]),
        Quat::new(1.0, 2.0, 3.0, 4.0)
    );
}

#[test]
fn array_from_quat() {
    assert_eq!(
        <[f32; 4]>::from(Quat::new(1.0, 2.0, 3.0, 4.0)),
        [1.0, 2.0, 3.0, 4.0]
    );
}

#[test]
fn from_slice_trait() {
    let slice: &[f32] = &[1.0, 2.0, 3.0, 4.0];
    assert_eq!(Quat::from(slice), Quat::new(1.0, 2.0, 3.0, 4.0));
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn from_slice_trait_panics_if_too_short() {
    let slice: &[f32] = &[1.0, 2.0, 3.0];
    let _ = Quat::from(slice);
}

#[test]
fn from_vec4_trait() {
    assert_eq!(
        Quat::from(Vec4::new(1.0, 2.0, 3.0, 4.0)),
        Quat::new(1.0, 2.0, 3.0, 4.0)
    );
}
