Skip to content

Commit 974534a

Browse files
author
Felix
committed
(+) full test coverage
1 parent 147bcbf commit 974534a

11 files changed

Lines changed: 725 additions & 363 deletions

DualNumbers.Test/Interfaces/Dual_IDecrementOperatorsTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@ public class DualIDecrementOperatorsTests
77
{
88
private static T Decrement<T>(T value) where T : IDecrementOperators<T> => --value;
99

10+
private static Dual DecrementDirect(Dual value) => --value;
11+
1012
[Test]
1113
public void IDecrementOperators_Decrement_ReducesRealPartOnly()
1214
{
1315
Dual result = Decrement(new Dual(8.0, 3.0));
1416

1517
DualInterfaceAssert.AreEqual(result, 7.0, 3.0);
1618
}
19+
20+
[Test]
21+
public void OperatorDecrement_DirectOperator_ReducesRealPartOnly()
22+
{
23+
Dual result = DecrementDirect(new Dual(8.0, 3.0));
24+
25+
DualInterfaceAssert.AreEqual(result, 7.0, 3.0);
26+
}
1727
}

DualNumbers.Test/Interfaces/Dual_IEqualityOperatorsTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ public void IEqualityOperators_EqualityAndInequality_WorkAsExpected()
1717
Assert.That(AreEqual(left, new Dual(3.0, 2.0)), Is.True);
1818
Assert.That(AreNotEqual(left, new Dual(3.0, 5.0)), Is.True);
1919
}
20+
21+
[Test]
22+
public void IEqualityOperators_BranchCombinations_WorkAsExpected()
23+
{
24+
Dual reference = new(3.0, 2.0);
25+
26+
Assert.That(AreEqual(reference, new Dual(9.0, 2.0)), Is.False);
27+
Assert.That(AreEqual(reference, new Dual(3.0, 9.0)), Is.False);
28+
Assert.That(AreNotEqual(reference, new Dual(9.0, 2.0)), Is.True);
29+
Assert.That(AreNotEqual(reference, new Dual(3.0, 2.0)), Is.False);
30+
}
2031
}

DualNumbers.Test/Interfaces/Dual_IEquatableTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,26 @@ public void IEquatable_Equals_WorkAsExpected()
1313
Assert.That(EqualsViaInterface(left, new Dual(3.0, 2.0)), Is.True);
1414
Assert.That(EqualsViaInterface(left, new Dual(3.0, 5.0)), Is.False);
1515
}
16+
17+
[Test]
18+
public void IEquatable_EqualsObjectAndHashCode_WorkAsExpected()
19+
{
20+
Dual left = new(3.0, 2.0);
21+
object same = new Dual(3.0, 2.0);
22+
object different = new Dual(3.0, 5.0);
23+
24+
Assert.That(left.Equals(same), Is.True);
25+
Assert.That(left.Equals(different), Is.False);
26+
Assert.That(left.GetHashCode(), Is.EqualTo(((Dual)same).GetHashCode()));
27+
}
28+
29+
[Test]
30+
public void IEquatable_EqualsObject_BranchesForNullAndDifferentType()
31+
{
32+
Dual left = new(3.0, 2.0);
33+
34+
Assert.That(left.Equals(null), Is.False);
35+
Assert.That(left.Equals("not-a-dual"), Is.False);
36+
Assert.That(left.Equals(new Dual(9.0, 2.0)), Is.False);
37+
}
1638
}

DualNumbers.Test/Interfaces/Dual_IIncrementOperatorsTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@ public class DualIIncrementOperatorsTests
77
{
88
private static T Increment<T>(T value) where T : IIncrementOperators<T> => ++value;
99

10+
private static Dual IncrementDirect(Dual value) => ++value;
11+
1012
[Test]
1113
public void IIncrementOperators_Increment_IncreasesRealPartOnly()
1214
{
1315
Dual result = Increment(new Dual(8.0, 3.0));
1416

1517
DualInterfaceAssert.AreEqual(result, 9.0, 3.0);
1618
}
19+
20+
[Test]
21+
public void OperatorIncrement_DirectOperator_IncreasesRealPartOnly()
22+
{
23+
Dual result = IncrementDirect(new Dual(8.0, 3.0));
24+
25+
DualInterfaceAssert.AreEqual(result, 9.0, 3.0);
26+
}
1727
}

DualNumbers.Test/Interfaces/Dual_INumberBaseTests.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System.Numerics;
2+
using System.Globalization;
3+
using System.Diagnostics.CodeAnalysis;
24

35
namespace DualNumbers.Test.Interfaces;
46

@@ -14,6 +16,22 @@ public class DualINumberBaseTests
1416
private static double GetAbs<T>(T value) where T : INumberBase<T>
1517
=> double.CreateChecked(T.Abs(value));
1618

19+
private static bool IsFinite<T>(T value) where T : INumberBase<T> => T.IsFinite(value);
20+
21+
private static bool IsZero<T>(T value) where T : INumberBase<T> => T.IsZero(value);
22+
23+
private static T ParseFromString<T>(string s, NumberStyles style, IFormatProvider? provider) where T : INumberBase<T>
24+
=> T.Parse(s, style, provider);
25+
26+
private static T ParseFromSpan<T>(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) where T : INumberBase<T>
27+
=> T.Parse(s, style, provider);
28+
29+
private static bool TryParseFromString<T>(string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out T result) where T : INumberBase<T>
30+
=> T.TryParse(s, style, provider, out result);
31+
32+
private static bool TryParseFromSpan<T>(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out T result) where T : INumberBase<T>
33+
=> T.TryParse(s, style, provider, out result);
34+
1735
[Test]
1836
public void INumberBase_RadixOneAndZero_ReturnExpectedValues()
1937
{
@@ -29,4 +47,62 @@ public void INumberBase_Abs_UsesMagnitude()
2947

3048
Assert.That(abs, Is.EqualTo(5.0).Within(1e-12));
3149
}
50+
51+
[Test]
52+
public void INumberBase_IsFiniteAndIsZero_WorkAsExpected()
53+
{
54+
Assert.That(IsFinite(new Dual(1.0, 0.0)), Is.True);
55+
Assert.That(IsFinite(new Dual(double.PositiveInfinity, 0.0)), Is.False);
56+
Assert.That(IsZero(Dual.Zero), Is.True);
57+
}
58+
59+
[Test]
60+
public void INumberBase_ParseAndTryParse_WithNumberStyles_WorkAsExpected()
61+
{
62+
Complex expected = new(3.5, -2.25);
63+
string text = expected.ToString(CultureInfo.InvariantCulture);
64+
NumberStyles style = NumberStyles.Float | NumberStyles.AllowParentheses;
65+
66+
Dual parsedFromString = ParseFromString<Dual>(text, style, CultureInfo.InvariantCulture);
67+
Dual parsedFromSpan = ParseFromSpan<Dual>(text.AsSpan(), style, CultureInfo.InvariantCulture);
68+
bool tryStringOk = TryParseFromString<Dual>(text, style, CultureInfo.InvariantCulture, out Dual tryParsedFromString);
69+
bool trySpanOk = TryParseFromSpan<Dual>(text.AsSpan(), style, CultureInfo.InvariantCulture, out Dual tryParsedFromSpan);
70+
71+
Assert.That(tryStringOk, Is.True);
72+
Assert.That(trySpanOk, Is.True);
73+
DualInterfaceAssert.AreEqual(parsedFromString, expected.Real, expected.Imaginary);
74+
DualInterfaceAssert.AreEqual(parsedFromSpan, expected.Real, expected.Imaginary);
75+
DualInterfaceAssert.AreEqual(tryParsedFromString, expected.Real, expected.Imaginary);
76+
DualInterfaceAssert.AreEqual(tryParsedFromSpan, expected.Real, expected.Imaginary);
77+
}
78+
79+
[Test]
80+
public void INumberBase_ExplicitTryConvertFromMethods_WorkAsExpected()
81+
{
82+
bool checkedOk = Dual.TryConvertFromChecked(3.25d, out Dual checkedResult);
83+
bool saturatingOk = Dual.TryConvertFromSaturating(new Complex(double.PositiveInfinity, double.NegativeInfinity), out Dual saturatingResult);
84+
bool truncatingOk = Dual.TryConvertFromTruncating(new Complex(2.9, -7.2), out Dual truncatingResult);
85+
86+
Assert.That(checkedOk, Is.True);
87+
Assert.That(saturatingOk, Is.True);
88+
Assert.That(truncatingOk, Is.True);
89+
DualInterfaceAssert.AreEqual(checkedResult, 3.25, 0.0);
90+
DualInterfaceAssert.AreEqual(saturatingResult, double.MaxValue, double.MinValue);
91+
DualInterfaceAssert.AreEqual(truncatingResult, 2.0, -7.0);
92+
}
93+
94+
[Test]
95+
public void INumberBase_ExplicitTryConvertToMethods_WorkAsExpected()
96+
{
97+
bool checkedOk = Dual.TryConvertToChecked(new Dual(3.0, 4.0), out int checkedResult);
98+
bool saturatingOk = Dual.TryConvertToSaturating(new Dual(1e308, 1e308), out int saturatingResult);
99+
bool truncatingOk = Dual.TryConvertToTruncating(new Dual(3.0, 4.0), out Complex truncatingResult);
100+
101+
Assert.That(checkedOk, Is.True);
102+
Assert.That(saturatingOk, Is.True);
103+
Assert.That(truncatingOk, Is.True);
104+
Assert.That(checkedResult, Is.EqualTo(5));
105+
Assert.That(saturatingResult, Is.EqualTo(int.MaxValue));
106+
Assert.That(truncatingResult, Is.EqualTo(new Complex(3.0, 4.0)));
107+
}
32108
}

