Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions PolyShim.Tests/Net100/RandomTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using FluentAssertions;
using Xunit;

namespace PolyShim.Tests.Net100;

public class RandomTests
{
[Fact]
public void GetHexString_Test()
{
// Arrange
var random = new Random(0);

// Act & assert
for (var i = 0; i < 100; i++)
{
random.GetHexString(16).Should().MatchRegex("^[0-9A-F]{16}$");
random.GetHexString(16, true).Should().MatchRegex("^[0-9a-f]{16}$");
}
}

[Fact]
public void GetString_Array_Test()
{
// Arrange
var random = new Random(0);
var choices =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray();

// Act
for (var i = 0; i < 100; i++)
{
var str = random.GetString(choices, 16);

// Assert
str.Length.Should().Be(16);

foreach (var ch in str)
{
choices.Should().Contain(ch);
}
}
}

[Fact]
public void GetString_Span_Test()
{
// Arrange
var random = new Random(0);
var choices = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".AsSpan();

// Act
for (var i = 0; i < 100; i++)
{
var str = random.GetString(choices, 16);

// Assert
str.Length.Should().Be(16);

foreach (var ch in str)
{
choices.ToArray().Should().Contain(ch);
}
}
}
}
28 changes: 24 additions & 4 deletions PolyShim.Tests/Net60/RandomTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,30 @@ public class RandomTests
[Fact]
public void Shared_Test()
{
// Act
var value = Random.Shared.Next(1, 100);
// Act & assert
Random.Shared.Should().NotBeNull();
Random.Shared.Next(1, 100).Should().BeInRange(1, 99);
}

// Assert
value.Should().BeInRange(1, 100);
[Fact]
public void NextInt64_Test()
{
// Act & assert
for (var i = 0; i < 100; i++)
{
Random.Shared.NextInt64(10, 20).Should().BeInRange(10, 19);
Random.Shared.NextInt64(20).Should().BeInRange(0, 19);
Random.Shared.NextInt64().Should().BeInRange(0, long.MaxValue - 1);
}
}

[Fact]
public void NextSingle_Test()
{
// Act & assert
for (var i = 0; i < 100; i++)
{
Random.Shared.NextSingle().Should().BeInRange(0f, 1f);
}
}
}
54 changes: 54 additions & 0 deletions PolyShim.Tests/Net80/RandomTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using FluentAssertions;
using Xunit;

namespace PolyShim.Tests.Net80;

public class RandomTests
{
[Fact]
public void GetItems_Test()
{
// Arrange
var random = new Random(0);
var choices = new[] { 1, 2, 3, 4, 5 };

// Act
for (var i = 0; i < 100; i++)
{
var items = random.GetItems(choices, 3);

// Assert
items.Should().HaveCount(3);

foreach (var item in items)
{
choices.Should().Contain(item);
}
}
}

[Fact]
public void Shuffle_Test()
{
// Arrange
var random = new Random(0);
var originalItems = new[] { 1, 2, 3, 4, 5 };

// Act
for (var i = 0; i < 100; i++)
{
var items = (int[])originalItems.Clone();
random.Shuffle(items);

// Assert
items.Should().HaveCount(originalItems.Length);
items.Should().BeEquivalentTo(originalItems);

foreach (var item in items)
{
originalItems.Should().Contain(item);
}
}
}
}
47 changes: 47 additions & 0 deletions PolyShim/Net100/Random.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#if (NETCOREAPP && !NET10_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)
#nullable enable
// ReSharper disable RedundantUsingDirective
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.Collections.Generic;
using System.Text;

internal static partial class PolyfillExtensions
{
extension(Random random)
{
// https://learn.microsoft.com/dotnet/api/system.random.gethexstring#system-random-gethexstring(system-int32-system-boolean)
public string GetHexString(int stringLength, bool lowercase = false)
{
var bytes = new byte[(stringLength + 1) / 2];
random.NextBytes(bytes);

return lowercase ? Convert.ToHexStringLower(bytes) : Convert.ToHexString(bytes);
}

// Signature-compatible replacement for GetString(ReadOnlySpan<char>, int)
// https://learn.microsoft.com/dotnet/api/system.random.getstring
public string GetString(char[] choices, int length)
{
var buffer = new StringBuilder();

for (var i = 0; i < length; i++)
{
var index = random.Next(choices.Length);
buffer.Append(choices[index]);
}

return buffer.ToString();
}

#if FEATURE_MEMORY
// https://learn.microsoft.com/dotnet/api/system.random.getstring
public string GetString(ReadOnlySpan<char> choices, int length) =>
random.GetString(choices.ToArray(), length);
#endif
}
}
#endif
43 changes: 43 additions & 0 deletions PolyShim/Net60/Random.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,49 @@

