1 // ***********************************************************************
2 // Copyright (c) 2013-2015 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Reflection;
35 namespace NUnit.Framework.Internal
38 /// Randomizer returns a set of random _values in a repeatable
39 /// way, to allow re-running of tests if necessary. It extends
40 /// the .NET Random class, providing random values for a much
41 /// wider range of types.
43 /// The class is used internally by the framework to generate
44 /// test case data and is also exposed for use by users through
45 /// the TestContext.Random property.
48 /// For consistency with the underlying Random Type, methods
49 /// returning a single value use the prefix "Next..." Those
50 /// without an argument return a non-negative value up to
51 /// the full positive range of the Type. Overloads are provided
52 /// for specifying a maximum or a range. Methods that return
53 /// arrays or strings use the prefix "Get..." to avoid
54 /// confusion with the single-value methods.
56 public class Randomizer : Random
58 #region Static Members
60 // Static constructor initializes values
63 InitialSeed = new Random().Next();
64 Randomizers = new Dictionary<MemberInfo, Randomizer>();
67 // Static Random instance used exclusively for the generation
68 // of seed values for new Randomizers.
69 private static Random _seedGenerator;
72 /// Initial seed used to create randomizers for this run
74 public static int InitialSeed
76 get { return _initialSeed; }
80 // Setting or resetting the initial seed creates seed generator
81 _seedGenerator = new Random(_initialSeed);
84 private static int _initialSeed;
86 // Lookup Dictionary used to find randomizers for each member
87 private static Dictionary<MemberInfo, Randomizer> Randomizers;
90 /// Get a Randomizer for a particular member, returning
91 /// one that has already been created if it exists.
92 /// This ensures that the same _values are generated
93 /// each time the tests are reloaded.
95 public static Randomizer GetRandomizer(MemberInfo member)
97 if (Randomizers.ContainsKey(member))
98 return Randomizers[member];
101 var r = CreateRandomizer();
102 Randomizers[member] = r;
109 /// Get a randomizer for a particular parameter, returning
110 /// one that has already been created if it exists.
111 /// This ensures that the same values are generated
112 /// each time the tests are reloaded.
114 public static Randomizer GetRandomizer(ParameterInfo parameter)
116 return GetRandomizer(parameter.Member);
120 /// Create a new Randomizer using the next seed
121 /// available to ensure that each randomizer gives
122 /// a unique sequence of values.
124 /// <returns></returns>
125 public static Randomizer CreateRandomizer()
127 return new Randomizer(_seedGenerator.Next());
135 /// Default constructor
137 public Randomizer() { }
140 /// Construct based on seed value
142 /// <param name="seed"></param>
143 public Randomizer(int seed) : base(seed) { }
149 // NOTE: Next(), Next(int max) and Next(int min, int max) are
150 // inherited from Random.
154 #region Unsigned Ints
157 /// Returns a random unsigned int.
159 //[CLSCompliant(false)]
160 public uint NextUInt()
162 return NextUInt(0u, uint.MaxValue);
166 /// Returns a random unsigned int less than the specified maximum.
168 //[CLSCompliant(false)]
169 public uint NextUInt(uint max)
171 return NextUInt(0u, max);
175 /// Returns a random unsigned int within a specified range.
177 //[CLSCompliant(false)]
178 public uint NextUInt(uint min, uint max)
180 Guard.ArgumentInRange(max >= min, "Maximum value must be greater than or equal to minimum.", "max");
185 uint range = max - min;
187 // Avoid introduction of modulo bias
188 uint limit = uint.MaxValue - uint.MaxValue % range;
196 return unchecked(raw % range + min);
204 /// Returns a non-negative random short.
206 public short NextShort()
208 return NextShort(0, short.MaxValue);
212 /// Returns a non-negative random short less than the specified maximum.
214 public short NextShort(short max)
216 return NextShort((short)0, max);
220 /// Returns a non-negative random short within a specified range.
222 public short NextShort(short min, short max)
224 return (short)Next(min, max);
229 #region Unsigned Shorts
232 /// Returns a random unsigned short.
234 //[CLSCompliant(false)]
235 public ushort NextUShort()
237 return NextUShort((ushort)0, ushort.MaxValue);
241 /// Returns a random unsigned short less than the specified maximum.
243 //[CLSCompliant(false)]
244 public ushort NextUShort(ushort max)
246 return NextUShort((ushort)0, max);
250 /// Returns a random unsigned short within a specified range.
252 //[CLSCompliant(false)]
253 public ushort NextUShort(ushort min, ushort max)
255 return (ushort)Next(min, max);
263 /// Returns a random long.
265 public long NextLong()
267 return NextLong(0L, long.MaxValue);
271 /// Returns a random long less than the specified maximum.
273 public long NextLong(long max)
275 return NextLong(0L, max);
279 /// Returns a non-negative random long within a specified range.
281 public long NextLong(long min, long max)
283 Guard.ArgumentInRange(max >= min, "Maximum value must be greater than or equal to minimum.", "max");
288 ulong range = (ulong)(max - min);
290 // Avoid introduction of modulo bias
291 ulong limit = ulong.MaxValue - ulong.MaxValue % range;
299 return (long)(raw % range + (ulong)min);
304 #region Unsigned Longs
307 /// Returns a random ulong.
309 //[CLSCompliant(false)]
310 public ulong NextULong()
312 return NextULong(0ul, ulong.MaxValue);
316 /// Returns a random ulong less than the specified maximum.
318 //[CLSCompliant(false)]
319 public ulong NextULong(ulong max)
321 return NextULong(0ul, max);
325 /// Returns a non-negative random long within a specified range.
327 //[CLSCompliant(false)]
328 public ulong NextULong(ulong min, ulong max)
330 Guard.ArgumentInRange(max >= min, "Maximum value must be greater than or equal to minimum.", "max");
332 ulong range = max - min;
337 // Avoid introduction of modulo bias
338 ulong limit = ulong.MaxValue - ulong.MaxValue % range;
346 return unchecked(raw % range + min);
354 /// Returns a random Byte
356 public byte NextByte()
358 return NextByte((byte)0, Byte.MaxValue);
362 /// Returns a random Byte less than the specified maximum.
364 public byte NextByte(byte max)
366 return NextByte((byte)0, max);
370 /// Returns a random Byte within a specified range
372 public byte NextByte(byte min, byte max)
374 return (byte)Next(min, max);
382 /// Returns a random SByte
384 //[CLSCompliant(false)]
385 public sbyte NextSByte()
387 return NextSByte((sbyte)0, SByte.MaxValue);
391 /// Returns a random sbyte less than the specified maximum.
393 //[CLSCompliant(false)]
394 public sbyte NextSByte(sbyte max)
396 return NextSByte((sbyte)0, max);
400 /// Returns a random sbyte within a specified range
402 //[CLSCompliant(false)]
403 public sbyte NextSByte(sbyte min, sbyte max)
405 return (sbyte)Next(min, max);
413 /// Returns a random bool
415 public bool NextBool()
417 return NextDouble() < 0.5;
421 /// Returns a random bool based on the probablility a true result
423 public bool NextBool(double probability)
425 Guard.ArgumentInRange(probability >= 0.0 && probability <= 1.0, "Probability must be from 0.0 to 1.0", "probability");
427 return NextDouble() < probability;
434 // NOTE: NextDouble() is inherited from Random.
437 /// Returns a random double between 0.0 and the specified maximum.
439 public double NextDouble(double max)
441 return NextDouble() * max;
445 /// Returns a random double within a specified range.
447 public double NextDouble(double min, double max)
449 Guard.ArgumentInRange(max >= min, "Maximum value must be greater than or equal to minimum.", "max");
454 double range = max - min;
455 return NextDouble() * range + min;
463 /// Returns a random float.
465 public float NextFloat()
467 return (float)NextDouble();
471 /// Returns a random float between 0.0 and the specified maximum.
473 public float NextFloat(float max)
475 return (float)NextDouble(max);
479 /// Returns a random float within a specified range.
481 public float NextFloat(float min, float max)
483 return (float)NextDouble(min, max);
491 /// Returns a random enum value of the specified Type as an object.
493 public object NextEnum(Type type)
495 Array enums = TypeHelper.GetEnumValues(type);
496 return enums.GetValue(Next(0, enums.Length));
500 /// Returns a random enum value of the specified Type.
502 public T NextEnum<T>()
504 return (T)NextEnum(typeof(T));
512 /// Default characters for random functions.
514 /// <remarks>Default characters are the English alphabet (uppercase & lowercase), arabic numerals, and underscore</remarks>
515 public const string DefaultStringChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789_";
517 private const int DefaultStringLength = 25;
520 /// Generate a random string based on the characters from the input string.
522 /// <param name="outputLength">desired length of output string.</param>
523 /// <param name="allowedChars">string representing the set of characters from which to construct the resulting string</param>
524 /// <returns>A random string of arbitrary length</returns>
525 public string GetString(int outputLength, string allowedChars)
528 var sb = new StringBuilder(outputLength);
530 for (int i = 0; i < outputLength ; i++)
532 sb.Append(allowedChars[Next(0,allowedChars.Length)]);
535 return sb.ToString();
539 /// Generate a random string based on the characters from the input string.
541 /// <param name="outputLength">desired length of output string.</param>
542 /// <returns>A random string of arbitrary length</returns>
543 /// <remarks>Uses <see cref="DefaultStringChars">DefaultStringChars</see> as the input character set </remarks>
544 public string GetString(int outputLength)
546 return GetString(outputLength, DefaultStringChars);
550 /// Generate a random string based on the characters from the input string.
552 /// <returns>A random string of the default length</returns>
553 /// <remarks>Uses <see cref="DefaultStringChars">DefaultStringChars</see> as the input character set </remarks>
554 public string GetString()
556 return GetString(DefaultStringLength, DefaultStringChars);
563 // We treat decimal as an integral type for now.
564 // The scaling factor is always zero.
567 /// Returns a random decimal.
569 public decimal NextDecimal()
571 int low = Next(0, int.MaxValue);
572 int mid = Next(0, int.MaxValue);
573 int high = Next(0, int.MaxValue);
574 return new Decimal(low, mid, high, false, 0);
578 /// Returns a random decimal between positive zero and the specified maximum.
580 public decimal NextDecimal(decimal max)
582 return NextDecimal() % max;
586 /// Returns a random decimal within a specified range, which is not
587 /// permitted to exceed decimal.MaxVal in the current implementation.
590 /// A limitation of this implementation is that the range from min
591 /// to max must not exceed decimal.MaxVal.
593 public decimal NextDecimal(decimal min, decimal max)
595 Guard.ArgumentInRange(max >= min, "Maximum value must be greater than or equal to minimum.", "max");
597 // Check that the range is not greater than MaxValue without
598 // first calculating it, since this would cause overflow
599 Guard.ArgumentValid(max < 0M == min < 0M || min + decimal.MaxValue >= max,
600 "Range too great for decimal data, use double range", "max");
605 decimal range = max - min;
607 // Avoid introduction of modulo bias
608 decimal limit = decimal.MaxValue - decimal.MaxValue % range;
616 return unchecked(raw % range + min);
621 #region Helper Methods
623 private uint RawUInt()
625 var buffer = new byte[sizeof(uint)];
627 return BitConverter.ToUInt32(buffer, 0);
630 private uint RawUShort()
632 var buffer = new byte[sizeof(uint)];
634 return BitConverter.ToUInt32(buffer, 0);
637 private ulong RawULong()
639 var buffer = new byte[sizeof(ulong)];
641 return BitConverter.ToUInt64(buffer, 0);
644 private long RawLong()
646 var buffer = new byte[sizeof(long)];
648 return BitConverter.ToInt64(buffer, 0);
651 private decimal RawDecimal()
653 int low = Next(0, int.MaxValue);
654 int mid = Next(0, int.MaxValue);
655 int hi = Next(0, int.MaxValue);
656 bool isNegative = NextBool();
657 byte scale = NextByte(29);
658 return new Decimal(low, mid, hi, isNegative, scale);