Update of /cvsroot/nmock/nmock2/src/NMock2/Monitoring In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24181/src/NMock2/Monitoring Added Files: ProxiedObjectIdentity.cs IInvokable.cs ParameterList.cs Invocation.cs Invoker.cs MultiInterfaceFactory.cs ProxyInvokableAdapter.cs Log Message: first upload of nmock2 --- NEW FILE: MultiInterfaceFactory.cs --- using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; namespace NMock2.Monitoring { public class MultiInterfaceFactory { private ModuleBuilder moduleBuilder; private Hashtable createdTypes = new Hashtable(); public MultiInterfaceFactory(string name) { AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = name; AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); moduleBuilder = assemblyBuilder.DefineDynamicModule(name); } public Type GetType(params Type[] baseInterfaces) { TypeId id = Id(baseInterfaces); if (createdTypes.ContainsKey(id)) { return (Type) createdTypes[id]; } else { string typeName = "MultiInterface" + (createdTypes.Count+1); Type newType = CreateType(typeName, baseInterfaces); createdTypes[id] = newType; return newType; } } private Type CreateType(string typeName, Type[] baseInterfaces) { TypeBuilder typeBuilder = moduleBuilder.DefineType( typeName, TypeAttributes.Public|TypeAttributes.Abstract|TypeAttributes.Interface, null, baseInterfaces ); return typeBuilder.CreateType(); } private TypeId Id(params Type[] types) { return new TypeId(types); } private class TypeId { Type[] types; public TypeId(params Type[] types) { this.types = types; } public override int GetHashCode() { int hashCode = 0; foreach (Type type in types) { hashCode ^= type.GetHashCode(); } return hashCode; } public override bool Equals(object obj) { return obj is TypeId && ContainsSameTypesAs( (TypeId)obj ); } private bool ContainsSameTypesAs(TypeId other) { if (other.types.Length != types.Length) return false; for (int i = 0; i < types.Length; i++) { if (Array.IndexOf(other.types, types[i]) < 0) return false; } return true; } } } } --- NEW FILE: ProxiedObjectIdentity.cs --- using System; using System.Reflection; namespace NMock2.Monitoring { public class ProxiedObjectIdentity : IInvokable { private static readonly MethodInfo EQUALS_METHOD = typeof(object).GetMethod("Equals",new Type[]{typeof(object)}); private readonly object identityProvider; private readonly IInvokable next; public ProxiedObjectIdentity(object identityProvider, IInvokable next) { this.identityProvider = identityProvider; this.next = next; } public void Invoke(Invocation invocation) { if (invocation.Method.DeclaringType == typeof(object)) { if (invocation.Method.Equals(EQUALS_METHOD)) { invocation.Result = Object.ReferenceEquals(invocation.Receiver, invocation.Parameters[0]); } else { invocation.InvokeOn(identityProvider); } } else { next.Invoke(invocation); } } } } --- NEW FILE: Invoker.cs --- using System; namespace NMock2.Monitoring { public class Invoker : IInvokable { private readonly Type targetType; private readonly object target; private readonly IInvokable next; public Invoker(Type targetType, object target, IInvokable next) { this.targetType = targetType; this.target = target; this.next = next; } public void Invoke(Invocation invocation) { if (targetType == invocation.Method.DeclaringType) { invocation.InvokeOn(target); } else { next.Invoke(invocation); } } } } --- NEW FILE: IInvokable.cs --- namespace NMock2.Monitoring { public interface IInvokable { void Invoke( Invocation invocation ); } } --- NEW FILE: ParameterList.cs --- using System; using System.Collections; using System.Reflection; namespace NMock2.Monitoring { public class ParameterList { private MethodInfo method; private object[] values; private BitArray isValueSet; public ParameterList(MethodInfo method, object[] values) { this.method = method; this.values = values; isValueSet = new BitArray(values.Length); ParameterInfo[] parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { isValueSet[i] = !parameters[i].IsOut; } } public int Count { get { return values.Length; } } public object this[int i] { get { if (IsValueSet(i)) { return values[i]; } else { throw new InvalidOperationException("parameter "+ParameterName(i)+" has not been set"); } } set { if (CanValueBeSet(i)) { values[i] = value; isValueSet[i] = true; } else { throw new InvalidOperationException("cannot set the value of in parameter "+ParameterName(i)); } } } internal object[] AsArray { get { return values; } } internal void MarkAllValuesAsSet() { isValueSet.SetAll(true); } private bool CanValueBeSet(int i) { return !method.GetParameters()[i].IsIn; } public bool IsValueSet(int i) { return isValueSet[i]; } private string ParameterName(int i) { return method.GetParameters()[i].Name; } } } --- NEW FILE: ProxyInvokableAdapter.cs --- using System; using System.Collections; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Proxies; namespace NMock2.Monitoring { public class ProxyInvokableAdapter : RealProxy { private readonly IInvokable invokable; public ProxyInvokableAdapter(Type proxyType, IInvokable invokable ) : base(proxyType) { this.invokable = invokable; } public override IMessage Invoke(IMessage msg) { MethodCall call = new MethodCall(msg); ParameterInfo[] parameters = call.MethodBase.GetParameters(); Invocation invocation = new Invocation(GetTransparentProxy(), (MethodInfo)call.MethodBase, call.Args); invokable.Invoke(invocation); if (invocation.IsThrowing) { //TODO: it is impossible to set output parameters and throw an exception, // even though this is allowed by .NET method call semantics. return new ReturnMessage(invocation.Exception, call); } else { object[] outArgs = CollectOutputArguments(invocation, call, parameters); return new ReturnMessage( invocation.Result, outArgs, outArgs.Length, call.LogicalCallContext, call ); } } private static object[] CollectOutputArguments(Invocation invocation, MethodCall call, ParameterInfo[] parameters) { ArrayList outArgs = new ArrayList(call.ArgCount); for (int i = 0; i < call.ArgCount; i++) { if (!parameters[i].IsIn) outArgs.Add(invocation.Parameters[i]); } return outArgs.ToArray(); } } } --- NEW FILE: Invocation.cs --- using System; using System.IO; using System.Reflection; namespace NMock2.Monitoring { public class Invocation : ISelfDescribing { public readonly object Receiver; public readonly MethodInfo Method; public readonly ParameterList Parameters; private object result = null; private Exception exception = null; private bool isThrowing = false; public Invocation(object receiver, MethodInfo method, object[] parameters) { Receiver = receiver; Method = method; Parameters = new ParameterList(method, parameters); } public object Result { get { return result; } set { CheckReturnType(value); result = value; exception = null; isThrowing = false; } } private void CheckReturnType(object value) { if (Method.ReturnType == typeof(void) && value != null) { throw new ArgumentException("cannot return a value from a void method", "Result"); } if (Method.ReturnType != typeof(void) && Method.ReturnType.IsValueType && value == null) { throw new ArgumentException("cannot return a null value type", "Result"); } if (value != null && !Method.ReturnType.IsInstanceOfType(value)) { throw new ArgumentException("cannot return a value of type " + value.GetType() + " from a method returning " + Method.ReturnType, "Result"); } } public Exception Exception { get { return exception; } set { if (value == null) throw new ArgumentNullException("Exception"); exception = value; result = null; isThrowing = true; } } public bool IsThrowing { get { return isThrowing; } } public void InvokeOn(object otherReceiver) { try { Result = Method.Invoke(otherReceiver, Parameters.AsArray); Parameters.MarkAllValuesAsSet(); } catch(TargetInvocationException e) { Exception = e.InnerException; } } public void DescribeTo(TextWriter writer) { writer.Write(Receiver.ToString()); if (MethodIsIndexerGetter()) { DescribeAsIndexerGetter(writer); } else if (MethodIsIndexerSetter()) { DescribeAsIndexerSetter(writer); } else if (MethodIsEventAdder()) { DescribeAsEventAdder(writer); } else if (MethodIsEventRemover()) { DescribeAsEventRemover(writer); } else if (MethodIsProperty()) { DescribeAsProperty(writer); } else { DescribeNormalMethod(writer); } } private bool MethodIsProperty() { return Method.IsSpecialName && ((Method.Name.StartsWith("get_") && Parameters.Count == 0) || (Method.Name.StartsWith("set_") && Parameters.Count == 1)); } private bool MethodIsIndexerGetter() { return Method.IsSpecialName && Method.Name == "get_Item" && Parameters.Count >= 1; } private bool MethodIsIndexerSetter() { return Method.IsSpecialName && Method.Name == "set_Item" && Parameters.Count >= 2; } private bool MethodIsEventAdder() { return Method.IsSpecialName && Method.Name.StartsWith("add_") && Parameters.Count == 1 && typeof(Delegate).IsAssignableFrom(Method.GetParameters()[0].ParameterType); } private bool MethodIsEventRemover() { return Method.IsSpecialName && Method.Name.StartsWith("remove_") && Parameters.Count == 1 && typeof(Delegate).IsAssignableFrom(Method.GetParameters()[0].ParameterType); } private void DescribeAsProperty(TextWriter writer) { writer.Write("."); writer.Write(Method.Name.Substring(4)); if (Parameters.Count > 0) { writer.Write(" = "); writer.Write(Parameters[0]); } } private void DescribeAsIndexerGetter(TextWriter writer) { writer.Write("["); WriteParameterList(writer, Parameters.Count); writer.Write("]"); } private void DescribeAsIndexerSetter(TextWriter writer) { writer.Write("["); WriteParameterList(writer, Parameters.Count-1); writer.Write("] = "); writer.Write(Parameters[Parameters.Count-1]); } private void DescribeNormalMethod(TextWriter writer) { writer.Write("."); writer.Write(Method.Name); writer.Write("("); WriteParameterList(writer, Parameters.Count); writer.Write(")"); } private void WriteParameterList(TextWriter writer, int count) { for (int i = 0; i < count; i++) { if (i > 0) writer.Write(", "); if (Method.GetParameters()[i].IsOut) { writer.Write("out"); } else { writer.Write(Parameters[i]); } } } private void DescribeAsEventAdder(TextWriter writer) { writer.Write(" += "); writer.Write(Parameters[0]); } private void DescribeAsEventRemover(TextWriter writer) { writer.Write(" -= "); writer.Write(Parameters[0]); } } } |