Update of /cvsroot/dotnetmock/dotnetmock/DotNetMock/TestFramework In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22568/DotNetMock/TestFramework Added Files: Tag: RFE_1098585 AbstractStubMaker.cs IStubMaker.cs MbUnitStubMaker.cs NUnitStubMaker.cs StubClassBuilder.cs Log Message: Initial implementation of dynamically generating implementations of ITestFramework on startup. So far created impls for NUnit and MbUnit. Needs some cleanup. --- NEW FILE: NUnitStubMaker.cs --- #region License // Copyright (c) 2004 Choy Rim. All rights reserved. #endregion #region Imports using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; #endregion namespace DotNetMock.TestFramework { /// <summary> /// <see cref="IStubMaker"/> for NUnit. /// </summary> public class NUnitStubMaker : AbstractStubMaker { /// <summary> /// Create NUnit stub maker. /// </summary> /// <param name="providerAssembly">nunit.framework assembly</param> public NUnitStubMaker( Assembly providerAssembly ) : base(providerAssembly, "NUnit.Framework.Assertion") { } /// <summary> /// Implement stub methods that forward to the /// NUnit.Framework.Assertion class. /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> for the method /// we are stubbing</param> /// <param name="mi"><see cref="MethodInfo"/> for the method /// we are stubbing</param> public override void ImplementStubMethod(ILGenerator ilg, MethodInfo mi) { IList parameterTypes = GetParameterTypes(mi); for (int i = 0; i<parameterTypes.Count; ++i) { EmitLdarg(ilg, i+1); } EmitProviderCall(ilg, mi.Name, parameterTypes); } } } --- NEW FILE: StubClassBuilder.cs --- #region License // Copyright (c) 2004 Choy Rim. All rights reserved. #endregion #region Imports using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; #endregion namespace DotNetMock.TestFramework { /// <summary> /// Creates stub classes that implement an interface. /// </summary> /// <author>Choy Rim</author> public class StubClassMaker { AssemblyBuilder _assemblyBuilder = null; ModuleBuilder _moduleBuilder = null; /// <summary> /// Create stub class maker. /// </summary> public StubClassMaker() { _assemblyBuilder = newAssemblyBuilder(AssemblyBuilderAccess.Run); _moduleBuilder = _assemblyBuilder.DefineDynamicModule("ProviderStub"); } /// <summary> /// /// </summary> /// <param name="supportedInterface">interface which the stub /// class will support</param> /// <param name="stubMaker">object which will generate /// method bodies</param> /// <returns>new stub class</returns> public Type MakeStubClass(Type supportedInterface, IStubMaker stubMaker) { if ( ! supportedInterface.IsInterface ) { throw new ArgumentException( "Can only stub interfaces.", "supportedInterface" ); } TypeBuilder typeBuilder = _moduleBuilder.DefineType( "ProviderStub", TypeAttributes.Public, null, new Type[] { supportedInterface } ); defineAndImplementStubMethods(typeBuilder, supportedInterface, stubMaker); Type stubClass = typeBuilder.CreateType(); return stubClass; } /// <summary> /// Define stub methods through <see cref="IStubMaker"/> /// </summary> /// <param name="typeBuilder">where to add methods</param> /// <param name="supportedInterface">interface which the stub /// class will support</param> /// <param name="stubMaker">object which will generate /// method bodies</param> private static void defineAndImplementStubMethods( TypeBuilder typeBuilder, Type supportedInterface, IStubMaker stubMaker ) { ArrayList methods = new ArrayList(); getMethodsForInterface(supportedInterface, methods); foreach (MethodInfo mi in methods) { MethodBuilder methodBuilder = typeBuilder.DefineMethod( mi.Name, MethodAttributes.Public | MethodAttributes.Virtual, mi.ReturnType, getParameterTypes(mi) ); ILGenerator ilg = methodBuilder.GetILGenerator(); stubMaker.ImplementStubMethod(ilg, mi); ilg.Emit(OpCodes.Ret); } } /// <summary> /// Returns the array of parameters types given a /// <see cref="MethodInfo"/> /// </summary> /// <param name="mi">method we want the parameter types of</param> /// <returns>array of parameter types in method signature</returns> private static Type[] getParameterTypes(MethodInfo mi) { ArrayList types = new ArrayList(); foreach (ParameterInfo pi in mi.GetParameters()) { types.Add(pi.ParameterType); } return (Type[]) types.ToArray(typeof(Type)); } private static void getMethodsForInterface(Type type, ArrayList list) { list.AddRange(type.GetMethods()); foreach (Type interfaceType in type.GetInterfaces()) { getMethodsForInterface(interfaceType, list); } } private static AssemblyBuilder newAssemblyBuilder(AssemblyBuilderAccess access) { AppDomain appDomain = AppDomain.CurrentDomain; AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "ProviderStubAssembly"; return appDomain.DefineDynamicAssembly( assemblyName, access ); } } } --- NEW FILE: AbstractStubMaker.cs --- #region License // Copyright (c) 2004 Choy Rim. All rights reserved. #endregion #region Imports using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; #endregion namespace DotNetMock.TestFramework { /// <summary> /// Abstract base class for implementations of <see cref="IStubMaker"/>. /// </summary> public abstract class AbstractStubMaker : IStubMaker { private Type _providerClass; /// <summary> /// Initialize stub maker. /// </summary> /// <param name="providerClass">class that we will /// forward all methods to</param> public AbstractStubMaker( Type providerClass ) { if ( providerClass==null ) { throw new ArgumentNullException( "providerClass", "Cannot specify null provider class" ); } _providerClass = providerClass; } /// <summary> /// Initialize a stub maker. /// </summary> /// <param name="providerAssembly">Assembly that provides /// assertion class</param> /// <param name="_providerClassName">name of assertion /// class</param> public AbstractStubMaker( Assembly providerAssembly, string _providerClassName ) : this(providerAssembly.GetType(_providerClassName, true)) { } #region IStubMaker Members /// <summary> /// Implement one of the methods of the interface we are required /// to stub out. /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> of the method /// on the dynamically generated type</param> /// <param name="mi"><see cref="MethodInfo"/> of the method /// on the interface we want to implement</param> public abstract void ImplementStubMethod(ILGenerator ilg, MethodInfo mi); #endregion /// <summary> /// Get list of parameter types on a <see cref="MethodInfo"/>. /// </summary> /// <param name="mi"><see cref="MethodInfo"/> of method we're /// interested in</param> /// <returns><see cref="IList"/> of parameter types.</returns> protected static IList GetParameterTypes( MethodInfo mi ) { ArrayList types = new ArrayList(); foreach (ParameterInfo pi in mi.GetParameters()) { types.Add(pi.ParameterType); } return types; } /// <summary> /// Emit IL Call to method. /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> of the method /// on the dynamically generated type</param> /// <param name="methodName">name of method to call</param> /// <param name="parameterTypeList"><see cref="IList"/> /// of parameters in method we want to call</param> protected void EmitProviderCall( ILGenerator ilg, string methodName, IList parameterTypeList ) { Type[] parameterTypes = new Type[parameterTypeList.Count]; for (int i = 0; i<parameterTypeList.Count; ++i) { parameterTypes[i] = (Type) parameterTypeList[i]; } MethodInfo mi = _providerClass.GetMethod(methodName, parameterTypes); if ( mi==null ) { throw new ArgumentException(String.Format( "Cannot find method named {0}", methodName )); } ilg.EmitCall(OpCodes.Call, mi, null); } /// <summary> /// Emit IL ldarg /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> of the method /// on the dynamically generated type</param> /// <param name="argIndex">index of argument to put on /// the stack</param> protected static void EmitLdarg( ILGenerator ilg, int argIndex ) { if ( argIndex>0xff ) { ilg.Emit(OpCodes.Ldarg, (short) argIndex); return; } switch (argIndex) { case 0: ilg.Emit(OpCodes.Ldarg_0); break; case 1: ilg.Emit(OpCodes.Ldarg_1); break; case 2: ilg.Emit(OpCodes.Ldarg_2); break; case 3: ilg.Emit(OpCodes.Ldarg_3); break; default: ilg.Emit(OpCodes.Ldarg_S, (sbyte) argIndex); break; } } } } --- NEW FILE: IStubMaker.cs --- #region License // Copyright (c) 2004 Choy Rim. All rights reserved. #endregion #region Imports using System; using System.Reflection; using System.Reflection.Emit; #endregion namespace DotNetMock.TestFramework { /// <summary> /// Interface for making method stubs for test framework providers. /// </summary> public interface IStubMaker { /// <summary> /// Implement one of the methods of the interface we are required /// to stub out. /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> of the method /// on the dynamically generated type</param> /// <param name="mi"><see cref="MethodInfo"/> of the method /// on the interface we want to implement</param> void ImplementStubMethod(ILGenerator ilg, MethodInfo mi); } } --- NEW FILE: MbUnitStubMaker.cs --- #region License // Copyright (c) 2004 Choy Rim. All rights reserved. #endregion #region Imports using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; #endregion namespace DotNetMock.TestFramework { /// <summary> /// <see cref="IStubMaker"/> for NUnit. /// </summary> public class MbUnitStubMaker : AbstractStubMaker { /// <summary> /// Create NUnit stub maker. /// </summary> /// <param name="providerAssembly">MbUnit.Core assembly</param> public MbUnitStubMaker( Assembly providerAssembly ) : base(providerAssembly, "MbUnit.Core.Framework.Assert") { } /// <summary> /// Implement stub methods that forward to the /// NUnit.Framework.Assertion class. /// </summary> /// <param name="ilg"><see cref="ILGenerator"/> for the method /// we are stubbing</param> /// <param name="mi"><see cref="MethodInfo"/> for the method /// we are stubbing</param> public override void ImplementStubMethod(ILGenerator ilg, MethodInfo mi) { IList parameterTypes = GetParameterTypes(mi); // take message parameter and put it at end of parameter list bool hasMessageParameter = parameterTypes.Count>0 && typeof(string).Equals(parameterTypes[0]) ; if ( hasMessageParameter ) { parameterTypes.RemoveAt(0); parameterTypes.Add(typeof(string)); for (int i = 1; i<parameterTypes.Count; ++i) { EmitLdarg(ilg, i+1); } EmitLdarg(ilg, 1); parameterTypes.Add(typeof(object[])); ilg.Emit(OpCodes.Ldnull); } else { for (int i = 0; i<parameterTypes.Count; ++i) { EmitLdarg(ilg, i+1); } } string methodName = MapMethod(mi); EmitProviderCall(ilg, methodName, parameterTypes); } private string MapMethod(MethodInfo mi) { switch ( mi.Name ) { case "Assert": return "IsTrue"; case "AssertNotNull": return "IsNotNull"; case "AssertEquals": return "AreEqual"; case "Fail": return "Fail"; case "AssertNull": return "IsNull"; default: throw new ArgumentException(String.Format( "Cannot map method name {0}", mi.Name )); } } } } |