Coverage for tests \ test_float_vector_field_operations.py: 100%
64 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-27 03:59 -0400
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-27 03:59 -0400
1# SPDX-FileCopyrightText: 2026-present Pavel M. Penev <pavpen@gmail.com>
2#
3# SPDX-License-Identifier: MIT
5import pytest
7from pavpen.geometry_calculator.float_vector_field_operations import FloatVectorFieldOperations
10class UnimplementedFloatVectorFieldOperations[Vector](FloatVectorFieldOperations[Vector]):
11 @property
12 def additive_identity(self) -> Vector:
13 raise NotImplementedError
15 def negated(self, value: Vector) -> Vector:
16 return self.scaled(value, self.multiplicative_negator)
18 def added(self, addend1: Vector, addend2: Vector) -> Vector:
19 raise NotImplementedError
21 def subtracted(self, diminuend: Vector, subtrahend: Vector) -> Vector:
22 return self.added(diminuend, self.negated(subtrahend))
24 def scaled(self, multiplicand: Vector, scalar: float) -> Vector:
25 raise NotImplementedError
27 def inner_multiplied(self, multiplicand1: Vector, multiplicand2: Vector) -> float:
28 raise NotImplementedError
31class TestUnimplementedFloatVectorFieldOperations:
32 """Code coverage include tests, so we test our test helpers
34 See the tip in
35 [Exclude code from test coverage](https://python-basics-tutorial.readthedocs.io/en/latest/test/pytest/coverage.html#exclude-code-from-test-coverage)
36 """
38 def test_additive_identity_throws(self):
39 # Setup
40 operations = UnimplementedFloatVectorFieldOperations[complex]()
42 # Act, and verify
43 with pytest.raises(NotImplementedError):
44 _ = operations.additive_identity
46 def test_negated_throws(self):
47 # Setup
48 operations = UnimplementedFloatVectorFieldOperations[complex]()
50 # Act, and verify
51 with pytest.raises(NotImplementedError):
52 operations.negated(3 + 4j)
54 def test_added_throws(self):
55 # Setup
56 operations = UnimplementedFloatVectorFieldOperations[complex]()
58 # Act, and verify
59 with pytest.raises(NotImplementedError):
60 operations.added(3 + 4j, 5 + 6j)
62 def test_subtracted_throws(self):
63 # Setup
64 operations = UnimplementedFloatVectorFieldOperations[complex]()
66 # Act, and verify
67 with pytest.raises(NotImplementedError):
68 operations.subtracted(3 + 4j, 5 + 6j)
70 def test_inner_multiplied_throws(self):
71 # Setup
72 operations = UnimplementedFloatVectorFieldOperations[complex]()
74 # Act, and verify
75 with pytest.raises(NotImplementedError):
76 operations.inner_multiplied(3 + 4j, 5 + 6j)
79class TestFloatVectorFieldOperations:
80 def test_norm_returns_a_value_corresponding_to_inner_product(self):
81 # Setup
82 class SampleVectorFieldOperations(UnimplementedFloatVectorFieldOperations[tuple[float, float]]):
83 def inner_multiplied(self, multiplicand1: tuple[float, float], multiplicand2: tuple[float, float]) -> float:
84 return multiplicand1[0] * multiplicand2[0] + multiplicand1[1] * multiplicand2[1]
86 vector_field_operations = SampleVectorFieldOperations()
88 # Act, and verify
89 assert vector_field_operations.norm((3, 4)) == pytest.approx(5)
91 def test_normalized_returns_a_unit_vector(self):
92 # Setup
93 class SampleVectorFieldOperations(UnimplementedFloatVectorFieldOperations[tuple[float, float]]):
94 def scaled(self, multiplicand: tuple[float, float], scalar: float) -> tuple[float, float]:
95 return (multiplicand[0] * scalar, multiplicand[1] * scalar)
97 def inner_multiplied(self, multiplicand1: tuple[float, float], multiplicand2: tuple[float, float]) -> float:
98 return multiplicand1[0] * multiplicand2[0] + multiplicand1[1] * multiplicand2[1]
100 vector_field_operations = SampleVectorFieldOperations()
102 # Act, and verify
103 assert vector_field_operations.normalized((3, -4)) == pytest.approx((3.0 / 5.0, -4.0 / 5.0))
105 def test_projection_length_on_calculates_a_positive_length(self):
106 # Setup
107 class SampleVectorFieldOperations(UnimplementedFloatVectorFieldOperations[tuple[float, float]]):
108 def inner_multiplied(self, multiplicand1: tuple[float, float], multiplicand2: tuple[float, float]) -> float:
109 return multiplicand1[0] * multiplicand2[0] + multiplicand1[1] * multiplicand2[1]
111 vector_field_operations = SampleVectorFieldOperations()
113 # Act, and verify
114 assert vector_field_operations.projection_length_along((3, 4), (0, 1)) == pytest.approx(4)
116 def test_projection_length_on_calculates_a_negative_length(self):
117 # Setup
118 class SampleVectorFieldOperations(UnimplementedFloatVectorFieldOperations[tuple[float, float]]):
119 def inner_multiplied(self, multiplicand1: tuple[float, float], multiplicand2: tuple[float, float]) -> float:
120 return multiplicand1[0] * multiplicand2[0] + multiplicand1[1] * multiplicand2[1]
122 vector_field_operations = SampleVectorFieldOperations()
124 # Act, and verify
125 assert vector_field_operations.projection_length_along((3, 4), (0, -1)) == pytest.approx(-4)