/// <summary> /// Creates and fills a list of the given <paramref name="propertyType"/> /// </summary> /// <param name="propertyType"> /// Type of the list /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// Created and filled list of the given <paramref name="propertyType"/> /// </returns> private IEnumerable GetFilledCollection(Type propertyType, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker) { Type genType = propertyType.GetGenericTypeArguments()[0]; if (this.CheckForCircularReference(genType, typeTracker, currentSetupItem)) { return(null); } IEnumerable target; if (!propertyType.IsInterface() && propertyType.GetImplementedInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(ICollection <>) #if (!NET35 && !NET40) || x.GetGenericTypeDefinition() == typeof(IReadOnlyCollection <>) #endif )) { target = (IEnumerable)Activator.CreateInstance(propertyType); } else if (propertyType.IsGenericType() && propertyType.GetGenericTypeDefinition() == typeof(ICollection <>) || propertyType.GetImplementedInterfaces().Any(x => x.IsGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection <>)) #if (!NET35 && !NET40) || propertyType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection <>) || propertyType.GetImplementedInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(IReadOnlyCollection <>)) #endif ) { Type openListType = typeof(List <>); Type genericListType = openListType.MakeGenericType(genType); target = (IEnumerable)Activator.CreateInstance(genericListType); } else { target = (IEnumerable)Activator.CreateInstance(propertyType); } int maxListItems = Random.Next(currentSetupItem.ListMinCount, currentSetupItem.ListMaxCount); for (int i = 0; i < maxListItems; i++) { object listObject = this.CreateAndFillObject(genType, currentSetupItem, typeTracker); MethodInfo method = target.GetType().GetMethod("Add"); method.Invoke(target, new object[] { listObject }); } return(target); }
/// <summary> /// Gets a random value of the given <paramref name="propertyType"/> /// </summary> /// <param name="propertyType"> /// The property dictionaryType. /// </param> /// <param name="setupItem"> /// The setup item. /// </param> /// <returns> /// A random value of the given <paramref name="propertyType"/> /// </returns> /// <exception cref="TypeInitializationException"> /// Throws exception if object filler was not able to create random data /// </exception> private object GetRandomValue(Type propertyType, FillerSetupItem setupItem) { if (setupItem.TypeToRandomFunc.ContainsKey(propertyType)) { return(setupItem.TypeToRandomFunc[propertyType]()); } if (setupItem.IgnoreAllUnknownTypes) { return(GetDefaultValueOfType(propertyType)); } string message = "The type [" + propertyType.Name + "] was not registered in the randomizer."; throw new TypeInitializationException(propertyType.FullName, new Exception(message)); }
/// <summary> /// Creates and fills a POCO class /// </summary> /// <param name="type"> /// The target dictionaryType. /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// The created and filled POCO class /// </returns> private object GetFilledPoco(Type type, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker) { if (this.CheckForCircularReference(type, typeTracker, currentSetupItem)) { return(GetDefaultValueOfType(type)); } typeTracker.Push(type); object result = this.CreateInstanceOfType(type, currentSetupItem, typeTracker); this.FillInternal(result, typeTracker); typeTracker.Pop(); return(result); }
/// <summary> /// This method will fill the given <paramref name="properties"/> of the given <paramref name="objectToFill"/> /// </summary> /// <param name="objectToFill">The object to fill</param> /// <param name="properties">The properties of the <paramref name="objectToFill"/> which shall get filled</param> /// <param name="currentSetup"> /// The setup for the current object /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> private void FillProperties(object objectToFill, PropertyInfo[] properties, FillerSetupItem currentSetup, HashStack <Type> typeTracker) { if (properties.Length == 0) { return; } Queue <PropertyInfo> orderedProperties = this.OrderPropertiers(currentSetup, properties); while (orderedProperties.Count != 0) { PropertyInfo property = orderedProperties.Dequeue(); if (currentSetup.TypesToIgnore.Contains(property.PropertyType)) { continue; } if (this.IgnoreProperty(property, currentSetup)) { continue; } if (this.ContainsProperty(currentSetup.PropertyToRandomFunc.Keys, property)) { PropertyInfo propertyInfo = this.GetPropertyFromProperties(currentSetup.PropertyToRandomFunc.Keys, property).Single(); this.SetPropertyValue(property, objectToFill, currentSetup.PropertyToRandomFunc[propertyInfo]()); continue; } if (this.justConfiguredProperties && !this.setupManager.FillerSetup.TypeToFillerSetup.ContainsKey(property.PropertyType)) { continue; } object filledObject = this.CreateAndFillObject(property.PropertyType, currentSetup, typeTracker); this.SetPropertyValue(property, objectToFill, filledObject); } }
/// <summary> /// Creates a object of the target <see cref="type"/> and fills it up with data according to the given <see cref="currentSetupItem"/> /// </summary> /// <param name="type"> /// The target dictionaryType to create and fill /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// The created and filled object of the given <see cref="type"/> /// </returns> private object CreateAndFillObject( Type type, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker = null) { if (HasTypeARandomFunc(type, currentSetupItem)) { return(this.GetRandomValue(type, currentSetupItem)); } if (TypeIsDictionary(type)) { IDictionary dictionary = this.GetFilledDictionary(type, currentSetupItem, typeTracker); return(dictionary); } if (TypeIsList(type)) { IList list = this.GetFilledList(type, currentSetupItem, typeTracker); return(list); } if (type.IsInterface || type.IsAbstract) { return(this.CreateInstanceOfInterfaceOrAbstractClass(type, currentSetupItem, typeTracker)); } if (TypeIsEnum(type)) { return(this.GetRandomEnumValue(type)); } if (TypeIsPoco(type)) { return(this.GetFilledPoco(type, currentSetupItem, typeTracker)); } object newValue = this.GetRandomValue(type, currentSetupItem); return(newValue); }
/// <summary> /// Sorts the properties like the <paramref name="currentSetupItem"/> wants to have it /// </summary> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="properties"> /// The properties to sort /// </param> /// <returns> /// Sorted properties as a queue /// </returns> private Queue <PropertyInfo> OrderPropertiers(FillerSetupItem currentSetupItem, PropertyInfo[] properties) { var propertyQueue = new Queue <PropertyInfo>(); var firstProperties = currentSetupItem.PropertyOrder.Where( x => x.Value == At.TheBegin && this.ContainsProperty(properties, x.Key)).Select(x => x.Key).ToList(); var lastProperties = currentSetupItem.PropertyOrder.Where( x => x.Value == At.TheEnd && this.ContainsProperty(properties, x.Key)).Select(x => x.Key).ToList(); var propertiesWithoutOrder = properties.Where(x => !this.ContainsProperty(currentSetupItem.PropertyOrder.Keys, x)).ToList(); firstProperties.ForEach(propertyQueue.Enqueue); propertiesWithoutOrder.ForEach(propertyQueue.Enqueue); lastProperties.ForEach(propertyQueue.Enqueue); return(propertyQueue); }
/// <summary> /// Creates and fills a list of the given <see cref="propertyType"/> /// </summary> /// <param name="propertyType"> /// Type of the list /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// Created and filled list of the given <see cref="propertyType"/> /// </returns> private IList GetFilledList(Type propertyType, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker) { Type genType = propertyType.GetGenericArguments()[0]; if (this.CheckForCircularReference(genType, typeTracker, currentSetupItem)) { return(null); } IList list; if (!propertyType.IsInterface && propertyType.GetInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(ICollection <>))) { list = (IList)Activator.CreateInstance(propertyType); } else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(IEnumerable <>) || propertyType.GetInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(IEnumerable <>))) { Type openListType = typeof(List <>); Type genericListType = openListType.MakeGenericType(genType); list = (IList)Activator.CreateInstance(genericListType); } else { list = (IList)Activator.CreateInstance(propertyType); } int maxListItems = Random.Next(currentSetupItem.ListMinCount, currentSetupItem.ListMaxCount); for (int i = 0; i < maxListItems; i++) { object listObject = this.CreateAndFillObject(genType, currentSetupItem, typeTracker); list.Add(listObject); } return(list); }
/// <summary> /// Checks if the given dictionaryType was already been used in the object hierarchy /// </summary> /// <param name="targetType"> /// The target dictionaryType. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <returns> /// True if there is a circular dependency /// </returns> /// <exception cref="InvalidOperationException"> /// Throws exception if a circular dependency exists and the setup is set to throw exception on circular dependency /// </exception> private bool CheckForCircularReference( Type targetType, HashStack <Type> typeTracker, FillerSetupItem currentSetupItem) { if (typeTracker != null) { if (typeTracker.Contains(targetType)) { if (currentSetupItem.ThrowExceptionOnCircularReference) { throw new InvalidOperationException( string.Format( "The type {0} was already encountered before, which probably means you have a circular reference in your model. Either ignore the properties which cause this or specify explicit creation rules for them which do not rely on types.", targetType.Name)); } return(true); } } return(false); }
/// <summary> /// Creates a instance of the given <see cref="Type"/> /// </summary> /// <param name="type"> /// The dictionaryType to create /// </param> /// <param name="currentSetupItem"> /// The setup for the current object dictionaryType /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// Created instance of the given <see cref="Type"/> /// </returns> /// <exception cref="InvalidOperationException"> /// Throws exception if the constructor could not be created by filler setup /// </exception> private object CreateInstanceOfType(Type type, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker) { var constructorArgs = new List <object>(); if (type.GetConstructors().All(ctor => ctor.GetParameters().Length != 0)) { IEnumerable <ConstructorInfo> ctorInfos; if ((ctorInfos = type.GetConstructors().Where(ctr => ctr.GetParameters().Length != 0)).Any()) { foreach (ConstructorInfo ctorInfo in ctorInfos.OrderBy(x => x.GetParameters().Length)) { Type[] paramTypes = ctorInfo.GetParameters().Select(p => p.ParameterType).ToArray(); if (paramTypes.All(ctorParamType => TypeIsValidForObjectFiller(ctorParamType, currentSetupItem) && ctorParamType != type)) { foreach (Type paramType in paramTypes) { constructorArgs.Add(this.CreateAndFillObject(paramType, currentSetupItem, typeTracker)); } break; } } if (constructorArgs.Count == 0) { var message = "Could not found a constructor for type [" + type.Name + "] where the parameters can be filled with the current objectfiller setup"; throw new InvalidOperationException(message); } } } object result = Activator.CreateInstance(type, constructorArgs.ToArray()); return(result); }
/// <summary> /// Creates a instance of an interface or abstract class. Like an IoC-Framework /// </summary> /// <param name="interfaceType"> /// The dictionaryType of interface or abstract class /// </param> /// <param name="setupItem"> /// The setup item. /// </param> /// <param name="typeTracker"> /// The type tracker to find circular dependencies /// </param> /// <returns> /// The created and filled instance of the <paramref name="interfaceType"/> /// </returns> /// <exception cref="InvalidOperationException"> /// Throws Exception if no dictionaryType was registered for the given <paramref name="interfaceType"/> /// </exception> private object CreateInstanceOfInterfaceOrAbstractClass( Type interfaceType, FillerSetupItem setupItem, HashStack <Type> typeTracker) { object result; if (setupItem.TypeToRandomFunc.ContainsKey(interfaceType)) { return(setupItem.TypeToRandomFunc[interfaceType]()); } if (setupItem.InterfaceToImplementation.ContainsKey(interfaceType)) { Type implType = setupItem.InterfaceToImplementation[interfaceType]; result = this.CreateInstanceOfType(implType, setupItem, typeTracker); } else { if (setupItem.InterfaceMocker == null) { string message = string.Format( "ObjectFiller Interface mocker missing and type [{0}] not registered", interfaceType.Name); throw new InvalidOperationException(message); } MethodInfo method = setupItem.InterfaceMocker.GetType().GetMethod("Create"); MethodInfo genericMethod = method.MakeGenericMethod(new[] { interfaceType }); result = genericMethod.Invoke(setupItem.InterfaceMocker, null); } this.FillInternal(result, typeTracker); return(result); }
/// <summary> /// Initializes static members of the <see cref="Randomizer{T}"/> class. /// </summary> static Randomizer() { Setup = new FillerSetupItem(); }
/// <summary> /// Creates and fills a dictionary of the target <paramref name="propertyType"/> /// </summary> /// <param name="propertyType"> /// The dictionaryType of the dictionary /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <param name="typeTracker"> /// The dictionaryType tracker to find circular dependencies /// </param> /// <returns> /// A created and filled dictionary /// </returns> /// <exception cref="ArgumentException"> /// Throws exception if the setup was made in a way that the keys of the dictionary are always the same /// </exception> private IDictionary GetFilledDictionary( Type propertyType, FillerSetupItem currentSetupItem, HashStack <Type> typeTracker) { IDictionary dictionary = (IDictionary)Activator.CreateInstance(propertyType); bool derivedType = !propertyType.GetGenericTypeArguments().Any(); Type keyType = !derivedType ? propertyType.GetGenericTypeArguments()[0] : propertyType.GetTypeInfo().BaseType.GetGenericTypeArguments()[0]; Type valueType = !derivedType ? propertyType.GetGenericTypeArguments()[1] : propertyType.GetTypeInfo().BaseType.GetGenericTypeArguments()[1]; int maxDictionaryItems = 0; if (keyType.IsEnum()) { maxDictionaryItems = Enum.GetValues(keyType).Length; } else { maxDictionaryItems = Random.Next( currentSetupItem.DictionaryKeyMinCount, currentSetupItem.DictionaryKeyMaxCount); } for (int i = 0; i < maxDictionaryItems; i++) { object keyObject = null; if (keyType.IsEnum()) { keyObject = Enum.GetValues(keyType).GetValue(i); } else { keyObject = this.CreateAndFillObject(keyType, currentSetupItem, typeTracker); } if (dictionary.Contains(keyObject)) { string message = string.Format( "Generating Keyvalue failed because it generates always the same data for dictionaryType [{0}]. Please check your setup.", keyType); throw new ArgumentException(message); } object valueObject = this.CreateAndFillObject(valueType, currentSetupItem, typeTracker); dictionary.Add(keyObject, valueObject); } if (derivedType) { var remainingProperties = propertyType.GetProperties(true) .Where(prop => this.GetSetMethodOnDeclaringType(prop) != null) .ToArray(); this.FillProperties(dictionary, remainingProperties, currentSetupItem, typeTracker); } return(dictionary); }
/// <summary> /// Checks if there is a random function for the given <see cref="Type"/> /// </summary> /// <param name="type"> /// The dictionaryType. /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <returns> /// True if there is a random function in the <paramref name="currentSetupItem"/> for the given <see cref="Type"/> /// </returns> private static bool HasTypeARandomFunc(Type type, FillerSetupItem currentSetupItem) { return(currentSetupItem.TypeToRandomFunc.ContainsKey(type)); }
/// <summary> /// Checks if a property is ignored by the <paramref name="currentSetupItem"/> /// </summary> /// <param name="property"> /// The property to check for ignorance /// </param> /// <param name="currentSetupItem"> /// The current setup item. /// </param> /// <returns> /// True if the <paramref name="property"/> should be ignored /// </returns> private bool IgnoreProperty(PropertyInfo property, FillerSetupItem currentSetupItem) { return(this.ContainsProperty(currentSetupItem.PropertiesToIgnore, property)); }