Skip to content

Commit

Permalink
Long checkin as I worked a lot in-transit without inet :(.
Browse files Browse the repository at this point in the history
Implemented #137 improvement to argument matchers.
Improved Silverlight compatibility by re-enabling many members that were #if'ed out (including new syntax for SetupSet and events).
Started migration of XML documentation comments to external files (work in progress). This should make the source much easier to read :).

git-svn-id: http://moq.googlecode.com/svn/trunk@487 b33fba48-7441-0410-8d5c-f397f7ceaa6c
  • Loading branch information
kzu.net committed Feb 22, 2009
1 parent 66eae8b commit 3b085e7
Show file tree
Hide file tree
Showing 37 changed files with 1,290 additions and 976 deletions.
6 changes: 4 additions & 2 deletions Moq.sln
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ Global
{81BBC911-4916-4E10-A955-752AE47CB2B9}.Release|x86.Build.0 = Release|x86
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Debug|x86.ActiveCfg = Debug|Any CPU
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Debug|x86.ActiveCfg = Debug|x86
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Debug|x86.Build.0 = Debug|x86
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Release|Any CPU.Build.0 = Release|Any CPU
{5136C8E1-E17F-481F-B29A-C7FAB528BD2D}.Release|x86.ActiveCfg = Release|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Debug|x86.ActiveCfg = Debug|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Debug|x86.ActiveCfg = Debug|x86
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Debug|x86.Build.0 = Debug|x86
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Release|Any CPU.Build.0 = Release|Any CPU
{02A2F6A6-D8CF-45EB-A424-BFD8C26034CE}.Release|x86.ActiveCfg = Release|Any CPU
Expand Down
59 changes: 36 additions & 23 deletions Source.Silverlight/Moq.Silverlight.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Moq.Silverlight.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
<DocumentationFile>bin\Debug\Moq.Silverlight.xml</DocumentationFile>
<NoStdLib>true</NoStdLib>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
<DocumentationFile>bin\Release\Moq.Silverlight.xml</DocumentationFile>
<Optimize>true</Optimize>
<NoStdLib>true</NoStdLib>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="Castle.Core-Silverlight, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
Expand Down Expand Up @@ -93,15 +117,6 @@
<Compile Include="..\Source\IHideObjectMembers.cs">
<Link>IHideObjectMembers.cs</Link>
</Compile>
<Compile Include="..\Source\IL\Enums.cs">
<Link>IL\Enums.cs</Link>
</Compile>
<Compile Include="..\Source\IL\ILReader.cs">
<Link>IL\ILReader.cs</Link>
</Compile>
<Compile Include="..\Source\IL\ILReader.Utilities.cs">
<Link>IL\ILReader.Utilities.cs</Link>
</Compile>
<Compile Include="..\Source\IMatcher.cs">
<Link>IMatcher.cs</Link>
</Compile>
Expand Down Expand Up @@ -162,30 +177,27 @@
<Compile Include="..\Source\Language\IThrows.cs">
<Link>Language\IThrows.cs</Link>
</Compile>
<Compile Include="..\Source\Match.cs">
<Link>Match.cs</Link>
</Compile>
<Compile Include="..\Source\MatcherAttribute.cs">
<Link>MatcherAttribute.cs</Link>
</Compile>
<Compile Include="..\Source\MatcherFactory.cs">
<Link>MatcherFactory.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\AnyMatcher.cs">
<Link>Matchers\AnyMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\ConstantMatcher.cs">
<Link>Matchers\ConstantMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\Matcher.cs">
<Link>Matchers\Matcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\MatcherAttributeMatcher.cs">
<Link>Matchers\MatcherAttributeMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\ParamArrayMatcher.cs">
<Link>Matchers\ParamArrayMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\RegexMatcher.cs">
<Link>Matchers\RegexMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\RangeMatcher.cs">
<Link>Matchers\RangeMatcher.cs</Link>
</Compile>
<Compile Include="..\Source\Matchers\LazyEvalMatcher.cs">
<Link>Matchers\LazyEvalMatcher.cs</Link>
</Compile>
Expand Down Expand Up @@ -225,6 +237,9 @@
<Compile Include="..\Source\MockException.cs">
<Link>MockException.cs</Link>
</Compile>
<Compile Include="..\Source\MockExtensions.cs">
<Link>MockExtensions.cs</Link>
</Compile>
<Compile Include="..\Source\MockFactory.cs">
<Link>MockFactory.cs</Link>
</Compile>
Expand Down Expand Up @@ -280,11 +295,9 @@
<None Include="..\Moq.snk">
<Link>Moq.snk</Link>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="..\Source\IL\Readme.txt">
<Link>IL\Readme.txt</Link>
</Content>
<None Include="..\Source\Mock.xdoc">
<Link>Mock.xdoc</Link>
</None>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
52 changes: 51 additions & 1 deletion Source/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Moq
{
Expand Down Expand Up @@ -182,10 +183,21 @@ public static Expression PartialMatcherAwareEval(this Expression expression)
return Evaluator.PartialEval(expression,
e => e.NodeType != ExpressionType.Parameter &&
!(e.NodeType == ExpressionType.Call &&
((MethodCallExpression)e).Method.GetCustomAttribute<AdvancedMatcherAttribute>(true) != null)
((MethodCallExpression)e).Method.GetCustomAttribute<AdvancedMatcherAttribute>(true) != null) &&
!(e.NodeType == ExpressionType.Call && ReturnsMatch((MethodCallExpression)e))
);
}

