// 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; } }