Files
QWERTYkez.Mensura/QWERTYkez.Mensura.Tests/DoubleExtensionsTest.cs

394 lines
13 KiB
C#
Raw Normal View History

2026-06-12 23:34:00 +07:00
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
}
}