@@ -14,26 +14,38 @@ public static class ValuesGenerator
14
14
{
15
15
private const int Seed = 12345 ; // we always use the same seed to have repeatable results!
16
16
17
+ /// <summary>
18
+ /// Returns a T value that is NOT the default(T) (typically zero) value.
19
+ /// For bool, there's only one choice (true/1).
20
+ /// For byte/sbyte, will never return byte.MaxValue (256) so there are a maximum of 254 values.
21
+ /// </summary>
17
22
public static T GetNonDefaultValue < T > ( )
18
23
{
19
- if ( typeof ( T ) == typeof ( byte ) ) // we can't use ArrayOfUniqueValues for byte
20
- return Array < T > ( byte . MaxValue ) . First ( value => ! value . Equals ( default ) ) ;
24
+ if ( typeof ( T ) == typeof ( byte ) || typeof ( T ) == typeof ( sbyte ) ) // we can't use ArrayOfUniqueValues for byte/sbyte (but they have the same range)
25
+ return Array < T > ( byte . MaxValue ) . First ( value => ! value . Equals ( default ( T ) ) ) ;
21
26
else
22
- return ArrayOfUniqueValues < T > ( 2 ) . First ( value => ! value . Equals ( default ) ) ;
27
+ return ArrayOfUniqueValues < T > ( 2 ) . First ( value => ! value . Equals ( default ( T ) ) ) ;
23
28
}
24
29
25
30
/// <summary>
26
- /// does not support byte because there are only 256 unique byte values
31
+ /// Returns an array of the requested size where each entry is a distinct value.
32
+ /// For byte and sbyte support a maximum count of 255 because there are only 256
33
+ /// unique byte values. For bool, there are only 2 values so throw for more requested
27
34
/// </summary>
28
35
public static T [ ] ArrayOfUniqueValues < T > ( int count )
29
36
{
37
+ if ( count > 2 && typeof ( T ) == typeof ( bool ) )
38
+ throw new ArgumentOutOfRangeException ( "count" , "Cannot exceed 2 for bool values" ) ;
39
+ if ( count > 255 && ( typeof ( T ) == typeof ( byte ) || typeof ( T ) == typeof ( sbyte ) ) )
40
+ throw new ArgumentOutOfRangeException ( "count" , "Cannot exceed 255 for byte or sbyte values" ) ;
41
+
30
42
// allocate the array first to try to take advantage of memory randomization
31
43
// as it's usually the first thing called from GlobalSetup method
32
44
// which with MemoryRandomization enabled is the first method called right after allocation
33
45
// of random-sized memory by BDN engine
34
46
T [ ] result = new T [ count ] ;
35
47
36
- var random = new Random ( Seed ) ;
48
+ var random = new Random ( Seed ) ;
37
49
38
50
var uniqueValues = new HashSet < T > ( ) ;
39
51
@@ -49,12 +61,17 @@ public static T[] ArrayOfUniqueValues<T>(int count)
49
61
50
62
return result ;
51
63
}
52
-
64
+
65
+ /// <summary>
66
+ /// Returns an array of the requested size where each entry is a random value and values could repeat
67
+ /// For byte and sbyte values are built from Random.NextBytes, for other types GenerateValue is used
68
+ /// to generate a random value in the appropriate range
69
+ /// </summary>
53
70
public static T [ ] Array < T > ( int count )
54
71
{
55
72
var result = new T [ count ] ;
56
73
57
- var random = new Random ( Seed ) ;
74
+ var random = new Random ( Seed ) ;
58
75
59
76
if ( typeof ( T ) == typeof ( byte ) || typeof ( T ) == typeof ( sbyte ) )
60
77
{
@@ -82,6 +99,10 @@ public static T[] Array<T>(int count)
82
99
52 , 53 , 54 , 55 , 56 , 57 , 43 , 47 //4..9, +, /
83
100
} ;
84
101
102
+ /// <summary>
103
+ /// Returns an array of bytes of the requested size where each entry is a random value
104
+ /// from the legal subset of ASCII characters used in Base-64 encoded values
105
+ /// </summary>
85
106
public static byte [ ] ArrayBase64EncodingBytes ( int count )
86
107
{
87
108
var result = new byte [ count ] ;
@@ -97,8 +118,18 @@ public static byte[] ArrayBase64EncodingBytes(int count)
97
118
return result ;
98
119
}
99
120
121
+ /// <summary>
122
+ /// Returns a Dictionary of the requested size where each entry is a has a distinct key value and
123
+ /// the stored values are randomly generated.
124
+ /// GenerateValue is used to generate a random value in the appropriate range for both the key and value
125
+ /// </summary>
100
126
public static Dictionary < TKey , TValue > Dictionary < TKey , TValue > ( int count )
101
127
{
128
+ if ( count > 2 && typeof ( TKey ) == typeof ( bool ) )
129
+ throw new ArgumentOutOfRangeException ( "count" , "Cannot exceed 2 for Dictionary<bool, TValue>" ) ;
130
+ if ( count > 255 && ( typeof ( TKey ) == typeof ( byte ) || typeof ( TKey ) == typeof ( sbyte ) ) )
131
+ throw new ArgumentOutOfRangeException ( "count" , "Cannot exceed 255 for Dictionary<byte, TValue> or Dictionary<sbyte, TValue>" ) ;
132
+
102
133
var dictionary = new Dictionary < TKey , TValue > ( ) ;
103
134
104
135
var random = new Random ( Seed ) ;
@@ -114,6 +145,11 @@ public static Dictionary<TKey, TValue> Dictionary<TKey, TValue>(int count)
114
145
return dictionary ;
115
146
}
116
147
148
+ /// <summary>
149
+ /// Returns an array of the requested size where each entry is a random string value.
150
+ /// The values are random length strings within the range requested and are composed
151
+ /// a random assortment of the letters a..z, A..Z, and digits 0..9
152
+ /// </summary>
117
153
public static string [ ] ArrayOfStrings ( int count , int minLength , int maxLength )
118
154
{
119
155
var random = new Random ( Seed ) ;
@@ -126,36 +162,52 @@ public static string[] ArrayOfStrings(int count, int minLength, int maxLength)
126
162
return strings ;
127
163
}
128
164
165
+ /// <summary>
166
+ /// Returns a random of the type requested
167
+ /// For strings, it will be a random assortment of the letters 'a'..'z', 'A'..'Z', or '0'..'9' that is 1 to 50 characters long
168
+ /// </summary>
129
169
private static T GenerateValue < T > ( Random random )
130
170
{
171
+ // Note: some of these types (especially the unsigned and values larger than int) are not giving the full range of values.
172
+ // WE CANNOT change that now because existing performance tests are based on the values returned previously.
173
+ if ( typeof ( T ) == typeof ( byte ) )
174
+ return ( T ) ( object ) ( byte ) random . Next ( byte . MinValue , byte . MaxValue ) ; // note: will never return 256 as Random.Next max value is exclusive
175
+ if ( typeof ( T ) == typeof ( sbyte ) )
176
+ return ( T ) ( object ) ( sbyte ) random . Next ( sbyte . MinValue , sbyte . MaxValue ) ; // note: will never return 128 as Random.Next max value is exclusive
131
177
if ( typeof ( T ) == typeof ( char ) )
132
- return ( T ) ( object ) ( char ) random . Next ( char . MinValue , char . MaxValue ) ;
178
+ return ( T ) ( object ) ( char ) random . Next ( char . MinValue , char . MaxValue ) ; // note: will never return `\uffff` as Random.Next max value is exclusive
133
179
if ( typeof ( T ) == typeof ( short ) )
134
- return ( T ) ( object ) ( short ) random . Next ( short . MaxValue ) ;
180
+ return ( T ) ( object ) ( short ) random . Next ( short . MaxValue ) ; // note: will never return short.MaxValue as Random.Next max value is exclusive
135
181
if ( typeof ( T ) == typeof ( ushort ) )
136
- return ( T ) ( object ) ( ushort ) random . Next ( short . MaxValue ) ;
182
+ return ( T ) ( object ) ( ushort ) random . Next ( short . MaxValue ) ; // note: will never return short.MaxValue (right in the middle of the domain)
137
183
if ( typeof ( T ) == typeof ( int ) )
138
- return ( T ) ( object ) random . Next ( ) ;
184
+ return ( T ) ( object ) random . Next ( ) ; // note: cannot call NextInt32 here, because that would change what we've returned in the past
139
185
if ( typeof ( T ) == typeof ( uint ) )
140
- return ( T ) ( object ) ( uint ) random . Next ( ) ;
186
+ return ( T ) ( object ) ( uint ) random . Next ( ) ; // note: cannot call NextInt32 here, because that would change what we've returned in the past
141
187
if ( typeof ( T ) == typeof ( long ) )
142
- return ( T ) ( object ) ( long ) random . Next ( ) ;
188
+ return ( T ) ( object ) ( long ) random . Next ( ) ; // note: will never return a value at or above int.MaxValue
143
189
if ( typeof ( T ) == typeof ( ulong ) )
144
- return ( T ) ( object ) ( ulong ) random . Next ( ) ;
190
+ return ( T ) ( object ) ( ulong ) random . Next ( ) ; // note: will never return a value at or above int.MaxValue because Random.Next never returns negatives
145
191
if ( typeof ( T ) == typeof ( float ) )
146
192
return ( T ) ( object ) ( float ) random . NextDouble ( ) ;
147
193
if ( typeof ( T ) == typeof ( double ) )
148
194
return ( T ) ( object ) random . NextDouble ( ) ;
149
195
if ( typeof ( T ) == typeof ( bool ) )
150
196
return ( T ) ( object ) ( random . NextDouble ( ) > 0.5 ) ;
197
+ if ( typeof ( T ) == typeof ( decimal ) )
198
+ return ( T ) ( object ) GenerateRandomDecimal ( random ) ;
151
199
if ( typeof ( T ) == typeof ( string ) )
152
- return ( T ) ( object ) GenerateRandomString ( random , 1 , 50 ) ;
200
+ return ( T ) ( object ) GenerateRandomString ( random , 1 , 50 ) ; // note: all strings have only the characters 'a'..'z', 'A'..'Z', or '0'..'9'
153
201
if ( typeof ( T ) == typeof ( Guid ) )
154
- return ( T ) ( object ) GenerateRandomGuid ( random ) ;
202
+ return ( T ) ( object ) GenerateRandomGuid ( random ) ; // note: may return malformed Guids (not logically valid per RFC 4122 formatting)
155
203
156
204
throw new NotImplementedException ( $ "{ typeof ( T ) . Name } is not implemented") ;
157
205
}
158
-
206
+
207
+ /// <summary>
208
+ /// Returns a random length strings within the range requested and are composed
209
+ /// a random assortment of the letters a..z, A..Z, and digits 0..9
210
+ /// </summary>
159
211
private static string GenerateRandomString ( Random random , int minLength , int maxLength )
160
212
{
161
213
var length = random . Next ( minLength , maxLength ) ;
@@ -166,21 +218,58 @@ private static string GenerateRandomString(Random random, int minLength, int max
166
218
var rangeSelector = random . Next ( 0 , 3 ) ;
167
219
168
220
if ( rangeSelector == 0 )
169
- builder . Append ( ( char ) random . Next ( 'a' , 'z' ) ) ;
221
+ builder . Append ( ( char ) random . Next ( 'a' , 'z' ) ) ;
170
222
else if ( rangeSelector == 1 )
171
- builder . Append ( ( char ) random . Next ( 'A' , 'Z' ) ) ;
223
+ builder . Append ( ( char ) random . Next ( 'A' , 'Z' ) ) ;
172
224
else
173
- builder . Append ( ( char ) random . Next ( '0' , '9' ) ) ;
225
+ builder . Append ( ( char ) random . Next ( '0' , '9' ) ) ;
174
226
}
175
227
176
228
return builder . ToString ( ) ;
177
229
}
178
230
231
+ /// <summary>
232
+ /// Returns a randomly generated Guid.
233
+ /// Note: this is not guaranteed to be a reasonably formatted RFC 4122 Guid, NOR is this
234
+ /// necessarily a "Version 4 Random" guid.
235
+ /// </summary>
179
236
private static Guid GenerateRandomGuid ( Random random )
180
237
{
181
238
byte [ ] bytes = new byte [ 16 ] ;
182
239
random . NextBytes ( bytes ) ;
183
240
return new Guid ( bytes ) ;
184
241
}
242
+
243
+ /// <summary>
244
+ /// Returns a randomly generated decimal value.
245
+ /// Note: returns a value across the entire valid decimal value-space
246
+ /// </summary>
247
+ private static decimal GenerateRandomDecimal ( Random random )
248
+ {
249
+ // Decimal values have a sign, a scale, and 96 bits of significance (lo/mid/high)
250
+ // generate those parts randomly and assemble a valid decimal
251
+ byte scale = ( byte ) random . Next ( 29 ) ;
252
+ bool sign = random . Next ( 2 ) == 0 ;
253
+ return new decimal ( random . NextInt32 ( ) ,
254
+ random . NextInt32 ( ) ,
255
+ random . NextInt32 ( ) ,
256
+ sign ,
257
+ scale ) ;
258
+ }
259
+
260
+ /// <summary>
261
+ /// Returns a randomly generated int value from the entire range of legal 32-bit integers
262
+ /// Note: using Random.Next will never return negative values so we can't use that where
263
+ /// we want the complete bit-space.
264
+ /// WARNING: Do not use this method in the GenerateValue for the various int-like types
265
+ /// as that would change the range and order of values returned and THAT would change the
266
+ /// performance benchmarks
267
+ /// </summary>
268
+ private static int NextInt32 ( this Random random )
269
+ {
270
+ int firstBits = random . Next ( 0 , 1 << 4 ) << 28 ;
271
+ int lastBits = random . Next ( 0 , 1 << 28 ) ;
272
+ return firstBits | lastBits ;
273
+ }
185
274
}
186
275
}
0 commit comments