Skip to content

Commit 05e1fe1

Browse files
vcsjonesDaZombieKillerteo-tsirpanisMichalPetrykadanmoseley
authored
Implement Shuffle, GetString, and GetItems on Random{NumberGenerator} (#78598)
* Implement Shuffle, GetString, and GetItems. * Cleanup and additional tests * Use where possible * Code review feedback * Additional uses of Random throughout tests * Feedback on documentation * Use ref to span to get span in string.Create. Co-authored-by: Benjamin Moir <[email protected]> Co-authored-by: Theodore Tsirpanis <[email protected]> Co-authored-by: Michał Petryka <[email protected]> * Code review feedback * Code review feedback * Apply suggestions from code review Co-authored-by: Dan Moseley <[email protected]> * Use AssertExtensions over Assert * Improve comment * No idea where AssertHexString came from * Update src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs Co-authored-by: Jeremy Barton <[email protected]> Co-authored-by: Benjamin Moir <[email protected]> Co-authored-by: Theodore Tsirpanis <[email protected]> Co-authored-by: Michał Petryka <[email protected]> Co-authored-by: Dan Moseley <[email protected]> Co-authored-by: Stephen Toub <[email protected]> Co-authored-by: Jeremy Barton <[email protected]>
1 parent 210a7a9 commit 05e1fe1

File tree

21 files changed

+840
-136
lines changed

21 files changed

+840
-136
lines changed

src/libraries/Common/tests/System/RandomExtensions.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/libraries/Common/tests/Tests/System/StringTests.cs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3776,12 +3776,7 @@ public static void IsWhiteSpaceTrueLatin1()
37763776
Random rand = new Random(42);
37773777
for (int length = 0; length < 32; length++)
37783778
{
3779-
char[] a = new char[length];
3780-
for (int i = 0; i < length; i++)
3781-
{
3782-
a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length - 1)];
3783-
}
3784-
3779+
char[] a = rand.GetItems<char>(s_whiteSpaceCharacters, length);
37853780
string s1 = new string(a);
37863781
bool result = string.IsNullOrWhiteSpace(s1);
37873782
Assert.True(result);
@@ -3810,11 +3805,7 @@ public static void IsWhiteSpaceTrue()
38103805
Random rand = new Random(42);
38113806
for (int length = 0; length < 32; length++)
38123807
{
3813-
char[] a = new char[length];
3814-
for (int i = 0; i < length; i++)
3815-
{
3816-
a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length)];
3817-
}
3808+
char[] a = rand.GetItems<char>(s_whiteSpaceCharacters, length);
38183809

38193810
string s1 = new string(a);
38203811
bool result = string.IsNullOrWhiteSpace(s1);
@@ -3832,11 +3823,7 @@ public static void IsWhiteSpaceFalse()
38323823
Random rand = new Random(42);
38333824
for (int length = 1; length < 32; length++)
38343825
{
3835-
char[] a = new char[length];
3836-
for (int i = 0; i < length; i++)
3837-
{
3838-
a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length)];
3839-
}
3826+
char[] a = rand.GetItems<char>(s_whiteSpaceCharacters, length);
38403827
var span = new Span<char>(a);
38413828

38423829
// first character is not a white-space character

src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Common.System;
54
using System.Collections.Generic;
65
using System.Globalization;
76
using System.Linq;

src/libraries/System.Collections/tests/System.Collections.Tests.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@
4545
Link="Common\System\EnumTypes.cs" />
4646
<Compile Include="$(CommonTestPath)System\ObjectCloner.cs"
4747
Link="Common\System\ObjectCloner.cs" />
48-
<Compile Include="$(CommonTestPath)System\RandomExtensions.cs"
49-
Link="Common\System\RandomExtensions.cs" />
5048
<Compile Include="$(CommonTestPath)System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs"
5149
Link="Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs" />
5250
<!-- Generic tests -->