private static bool ReturnsMatch(MethodCallExpression expression)
{
using (var context = new FluentMockContext())
{
Expression.Lambda<Action>(expression).Compile().Invoke();

return context.LastMatch != null;
}
}

/// <summary>
/// Creates an expression that casts the given expression to the <typeparamref name="T"/>
/// type.
Expand All @@ -204,9 +216,33 @@ public static string ToStringFixed(this Expression expression)
return new ToStringFixVisitor(expression).ExpressionString;
}

internal sealed class RemoveMatcherConvertVisitor : ExpressionVisitor
{
public RemoveMatcherConvertVisitor(Expression expression)
{
this.Expression = this.Visit(expression);
}

protected override Expression VisitUnary(UnaryExpression u)
{
if (u.NodeType == ExpressionType.Convert &&
u.Operand.NodeType == ExpressionType.Call &&
typeof(Match).IsAssignableFrom(((MethodCallExpression)u.Operand).Method.ReturnType))
{
// Remove the cast.
return u.Operand;
}

return base.VisitUnary(u);
}

public Expression Expression { get; private set; }
}

internal sealed class ToStringFixVisitor : ExpressionVisitor
{
private List<MethodCallExpression> calls = new List<MethodCallExpression>();
private Regex convertRegex = new Regex(@"Convert\((.+?)\)");

public ToStringFixVisitor(Expression expression)
{
Expand All @@ -227,6 +263,8 @@ public ToStringFixVisitor(Expression expression)
}
}

fullString = convertRegex.Replace(fullString, m => m.Groups[1].Value);

this.ExpressionString = fullString;
}

Expand Down Expand Up @@ -285,6 +323,18 @@ protected override Expression VisitMethodCall(MethodCallExpression m)

return base.VisitMethodCall(m);
}

//protected override Expression VisitUnary(UnaryExpression u)
//{
// if (u.NodeType == ExpressionType.Convert &&
// u.Operand.NodeType == ExpressionType.Call &&
// typeof(Match).IsAssignableFrom(((MethodCallExpression)u.Operand).Method.ReturnType))
// {
// return u.Operand;
// }

// return base.VisitUnary(u);
//}
}
}
}
10 changes: 5 additions & 5 deletions Source/FluentMockContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ public FluentMockContext()

public void Add(Mock mock, IInvocation invocation)
{
invocations.Add(new MockInvocation(mock, invocation, LastMatcherInvocation));
invocations.Add(new MockInvocation(mock, invocation, LastMatch));
}

public MockInvocation LastInvocation { get { return invocations.LastOrDefault(); } }
public Expression LastMatcherInvocation { get; set; }
public Match LastMatch { get; set; }

