128 lines
3.5 KiB
Python
128 lines
3.5 KiB
Python
"""Tests der eigenen Vektorklasse."""
|
|
|
|
import copy
|
|
import math
|
|
import pickle
|
|
|
|
import pytest
|
|
|
|
from sandbox.physics.vector import ZERO, Vector2
|
|
|
|
|
|
def test_addition_and_subtraction() -> None:
|
|
assert Vector2(1, 2) + Vector2(3, -5) == Vector2(4, -3)
|
|
assert Vector2(1, 2) - Vector2(3, -5) == Vector2(-2, 7)
|
|
|
|
|
|
def test_scaling_from_both_sides_and_division() -> None:
|
|
assert Vector2(1.5, -2) * 2 == Vector2(3, -4)
|
|
assert 2 * Vector2(1.5, -2) == Vector2(3, -4)
|
|
assert Vector2(3, -4) / 2 == Vector2(1.5, -2)
|
|
|
|
|
|
def test_negation() -> None:
|
|
assert -Vector2(1, -2) == Vector2(-1, 2)
|
|
|
|
|
|
def test_dot_product() -> None:
|
|
assert Vector2(1, 2).dot(Vector2(3, 4)) == 11
|
|
assert Vector2(1, 0).dot(Vector2(0, 5)) == 0 # orthogonal
|
|
|
|
|
|
def test_cross_product_sign_and_value() -> None:
|
|
assert Vector2(1, 0).cross(Vector2(0, 1)) == 1
|
|
assert Vector2(0, 1).cross(Vector2(1, 0)) == -1
|
|
assert Vector2(2, 3).cross(Vector2(4, 6)) == 0 # parallel
|
|
|
|
|
|
def test_length_and_length_squared() -> None:
|
|
v = Vector2(3, 4)
|
|
assert v.length() == 5
|
|
assert v.length_squared() == 25
|
|
|
|
|
|
def test_normalized_has_unit_length_and_same_direction() -> None:
|
|
n = Vector2(3, 4).normalized()
|
|
assert n.length() == pytest.approx(1.0)
|
|
assert n.is_close(Vector2(0.6, 0.8))
|
|
|
|
|
|
def test_normalizing_the_zero_vector_returns_zero_instead_of_nan() -> None:
|
|
assert Vector2(0, 0).normalized() == ZERO
|
|
|
|
|
|
def test_perpendicular_is_rotated_by_plus_90_degrees() -> None:
|
|
v = Vector2(2, 1)
|
|
p = v.perpendicular()
|
|
assert p == Vector2(-1, 2)
|
|
assert v.dot(p) == 0
|
|
assert v.cross(p) > 0
|
|
|
|
|
|
def test_distance() -> None:
|
|
assert Vector2(1, 1).distance_to(Vector2(4, 5)) == 5
|
|
|
|
|
|
def test_clamped_limits_only_long_vectors() -> None:
|
|
short = Vector2(1, 1)
|
|
assert short.clamped(10) is short
|
|
clamped = Vector2(30, 40).clamped(10)
|
|
assert clamped.length() == pytest.approx(10)
|
|
assert clamped.is_close(Vector2(6, 8))
|
|
|
|
|
|
def test_lerp() -> None:
|
|
a = Vector2(0, 10)
|
|
b = Vector2(10, 20)
|
|
assert a.lerp(b, 0) == a
|
|
assert a.lerp(b, 1) == b
|
|
assert a.lerp(b, 0.5) == Vector2(5, 15)
|
|
|
|
|
|
def test_is_finite() -> None:
|
|
assert Vector2(1, 2).is_finite()
|
|
assert not Vector2(math.nan, 0).is_finite()
|
|
assert not Vector2(0, math.inf).is_finite()
|
|
|
|
|
|
def test_is_close_uses_absolute_tolerance() -> None:
|
|
assert Vector2(1, 1).is_close(Vector2(1 + 1e-12, 1))
|
|
assert not Vector2(1, 1).is_close(Vector2(1.1, 1))
|
|
assert Vector2(1, 1).is_close(Vector2(1.1, 1), tolerance=0.2)
|
|
|
|
|
|
def test_equality_hash_and_comparison_with_other_types() -> None:
|
|
assert Vector2(1, 2) == Vector2(1.0, 2.0)
|
|
assert Vector2(1, 2) != Vector2(2, 1)
|
|
assert Vector2(1, 2) != (1, 2)
|
|
assert len({Vector2(1, 2), Vector2(1, 2), Vector2(2, 1)}) == 2
|
|
|
|
|
|
def test_vectors_are_immutable() -> None:
|
|
v = Vector2(1, 2)
|
|
with pytest.raises(AttributeError):
|
|
v.x = 5 # type: ignore[misc]
|
|
with pytest.raises(AttributeError):
|
|
del v.y
|
|
assert v == Vector2(1, 2)
|
|
|
|
|
|
def test_operations_do_not_modify_operands() -> None:
|
|
a = Vector2(1, 2)
|
|
b = Vector2(3, 4)
|
|
_ = (a + b, a - b, a * 3, a / 2, -a, a.normalized(), a.clamped(0.1), a.lerp(b, 0.5))
|
|
assert a == Vector2(1, 2)
|
|
assert b == Vector2(3, 4)
|
|
|
|
|
|
def test_copy_and_pickle_round_trip() -> None:
|
|
v = Vector2(1.5, -2.5)
|
|
assert copy.copy(v) == v
|
|
assert copy.deepcopy(v) == v
|
|
assert pickle.loads(pickle.dumps(v)) == v
|
|
|
|
|
|
def test_repr_and_tuple() -> None:
|
|
assert repr(Vector2(1.5, 2)) == "Vector2(1.5, 2)"
|
|
assert Vector2(1.5, 2).to_tuple() == (1.5, 2)
|