394 lines
13 KiB
C#
394 lines
13 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using QWERTYkez.Mensura.Extensions;
|
|||
|
|
using Xunit;
|
|||
|
|
|
|||
|
|
namespace QWERTYkez.Mensura.Tests
|
|||
|
|
{
|
|||
|
|
public class DoubleExtensionsTests
|
|||
|
|
{
|
|||
|
|
private const double Tolerance = 1e-12;
|
|||
|
|
|
|||
|
|
#region Single value conversions (non-nullable)
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(1)]
|
|||
|
|
[InlineData(255)]
|
|||
|
|
public void ToDouble_Byte_ReturnsExpected(byte value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(-128)]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(127)]
|
|||
|
|
public void ToDouble_SByte_ReturnsExpected(sbyte value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(-32768)]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(32767)]
|
|||
|
|
public void ToDouble_Short_ReturnsExpected(short value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(1)]
|
|||
|
|
[InlineData(65535)]
|
|||
|
|
public void ToDouble_UShort_ReturnsExpected(ushort value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(-2147483648)]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(2147483647)]
|
|||
|
|
public void ToDouble_Int_ReturnsExpected(int value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0U)]
|
|||
|
|
[InlineData(1U)]
|
|||
|
|
[InlineData(uint.MaxValue)]
|
|||
|
|
public void ToDouble_UInt_ReturnsExpected(uint value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(-9223372036854775808)]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(9223372036854775807)]
|
|||
|
|
public void ToDouble_Long_ReturnsExpected(long value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0UL)]
|
|||
|
|
[InlineData(1UL)]
|
|||
|
|
[InlineData(ulong.MaxValue)]
|
|||
|
|
public void ToDouble_ULong_ReturnsExpected(ulong value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(-123456789)]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(123456789)]
|
|||
|
|
public void ToDouble_NInt_ReturnsExpected(nint value) => Assert.Equal(value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0u)]
|
|||
|
|
[InlineData(123456789u)]
|
|||
|
|
public void ToDouble_NUInt_ReturnsExpected(nuint value) => Assert.Equal((double)value, value.ToDouble());
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0.0f)]
|
|||
|
|
[InlineData(123.456f)]
|
|||
|
|
[InlineData(-987.654f)]
|
|||
|
|
[InlineData(float.Epsilon)]
|
|||
|
|
[InlineData(float.MaxValue)]
|
|||
|
|
public void ToDouble_Float_ReturnsExpected(float value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0.0)]
|
|||
|
|
[InlineData(123.456)]
|
|||
|
|
[InlineData(-987.654)]
|
|||
|
|
public void ToDouble_Decimal_ReturnsExpected(decimal value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0.0)]
|
|||
|
|
[InlineData(123.456)]
|
|||
|
|
[InlineData(-987.654)]
|
|||
|
|
public void ToDouble_Half_ReturnsExpected(Half value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Single value conversions (nullable)
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableByte_Null_ReturnsZero() => Assert.Equal(0.0, ((byte?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableSByte_Null_ReturnsZero() => Assert.Equal(0.0, ((sbyte?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableShort_Null_ReturnsZero() => Assert.Equal(0.0, ((short?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableUShort_Null_ReturnsZero() => Assert.Equal(0.0, ((ushort?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableInt_Null_ReturnsZero() => Assert.Equal(0.0, ((int?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableUInt_Null_ReturnsZero() => Assert.Equal(0.0, ((uint?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableLong_Null_ReturnsZero() => Assert.Equal(0.0, ((long?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableULong_Null_ReturnsZero() => Assert.Equal(0.0, ((ulong?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableNInt_Null_ReturnsZero() => Assert.Equal(0.0, ((nint?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableNUInt_Null_ReturnsZero() => Assert.Equal(0.0, ((nuint?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableFloat_Null_ReturnsZero() => Assert.Equal(0.0, ((float?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableDecimal_Null_ReturnsZero() => Assert.Equal(0.0, ((decimal?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableHalf_Null_ReturnsZero() => Assert.Equal(0.0, ((Half?)null).ToDouble());
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region NET7_0_OR_GREATER
|
|||
|
|
|
|||
|
|
#if NET7_0_OR_GREATER
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(1)]
|
|||
|
|
[InlineData(-1)]
|
|||
|
|
[InlineData(long.MaxValue)]
|
|||
|
|
public void ToDouble_Int128_ReturnsExpected(Int128 value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Theory]
|
|||
|
|
[InlineData(0)]
|
|||
|
|
[InlineData(1)]
|
|||
|
|
[InlineData(ulong.MaxValue)]
|
|||
|
|
public void ToDouble_UInt128_ReturnsExpected(UInt128 value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableInt128_Null_ReturnsZero() => Assert.Equal(0.0, ((Int128?)null).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableUInt128_Null_ReturnsZero() => Assert.Equal(0.0, ((UInt128?)null).ToDouble());
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region IEnumerable<T> -> IEnumerable<double> (non-nullable)
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableByte_ReturnsCorrect()
|
|||
|
|
{
|
|||
|
|
byte[] source = [1, 2, 3];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(new double[] { 1, 2, 3 }, result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableByte_Empty_ReturnsEmpty()
|
|||
|
|
{
|
|||
|
|
var source = Array.Empty<byte>();
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Empty(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableByte_Null_Throws() => Assert.Null(((IEnumerable<byte>)null!).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableInt_ReturnsCorrect()
|
|||
|
|
{
|
|||
|
|
int[] source = [-5, 0, 10];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(new double[] { -5, 0, 10 }, result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableInt_Null_Throws() => Assert.Null(((IEnumerable<int>)null!).ToDouble());
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region IEnumerable<T?> -> IEnumerable<double?>
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableNullableInt_ReturnsCorrect()
|
|||
|
|
{
|
|||
|
|
int?[] source = [1, null, 3];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(3, result.Length);
|
|||
|
|
Assert.Equal(1.0, result.First());
|
|||
|
|
Assert.Null(result.Skip(1).First());
|
|||
|
|
Assert.Equal(3.0, result.Last());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IEnumerableNullableInt_Null_Throws() => Assert.Null(((IEnumerable<int?>)null!).ToDouble());
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Array and List conversions (non-nullable)
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_ByteArray_ReturnsDoubleArray()
|
|||
|
|
{
|
|||
|
|
byte[] arr = [10, 20];
|
|||
|
|
var result = arr.ToDouble();
|
|||
|
|
Assert.Equal(new double[] { 10, 20 }, result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_ByteArray_Null_ReturnsNull() => Assert.Null(((byte[])null!).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_ByteList_ReturnsDoubleList()
|
|||
|
|
{
|
|||
|
|
var list = new List<byte> { 10, 20 };
|
|||
|
|
var result = list.ToDouble();
|
|||
|
|
Assert.Equal([10, 20], result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_ByteList_Null_ReturnsNull() => Assert.Null(((List<byte>)null!).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IntArray_ReturnsDoubleArray()
|
|||
|
|
{
|
|||
|
|
int[] arr = [-5, 0, 7];
|
|||
|
|
var result = arr.ToDouble();
|
|||
|
|
Assert.Equal(new double[] { -5, 0, 7 }, result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IntList_ReturnsDoubleList()
|
|||
|
|
{
|
|||
|
|
var list = new List<int> { -5, 0, 7 };
|
|||
|
|
var result = list.ToDouble();
|
|||
|
|
Assert.Equal([-5, 0, 7], result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Array and List conversions (nullable)
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableIntArray_ReturnsNullableDoubleArray()
|
|||
|
|
{
|
|||
|
|
int?[] arr = [1, null, 3];
|
|||
|
|
var result = arr.ToDouble();
|
|||
|
|
Assert.Equal(3, result.Length);
|
|||
|
|
Assert.Equal(1.0, result[0]);
|
|||
|
|
Assert.Null(result[1]);
|
|||
|
|
Assert.Equal(3.0, result[2]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableIntArray_Null_ReturnsNull() => Assert.Null(((int?[])null!).ToDouble());
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableIntList_ReturnsNullableDoubleList()
|
|||
|
|
{
|
|||
|
|
var list = new List<int?> { 1, null, 3 };
|
|||
|
|
var result = list.ToDouble();
|
|||
|
|
Assert.Equal(3, result.Count);
|
|||
|
|
Assert.Equal(1.0, result[0]);
|
|||
|
|
Assert.Null(result[1]);
|
|||
|
|
Assert.Equal(3.0, result[2]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_NullableIntList_Null_ReturnsNull() => Assert.Null(((List<int?>)null!).ToDouble());
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region IReadOnlyCollection<T> -> Span<double>
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IReadOnlyCollectionByte_Span_Works()
|
|||
|
|
{
|
|||
|
|
byte[] source = [1, 2];
|
|||
|
|
Span<double> dest = new double[source.Length];
|
|||
|
|
((IReadOnlyCollection<byte>)source).ToDouble(dest);
|
|||
|
|
Assert.Equal(1.0, dest[0]);
|
|||
|
|
Assert.Equal(2.0, dest[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IReadOnlyCollectionByte_EmptySpan_Works()
|
|||
|
|
{
|
|||
|
|
byte[] source = [];
|
|||
|
|
Span<double> dest = [];
|
|||
|
|
((IReadOnlyCollection<byte>)source).ToDouble(dest);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IReadOnlyCollectionByte_DestinationTooShort_Throws()
|
|||
|
|
{
|
|||
|
|
byte[] source = [1, 2];
|
|||
|
|
Assert.Throws<ArgumentException>(() =>
|
|||
|
|
{
|
|||
|
|
Span<double> dest = new double[1];
|
|||
|
|
((IReadOnlyCollection<byte>)source).ToDouble(dest);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_IReadOnlyCollectionNullableInt_Span_HandlesNulls()
|
|||
|
|
{
|
|||
|
|
int?[] source = [1, null, 3];
|
|||
|
|
Span<double?> dest = new double?[3];
|
|||
|
|
((IReadOnlyCollection<int?>)source).ToDouble(dest);
|
|||
|
|
Assert.Equal(1.0, dest[0]);
|
|||
|
|
Assert.Null(dest[1]);
|
|||
|
|
Assert.Equal(3.0, dest[2]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Span conversions (ToDoubleCore) - через массивы
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void IntSpan_ToDouble_ConversionWorks()
|
|||
|
|
{
|
|||
|
|
int[] source = [1, 2, 3];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(new double[] { 1, 2, 3 }, result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void FloatSpan_ToDouble_ConversionWorks()
|
|||
|
|
{
|
|||
|
|
float[] source = [1.1f, -2.2f];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(1.1f, result[0], Tolerance);
|
|||
|
|
Assert.Equal(-2.2f, result[1], Tolerance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void NullableDecimalSpan_ToDouble_HandlesNulls()
|
|||
|
|
{
|
|||
|
|
decimal?[] source = [1.5m, null, -3.3m];
|
|||
|
|
var result = source.ToDouble();
|
|||
|
|
Assert.Equal(3, result.Length);
|
|||
|
|
Assert.Equal(1.5, result[0]!.Value, Tolerance);
|
|||
|
|
Assert.Null(result[1]);
|
|||
|
|
Assert.Equal(-3.3, result[2]!.Value, Tolerance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Edge cases
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_LongMaxValue_DoesNotOverflow()
|
|||
|
|
{
|
|||
|
|
long max = long.MaxValue;
|
|||
|
|
double result = max.ToDouble();
|
|||
|
|
Assert.Equal((double)max, result, Tolerance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_ULongMaxValue_DoesNotOverflow()
|
|||
|
|
{
|
|||
|
|
ulong max = ulong.MaxValue;
|
|||
|
|
double result = max.ToDouble();
|
|||
|
|
Assert.Equal((double)max, result, Tolerance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void ToDouble_Decimal_HighPrecision_DoesNotCrash()
|
|||
|
|
{
|
|||
|
|
decimal huge = decimal.MaxValue;
|
|||
|
|
var result = huge.ToDouble();
|
|||
|
|
Assert.False(double.IsInfinity(result));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
}
|
|||
|
|
}
|