You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Consider to include to Moq code base a function to generate mock from anonymous object. I wrote the following working prototype.
usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Linq.Expressions;usingSystem.Reflection;usingSystem.Diagnostics;usingSystem.Runtime.CompilerServices;namespaceTests{usingPropertyValue=KeyValuePair<string,object>;/// <summary>/// Builds <see cref="Mock<T>"/> from anonymous object./// </summary>internalclassAnonyMock{/// <summary>/// Builds mock for given type from anonymous object./// </summary>/// <typeparam name="T">The interface to mock.</typeparam>/// <param name="obj">Anonymous object.</param>/// <returns></returns>publicstaticTOf<T>(objectobj)whereT:class{Debug.Assert(IsAnon(obj));returnMock.Of(MakePredicate<T>(obj));}privatestaticExpression<Func<T,bool>>MakePredicate<T>(objectobj){vartype=typeof(T);varparameter=Expression.Parameter(typeof(T),"t");varprops=(frompinobj.GetType().GetProperties()wherep.Name!="type"selectPropertyPredicate(parameter,obj,type,p)).ToArray();returnExpression.Lambda<Func<T,bool>>(props.Skip(1).Aggregate(props[0],Expression.AndAlso),parameter);}privatestaticExpressionPropertyPredicate(Expressionparameter,objectinstance,TypetargetType,PropertyInfopi){varvalue=pi.GetValue(instance,null);// example of composite propertiesFunc<object,IEnumerable<PropertyValue>>destruct;if(CompositeProperties.TryGetValue(pi.Name,outdestruct)){varprops=(frompindestruct(value)selectPropertyEqual(parameter,targetType,p.Key,p.Value)).ToArray();returnprops.Skip(1).Aggregate(props[0],Expression.AndAlso);}vartargetProperty=ResolveProperty(targetType,pi.Name);Debug.Assert(targetProperty!=null);// support T[], IEnumerable<T>, IItemCollection<T>vararray=valueasArray;if(array!=null){// replace anonymous objectsvaritemType=GetItemType(targetProperty.PropertyType);varitems=(fromitinarray.Cast<object>()selectMockIfAnon(it,itemType)).ToArray();vartargetArray=Array.CreateInstance(itemType,items.Length);for(vari=0;i<items.Length;i++){targetArray.SetValue(items[i],i);}value=targetArray;if(targetProperty.PropertyType.GetGenericTypeDefinition()==typeof(IItemCollection<>)){value=CreateItemCollection(targetArray,itemType);}}returnExpression.Equal(Expression.Property(parameter,targetProperty),Expression.Constant(value));}privatestaticobjectMockIfAnon(objectobj,Typetype){if(!IsAnon(obj))returnobj;vartypeProperty=obj.GetType().GetProperty("type");if(typeProperty!=null){type=(Type)typeProperty.GetValue(obj,null);}varmethod=typeof(Amock).GetMethod("Of").MakeGenericMethod(type);returnmethod.Invoke(null,new[]{obj});}privatestaticExpressionPropertyEqual(Expressiontarget,TypedeclType,stringname,objectvalue){varprop=GetProperty(target,declType,name);returnExpression.Equal(prop,Expression.Constant(value));}privatestaticExpressionGetProperty(Expressiontarget,TypedeclType,stringname){returnExpression.Property(target,ResolveProperty(declType,name));}privatestaticPropertyInfoResolveProperty(Typetype,stringname){// TODO cache propertiesvartypes=new[]{type}.Concat(BaseTypes(type)).Concat(type.GetInterfaces()).ToArray();returntypes.Select(t =>t.GetProperty(name)).FirstOrDefault(x =>x!=null);}privatestaticIEnumerable<Type>BaseTypes(Typetype){while(type!=null&&type.BaseType!=null){yieldreturntype.BaseType;type=type.BaseType;}}privatestaticboolIsAnon(objectvalue){returnvalue!=null&&CheckIfAnonymousType(value.GetType());}privatestaticboolCheckIfAnonymousType(Typetype){if(type==null)thrownewArgumentNullException("type");// HACK: The only way to detect anonymous types right now.returnAttribute.IsDefined(type,typeof(CompilerGeneratedAttribute),false)&&type.IsGenericType&&type.Name.Contains("AnonymousType")&&(type.Name.StartsWith("<>")||type.Name.StartsWith("VB$"))&&(type.Attributes&TypeAttributes.NotPublic)==TypeAttributes.NotPublic;}privatestaticTypeGetItemType(Typetype){if(type==null)returnnull;if(type.IsArray)returntype.GetElementType();// IEnumerable<T>vari=FindIEnumerableT(type);if(i!=null)returni.GetGenericArguments()[0];// support non-generic collections like old .NET 1 collections based on CollectionBaseif(!typeof(IEnumerable).IsAssignableFrom(type))returnnull;varadd=type.GetMethod("Add");if(add==null)returnnull;varparameters=add.GetParameters();if(parameters.Length!=1)returnnull;returnparameters[0].ParameterType;}privatestaticTypeFindIEnumerableT(Typetype){if(type==null||type==typeof(string))returnnull;if(type.IsArray)returntypeof(IEnumerable<>).MakeGenericType(type.GetElementType());if(type.IsGenericType){varienum=type.GetGenericArguments().Select(x =>typeof(IEnumerable<>).MakeGenericType(x)).FirstOrDefault(x =>x.IsAssignableFrom(type));if(ienum!=null){returnienum;}}varifaces=type.GetInterfaces();if(ifaces.Length>0){varienum=ifaces.Select(x =>FindIEnumerableT(x)).FirstOrDefault(x =>x!=null);if(ienum!=null){returnienum;}}if(type.BaseType!=null&&type.BaseType!=typeof(object)){returnFindIEnumerableT(type.BaseType);}returnnull;}privatestaticobjectCreateItemCollection(Arrayitems,TypeitemType){varmethod=typeof(Amock).GetMethod("ItemCollection").MakeGenericMethod(itemType);returnmethod.Invoke(null,new[]{items});}publicstaticIItemCollection<T>ItemCollection<T>(paramsT[]items){returnitems.ToItemCollection();}}}
Consider to include to Moq code base a function to generate mock from anonymous object. I wrote the following working prototype.
Usage
The text was updated successfully, but these errors were encountered: