Skip to content

Commit b02763a

Browse files
committed
feat: add MustBeLessThanOrApproximately
Signed-off-by: Kenny Pflug <kenny.pflug@live.de>
1 parent 444ca1a commit b02763a

File tree

3 files changed

+615
-0
lines changed

3 files changed

+615
-0
lines changed
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
using System;
2+
using FluentAssertions;
3+
using Xunit;
4+
5+
namespace Light.GuardClauses.Tests.ComparableAssertions;
6+
7+
public static class MustBeLessThanOrApproximatelyTests
8+
{
9+
[Theory]
10+
[InlineData(17.3, 17.4)]
11+
[InlineData(19.9999999, 20.0)]
12+
[InlineData(-5.5, -5.49998)]
13+
[InlineData(0.0001, 0.0001)]
14+
public static void EqualOrLess_Double(double first, double second) =>
15+
first.MustBeLessThanOrApproximately(second).Should().Be(first);
16+
17+
[Theory]
18+
[InlineData(15.9, 15.91, 0.1)]
19+
[InlineData(24.45, 24.49999, 0.0001)]
20+
[InlineData(-3.2, -3.12, 0.001)]
21+
[InlineData(2.37, 2.369, 0.05)]
22+
public static void EqualOrLessWithTolerance_Double(double first, double second, double tolerance) =>
23+
first.MustBeLessThanOrApproximately(second, tolerance).Should().Be(first);
24+
25+
[Theory]
26+
[InlineData(100.2f, 100.225f)]
27+
[InlineData(-5.900005f, -5.9f)]
28+
[InlineData(-0.02f, 0f)]
29+
[InlineData(0f, 0.00001f)]
30+
public static void EqualOrLess_Float(float first, float second) =>
31+
first.MustBeLessThanOrApproximately(second).Should().Be(first);
32+
33+
[Theory]
34+
[InlineData(1.0f, 2.0f, 0.1f)]
35+
[InlineData(1.0f, 1.0f, 0.1f)]
36+
[InlineData(1.1f, 1.01f, 0.1f)]
37+
[InlineData(1.0f, 2.0f, 1.0f)]
38+
public static void EqualOrLessWithTolerance_Float(float first, float second, float tolerance) =>
39+
first.MustBeLessThanOrApproximately(second, tolerance).Should().Be(first);
40+
41+
[Theory]
42+
[InlineData(5.3, 5.0, 0.1)]
43+
[InlineData(100.5, 100.0, 0.1)]
44+
[InlineData(-19.8, -20.0, 0.1)]
45+
[InlineData(0.0003, 0.0001, 0.00005)]
46+
public static void NotLessThanOrApproximately_Double(double value, double other, double tolerance)
47+
{
48+
var act = () => value.MustBeLessThanOrApproximately(other, tolerance, nameof(value));
49+
50+
var exceptionAssertion = act.Should().Throw<ArgumentOutOfRangeException>().Which;
51+
exceptionAssertion.Message.Should().Contain(
52+
$"{nameof(value)} must be less than or approximately equal to {other} with a tolerance of {tolerance}, but it actually is {value}."
53+
);
54+
exceptionAssertion.ParamName.Should().BeSameAs(nameof(value));
55+
}
56+
57+
[Theory]
58+
[InlineData(5.3f, 5.0f, 0.1f)]
59+
[InlineData(100.5f, 100.0f, 0.1f)]
60+
[InlineData(-19.8f, -20.0f, 0.1f)]
61+
[InlineData(0.0003f, 0.0001f, 0.00005f)]
62+
public static void NotLessThanOrApproximately_Float(float value, float other, float tolerance)
63+
{
64+
var act = () => value.MustBeLessThanOrApproximately(other, tolerance, nameof(value));
65+
66+
var exceptionAssertion = act.Should().Throw<ArgumentOutOfRangeException>().Which;
67+
exceptionAssertion.Message.Should().Contain(
68+
$"{nameof(value)} must be less than or approximately equal to {other} with a tolerance of {tolerance}, but it actually is {value}."
69+
);
70+
exceptionAssertion.ParamName.Should().BeSameAs(nameof(value));
71+
}
72+
73+
[Fact]
74+
public static void DefaultTolerance_Double()
75+
{
76+
// Should pass - difference is 0.00005 which is less than default tolerance 0.0001
77+
const double value = 1.0;
78+
value.MustBeLessThanOrApproximately(1.00005).Should().Be(value);
79+
80+
// Should throw - difference is 0.0002 which is greater than default tolerance 0.0001
81+
Action act = () => 1.0002.MustBeLessThanOrApproximately(1.0, "parameter");
82+
act.Should().Throw<ArgumentOutOfRangeException>()
83+
.WithParameterName("parameter");
84+
}
85+
86+
[Fact]
87+
public static void DefaultTolerance_Float()
88+
{
89+
// Should pass - difference is 0.00005f which is less than default tolerance 0.0001f
90+
const float value = 1.0f;
91+
value.MustBeLessThanOrApproximately(1.00005f).Should().Be(value);
92+
93+
// Should throw - difference is 0.0002f which is greater than default tolerance 0.0001f
94+
Action act = () => 1.0002f.MustBeLessThanOrApproximately(1.0f, "parameter");
95+
act.Should().Throw<ArgumentOutOfRangeException>()
96+
.WithParameterName("parameter");
97+
}
98+
99+
[Fact]
100+
public static void CustomException_Double() =>
101+
Test.CustomException(
102+
5.3,
103+
5.0,
104+
(x, y, exceptionFactory) => x.MustBeLessThanOrApproximately(y, exceptionFactory)
105+
);
106+
107+
[Fact]
108+
public static void CustomExceptionWithTolerance_Double() =>
109+
Test.CustomException(
110+
5.5,
111+
5.0,
112+
0.1,
113+
(x, y, z, exceptionFactory) => x.MustBeLessThanOrApproximately(y, z, exceptionFactory)
114+
);
115+
116+
[Fact]
117+
public static void CustomException_Float() =>
118+
Test.CustomException(
119+
5.3f,
120+
5.0f,
121+
(x, y, exceptionFactory) => x.MustBeLessThanOrApproximately(y, exceptionFactory)
122+
);
123+
124+
[Fact]
125+
public static void CustomExceptionWithTolerance_Float() =>
126+
Test.CustomException(
127+
5.5f,
128+
5.0f,
129+
0.1f,
130+
(x, y, z, exceptionFactory) => x.MustBeLessThanOrApproximately(y, z, exceptionFactory)
131+
);
132+
133+
[Fact]
134+
public static void NoCustomExceptionThrown_Double() =>
135+
5.1.MustBeLessThanOrApproximately(5.2, (_, _) => null).Should().Be(5.1);
136+
137+
[Fact]
138+
public static void NoCustomExceptionThrownWithTolerance_Double() =>
139+
5.0.MustBeLessThanOrApproximately(5.2, 0.1, (_, _, _) => null).Should().Be(5.0);
140+
141+
[Fact]
142+
public static void NoCustomExceptionThrown_Float() =>
143+
5.0f.MustBeLessThanOrApproximately(5.2f, (_, _) => null).Should().Be(5.0f);
144+
145+
[Fact]
146+
public static void NoCustomExceptionThrownWithTolerance_Float() =>
147+
5.0f.MustBeLessThanOrApproximately(5.2f, 0.1f, (_, _, _) => null).Should().Be(5.0f);
148+
149+
[Fact]
150+
public static void CustomMessage_Double() =>
151+
Test.CustomMessage<ArgumentOutOfRangeException>(
152+
message => 101.0.MustBeLessThanOrApproximately(100.0, 0.5, message: message)
153+
);
154+
155+
[Fact]
156+
public static void CustomMessage_Float() =>
157+
Test.CustomMessage<ArgumentOutOfRangeException>(
158+
message => 101.0f.MustBeLessThanOrApproximately(100.0f, 0.5f, message: message)
159+
);
160+
161+
[Fact]
162+
public static void CallerArgumentExpression_Double()
163+
{
164+
const double seventyNinePoint0 = 79.0;
165+
166+
var act = () => seventyNinePoint0.MustBeLessThanOrApproximately(78.1);
167+
168+
act.Should().Throw<ArgumentOutOfRangeException>()
169+
.WithParameterName(nameof(seventyNinePoint0));
170+
}
171+
172+
[Fact]
173+
public static void CallerArgumentExpressionWithTolerance_Double()
174+
{
175+
const double threePointFive = 3.5;
176+
177+
var act = () => threePointFive.MustBeLessThanOrApproximately(3.14159, 0.1);
178+
179+
act.Should().Throw<ArgumentOutOfRangeException>()
180+
.WithParameterName(nameof(threePointFive));
181+
}
182+
183+
[Fact]
184+
public static void CallerArgumentExpression_Float()
185+
{
186+
const float seventyNinePoint0 = 79.0f;
187+
188+
var act = () => seventyNinePoint0.MustBeLessThanOrApproximately(78.1f);
189+
190+
act.Should().Throw<ArgumentOutOfRangeException>()
191+
.WithParameterName(nameof(seventyNinePoint0));
192+
}
193+
194+
[Fact]
195+
public static void CallerArgumentExpressionWithTolerance_Float()
196+
{
197+
const float threePointFive = 3.5f;
198+
199+
var act = () => threePointFive.MustBeLessThanOrApproximately(3.14159f, 0.1f);
200+
201+
act.Should().Throw<ArgumentOutOfRangeException>()
202+
.WithParameterName(nameof(threePointFive));
203+
}
204+
205+
#if NET8_0
206+
[Theory]
207+
[InlineData(15.9, 15.91, 0.1)]
208+
[InlineData(24.45, 24.4999, 0.0001)]
209+
[InlineData(-3.2, -3.12, 0.001)]
210+
[InlineData(2.37, 2.369, 0.05)]
211+
[InlineData(14.0, 15.0, 0.1)] // Less than case
212+
[InlineData(15.0, 14.95, 0.1)] // Approximately equal case
213+
public static void EqualOrLessWithCustomTolerance_GenericDouble(double first, double second, double tolerance) =>
214+
first.MustBeLessThanOrApproximately<double>(second, tolerance).Should().Be(first);
215+
216+
[Theory]
217+
[InlineData(5, 10, 1)] // Less than case
218+
[InlineData(5, 5, 1)] // Equal case
219+
[InlineData(6, 5, 1)] // Approximately equal case
220+
[InlineData(7, 5, 2)] // Not less than or approximately equal case
221+
public static void EqualOrLessWithCustomTolerance_GenericInt32(int first, int second, int tolerance) =>
222+
first.MustBeLessThanOrApproximately(second, tolerance).Should().Be(first);
223+
224+
[Theory]
225+
[InlineData(5L, 10L, 1L)] // Less than case
226+
[InlineData(5L, 5L, 1L)] // Equal case
227+
[InlineData(6L, 5L, 1L)] // Approximately equal case
228+
[InlineData(7L, 4L, 3L)] // Not less than or approximately equal case
229+
public static void EqualOrLessWithCustomTolerance_GenericInt64(long first, long second, long tolerance) =>
230+
first.MustBeLessThanOrApproximately(second, tolerance).Should().Be(first);
231+
232+
[Theory]
233+
[MemberData(nameof(DecimalTestData))]
234+
public static void GenericDecimalWithCustomTolerance(
235+
decimal first,
236+
decimal second,
237+
decimal tolerance
238+
) =>
239+
first.MustBeLessThanOrApproximately(second, tolerance).Should().Be(first);
240+
241+
public static TheoryData<decimal, decimal, decimal> DecimalTestData() => new ()
242+
{
243+
{ 1.1m, 1.3m, 0.1m }, // Less than case
244+
{ 1.1m, 1.1m, 0.1m }, // Equal case
245+
{ 1.1m, 1.0m, 0.2m }, // Approximately equal case
246+
{ 1.3m, 1.292m, 0.1m }, // Not less than or approximately equal case
247+
};
248+
249+
[Theory]
250+
[InlineData(5.3, 5.0, 0.1)]
251+
[InlineData(100.5, 100.0, 0.1)]
252+
[InlineData(-19.8, -20.0, 0.1)]
253+
[InlineData(0.0003, 0.0001, 0.00005)]
254+
public static void NotLessThanOrApproximately_Generic(double value, double other, double tolerance)
255+
{
256+
var act = () => value.MustBeLessThanOrApproximately<double>(other, tolerance, nameof(value));
257+
258+
var exceptionAssertion = act.Should().Throw<ArgumentOutOfRangeException>().Which;
259+
exceptionAssertion.Message.Should().Contain(
260+
$"{nameof(value)} must be less than or approximately equal to {other} with a tolerance of {tolerance}, but it actually is {value}."
261+
);
262+
exceptionAssertion.ParamName.Should().BeSameAs(nameof(value));
263+
}
264+
265+
[Fact]
266+
public static void CustomExceptionWithTolerance_Generic() =>
267+
Test.CustomException(
268+
5.5,
269+
5.0,
270+
0.1,
271+
(x, y, t, exceptionFactory) => x.MustBeLessThanOrApproximately<double>(y, t, exceptionFactory)
272+
);
273+
274+
[Fact]
275+
public static void NoCustomExceptionThrown_Generic() =>
276+
5.0.MustBeLessThanOrApproximately<double>(5.2, 0.1, (_, _, _) => null).Should().Be(5.0);
277+
278+
[Fact]
279+
public static void CustomMessage_Generic() =>
280+
Test.CustomMessage<ArgumentOutOfRangeException>(
281+
message => 101.0.MustBeLessThanOrApproximately<double>(100.0, 0.5, message: message)
282+
);
283+
284+
[Fact]
285+
public static void CallerArgumentExpressionWithTolerance_Generic()
286+
{
287+
const double seventyNinePoint0 = 79.0;
288+
289+
var act = () => seventyNinePoint0.MustBeLessThanOrApproximately<double>(78.1, 0.5);
290+
291+
act.Should().Throw<ArgumentOutOfRangeException>()
292+
.WithParameterName(nameof(seventyNinePoint0));
293+
}
294+
#endif
295+
}

0 commit comments

Comments
 (0)