Skip to content

Commit

Permalink
Merged branch for dynamic types.
Browse files Browse the repository at this point in the history
Added ILMerge so that Castle libraries are merged into MoQ assembly (no need for external references)
Signed assembly.
Updated help file.

git-svn-id: http://moq.googlecode.com/svn/trunk@39 b33fba48-7441-0410-8d5c-f397f7ceaa6c
  • Loading branch information
kzu.net committed Jan 3, 2008
1 parent 1229526 commit ecff466
Show file tree
Hide file tree
Showing 22 changed files with 4,192 additions and 172 deletions.
Binary file added Lib/Castle.Core.dll
Binary file not shown.
3,049 changes: 3,049 additions & 0 deletions Lib/Castle.Core.xml

Large diffs are not rendered by default.

Binary file added Lib/Castle.DynamicProxy2.dll
Binary file not shown.
635 changes: 635 additions & 0 deletions Lib/Castle.DynamicProxy2.xml

Large diffs are not rendered by default.

33 changes: 25 additions & 8 deletions Moq.shfb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,30 @@
</assemblies>
<namespaceSummaries>
<namespaceSummaryItem name="" isDocumented="False" />
<namespaceSummaryItem name="Moq" isDocumented="True">Root namespace of Moq (pronounced "Mock-you"), the only mocking library for .NET developed from scratch to take full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features (i.e. lambda expressions) that make it the most productive, simple and refactoring-friendly mocking library available.
<namespaceSummaryItem name="Castle.Core" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Configuration" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Interceptor" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Internal" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Logging" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Logging.Factories" isDocumented="False" />
<namespaceSummaryItem name="Castle.Core.Resource" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy.Generators" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy.Generators.Emitters" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy.Generators.Emitters.CodeBuilders" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy.Generators.Emitters.SimpleAST" isDocumented="False" />
<namespaceSummaryItem name="Castle.DynamicProxy.Serialization" isDocumented="False" />
<namespaceSummaryItem name="Moq" isDocumented="True">Root namespace of MoQ (pronounced "Mock-you"), the only mocking library for .NET developed from scratch to take full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features (i.e. lambda expressions) that make it the most productive, simple and refactoring-friendly mocking library available.
&lt;p&gt;
See the &lt;a href="http://code.google.com/p/moq/wiki/QuickStart"&gt;online quickstarts&lt;/a&gt; for more examples than those available in this code documentation.
&lt;/p&gt;
The Mock&amp;lt;TInterface&amp;gt; class is the core of the library, so it's a good place to start.</namespaceSummaryItem>
The Mock&amp;lt;TTarget&amp;gt; class is the core of the library, so it's a good place to start.</namespaceSummaryItem>
<namespaceSummaryItem name="Moq.Properties" isDocumented="False" />
</namespaceSummaries>
<componentConfigurations>
<component id="Code Block Component" enabled="True" configuration="&lt;component id=&quot;Code Block Component&quot; type=&quot;SandcastleBuilder.Components.CodeBlockComponent&quot; assembly=&quot;{@SHFBFolder}SandcastleBuilder.Components.dll&quot;&gt;&lt;!-- Base path for relative filenames in source attributes&#xD;&#xA; (optional) --&gt;&lt;basePath value=&quot;{@ProjectFolder}&quot; /&gt;&lt;!-- Connect to language filter (optional). If omitted,&#xD;&#xA; language filtering is enabled by default. --&gt;&lt;languageFilter value=&quot;true&quot; /&gt;&lt;!-- Code colorizer options (required).&#xD;&#xA; Attributes:&#xD;&#xA; Language syntax configuration file (required)&#xD;&#xA; XSLT style file (required)&#xD;&#xA; &quot;Copy&quot; image file URL (required)&#xD;&#xA; Default language (optional)&#xD;&#xA; Enable line numbering (optional)&#xD;&#xA; Enable outlining (optional)&#xD;&#xA; Tab size override (optional, 0 = Use syntax file setting)&#xD;&#xA; Use language name as default title (optional) --&gt;&lt;colorizer syntaxFile=&quot;{@SHFBFolder}Colorizer\highlight.xml&quot; styleFile=&quot;{@SHFBFolder}Colorizer\highlight.xsl&quot; copyImageUrl=&quot;../icons/CopyCode.gif&quot; language=&quot;cs&quot; numberLines=&quot;false&quot; outlining=&quot;false&quot; tabSize=&quot;0&quot; defaultTitle=&quot;true&quot; /&gt;&lt;/component&gt;" />
<component id="Post-transform Component" enabled="True" configuration="&lt;component id=&quot;Post-transform Component&quot; type=&quot;SandcastleBuilder.Components.PostTransformComponent&quot; assembly=&quot;{@SHFBFolder}SandcastleBuilder.Components.dll&quot;&gt;&lt;!-- Code colorizer files (required).&#xD;&#xA; Attributes:&#xD;&#xA; Stylesheet file (required)&#xD;&#xA; Script file (required)&#xD;&#xA; &quot;Copy&quot; image file (required) --&gt;&lt;colorizer stylesheet=&quot;{@SHFBFolder}Colorizer\highlight.css&quot; scriptFile=&quot;{@SHFBFolder}Colorizer\highlight.js&quot; copyImage=&quot;{@SHFBFolder}Colorizer\CopyCode.gif&quot; /&gt;&lt;!-- Base output path for the files (required). This should match&#xD;&#xA; the parent folder of the output path of the HTML files (see&#xD;&#xA; SaveComponent). --&gt;&lt;outputPath value=&quot;Output\&quot; /&gt;&lt;!-- Logo image file (optional). Filename is required. The height,&#xD;&#xA; width, altText, placement, and alignment attributes are&#xD;&#xA; optional. --&gt;&lt;logoFile filename=&quot;&quot; height=&quot;0&quot; width=&quot;0&quot; altText=&quot;&quot; placement=&quot;left&quot; alignment=&quot;left&quot; /&gt;&lt;/component&gt;" />
</componentConfigurations>
<ProjectSummary>Moq (pronounced "Mock-you") is the only mocking library for .NET developed from scratch to take full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features (i.e. lambda expressions) that make it the most productive, simple and refactoring-friendly mocking library available.</ProjectSummary>
<MissingTags>Summary, Parameter, AutoDocumentCtors, Namespace</MissingTags>
<VisibleItems>InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected</VisibleItems>
Expand All @@ -20,22 +37,22 @@ The Mock&amp;lt;TInterface&amp;gt; class is the core of the library, so it's a g
<SandcastlePath path="" />
<WorkingPath path="" />
<CleanIntermediates>True</CleanIntermediates>
<KeepLogFile>True</KeepLogFile>
<KeepLogFile>False</KeepLogFile>
<HelpFileFormat>Help1xAndWebsite</HelpFileFormat>
<PurgeDuplicateTopics>True</PurgeDuplicateTopics>
<CppCommentsFixup>False</CppCommentsFixup>
<FrameworkVersion>3.5</FrameworkVersion>
<BinaryTOC>True</BinaryTOC>
<IncludeFavorites>False</IncludeFavorites>
<Preliminary>False</Preliminary>
<Preliminary>True</Preliminary>
<RootNamespaceContainer>False</RootNamespaceContainer>
<RootNamespaceTitle />
<HelpTitle>Moq</HelpTitle>
<HtmlHelpName>Moq</HtmlHelpName>
<HelpTitle>MoQ</HelpTitle>
<HtmlHelpName>MoQ</HtmlHelpName>
<Language>en-US</Language>
<CopyrightHref />
<CopyrightText />
<FeedbackEMailAddress />
<FeedbackEMailAddress>[email protected]</FeedbackEMailAddress>
<HeaderText />
<FooterText />
<ProjectLinkType>Local</ProjectLinkType>
Expand All @@ -44,7 +61,7 @@ The Mock&amp;lt;TInterface&amp;gt; class is the core of the library, so it's a g
<PresentationStyle>vs2005</PresentationStyle>
<NamingMethod>HashedMemberName</NamingMethod>
<SyntaxFilters>CSharp</SyntaxFilters>
<ShowFeedbackControl>False</ShowFeedbackControl>
<ShowFeedbackControl>True</ShowFeedbackControl>
<ContentPlacement>AboveNamespaces</ContentPlacement>
<ContentSiteMap path="" />
<TopicFileTransform path="" />
Expand Down
Binary file added Moq.snk
Binary file not shown.
5 changes: 3 additions & 2 deletions Source/IProxyCall.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Runtime.Remoting.Messaging;
using Castle.Core.Interceptor;

