Files
QWERTYkez.Mensura/QWERTYkez.Mensura.Tests/DoubleExtensions.cs

164 lines
6.0 KiB
C#
Raw Normal View History

2026-06-11 15:42:01 +07:00
namespace QWERTYkez.Mensura.Tests;
public class DoubleExtensions
{
#region 1. Тесты скалярных типов (Обычные, Экзотические и Nullable)
[Fact]
public void ToDouble_Should_Convert_ExoticTypes_Without_InvalidCastException()
{
// Проверяем типы, которые раньше могли падать в рантайме из-за Convert.ToDouble(object)
Half halfValue = (Half)3.14f;
Int128 int128Value = Int128.Parse("1234567890123456789012345");
UInt128 uInt128Value = UInt128.Parse("9876543210987654321098765");
nint nintValue = 42;
// Act & Assert
Assert.Equal(3.14, halfValue.ToDouble(), 2);
Assert.Equal((double)int128Value, int128Value.ToDouble());
Assert.Equal((double)uInt128Value, uInt128Value.ToDouble());
Assert.Equal(42.0, nintValue.ToDouble());
}
[Theory]
[InlineData((int)100, 100.0)]
[InlineData((byte)5, 5.0)]
[InlineData((float)1.5f, 1.5)]
public void ToDouble_StandardScalars_ShouldConvertCorrectly(object input, double expected)
{
double result = input switch
{
int i => i.ToDouble(),
byte b => b.ToDouble(),
float f => f.ToDouble(),
_ => throw new ArgumentException("Unsupported type in test")
};
Assert.Equal(expected, result);
}
[Fact]
public void ToDouble_NullableScalars_Should_Return_Zero_When_Null()
{
// Arrange
int? nullInt = null;
Half? nullHalf = null;
Int128? nullInt128 = null;
int? validInt = 10;
Half? validHalf = (Half)2.5f;
// Act & Assert
Assert.Equal(0d, nullInt.ToDouble());
Assert.Equal(0d, nullHalf.ToDouble());
Assert.Equal(0d, nullInt128.ToDouble());
Assert.Equal(10d, validInt.ToDouble());
Assert.Equal(2.5d, validHalf.ToDouble(), 1);
}
#endregion
#region 2. Тесты SIMD и оптимизаций коллекций (Различные длины массивов)
[Theory]
[InlineData(0)] // Пустой массив
[InlineData(1)] // 1 элемент (чисто скалярный fallback)
[InlineData(7)] // Нечетное число элементов
[InlineData(16)] // Кратный размер (размер Vector128/Vector256)
[InlineData(35)] // Большой массив с остатком для скалярного хвоста
public void ToDouble_ArrayAndList_Should_Correctly_Map_Via_SIMD_Or_Fallback(int count)
{
// Arrange
float[] sourceArray = [.. Enumerable.Range(1, count).Select(x => x * 1.5f)];
List<float> sourceList = [.. sourceArray];
double[] destFromArray = new double[count];
double[] destFromList = new double[count];
// Act
// Явное приведение к IReadOnlyCollection устраняет ошибку CS0121 (неоднозначность вызова)
((IReadOnlyCollection<float>)sourceArray).ToDouble(destFromArray);
((IReadOnlyCollection<float>)sourceList).ToDouble(destFromList);
// Assert
for (int i = 0; i < count; i++)
{
double expected = sourceArray[i];
Assert.Equal(expected, destFromArray[i]);
Assert.Equal(expected, destFromList[i]);
}
}
#endregion
#region 3. Тесты Nullable-коллекций (Проверка на null-элементы внутри)
[Fact]
public void ToDouble_Nullable_Collections_Should_Keep_Nulls_In_Destination()
{
// Arrange
UInt128?[] sourceArray = [10, null, 20, null, 30];
double?[] destination = new double?[sourceArray.Length];
// Act
((IReadOnlyCollection<UInt128?>)sourceArray).ToDouble(destination);
// Assert
Assert.Equal(10d, destination[0]);
Assert.Null(destination[1]);
Assert.Equal(20d, destination[2]);
Assert.Null(destination[3]);
Assert.Equal(30d, destination[4]);
}
#endregion
#region 4. Тесты LINQ / Отложенного выполнения (IEnumerable)
[Fact]
public void ToDouble_IEnumerable_Extension_Should_Handle_Execution_Types_Correctly()
{
// Arrange
int[] array = [1, 2, 3];
List<int> list = [4, 5, 6];
IEnumerable<int> genericEnum = Enumerable.Range(7, 3);
// Act
var resFromArray = array.ToDouble(); // Быстрый бранч для массива
var resFromList = list.ToDouble(); // Быстрый бранч для списка
var resFromEnum = genericEnum.ToDouble(); // Медленный итератор по IEnumerable
// Assert
Assert.Equal([1d, 2d, 3d], resFromArray);
Assert.Equal([4d, 5d, 6d], resFromList);
Assert.Equal([7d, 8d, 9d], resFromEnum);
}
#endregion
#region 5. Тесты безопасности и валидации аргументов
[Fact]
public void ToDouble_Should_Throw_ArgumentException_When_Destination_Is_Too_Short()
{
// Arrange
int[] source = [1, 2, 3, 4, 5];
double[] destinationTooShort = new double[4]; // Нужен размер >= 5
// Act & Assert
Assert.Throws<ArgumentException>(() => ((IReadOnlyCollection<int>)source).ToDouble(destinationTooShort));
}
[Fact]
public void ToDouble_Should_Do_Nothing_And_Return_When_Collection_Is_Empty_Or_Null()
{
// Arrange
int[]? nullArray = null;
int[] emptyArray = [];
double[] destination = new double[5];
// Act & Assert (Не должно выбрасывать NullReferenceException или ArgumentException)
((IReadOnlyCollection<int>?)nullArray)!.ToDouble(destination);
((IReadOnlyCollection<int>)emptyArray).ToDouble(destination);
Assert.All(destination, x => Assert.Equal(0d, x)); // Назначение осталось нетронутым (все нули по умолчанию)
}
#endregion
}