1 // ***********************************************************************
2 // Copyright (c) 2008-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.Globalization;
33 using System.Reflection;
34 using NUnit.Compatibility;
35 using NUnit.Framework.Interfaces;
36 using NUnit.Framework.Internal;
38 namespace NUnit.Framework
41 /// RandomAttribute is used to supply a set of random _values
42 /// to a single parameter of a parameterized test.
44 public class RandomAttribute : DataAttribute, IParameterDataSource
46 private RandomDataSource _source;
52 /// Construct a random set of values appropriate for the Type of the
53 /// parameter on which the attribute appears, specifying only the count.
55 /// <param name="count"></param>
56 public RandomAttribute(int count)
62 /// Construct a set of ints within a specified range
64 public RandomAttribute(int min, int max, int count)
66 _source = new IntDataSource(min, max, count);
70 /// Construct a set of unsigned ints within a specified range
72 //[CLSCompliant(false)]
73 public RandomAttribute(uint min, uint max, int count)
75 _source = new UIntDataSource(min, max, count);
79 /// Construct a set of longs within a specified range
81 public RandomAttribute(long min, long max, int count)
83 _source = new LongDataSource(min, max, count);
87 /// Construct a set of unsigned longs within a specified range
89 //[CLSCompliant(false)]
90 public RandomAttribute(ulong min, ulong max, int count)
92 _source = new ULongDataSource(min, max, count);
96 /// Construct a set of shorts within a specified range
98 public RandomAttribute(short min, short max, int count)
100 _source = new ShortDataSource(min, max, count);
104 /// Construct a set of unsigned shorts within a specified range
106 //[CLSCompliant(false)]
107 public RandomAttribute(ushort min, ushort max, int count)
109 _source = new UShortDataSource(min, max, count);
113 /// Construct a set of doubles within a specified range
115 public RandomAttribute(double min, double max, int count)
117 _source = new DoubleDataSource(min, max, count);
121 /// Construct a set of floats within a specified range
123 public RandomAttribute(float min, float max, int count)
125 _source = new FloatDataSource(min, max, count);
129 /// Construct a set of bytes within a specified range
131 public RandomAttribute(byte min, byte max, int count)
133 _source = new ByteDataSource(min, max, count);
137 /// Construct a set of sbytes within a specified range
139 //[CLSCompliant(false)]
140 public RandomAttribute(sbyte min, sbyte max, int count)
142 _source = new SByteDataSource(min, max, count);
147 #region IParameterDataSource Interface
150 /// Get the collection of _values to be used as arguments.
152 public IEnumerable GetData(IParameterInfo parameter)
154 // Since a separate Randomizer is used for each parameter,
155 // we can't fill in the data in the constructor of the
156 // attribute. Only now, when GetData is called, do we have
157 // sufficient information to create the values in a
158 // repeatable manner.
160 Type parmType = parameter.ParameterType;
164 if (parmType == typeof(int))
165 _source = new IntDataSource(_count);
166 else if (parmType == typeof(uint))
167 _source = new UIntDataSource(_count);
168 else if (parmType == typeof(long))
169 _source = new LongDataSource(_count);
170 else if (parmType == typeof(ulong))
171 _source = new ULongDataSource(_count);
172 else if (parmType == typeof(short))
173 _source = new ShortDataSource(_count);
174 else if (parmType == typeof(ushort))
175 _source = new UShortDataSource(_count);
176 else if (parmType == typeof(double))
177 _source = new DoubleDataSource(_count);
178 else if (parmType == typeof(float))
179 _source = new FloatDataSource(_count);
180 else if (parmType == typeof(byte))
181 _source = new ByteDataSource(_count);
182 else if (parmType == typeof(sbyte))
183 _source = new SByteDataSource(_count);
184 else if (parmType == typeof(decimal))
185 _source = new DecimalDataSource(_count);
186 else if (parmType.GetTypeInfo().IsEnum)
187 _source = new EnumDataSource(_count);
189 _source = new IntDataSource(_count);
191 else if (_source.DataType != parmType && WeConvert(_source.DataType, parmType))
193 _source = new RandomDataConverter(_source);
196 return _source.GetData(parameter);
198 //// Copy the random _values into the data array
199 //// and call the base class which may need to
200 //// convert them to another type.
201 //this.data = new object[values.Count];
202 //for (int i = 0; i < values.Count; i++)
203 // this.data[i] = values[i];
205 //return base.GetData(parameter);
208 private bool WeConvert(Type sourceType, Type targetType)
210 if (targetType == typeof(short) || targetType == typeof(ushort) || targetType == typeof(byte) || targetType == typeof(sbyte))
211 return sourceType == typeof(int);
213 if (targetType == typeof(decimal))
214 return sourceType == typeof(int) || sourceType == typeof(double);
221 #region Nested DataSource Classes
223 #region RandomDataSource
225 abstract class RandomDataSource : IParameterDataSource
227 public Type DataType { get; protected set; }
229 public abstract IEnumerable GetData(IParameterInfo parameter);
232 abstract class RandomDataSource<T> : RandomDataSource
237 private bool _inRange;
239 protected Randomizer _randomizer;
241 protected RandomDataSource(int count)
246 DataType = typeof(T);
249 protected RandomDataSource(T min, T max, int count)
256 DataType = typeof(T);
259 public override IEnumerable GetData(IParameterInfo parameter)
261 //Guard.ArgumentValid(parameter.ParameterType == typeof(T), "Parameter type must be " + typeof(T).Name, "parameter");
263 _randomizer = Randomizer.GetRandomizer(parameter.ParameterInfo);
265 for (int i = 0; i < _count; i++)
266 yield return _inRange
267 ? GetNext(_min, _max)
271 protected abstract T GetNext();
272 protected abstract T GetNext(T min, T max);
277 #region RandomDataConverter
279 class RandomDataConverter : RandomDataSource
281 IParameterDataSource _source;
283 public RandomDataConverter(IParameterDataSource source)
288 public override IEnumerable GetData(IParameterInfo parameter)
290 Type parmType = parameter.ParameterType;
292 foreach (object obj in _source.GetData(parameter))
296 int ival = (int)obj; // unbox first
297 if (parmType == typeof(short))
298 yield return (short)ival;
299 else if (parmType == typeof(ushort))
300 yield return (ushort)ival;
301 else if (parmType == typeof(byte))
302 yield return (byte)ival;
303 else if (parmType == typeof(sbyte))
304 yield return (sbyte)ival;
305 else if (parmType == typeof(decimal))
306 yield return (decimal)ival;
308 else if (obj is double)
310 double d = (double)obj; // unbox first
311 if (parmType == typeof(decimal))
312 yield return (decimal)d;
320 #region IntDataSource
322 class IntDataSource : RandomDataSource<int>
324 public IntDataSource(int count) : base(count) { }
326 public IntDataSource(int min, int max, int count) : base(min, max, count) { }
328 protected override int GetNext()
330 return _randomizer.Next();
333 protected override int GetNext(int min, int max)
335 return _randomizer.Next(min, max);
341 #region UIntDataSource
343 class UIntDataSource : RandomDataSource<uint>
345 public UIntDataSource(int count) : base(count) { }
347 public UIntDataSource(uint min, uint max, int count) : base(min, max, count) { }
349 protected override uint GetNext()
351 return _randomizer.NextUInt();
354 protected override uint GetNext(uint min, uint max)
356 return _randomizer.NextUInt(min, max);
362 #region LongDataSource
364 class LongDataSource : RandomDataSource<long>
366 public LongDataSource(int count) : base(count) { }
368 public LongDataSource(long min, long max, int count) : base(min, max, count) { }
370 protected override long GetNext()
372 return _randomizer.NextLong();
375 protected override long GetNext(long min, long max)
377 return _randomizer.NextLong(min, max);
383 #region ULongDataSource
385 class ULongDataSource : RandomDataSource<ulong>
387 public ULongDataSource(int count) : base(count) { }
389 public ULongDataSource(ulong min, ulong max, int count) : base(min, max, count) { }
391 protected override ulong GetNext()
393 return _randomizer.NextULong();
396 protected override ulong GetNext(ulong min, ulong max)
398 return _randomizer.NextULong(min, max);
404 #region ShortDataSource
406 class ShortDataSource : RandomDataSource<short>
408 public ShortDataSource(int count) : base(count) { }
410 public ShortDataSource(short min, short max, int count) : base(min, max, count) { }
412 protected override short GetNext()
414 return _randomizer.NextShort();
417 protected override short GetNext(short min, short max)
419 return _randomizer.NextShort(min, max);
425 #region UShortDataSource
427 class UShortDataSource : RandomDataSource<ushort>
429 public UShortDataSource(int count) : base(count) { }
431 public UShortDataSource(ushort min, ushort max, int count) : base(min, max, count) { }
433 protected override ushort GetNext()
435 return _randomizer.NextUShort();
438 protected override ushort GetNext(ushort min, ushort max)
440 return _randomizer.NextUShort(min, max);
446 #region DoubleDataSource
448 class DoubleDataSource : RandomDataSource<double>
450 public DoubleDataSource(int count) : base(count) { }
452 public DoubleDataSource(double min, double max, int count) : base(min, max, count) { }
454 protected override double GetNext()
456 return _randomizer.NextDouble();
459 protected override double GetNext(double min, double max)
461 return _randomizer.NextDouble(min, max);
467 #region FloatDataSource
469 class FloatDataSource : RandomDataSource<float>
471 public FloatDataSource(int count) : base(count) { }
473 public FloatDataSource(float min, float max, int count) : base(min, max, count) { }
475 protected override float GetNext()
477 return _randomizer.NextFloat();
480 protected override float GetNext(float min, float max)
482 return _randomizer.NextFloat(min, max);
488 #region ByteDataSource
490 class ByteDataSource : RandomDataSource<byte>
492 public ByteDataSource(int count) : base(count) { }
494 public ByteDataSource(byte min, byte max, int count) : base(min, max, count) { }
496 protected override byte GetNext()
498 return _randomizer.NextByte();
501 protected override byte GetNext(byte min, byte max)
503 return _randomizer.NextByte(min, max);
509 #region SByteDataSource
511 class SByteDataSource : RandomDataSource<sbyte>
513 public SByteDataSource(int count) : base(count) { }
515 public SByteDataSource(sbyte min, sbyte max, int count) : base(min, max, count) { }
517 protected override sbyte GetNext()
519 return _randomizer.NextSByte();
522 protected override sbyte GetNext(sbyte min, sbyte max)
524 return _randomizer.NextSByte(min, max);
530 #region EnumDataSource
532 class EnumDataSource : RandomDataSource
536 public EnumDataSource(int count)
539 DataType = typeof(Enum);
542 public override IEnumerable GetData(IParameterInfo parameter)
544 Guard.ArgumentValid(parameter.ParameterType.GetTypeInfo().IsEnum, "EnumDataSource requires an enum parameter", "parameter");
546 Randomizer randomizer = Randomizer.GetRandomizer(parameter.ParameterInfo);
547 DataType = parameter.ParameterType;
549 for (int i = 0; i < _count; i++ )
550 yield return randomizer.NextEnum(parameter.ParameterType);
556 #region DecimalDataSource
558 // Currently, Randomizer doesn't implement methods for decimal
559 // so we use random Ulongs and convert them. This doesn't cover
560 // the full range of decimal, so it's temporary.
561 class DecimalDataSource : RandomDataSource<decimal>
563 public DecimalDataSource(int count) : base(count) { }
565 public DecimalDataSource(decimal min, decimal max, int count) : base(min, max, count) { }
567 protected override decimal GetNext()
569 return _randomizer.NextDecimal();
572 protected override decimal GetNext(decimal min, decimal max)
574 return _randomizer.NextDecimal(min, max);