Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interface overload tests #11

Merged
merged 19 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions MockMe.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockMe.Abstractions", "src\MockMe.Abstractions\MockMe.Abstractions.csproj", "{B134418F-FADA-49D5-AC6F-6297F2C22598}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockMe.SampleMocks", "src\MockMe.SampleMocks\MockMe.SampleMocks.csproj", "{1C8CEE11-5494-4762-A4E7-62042CE51E56}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockMe.PostBuild", "src\MockMe.PostBuild\MockMe.PostBuild.csproj", "{511CE2FA-4247-4553-BFE6-AB049DC5EB5C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockMe.Tests.ExampleClasses", "tests\MockMe.Tests.ExampleClasses\MockMe.Tests.ExampleClasses.csproj", "{63E88E6D-9C69-4E6A-BDD4-45F84884220D}"
Expand All @@ -43,7 +41,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wiki", "wiki", "{4723EF4B-9
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockMe.Tests", "tests\MockMe.Tests\MockMe.Tests.csproj", "{25527E94-77F8-4FBC-B8B4-BB29C4BEBD75}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MockMe.Tests.Overloads", "tests\MockMe.Tests.Overloads\MockMe.Tests.Overloads.csproj", "{DF4654A0-0E51-47AE-95AE-0BECF958ED49}"
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "MockMe.Tests.Overloads", "tests\MockMe.Tests.Overloads\MockMe.Tests.Overloads.shproj", "{705ED000-6380-4C9E-BF2E-71BA8C390E28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MockMe.Tests.Overloads.Sealed", "tests\MockMe.Tests.Overloads.Sealed\MockMe.Tests.Overloads.Sealed.csproj", "{1CDE1684-1F3F-AF84-5126-85482E225FD8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MockMe.Tests.Overloads.Interface", "tests\MockMe.Tests.Overloads.Interface\MockMe.Tests.Overloads.Interface.csproj", "{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -63,10 +65,6 @@ Global
{B134418F-FADA-49D5-AC6F-6297F2C22598}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B134418F-FADA-49D5-AC6F-6297F2C22598}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B134418F-FADA-49D5-AC6F-6297F2C22598}.Release|Any CPU.Build.0 = Release|Any CPU
{1C8CEE11-5494-4762-A4E7-62042CE51E56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C8CEE11-5494-4762-A4E7-62042CE51E56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C8CEE11-5494-4762-A4E7-62042CE51E56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C8CEE11-5494-4762-A4E7-62042CE51E56}.Release|Any CPU.Build.0 = Release|Any CPU
{511CE2FA-4247-4553-BFE6-AB049DC5EB5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{511CE2FA-4247-4553-BFE6-AB049DC5EB5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{511CE2FA-4247-4553-BFE6-AB049DC5EB5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -79,10 +77,14 @@ Global
{25527E94-77F8-4FBC-B8B4-BB29C4BEBD75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25527E94-77F8-4FBC-B8B4-BB29C4BEBD75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25527E94-77F8-4FBC-B8B4-BB29C4BEBD75}.Release|Any CPU.Build.0 = Release|Any CPU
{DF4654A0-0E51-47AE-95AE-0BECF958ED49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF4654A0-0E51-47AE-95AE-0BECF958ED49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF4654A0-0E51-47AE-95AE-0BECF958ED49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF4654A0-0E51-47AE-95AE-0BECF958ED49}.Release|Any CPU.Build.0 = Release|Any CPU
{1CDE1684-1F3F-AF84-5126-85482E225FD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1CDE1684-1F3F-AF84-5126-85482E225FD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1CDE1684-1F3F-AF84-5126-85482E225FD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1CDE1684-1F3F-AF84-5126-85482E225FD8}.Release|Any CPU.Build.0 = Release|Any CPU
{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -91,13 +93,19 @@ Global
{19024BA2-842E-4E64-968B-AE05A495BB2D} = {AB32507E-2EED-4403-946B-1D1E7EC0D6F7}
{FFC11A22-7908-4ADA-997E-99201DF96F75} = {AB32507E-2EED-4403-946B-1D1E7EC0D6F7}
{B134418F-FADA-49D5-AC6F-6297F2C22598} = {AB32507E-2EED-4403-946B-1D1E7EC0D6F7}
{1C8CEE11-5494-4762-A4E7-62042CE51E56} = {AB32507E-2EED-4403-946B-1D1E7EC0D6F7}
{511CE2FA-4247-4553-BFE6-AB049DC5EB5C} = {AB32507E-2EED-4403-946B-1D1E7EC0D6F7}
{63E88E6D-9C69-4E6A-BDD4-45F84884220D} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
{25527E94-77F8-4FBC-B8B4-BB29C4BEBD75} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
{DF4654A0-0E51-47AE-95AE-0BECF958ED49} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
{705ED000-6380-4C9E-BF2E-71BA8C390E28} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
{1CDE1684-1F3F-AF84-5126-85482E225FD8} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
{E08ADBB1-7CB8-4BFF-9BAC-485DC7822719} = {134D18E2-ECAC-4571-B7BE-0C10796D5555}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CF07A0CA-1140-44DC-9E7E-F99E65D9EF97}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
tests\MockMe.Tests.Overloads\MockMe.Tests.Overloads.projitems*{1cde1684-1f3f-af84-5126-85482e225fd8}*SharedItemsImports = 5
tests\MockMe.Tests.Overloads\MockMe.Tests.Overloads.projitems*{705ed000-6380-4c9e-bf2e-71ba8c390e28}*SharedItemsImports = 13
tests\MockMe.Tests.Overloads\MockMe.Tests.Overloads.projitems*{e08adbb1-7cb8-4bff-9bac-485dc7822719}*SharedItemsImports = 5
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis;
using MockMe.Generator.Extensions;

namespace MockMe.Generator.MockGenerators.MethodGenerators;

internal class InitPropertyGenerator(IMethodSymbol methodSymbol)
: MethodMockGeneratorBase(methodSymbol)
{
public override StringBuilder AddMethodCallTrackerToStringBuilder(
StringBuilder sb,
Dictionary<string, PropertyMetadata> callTrackerMeta
)
{
var methodName = this.methodSymbol.GetPropertyName();

if (!callTrackerMeta.TryGetValue(methodName, out var propMeta))
{
propMeta = new() { Name = methodName, ReturnType = this.returnType };
callTrackerMeta.Add(methodName, propMeta);
}
propMeta.HasInit = true;

return sb;
}

public override StringBuilder AddMethodSetupToStringBuilder(
StringBuilder sb,
Dictionary<string, SetupPropertyMetadata> setupMeta
) => sb;

public override StringBuilder AddMethodToAsserterClass(
StringBuilder sb,
Dictionary<string, AssertPropertyMetadata> assertMeta
) => sb;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ method.MethodKind is MethodKind.PropertySet
&& (propertySymbol.SetMethod?.IsInitOnly ?? false)
)
{
// we skip 'init' properties because they can't be set at runtime
return null;
return new InitPropertyGenerator(method);
}
if (propertySymbol.IsIndexer)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,73 +59,62 @@ Dictionary<string, PropertyMetadata> callTrackerMeta
this.methodSymbol.GetParametersWithOriginalTypesAndModifiers();
string paramString = this.methodSymbol.GetParametersWithoutTypesAndModifiers();

if (this.methodSymbol.MethodKind == MethodKind.PropertyGet)
{
var methodName = this.methodSymbol.GetPropertyName();
var methodName = this.methodSymbol.GetPropertyName();

string? indexerType = null;
if (
this.methodSymbol.AssociatedSymbol is IPropertySymbol propertySymbol
&& propertySymbol.IsIndexer
)
{
indexerType = propertySymbol.Type.ToFullTypeString();
}
//string? indexerType = null;
//if (
// this.methodSymbol.AssociatedSymbol is IPropertySymbol propertySymbol
// && propertySymbol.IsIndexer
//)
//{
// indexerType = propertySymbol.Type.ToFullTypeString();
//}


if (this.methodSymbol.MethodKind == MethodKind.PropertyGet)
{
if (!callTrackerMeta.TryGetValue(methodName, out var propMeta))
{
propMeta = new()
{
Name = methodName,
ReturnType = this.returnType,
IndexerType = indexerType,
//IndexerType = indexerType,
};
callTrackerMeta.Add(methodName, propMeta);
}

if (string.IsNullOrEmpty(indexerType))
{
propMeta.GetterLogic =
@$"
//if (string.IsNullOrEmpty(indexerType))
//{
propMeta.GetterLogic =
@$"
this.{this.GetCallStoreName()}++;
return {this.voidPrefix}MockCallTracker.Call{this.voidPrefix}MemberMock(this.setup.{this.GetBagStoreName()});";
propMeta.GetterField = $"private int {this.GetCallStoreName()};";
}
else
{
propMeta.GetterLogic =
@$"
return {this.voidPrefix}MockCallTracker.Call{this.voidPrefix}MemberMock(this.setup.{this.GetBagStoreName()}, this.{this.GetCallStoreName()} ??= new(), index);";
propMeta.GetterField = $"private List<{indexerType}>? {this.GetCallStoreName()};";
}
propMeta.GetterField = $"private int {this.GetCallStoreName()};";
//}
//else
//{
// propMeta.GetterLogic =
// @$"
//return {this.voidPrefix}MockCallTracker.Call{this.voidPrefix}MemberMock(this.setup.{this.GetBagStoreName()}, this.{this.GetCallStoreName()} ??= new(), index);";
// propMeta.GetterField = $"private List<{indexerType}>? {this.GetCallStoreName()};";
//}
}
else if (this.methodSymbol.MethodKind == MethodKind.PropertySet)
{
var methodName = this.methodSymbol.GetPropertyName();

string? indexerType = null;
if (
this.methodSymbol.AssociatedSymbol is IPropertySymbol propertySymbol
&& propertySymbol.IsIndexer
)
{
indexerType = propertySymbol.Type.ToFullTypeString();
}

if (!callTrackerMeta.TryGetValue(methodName, out var propMeta))
{
propMeta = new()
{
Name = methodName,
ReturnType = this.methodSymbol.Parameters.First().Type.ToFullReturnTypeString(),
IndexerType = indexerType,
//IndexerType = indexerType,
};
callTrackerMeta.Add(methodName, propMeta);
}

propMeta.SetterLogic =
@$"
{this.voidPrefix}MockCallTracker.Call{this.voidPrefix}MemberMock(this.setup.{this.GetBagStoreName()}, this.{this.GetCallStoreName()} ??= new(){(string.IsNullOrEmpty(indexerType) ? "" : ", index")}, value);";
{this.voidPrefix}MockCallTracker.Call{this.voidPrefix}MemberMock(this.setup.{this.GetBagStoreName()}, this.{this.GetCallStoreName()} ??= new(), value);";

propMeta.SetterField =
$"private List<{this.methodSymbol.GetMethodArgumentsAsCollection()}>? {this.GetCallStoreName()};";
Expand Down
11 changes: 11 additions & 0 deletions src/MockMe.Generator/PropertyMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class PropertyMetadata
public string? SetterField { get; set; }
public virtual string? GetterLogic { get; set; }
public virtual string? SetterLogic { get; set; }
public bool HasInit { get; set; }

public void AddPropToSb(StringBuilder sb)
{
Expand Down Expand Up @@ -58,6 +59,16 @@ public void AddPropToSb(StringBuilder sb)
}}"
);
}
else if (this.HasInit)
{
sb.Append(
$@"
init
{{
throw new global::System.NotImplementedException();
}}"
);
}

sb.Append(
@"
Expand Down
81 changes: 69 additions & 12 deletions src/MockMe/Asserters/MemberAsserter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,62 @@ public MemberAsserter(int numTimesCalled)
this.numTimesCalled = numTimesCalled;
}

public void WasCalled() => this.WasCalled(NumTimes.AtLeast, 1);
public void WasCalled() => this.WasCalled(NumTimes.AtLeast(1));

public void WasNotCalled() => this.WasCalled(NumTimes.Exactly, 0);
public void WasNotCalled() => this.WasCalled(NumTimes.Exactly(0));

public void WasCalled(int numTimesCalled) => this.WasCalled(NumTimes.Exactly, numTimesCalled);
public void WasCalled(int numTimesCalled) => this.WasCalled(NumTimes.Exactly(numTimesCalled));

public void WasCalled(NumTimes intComparison, int numTimesCalled)
public void WasCalled(NumTimes numTimesExpected) =>
numTimesExpected.AssertSatisfied(this.numTimesCalled);
}

public abstract class NumTimes
{
public static NumTimes AtLeast(int numTimes) =>
new SingleNumComparisonNumTimes(NumComparison.AtLeast, numTimes);

public static NumTimes AtMost(int numTimes) =>
new SingleNumComparisonNumTimes(NumComparison.AtMost, numTimes);

public static NumTimes Exactly(int numTimes) =>
new SingleNumComparisonNumTimes(NumComparison.Exactly, numTimes);

public static NumTimes Between(int lowestValueExpected, int highestValueExpected) =>
new BetweenNumTimes(lowestValueExpected, highestValueExpected);

internal abstract void AssertSatisfied(int numTimesActuallyCalled);
}

internal class SingleNumComparisonNumTimes : NumTimes
{
private readonly NumComparison numComparison;
private readonly int expectedNumTimes;

internal SingleNumComparisonNumTimes(NumComparison numComparison, int expectedNumTimes)
{
this.numComparison = numComparison;
this.expectedNumTimes = expectedNumTimes;
}

internal override void AssertSatisfied(int numTimesActuallyCalled)
{
switch (intComparison)
switch (this.numComparison)
{
case NumTimes.Exactly:
if (this.numTimesCalled != numTimesCalled)
case NumComparison.Exactly:
if (numTimesActuallyCalled != this.expectedNumTimes)
{
throw new AssertionFailureException();
}
break;
case NumTimes.AtLeast:
if (this.numTimesCalled < numTimesCalled)
case NumComparison.AtLeast:
if (numTimesActuallyCalled < this.expectedNumTimes)
{
throw new AssertionFailureException();
}
break;
case NumTimes.AtMost:
if (this.numTimesCalled > numTimesCalled)
case NumComparison.AtMost:
if (numTimesActuallyCalled > this.expectedNumTimes)
{
throw new AssertionFailureException();
}
Expand All @@ -45,7 +77,32 @@ public void WasCalled(NumTimes intComparison, int numTimesCalled)
}
}

public enum NumTimes
internal class BetweenNumTimes : NumTimes
{
private readonly int lowestPossible;
private readonly int highestPossible;

internal BetweenNumTimes(int lowestPossible, int highestPossible)
{
this.lowestPossible = lowestPossible;
this.highestPossible = highestPossible;
}

internal override void AssertSatisfied(int numTimesActuallyCalled)
{
if (
this.lowestPossible <= numTimesActuallyCalled
&& numTimesActuallyCalled <= this.highestPossible
)
{
return;
}

throw new AssertionFailureException();
}
}

internal enum NumComparison
{
Exactly,
AtLeast,
Expand Down
Loading
Loading