namespace Moq
{
internal interface IProxyCall
{
bool Matches(IMethodCallMessage call);
IMethodReturnMessage Execute(IMethodCallMessage call);
bool Matches(IInvocation call);
void Execute(IInvocation call);
}
}
61 changes: 61 additions & 0 deletions Source/Interceptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Castle.Core.Interceptor;

namespace Moq
{
class Interceptor : MarshalByRefObject, IInterceptor
{
List<IProxyCall> calls = new List<IProxyCall>();
List<MethodInfo> objectMethods = new List<MethodInfo>(new MethodInfo[] {
Reflector<object>.GetMethod(x => x.GetType()),
Reflector<object>.GetMethod(x => x.Equals(null)),
Reflector<object>.GetMethod(x => x.GetHashCode()),
Reflector<object>.GetMethod(x => x.ToString())});

public void AddCall(IProxyCall call)
{
calls.Add(call);
}

public void Intercept(IInvocation invocation)
{
var call = calls.Find(x => x.Matches(invocation));
if (call != null)
{
call.Execute(invocation);
}
else if (invocation.Method.DeclaringType == typeof(object))
{
invocation.Proceed();
}
else if (invocation.TargetType.IsClass &&
!invocation.Method.IsAbstract)
{
// For mocked classes, if the target method was not abstract,
// invoke directly.
invocation.Proceed();
}
else if (invocation.Method != null && invocation.Method.ReturnType != null &&
invocation.Method.ReturnType != typeof(void))
{
// Return default value.
if (invocation.Method.ReturnType.IsValueType)
invocation.ReturnValue = 0;
else
invocation.ReturnValue = null;
//List<string> values = new List<string>(invocation.Arguments.Length);
//// Build arguments
//invocation.Arguments.ForEach(
// x => values.Add(x == null ? "null" : (x is string ? "\"" + (string)x + "\"" : x.ToString())));

//throw new InvalidOperationException(String.Format(
// Properties.Resources.UndeterminedReturnValue,
// invocation.Method.DeclaringType.Name,
// invocation.Method.Name,
// String.Join(", ", values.ToArray())));
}
}
}
}
20 changes: 7 additions & 13 deletions Source/MethodCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using Castle.Core.Interceptor;

