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

1# SPDX-FileCopyrightText: 2026-present Pavel M. Penev <pavpen@gmail.com> 

2# 

3# SPDX-License-Identifier: MIT 

4 

5import pytest 

6 

7from pavpen.geometry_calculator.float_vector_field_operations import FloatVectorFieldOperations 

8 

9 

10class UnimplementedFloatVectorFieldOperations[Vector](FloatVectorFieldOperations[Vector]): 

11 @property 

12 def additive_identity(self) -> Vector: 

13 raise NotImplementedError 

14 

15 def negated(self, value: Vector) -> Vector: 

16 return self.scaled(value, self.multiplicative_negator) 

17 

18 def added(self, addend1: Vector, addend2: Vector) -> Vector: 

19 raise NotImplementedError 

20 

21 def subtracted(self, diminuend: Vector, subtrahend: Vector) -> Vector: 

22 return self.added(diminuend, self.negated(subtrahend)) 

23 

24 def scaled(self, multiplicand: Vector, scalar: float) -> Vector: 

25 raise NotImplementedError 

26 

27 def inner_multiplied(self, multiplicand1: Vector, multiplicand2: Vector) -> float: 

28 raise NotImplementedError 

29 

30 

31class TestUnimplementedFloatVectorFieldOperations: 

32 """Code coverage include tests, so we test our test helpers 

33 

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 """ 

37 

38 def test_additive_identity_throws(self): 

39 # Setup 

40 operations = UnimplementedFloatVectorFieldOperations[complex]() 

41 

42 # Act, and verify 

43 with pytest.raises(NotImplementedError): 

44 _ = operations.additive_identity 

45 

46 def test_negated_throws(self): 

47 # Setup 

48 operations = UnimplementedFloatVectorFieldOperations[complex]() 

49 

50 # Act, and verify 

51 with pytest.raises(NotImplementedError): 

52 operations.negated(3 + 4j) 

53 

54 def test_added_throws(self): 

55 # Setup 

56 operations = UnimplementedFloatVectorFieldOperations[complex]() 

57 

58 # Act, and verify 

59 with pytest.raises(NotImplementedError): 

60 operations.added(3 + 4j, 5 + 6j) 

61 

62 def test_subtracted_throws(self): 

63 # Setup 

64 operations = UnimplementedFloatVectorFieldOperations[complex]() 

65 

66 # Act, and verify 

67 with pytest.raises(NotImplementedError): 

68 operations.subtracted(3 + 4j, 5 + 6j) 

69 

70 def test_inner_multiplied_throws(self): 

71 # Setup 

72 operations = UnimplementedFloatVectorFieldOperations[complex]() 

73 

74 # Act, and verify 

75 with pytest.raises(NotImplementedError): 

76 operations.inner_multiplied(3 + 4j, 5 + 6j) 

77 

78 

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] 

85 

86 vector_field_operations = SampleVectorFieldOperations() 

87 

88 # Act, and verify 

89 assert vector_field_operations.norm((3, 4)) == pytest.approx(5) 

90 

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) 

96 

97 def inner_multiplied(self, multiplicand1: tuple[float, float], multiplicand2: tuple[float, float]) -> float: 

98 return multiplicand1[0] * multiplicand2[0] + multiplicand1[1] * multiplicand2[1] 

99 

100 vector_field_operations = SampleVectorFieldOperations() 

101 

102 # Act, and verify 

103 assert vector_field_operations.normalized((3, -4)) == pytest.approx((3.0 / 5.0, -4.0 / 5.0)) 

104 

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] 

110 

111 vector_field_operations = SampleVectorFieldOperations() 

112 

113 # Act, and verify 

114 assert vector_field_operations.projection_length_along((3, 4), (0, 1)) == pytest.approx(4) 

115 

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] 

121 

122 vector_field_operations = SampleVectorFieldOperations() 

123 

124 # Act, and verify 

125 assert vector_field_operations.projection_length_along((3, 4), (0, -1)) == pytest.approx(-4)