DualNumbers.Test/Interfaces/Dual_INumberTests.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Numerics;
2+
using System.Globalization;
23

34
namespace DualNumbers.Test.Interfaces;
45

@@ -9,6 +10,20 @@ public class DualINumberTests
910

1011
private static bool LessThan<T>(T left, T right) where T : IComparisonOperators<T, T, bool> => left < right;
1112

13+
private const double Tolerance = 1e-12;
14+
15+
private static void AssertDualMatchesComplex(Dual actual, Complex expected)
16+
{
17+
Assert.That(actual.real, Is.EqualTo(expected.Real).Within(Tolerance));
18+
Assert.That(actual.dual, Is.EqualTo(expected.Imaginary).Within(Tolerance));
19+
}
20+
21+
private static bool GreaterThan(Dual left, Dual right) => left > right;
22+
23+
private static bool LessThanOrEqual(Dual left, Dual right) => left <= right;
24+
25+
private static bool GreaterThanOrEqual(Dual left, Dual right) => left >= right;
26+
1227
[Test]
1328
public void INumber_UnsupportedOperators_ThrowNotSupportedException()
1429
{
@@ -17,5 +32,78 @@ public void INumber_UnsupportedOperators_ThrowNotSupportedException()
1732

1833
Assert.Throws<NotSupportedException>(() => _ = Modulus(left, right));
1934
Assert.Throws<NotSupportedException>(() => _ = LessThan(left, right));
35+
Assert.Throws<NotSupportedException>(() => _ = GreaterThan(left, right));
36+
Assert.Throws<NotSupportedException>(() => _ = LessThanOrEqual(left, right));
37+
Assert.Throws<NotSupportedException>(() => _ = GreaterThanOrEqual(left, right));
38+
}
39+
40+
[Test]
41+
public void INumber_PredicateMembers_MatchComplexImplementations()
42+
{
43+
Dual value = new(2.0, 3.0);
44+
Complex expected = new(2.0, 3.0);
45+
46+
Assert.That(Dual.IsComplexNumber(value), Is.EqualTo(Complex.IsComplexNumber(expected)));
47+
Assert.That(Dual.IsEvenInteger(value), Is.EqualTo(Complex.IsEvenInteger(expected)));
48+
Assert.That(Dual.IsFinite(value), Is.EqualTo(Complex.IsFinite(expected)));
49+
Assert.That(Dual.IsImaginaryNumber(value), Is.EqualTo(Complex.IsImaginaryNumber(expected)));
50+
Assert.That(Dual.IsInfinity(value), Is.EqualTo(Complex.IsInfinity(expected)));
51+
Assert.That(Dual.IsInteger(value), Is.EqualTo(Complex.IsInteger(expected)));
52+
Assert.That(Dual.IsNaN(value), Is.EqualTo(Complex.IsNaN(expected)));
53+
Assert.That(Dual.IsNegative(value), Is.EqualTo(Complex.IsNegative(expected)));
54+
Assert.That(Dual.IsNegativeInfinity(value), Is.EqualTo(Complex.IsNegativeInfinity(expected)));
55+
Assert.That(Dual.IsNormal(value), Is.EqualTo(Complex.IsNormal(expected)));
56+
Assert.That(Dual.IsOddInteger(value), Is.EqualTo(Complex.IsOddInteger(expected)));
57+
Assert.That(Dual.IsPositive(value), Is.EqualTo(Complex.IsPositive(expected)));
58+
Assert.That(Dual.IsPositiveInfinity(value), Is.EqualTo(Complex.IsPositiveInfinity(expected)));
59+
Assert.That(Dual.IsRealNumber(value), Is.EqualTo(Complex.IsRealNumber(expected)));
60+
Assert.That(Dual.IsSubnormal(value), Is.EqualTo(Complex.IsSubnormal(expected)));
61+
Assert.That(Dual.IsZero(Dual.Zero), Is.True);
62+
}
63+
64+
[Test]
65+
public void INumber_AbsAndMagnitudeMethods_MatchComplex()
66+
{
67+
Dual x = new(3.0, 4.0);
68+
Dual y = new(2.0, -10.0);
69+
Complex cx = new(3.0, 4.0);
70+
Complex cy = new(2.0, -10.0);
71+
72+
Assert.That(Dual.Abs(x), Is.EqualTo(Complex.Abs(cx)).Within(Tolerance));
73+
AssertDualMatchesComplex(Dual.MaxMagnitude(x, y), Complex.MaxMagnitude(cx, cy));
74+
AssertDualMatchesComplex(Dual.MinMagnitude(x, y), Complex.MinMagnitude(cx, cy));
75+
}
76+
77+
[Test]
78+
public void INumber_ParseAndTryParse_WithNumberStyles_MatchComplex()
79+
{
80+
Complex expected = new(3.5, -2.25);
81+
string text = expected.ToString(CultureInfo.InvariantCulture);
82+
NumberStyles style = NumberStyles.Float | NumberStyles.AllowParentheses;
83+
84+
Dual parsedFromString = Dual.Parse(text, style, CultureInfo.InvariantCulture);
85+
Dual parsedFromSpan = Dual.Parse(text.AsSpan(), style, CultureInfo.InvariantCulture);
86+
bool tryStringOk = Dual.TryParse(text, style, CultureInfo.InvariantCulture, out Dual tryParsedString);
87+
bool trySpanOk = Dual.TryParse(text.AsSpan(), style, CultureInfo.InvariantCulture, out Dual tryParsedSpan);
88+
89+
Assert.That(tryStringOk, Is.True);
90+
Assert.That(trySpanOk, Is.True);
91+
AssertDualMatchesComplex(parsedFromString, expected);
92+
AssertDualMatchesComplex(parsedFromSpan, expected);
93+
AssertDualMatchesComplex(tryParsedString, expected);
94+
AssertDualMatchesComplex(tryParsedSpan, expected);
95+
}
96+
97+
[Test]
98+
public void INumber_UnsupportedMembers_ThrowNotSupportedException()
99+
{
100+
Dual left = new(2.0, 1.0);
101+
Dual right = new(1.0, 0.0);
102+
103+
Assert.Throws<NotSupportedException>(() => _ = Dual.IsCanonical(left));
104+
Assert.Throws<NotSupportedException>(() => _ = Dual.MaxMagnitudeNumber(left, right));
105+
Assert.Throws<NotSupportedException>(() => _ = Dual.MinMagnitudeNumber(left, right));
106+
Assert.Throws<NotSupportedException>(() => _ = left.CompareTo((object?)right));
107+
Assert.Throws<NotSupportedException>(() => _ = left.CompareTo(right));
20108
}
21109
}

DualNumbers.Test/Interfaces/Dual_IUnaryPlusOperatorsTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@ public class DualIUnaryPlusOperatorsTests
77
{
88
private static T UnaryPlus<T>(T value) where T : IUnaryPlusOperators<T, T> => +value;
99

10+
private static Dual UnaryPlusDirect(Dual value) => +value;
11+
1012
[Test]
1113
public void IUnaryPlusOperators_UnaryPlus_ReturnsUnchangedDual()
1214
{
1315
Dual result = UnaryPlus(new Dual(8.0, 3.0));
1416

1517
DualInterfaceAssert.AreEqual(result, 8.0, 3.0);
1618
}
19+
20+
[Test]
21+
public void OperatorUnaryPlus_DirectOperator_ReturnsUnchangedDual()
22+
{
23+
Dual result = UnaryPlusDirect(new Dual(8.0, 3.0));
24+
25+
DualInterfaceAssert.AreEqual(result, 8.0, 3.0);
26+
}
1727
}

0 commit comments

Comments
 (0)