internal static partial class PolyfillExtensions
{
extension(Random random)
{
// https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64(system-int64-system-int64)
public long NextInt64(long minValue, long maxValue)
{
if (minValue >= maxValue)
{
throw new ArgumentOutOfRangeException(
nameof(minValue),
"minValue must be less than maxValue"
);
}

var range = (ulong)(maxValue - minValue);

ulong ulongRand;
do
{
var buffer = new byte[8];
random.NextBytes(buffer);
ulongRand = BitConverter.ToUInt64(buffer, 0);
} while (ulongRand > ulong.MaxValue - (ulong.MaxValue % range + 1) % range);

return (long)(ulongRand % range) + minValue;
}

// https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64(system-int64)
public long NextInt64(long maxValue) => random.NextInt64(0, maxValue);

// https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64
public long NextInt64() => random.NextInt64(0, long.MaxValue);

// https://learn.microsoft.com/dotnet/api/system.random.nextsingle
public float NextSingle()
{
var buffer = new byte[4];
random.NextBytes(buffer);
var uintValue = BitConverter.ToUInt32(buffer, 0);

return uintValue / (float)uint.MaxValue;
}
}

[ThreadStatic]
private static Random? _threadRandom;

Expand Down
44 changes: 44 additions & 0 deletions PolyShim/Net80/Random.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#if (NETCOREAPP && !NET8_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)
#nullable enable
// ReSharper disable RedundantUsingDirective
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.Collections.Generic;

internal static partial class PolyfillExtensions
{
extension(Random random)
{
// https://learn.microsoft.com/dotnet/api/system.random.getitems#system-random-getitems-1(-0()-system-int32)
public T[] GetItems<T>(T[] choices, int length)
{
var result = new T[length];
var selectedIndices = new HashSet<int>();

while (selectedIndices.Count < length)
{
var index = random.Next(choices.Length);
if (selectedIndices.Add(index))
{
result[selectedIndices.Count - 1] = choices[index];
}
}

return result;
}

// https://learn.microsoft.com/dotnet/api/system.random.shuffle#system-random-shuffle-1(-0())
public void Shuffle<T>(T[] items)
{
for (var i = items.Length - 1; i > 0; i--)
{
var j = random.Next(i + 1);
(items[i], items[j]) = (items[j], items[i]);
}
}
}
}
#endif
13 changes: 11 additions & 2 deletions PolyShim/Signatures.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Signatures

- **Total:** 264
- **Total:** 273
- **Types:** 62
- **Members:** 202
- **Members:** 211

___

Expand Down Expand Up @@ -226,8 +226,17 @@ ___
- [`bool TryDequeue(out T?)`](https://learn.microsoft.com/dotnet/api/system.collections.generic.queue-1.trydequeue) <sup><sub>.NET Core 2.0</sub></sup>
- [`bool TryPeek(out T?)`](https://learn.microsoft.com/dotnet/api/system.collections.generic.queue-1.trypeek) <sup><sub>.NET Core 2.0</sub></sup>
- `Random`
- [`float NextSingle()`](https://learn.microsoft.com/dotnet/api/system.random.nextsingle) <sup><sub>.NET 6.0</sub></sup>
- [`long NextInt64()`](https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64) <sup><sub>.NET 6.0</sub></sup>
- [`long NextInt64(long, long)`](https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64(system-int64-system-int64)) <sup><sub>.NET 6.0</sub></sup>
- [`long NextInt64(long)`](https://learn.microsoft.com/dotnet/api/system.random.nextint64#system-random-nextint64(system-int64)) <sup><sub>.NET 6.0</sub></sup>
- [`Random Shared`](https://learn.microsoft.com/dotnet/api/system.random.shared) <sup><sub>.NET 6.0</sub></sup>
- [`string GetHexString(int, bool)`](https://learn.microsoft.com/dotnet/api/system.random.gethexstring#system-random-gethexstring(system-int32-system-boolean)) <sup><sub>.NET 10.0</sub></sup>
- [`string GetString(char[], int)`](https://learn.microsoft.com/dotnet/api/system.random.getstring) <sup><sub>.NET 10.0</sub></sup>
- [`string GetString(ReadOnlySpan<char>, int)`](https://learn.microsoft.com/dotnet/api/system.random.getstring) <sup><sub>.NET 10.0</sub></sup>
- [`T[] GetItems<T>(T[], int)`](https://learn.microsoft.com/dotnet/api/system.random.getitems#system-random-getitems-1(-0()-system-int32)) <sup><sub>.NET 8.0</sub></sup>
- [`void NextBytes(Span<byte>)`](https://learn.microsoft.com/dotnet/api/system.random.nextbytes#system-random-nextbytes(system-span((system-byte)))) <sup><sub>.NET Core 2.1</sub></sup>
- [`void Shuffle<T>(T[])`](https://learn.microsoft.com/dotnet/api/system.random.shuffle#system-random-shuffle-1(-0())) <sup><sub>.NET 8.0</sub></sup>
- `Range`
- [**[struct]**](https://learn.microsoft.com/dotnet/api/system.range) <sup><sub>.NET Core 3.0</sub></sup>
- `Regex`
Expand Down
Loading