namespace Moq
{
Expand Down Expand Up @@ -31,14 +32,14 @@ public ICall Callback(Action callback)
return this;
}

public bool Matches(IMethodCallMessage call)
public bool Matches(IInvocation call)
{
if (call.MethodBase == method &&
argumentMatchers.Length == call.ArgCount)
if (call.Method == method &&
argumentMatchers.Length == call.Arguments.Length)
{
for (int i = 0; i < argumentMatchers.Length; i++)
{
if (!argumentMatchers[i].Matches(call.Args[i]))
if (!argumentMatchers[i].Matches(call.Arguments[i]))
return false;
}

Expand All @@ -48,20 +49,13 @@ public bool Matches(IMethodCallMessage call)
return false;
}

public IMethodReturnMessage Execute(IMethodCallMessage call)
public virtual void Execute(IInvocation call)
{
if (callback != null)
callback();

if (exception != null)
return new ReturnMessage(exception, call);

return GetReturnMessage(call);
}

protected virtual IMethodReturnMessage GetReturnMessage(IMethodCallMessage call)
{
return new ReturnMessage(null, null, 0, null, call);
throw exception;
}
}
}
9 changes: 6 additions & 3 deletions Source/MethodCallReturn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using Castle.Core.Interceptor;

namespace Moq
{
Expand Down Expand Up @@ -31,12 +32,14 @@ public void Returns(TResult value)
return this;
}

protected override IMethodReturnMessage GetReturnMessage(IMethodCallMessage call)
public override void Execute(IInvocation call)
{
base.Execute(call);

if (valueFunc != null)
return new ReturnMessage(valueFunc(), null, 0, null, call);
call.ReturnValue = valueFunc();
else
return new ReturnMessage(value, null, 0, null, call);
call.ReturnValue = value;
}
}
}
63 changes: 52 additions & 11 deletions Source/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Castle.DynamicProxy;
using Castle.Core.Interceptor;

