// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using CommunityToolkit.HighPerformance.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CommunityToolkit.HighPerformance.UnitTests.Buffers.Internals;
namespace CommunityToolkit.HighPerformance.UnitTests.Helpers;
[TestClass]
public class Test_HashCodeOfT
{
///
/// Gets the list of counts to test the extension for
///
private static ReadOnlySpan TestCounts => new[] { 0, 1, 7, 128, 255, 256, short.MaxValue, short.MaxValue + 1, 123_938, 1_678_922, 71_890_819 };
[TestMethod]
public void Test_HashCodeOfT_VectorSupportedTypes_TestRepeatCount8()
{
TestForType();
TestForType();
TestForType();
}
[TestMethod]
public void Test_HashCodeOfT_VectorSupportedTypes_TestRepeatCount16()
{
TestForType();
TestForType();
}
[TestMethod]
public void Test_HashCodeOfT_VectorSupportedTypes_TestRepeatCount32()
{
TestForType();
TestForType();
TestForType();
}
[TestMethod]
public void Test_HashCodeOfT_VectorSupportedTypes_TestRepeatCount64()
{
TestForType();
TestForType();
TestForType();
}
[TestMethod]
public void Test_HashCodeOfT_VectorUnsupportedTypes_TestRepeat()
{
TestForType();
}
#if NET6_0_OR_GREATER
[TestMethod]
public void Test_HashCodeOfT_ManagedType_TestRepeat()
{
ReadOnlySpan localTestCounts = TestCounts.Slice(0, 8);
// Only rent a single array of the maximum necessary size, to save space
string[] data = new string[localTestCounts[localTestCounts.Length - 1]];
Random? random = new();
foreach (ref string text in data.AsSpan())
{
text = random.NextDouble().ToString("E");
}
foreach (int count in localTestCounts)
{
Span iterationData = data.AsSpan().Slice(0, count);
int hash1 = HashCode.Combine(iterationData);
int hash2 = HashCode.Combine(iterationData);
Assert.AreEqual(hash1, hash2, $"Failed {typeof(string)} test with count {count}: got {hash1} and then {hash2}");
}
}
#endif
///
/// Performs a test for a specified type.
///
/// The type to test.
private static void TestForType()
where T : unmanaged, IEquatable
{
foreach (int count in TestCounts)
{
using UnmanagedSpanOwner data = CreateRandomData(count);
int hash1 = HashCode.Combine(data.GetSpan());
int hash2 = HashCode.Combine(data.GetSpan());
Assert.AreEqual(hash1, hash2, $"Failed {typeof(T)} test with count {count}: got {hash1} and then {hash2}");
}
}
///
/// Creates a random array filled with random data.
///
/// The type of items to put in the array.
/// The number of array items to create.
/// An array of random elements.
private static UnmanagedSpanOwner CreateRandomData(int count)
where T : unmanaged
{
Random? random = new(count);
UnmanagedSpanOwner data = new(count);
foreach (ref byte n in MemoryMarshal.AsBytes(data.GetSpan()))
{
n = (byte)random.Next(0, byte.MaxValue);
}
return data;
}
}