public void Dispose()
{
Expand All @@ -53,19 +53,19 @@ internal class MockInvocation : IDisposable
{
DefaultValue defaultValue;

public MockInvocation(Mock mock, IInvocation invocation, Expression matcher)
public MockInvocation(Mock mock, IInvocation invocation, Match matcher)
{
this.Mock = mock;
this.Invocation = invocation;
this.Matcher = matcher;
this.Match = matcher;
defaultValue = mock.DefaultValue;
// Temporarily set mock default value to Mock so that recursion works.
mock.DefaultValue = DefaultValue.Mock;
}

public Mock Mock { get; private set; }
public IInvocation Invocation { get; private set; }
public Expression Matcher { get; private set; }
public Match Match { get; private set; }

public void Dispose()
{
Expand Down
71 changes: 43 additions & 28 deletions Source/It.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ public static class It
/// </code>
/// </example>
/// <typeparam name="TValue">Type of the value.</typeparam>
[AdvancedMatcher(typeof(AnyMatcher))]
public static TValue IsAny<TValue>()
{
SetLastMatcher<TValue>(MethodBase.GetCurrentMethod());
return default(TValue);
return SetLastMatch(new Match<TValue>(value =>
{
return value == null || typeof(TValue).IsAssignableFrom(value.GetType());
}));
}

/// <summary>
Expand All @@ -103,11 +104,9 @@ public static TValue IsAny<TValue>()
/// </code>
/// </example>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "match")]
[AdvancedMatcher(typeof(PredicateMatcher))]
public static TValue Is<TValue>(Expression<Predicate<TValue>> match)
{
SetLastMatcher<TValue>(MethodBase.GetCurrentMethod(), match);
return default(TValue);
return SetLastMatch(new Match<TValue>(value => match.Compile().Invoke(value)));
}

/// <summary>
Expand All @@ -130,12 +129,27 @@ public static TValue Is<TValue>(Expression<Predicate<TValue>> match)
[System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId="to")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "rangeKind")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "from")]
[AdvancedMatcher(typeof(RangeMatcher))]
public static TValue IsInRange<TValue>(TValue from, TValue to, Range rangeKind)
where TValue : IComparable
{
SetLastMatcher<TValue>(MethodBase.GetCurrentMethod(), from, to, rangeKind);
return default(TValue);
return SetLastMatch(new Match<TValue>(value =>
{
if (value == null)
{
return false;
}

if (rangeKind == Range.Exclusive)
{
return value.CompareTo(from) > 0 &&
value.CompareTo(to) < 0;
}
else
{
return value.CompareTo(from) >= 0 &&
value.CompareTo(to) <= 0;
}
}));
}

/// <summary>
Expand All @@ -150,11 +164,16 @@ public static TValue IsInRange<TValue>(TValue from, TValue to, Range rangeKind)
/// </code>
/// </example>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "regex")]
[AdvancedMatcher(typeof(RegexMatcher))]
public static string IsRegex(string regex)
{
SetLastMatcher<string>(MethodBase.GetCurrentMethod(), regex);
return default(string);
// The regex is constructed only once.
var re = new Regex(regex);

return SetLastMatch(new Match<string>(value =>
{
// But evaluated every time :)
return re.IsMatch(value);
}));
}

/// <summary>
Expand All @@ -171,11 +190,16 @@ public static string IsRegex(string regex)
/// </example>
[System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId="regex")]
[System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId="options")]
[AdvancedMatcher(typeof(RegexMatcher))]
public static string IsRegex(string regex, RegexOptions options)
{
SetLastMatcher<string>(MethodBase.GetCurrentMethod(), regex, options);
return default(string);
// The regex is constructed only once.
var re = new Regex(regex, options);

return SetLastMatch(new Match<string>(value =>
{
// But evaluated every time :)
return re.IsMatch(value);
}));
}

/// <devdoc>
Expand All @@ -188,21 +212,12 @@ public static string IsRegex(string regex, RegexOptions options)
/// methodcall we build the expression using it, rather than the null/default
/// value returned from the actual invocation.
/// </devdoc>
private static void SetLastMatcher<TValue>(MethodBase invokedMethod, params object[] args)
private static Match<TValue> SetLastMatch<TValue>(Match<TValue> match)
{
if (FluentMockContext.IsActive)
{
var concreteMethod = invokedMethod.IsGenericMethodDefinition ?
((MethodInfo)invokedMethod).MakeGenericMethod(typeof(TValue)) :
(MethodInfo)invokedMethod;

FluentMockContext.Current.LastMatcherInvocation =
Expression.Call(
concreteMethod,
args.Select(a => a is Expression ? (Expression)a : Expression.Constant(a))
.ToArray()
);
}
FluentMockContext.Current.LastMatch = match;

return match;
}
}
}
Loading

0 comments on commit 3b085e7

Please sign in to comment.