namespace Moq
{
/// <summary>
/// Provides a mock implementation of <typeparamref name="TInterface"/>.
/// Provides a mock implementation of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="TInterface">Type of the interface to mock.</typeparam>
/// <typeparam name="T">Type of the interface to mock.</typeparam>
/// <remarks>
/// The following example shows setting expectations with specific values
/// for method invocations:
Expand Down Expand Up @@ -47,21 +49,60 @@ namespace Moq
/// Assert.IsFalse(order.IsFilled);
/// </code>
/// </remarks>
public class Mock<TInterface> where TInterface : class
public class Mock<T> where T : class
{
MockProxy<TInterface> proxy = new MockProxy<TInterface>();
static readonly ProxyGenerator generator = new ProxyGenerator();
Interceptor interceptor = new Interceptor();
T instance;
RemotingProxy remotingProxy;

/// <summary>
/// Initializes an instance of the mock.
/// </summary>
public Mock()
{
if (typeof(MarshalByRefObject).IsAssignableFrom(typeof(T)))
{
remotingProxy = new RemotingProxy(typeof(T), x => interceptor.Intercept(x));
instance = (T)remotingProxy.GetTransparentProxy();
}
else if (typeof(T).IsInterface)
{
instance = generator.CreateInterfaceProxyWithoutTarget<T>(interceptor);
}
else
{
try
{
instance = generator.CreateClassProxy<T>(interceptor);
}
catch (TypeLoadException tle)
{
throw new ArgumentException(Properties.Resources.InvalidMockClass, tle);
}
}
}

/// <summary>
/// Exposes the mocked object instance.
/// </summary>
public TInterface Object
public T Object
{
get
{
return proxy.TransparentProxy;
return instance;
}
}

/// <summary>
/// Called by the <see cref="RemotingProxy"/> when a <see cref="MarshalByRefObject"/>
/// is the target type.
/// </summary>
internal void Intercept(IInvocation invocation)
{
interceptor.Intercept(invocation);
}

/// <summary>
/// Sets an expectation on the mocked interface for a call to
/// to a void-returning method.
Expand All @@ -73,15 +114,15 @@ public TInterface Object
/// mock.Expect(x =&gt; x.Execute("ping"));
/// </code>
/// </example>
public ICall Expect(Expression<Action<TInterface>> expression)
public ICall Expect(Expression<Action<T>> expression)
{
Guard.ArgumentNotNull(expression, "expression");

MethodCallExpression methodCall = expression.Body as MethodCallExpression;

var call = new MethodCallReturn<object>(
methodCall.Method, methodCall.Arguments.ToArray());
proxy.AddCall(call);
interceptor.AddCall(call);
return call;
}

Expand All @@ -95,7 +136,7 @@ public ICall Expect(Expression<Action<TInterface>> expression)
/// mock.Expect(x =&gt; x.HasInventory("Talisker", 50)).Returns(true);
/// </code>
/// </example>
public ICall<TResult> Expect<TResult>(Expression<Func<TInterface, TResult>> expression)
public ICall<TResult> Expect<TResult>(Expression<Func<T, TResult>> expression)
{
Guard.ArgumentNotNull(expression, "expression");

Expand All @@ -108,7 +149,7 @@ public ICall<TResult> Expect<TResult>(Expression<Func<TInterface, TResult>> expr
{
var call = new MethodCallReturn<TResult>(
methodCall.Method, methodCall.Arguments.ToArray());
proxy.AddCall(call);
interceptor.AddCall(call);
result = call;
}
else if (propField != null)
Expand All @@ -130,7 +171,7 @@ public ICall<TResult> Expect<TResult>(Expression<Func<TInterface, TResult>> expr
}

var call = new MethodCallReturn<TResult>(prop.GetGetMethod());
proxy.AddCall(call);
interceptor.AddCall(call);
result = call;
}
else if (field != null)
Expand Down
Loading

0 comments on commit ecff466

Please sign in to comment.