src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/TrustHelper.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -947,14 +947,8 @@ private static void ValidateTrustAttribute(TRUSTED_DOMAIN_INFORMATION_EX domainI
947947

948948
internal static string CreateTrustPassword()
949949
{
950-
#if NETCOREAPP3_0_OR_GREATER
951-
return string.Create<object?>(PASSWORD_LENGTH, null, static (destination, _) =>
952-
{
953-
for (int i = 0; i < destination.Length; i++)
954-
{
955-
destination[i] = PasswordCharacterSet[RandomNumberGenerator.GetInt32(PasswordCharacterSet.Length)];
956-
}
957-
});
950+
#if NET8_0_OR_GREATER
951+
return RandomNumberGenerator.GetString(PasswordCharacterSet, PASSWORD_LENGTH);
958952
#else
959953
char[] cBuf = new char[PASSWORD_LENGTH];
960954
byte[] randomBuffer = new byte[1];

src/libraries/System.IO/tests/StreamReader/StreamReaderTests.cs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ namespace System.IO.Tests
1515
{
1616
public partial class StreamReaderTests
1717
{
18+
private const string LowerAlpha = "abcdefghijklmnopqrstuvwxyz";
19+
1820
protected virtual Stream CreateStream()
1921
{
2022
return new MemoryStream();
@@ -400,12 +402,8 @@ public async Task Read_EmptySpan_ReadsNothing(int length)
400402
[InlineData(100, 50, 101)]
401403
public void Read_ReadsExpectedData(int readLength, int totalLength, int bufferSize)
402404
{
403-
var data = new char[totalLength];
404405
var r = new Random(42);
405-
for (int i = 0; i < data.Length; i++)
406-
{
407-
data[i] = (char)('a' + r.Next(0, 26));
408-
}
406+
char[] data = r.GetItems<char>(LowerAlpha, totalLength);
409407

410408
var result = new char[data.Length];
411409
Span<char> dst = result;
@@ -431,12 +429,8 @@ public void Read_ReadsExpectedData(int readLength, int totalLength, int bufferSi
431429
[InlineData(100, 50, 101)]
432430
public void ReadBlock_ReadsExpectedData(int readLength, int totalLength, int bufferSize)
433431
{
434-
var data = new char[totalLength];
435432
var r = new Random(42);
436-
for (int i = 0; i < data.Length; i++)
437-
{
438-
data[i] = (char)('a' + r.Next(0, 26));
439-
}
433+
char[] data = r.GetItems<char>(LowerAlpha, totalLength);
440434

441435
var result = new char[data.Length];
442436
Span<char> dst = result;
@@ -462,12 +456,8 @@ public void ReadBlock_ReadsExpectedData(int readLength, int totalLength, int buf
462456
[InlineData(100, 50, 101)]
463457
public async Task ReadAsync_ReadsExpectedData(int readLength, int totalLength, int bufferSize)
464458
{
465-
var data = new char[totalLength];
466459
var r = new Random(42);
467-
for (int i = 0; i < data.Length; i++)
468-
{
469-
data[i] = (char)('a' + r.Next(0, 26));
470-
}
460+
char[] data = r.GetItems<char>(LowerAlpha, totalLength);
471461

472462
var result = new char[data.Length];
473463
Memory<char> dst = result;
@@ -493,12 +483,9 @@ public async Task ReadAsync_ReadsExpectedData(int readLength, int totalLength, i
493483
[InlineData(100, 50, 101)]
494484
public async Task ReadBlockAsync_ReadsExpectedData(int readLength, int totalLength, int bufferSize)
495485
{
496-
var data = new char[totalLength];
497486
var r = new Random(42);
498-
for (int i = 0; i < data.Length; i++)
499-
{
500-
data[i] = (char)('a' + r.Next(0, 26));
501-
}
487+
char[] data = r.GetItems<char>(LowerAlpha, totalLength);
488+
502489

503490
var result = new char[data.Length];
504491
Memory<char> dst = result;

src/libraries/System.IO/tests/StreamWriter/StreamWriter.WriteTests.cs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace System.IO.Tests
1212
{
1313
public partial class WriteTests
1414
{
15+
private const string LowerAlpha = "abcdefghijklmnopqrstuvwxyz";
16+
1517
protected virtual Stream CreateStream()
1618
{
1719
return new MemoryStream();
@@ -250,12 +252,8 @@ public void Write_Span_WritesExpectedData(int length, int writeSize, int writerB
250252
using (var s = new MemoryStream())
251253
using (var writer = new StreamWriter(s, Encoding.ASCII, writerBufferSize) { AutoFlush = autoFlush })
252254
{
253-
var data = new char[length];
254255
var rand = new Random(42);
255-
for (int i = 0; i < data.Length; i++)
256-
{
257-
data[i] = (char)(rand.Next(0, 26) + 'a');
258-
}
256+
char[] data = rand.GetItems<char>(LowerAlpha, length);
259257

260258
Span<char> source = data;
261259
while (source.Length > 0)
@@ -283,12 +281,8 @@ public async Task Write_Memory_WritesExpectedData(int length, int writeSize, int
283281
using (var s = new MemoryStream())
284282
using (var writer = new StreamWriter(s, Encoding.ASCII, writerBufferSize) { AutoFlush = autoFlush })
285283
{
286-
var data = new char[length];
287284
var rand = new Random(42);
288-
for (int i = 0; i < data.Length; i++)
289-
{
290-
data[i] = (char)(rand.Next(0, 26) + 'a');
291-
}
285+
char[] data = rand.GetItems<char>(LowerAlpha, length);
292286

293287
ReadOnlyMemory<char> source = data;
294288
while (source.Length > 0)
@@ -316,12 +310,8 @@ public void WriteLine_Span_WritesExpectedData(int length, int writeSize, int wri
316310
using (var s = new MemoryStream())
317311
using (var writer = new StreamWriter(s, Encoding.ASCII, writerBufferSize) { AutoFlush = autoFlush })
318312
{
319-
var data = new char[length];
320313
var rand = new Random(42);
321-
for (int i = 0; i < data.Length; i++)
322-
{
323-
data[i] = (char)(rand.Next(0, 26) + 'a');
324-
}
314+
char[] data = rand.GetItems<char>(LowerAlpha, length);
325315

326316
Span<char> source = data;
327317
while (source.Length > 0)
@@ -349,12 +339,8 @@ public async Task WriteLineAsync_Memory_WritesExpectedData(int length, int write
349339
using (var s = new MemoryStream())
350340
using (var writer = new StreamWriter(s, Encoding.ASCII, writerBufferSize) { AutoFlush = autoFlush })
351341
{
352-
var data = new char[length];
353342
var rand = new Random(42);
354-
for (int i = 0; i < data.Length; i++)
355-
{
356-
data[i] = (char)(rand.Next(0, 26) + 'a');
357-
}
343+
char[] data = rand.GetItems<char>(LowerAlpha, length);
358344

359345
ReadOnlyMemory<char> source = data;
360346
while (source.Length > 0)

src/libraries/System.Linq/tests/Shuffler.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@ public static class Shuffler
1111
public static T[] Shuffle<T>(T[] array)
1212
{
1313
var r = new Random(42);
14-
int i = array.Length;
15-
while (i > 1)
16-
{
17-
int j = r.Next(i--);
18-
(array[i], array[j]) = (array[j], array[i]);
19-
}
14+
r.Shuffle(array);
2015
return array;
2116
}
2217

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,7 @@ private static string GetRandomAlphaNumericString()
207207
{
208208
const int Length = 16;
209209
const string CharacterSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
210-
211-
return string.Create<object?>(Length, null, static (destination, _) =>
212-
{
213-
for (int i = 0; i < destination.Length; i++)
214-
{
215-
destination[i] = CharacterSet[RandomNumberGenerator.GetInt32(CharacterSet.Length)];
216-
}
217-
});
210+
return RandomNumberGenerator.GetString(CharacterSet, Length);
218211
}
219212

220213
private static string ComputeHash(string data, string algorithm)

src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
215215
public async Task GetAsync_LargeHeader_Success(string headerName, int headerValueLength)
216216
{
217217
var rand = new Random(42);
218-
string headerValue = string.Concat(Enumerable.Range(0, headerValueLength).Select(_ => (char)('A' + rand.Next(26))));
218+
string headerValue = new string(rand.GetItems<char>("ABCDEFGHIJKLMNOPQRSTUVWXYZ", headerValueLength));
219219

220220
const string ContentString = "hello world";
221221
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>

src/libraries/System.Net.HttpListener/tests/HttpRequestStreamTests.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,7 @@ public async Task Read_FullLengthSynchronous_Success(bool transferEncodingChunke
229229
public async Task Read_LargeLengthAsynchronous_Success(bool transferEncodingChunked)
230230
{
231231
var rand = new Random(42);
232-
byte[] expected = Enumerable
233-
.Range(0, 128*1024 + 1) // More than 128kb
234-
.Select(_ => (byte)('a' + rand.Next(0, 26)))
235-
.ToArray();
232+
byte[] expected = rand.GetItems("abcdefghijklmnopqrstuvwxyz"u8, 128 * 1024 + 1);
236233

237234
Task<HttpListenerContext> contextTask = _listener.GetContextAsync();
238235

@@ -269,10 +266,7 @@ public async Task Read_LargeLengthAsynchronous_Success(bool transferEncodingChun
269266
public async Task Read_LargeLengthSynchronous_Success(bool transferEncodingChunked)
270267
{
271268
var rand = new Random(42);
272-
byte[] expected = Enumerable
273-
.Range(0, 128 * 1024 + 1) // More than 128kb
274-
.Select(_ => (byte)('a' + rand.Next(0, 26)))
275-
.ToArray();
269+
byte[] expected = rand.GetItems("abcdefghijklmnopqrstuvwxyz"u8, 128 * 1024 + 1);
276270

277271
Task<HttpListenerContext> contextTask = _listener.GetContextAsync();
278272

src/libraries/System.Net.WebClient/tests/WebClientTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ public async Task UploadData_LargeData_Success(Uri server)
661661
}
662662

663663
private static string GetRandomText(int length) =>
664-
new string(Enumerable.Range(0, 512 * 1024).Select(_ => (char)('a' + Random.Shared.Next(0, 26))).ToArray());
664+
new string(Random.Shared.GetItems<char>("abcdefghijklmnopqrstuvwxyz", 512 * 1024));
665665

666666
[OuterLoop("Uses external servers")]
667667
[Theory]

src/libraries/System.Private.CoreLib/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@
298298
<data name="Arg_EmptyArray" xml:space="preserve">
299299
<value>Array may not be empty.</value>
300300
</data>
301+
<data name="Arg_EmptySpan" xml:space="preserve">
302+
<value>Span may not be empty.</value>
303+
</data>
301304
<data name="Arg_EndOfStreamException" xml:space="preserve">
302305
<value>Attempted to read past the end of the stream.</value>
303306
</data>

0 commit comments

Comments
 (0)