diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs
index 9a865e49..53e4708a 100644
--- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs
+++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs
@@ -17,861 +17,273 @@ public static string MockClass(string name, Class @class, bool hasOverloadResolu
constructors?.Any(m => m.Parameters.Count > 0) == true;
string escapedClassName = @class.ClassFullName.EscapeForXmlDoc();
bool hasEvents = @class.AllEvents().Any(x => !x.IsStatic);
- bool hasStaticEvents = @class.IsInterface &&
- @class.AllEvents().Any(@event => @event.IsStatic);
- bool hasStaticMembers = @class.IsInterface &&
- (@class.AllMethods().Any(method => method.IsStatic) ||
- @class.AllProperties().Any(property => property.IsStatic));
+ bool hasStaticEvents = @class.IsInterface && @class.AllEvents().Any(@event => @event.IsStatic);
+ bool hasStaticMembers = @class.IsInterface && (@class.AllMethods().Any(method => method.IsStatic) || @class.AllProperties().Any(property => property.IsStatic));
bool hasProtectedEvents = !@class.IsInterface && @class.AllEvents().Any(@event => @event.IsProtected);
- bool hasProtectedMembers = !@class.IsInterface &&
- (@class.AllMethods().Any(method => method.IsProtected)
- || @class.AllProperties().Any(property => property.IsProtected));
- string setupType = hasProtectedMembers
- ? $"IMockSetupInitializationFor{name}"
- : $"global::Mockolate.Mock.IMockSetupFor{name}";
+ bool hasProtectedMembers = !@class.IsInterface && (@class.AllMethods().Any(method => method.IsProtected) || @class.AllProperties().Any(property => property.IsProtected));
+ string setupType = hasProtectedMembers ? $"IMockSetupInitializationFor{name}" : $"global::Mockolate.Mock.IMockSetupFor{name}";
string mockRegistryName = @class.GetUniqueName("MockRegistry", "MockolateMockRegistry");
MemberIdTable memberIds = ComputeMemberIds(@class);
string memberIdPrefix = $"global::Mockolate.Mock.{name}.";
+
StringBuilder sb = InitializeBuilder();
-
sb.Append("#nullable enable annotations").AppendLine();
sb.Append("namespace Mockolate;").AppendLine();
sb.AppendLine();
- #region MockForXXXExtensions
+ #region Mock
- sb.AppendXmlSummary($"Mock extensions for .", "");
+ sb.Append("internal static partial class Mock").AppendLine();
+ sb.Append("{").AppendLine();
+
+ #region MockForXXX
+
+ sb.AppendXmlSummary($"A mock implementation for .", "\t");
+ sb.Append("\t[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]").AppendLine();
#if !DEBUG
- sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
+ sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
#endif
- sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("internal static partial class MockExtensionsFor").Append(name).AppendLine();
- sb.Append("{").AppendLine();
-
- #region Type extensions
-
- sb.Append("\t/// ").AppendLine();
- sb.Append("\textension(").Append(@class.ClassFullName).Append(" mock)").AppendLine();
- sb.Append("\t{").AppendLine();
+ sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
+ sb.Append("\tinternal class ").Append(name).Append(" :").AppendLine();
+ sb.Append("\t\t").Append(@class.ClassFullName).Append(", IMockFor").Append(name).Append(", IMockSetupFor").Append(name);
+ if (hasProtectedMembers)
+ {
+ sb.Append(", IMockProtectedSetupFor").Append(name);
+ sb.Append(", global::Mockolate.MockExtensionsFor").Append(name).Append(".IMockSetupInitializationFor").Append(name);
+ }
- #region Mock Property
+ if (hasStaticMembers)
+ {
+ sb.Append(", IMockStaticSetupFor").Append(name);
+ }
- string mockPropertyName = CreateUniquePropertyName(@class, "Mock");
+ if (hasEvents)
+ {
+ sb.Append(", IMockRaiseOn").Append(name);
+ }
- List mockPropertyRemarks = new()
+ if (hasProtectedEvents)
{
- $"The accessor is the bridge between the strongly-typed instance of returned by CreateMock(...) and the underlying mock registry where setups and recorded interactions live.",
- "Through it you can:",
- "",
- " - Setup - configure how members respond when invoked (Returns, Throws, Do, InitializeWith, ...).
",
- " - Verify - assert how often (and in which order) members were invoked.
",
- };
- if (hasEvents)
+ sb.Append(", IMockProtectedRaiseOn").Append(name);
+ }
+
+ if (hasStaticEvents)
{
- mockPropertyRemarks.Add(
- " - Raise - trigger events declared on the mocked type.
");
+ sb.Append(", IMockStaticRaiseOn").Append(name);
}
+ sb.Append(", IMockVerifyFor").Append(name);
+
if (hasProtectedMembers || hasProtectedEvents)
{
- mockPropertyRemarks.Add(
- " - SetupProtected / VerifyProtected / RaiseProtected - target members on class mocks.
");
+ sb.Append(", IMockProtectedVerifyFor").Append(name);
}
if (hasStaticMembers || hasStaticEvents)
{
- mockPropertyRemarks.Add(
- " - SetupStatic / VerifyStatic / RaiseStatic - target members on interface mocks.
");
+ sb.Append(", IMockStaticVerifyFor").Append(name);
}
- mockPropertyRemarks.Add(
- " - InScenario / TransitionTo - scope setups and behavior to a named scenario and switch between scenarios.
");
- mockPropertyRemarks.Add(
- " - Monitor, ClearAllInteractions, VerifyThatAllInteractionsAreVerified, VerifyThatAllSetupsAreUsed - manage recorded interactions.
");
- mockPropertyRemarks.Add(
- " - VerifySetup - verify how often a specific setup matched.
");
- mockPropertyRemarks.Add("
");
+ sb.Append(',').AppendLine();
- sb.AppendXmlSummary(
- $"Gets the mock accessor for - the entry point for configuring setups, verifying interactions and raising events.");
- sb.AppendXmlRemarks(mockPropertyRemarks.ToArray());
- sb.AppendXmlException("global::Mockolate.Exceptions.MockException",
- $"The instance is not a Mockolate-generated mock of .");
- sb.Append("\t\tpublic global::Mockolate.Mock.IMockFor").Append(name).Append(' ').Append(mockPropertyName)
- .AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tget").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tif (mock is global::Mockolate.Mock.IMockFor").Append(name).Append(" mockInterface)")
- .AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\treturn mockInterface;").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
+ sb.Append("\t\tglobal::Mockolate.IMock").AppendLine();
+ sb.Append("\t{").AppendLine();
- #endregion Mock Property
+ memberIds.Emit(sb, "\t\t");
+ sb.AppendLine();
- #region CreateMock
+ AppendCreateFastInteractions(sb, "\t\t");
+ sb.AppendLine();
- string createMockReturns =
- $"A new mock instance of .";
+ bool hasMockRegistryProvider = constructors?.Count > 0 || (@class.IsInterface && hasStaticMembers);
+ AppendCreateRegistryFromBehavior(sb, "\t\t", hasMockRegistryProvider);
+ sb.AppendLine();
- List createMockRemarks = new()
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.").Append(mockRegistryName).Append(';').AppendLine();
+ if (constructors?.Count > 0)
{
- $"The returned instance is a strongly-typed mock generated at compile time - it implements and exposes the Mockolate surface through .Mock:",
- "",
- " - .Mock.Setup configures how members respond (Returns, Throws, Do, InitializeWith, sequences, callbacks).
",
- " - .Mock.Verify asserts how often and in which order members were invoked.
",
- };
- if (hasEvents)
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tget => field ?? MockRegistryProvider.Value;").AppendLine();
+ sb.Append("\t\t\tset;").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tinternal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();").AppendLine();
+ }
+ else
{
- createMockRemarks.Add(
- " - .Mock.Raise triggers events declared on the mocked type.
");
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }").AppendLine();
+ if (hasStaticMembers)
+ {
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tinternal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();").AppendLine();
+ }
}
- createMockRemarks.Add("
");
- createMockRemarks.Add(
- "With the default behavior, un-configured members return default values (empty collections / strings, completed tasks, otherwise) and base-class implementations are invoked for class mocks. Use one of the overloads that accepts a to customize this (for example to make un-configured calls throw or to skip the base class).");
- createMockRemarks.Add(
- "Overloads allow you to additionally pass constructor parameters (for class mocks), apply an initial setup callback before the instance is returned, or combine both.");
-
- sb.AppendXmlSummary(
- $"Creates a new mock of with the default .");
- sb.AppendXmlRemarks(createMockRemarks.ToArray());
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock()").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, null, (object?[]?)null);").AppendLine();
sb.AppendLine();
+
+ AppendCachedFieldDeclarations(sb, "\t\t", @class, memberIds, memberIdPrefix, mockRegistryName);
+
+ sb.AppendLine();
+
+ ImplementMockForInterface(sb, mockRegistryName, name, hasEvents, hasProtectedMembers, hasProtectedEvents, hasStaticMembers, hasStaticEvents);
- sb.AppendXmlSummary(
- $"Creates a new mock of with the default , applying the given immediately.");
- sb.AppendXmlRemarks(
- "The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- sb.AppendXmlParam("setup",
- "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::System.Action<")
- .Append(setupType).Append("> setup)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, setup, (object?[]?)null);").AppendLine();
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append("\t\tstring global::Mockolate.IMock.ToString()").AppendLine();
+ sb.Append("\t\t\t=> \"").Append(@class.DisplayString).Append(" mock\";").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- $"Creates a new mock of with the given .");
- sb.AppendXmlParam("mockBehavior",
- "Controls how the mock responds when members are invoked without a matching setup; see .");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(mockBehavior, null, (object?[]?)null);").AppendLine();
+ if (@class.IsInterface)
+ {
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append("\t\tpublic ").Append(name).Append("(global::Mockolate.MockRegistry mockRegistry)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tthis.").Append(mockRegistryName).Append(" = mockRegistry;").AppendLine();
+ if (hasStaticMembers)
+ {
+ sb.Append("\t\t\tMockRegistryProvider.Value = mockRegistry;").AppendLine();
+ }
+
+ sb.Append("\t\t}").AppendLine();
+ sb.AppendLine();
+
+ AppendMockSubject_BehaviorConstructor(sb, name);
+ }
+ else if (constructors is not null)
+ {
+ foreach (Method constructor in constructors)
+ {
+ AppendMockSubject_BaseClassConstructor(sb, mockRegistryName, name, constructor, @class.HasRequiredMembers);
+ AppendMockSubject_BehaviorBaseClassConstructor(sb, name, constructor, @class.HasRequiredMembers);
+ }
+ }
+
+ AppendMockSubject_ImplementClass(sb, @class, mockRegistryName, null, memberIds, memberIdPrefix);
+
sb.AppendLine();
- sb.AppendXmlSummary(
- $"Creates a new mock of with the given , applying the given immediately.");
- sb.AppendXmlRemarks(
- "The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- sb.AppendXmlParam("mockBehavior",
- "Controls how the mock responds when members are invoked without a matching setup; see .");
- sb.AppendXmlParam("setup",
- "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action<").Append(setupType)
- .Append("> setup)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(mockBehavior, setup, (object?[]?)null);").AppendLine();
+ #region Mock.Setup
+
+ sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
sb.AppendLine();
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
- if (hasParameterizedConstructor)
+ if (hasProtectedMembers)
{
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given to invoke the base-class constructor.");
- sb.AppendXmlParam("constructorParameters",
- "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(object?[] constructorParameters)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, null, constructorParameters);").AppendLine();
sb.AppendLine();
+ sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
+ sb.AppendLine();
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
+ }
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given and .");
- sb.AppendXmlParam("mockBehavior",
- "Controls how the mock responds when members are invoked without a matching setup; see .");
- sb.AppendXmlParam("constructorParameters",
- "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters)")
- .AppendLine();
- sb.Append("\t\t\t=> CreateMock(mockBehavior, null, constructorParameters);").AppendLine();
+ if (hasStaticMembers)
+ {
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockStaticSetupFor").Append(name).AppendLine();
sb.AppendLine();
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockStaticSetupFor{name}", MemberType.Static, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockStaticSetupFor").Append(name).AppendLine();
+ }
- sb.AppendXmlSummary(
- $"Creates a new mock of applying the given immediately, using the given .");
- sb.AppendXmlRemarks(
- "The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- sb.AppendXmlParam("setup",
- "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
- sb.AppendXmlParam("constructorParameters",
- "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(global::System.Action<").Append(setupType)
- .Append("> setup, object?[] constructorParameters)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, setup, constructorParameters);").AppendLine();
+ #endregion Mock.Setup
+
+ #region Mock.Raise
+
+ if (hasEvents)
+ {
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockRaiseOn").Append(name).AppendLine();
sb.AppendLine();
+ ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockRaiseOn{name}", MemberType.Public);
+ sb.Append("\t\t#endregion IMockRaiseOn").Append(name).AppendLine();
- AppendTypedCreateMockOverloads(sb, @class, constructors!.Value, setupType, escapedClassName, createMockReturns);
}
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given , applying the given immediately, using the given .");
- sb.AppendXmlRemarks(
- "The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- sb.AppendXmlParam("mockBehavior",
- "Controls how the mock responds when members are invoked without a matching setup, or for MockBehavior.Default.");
- sb.AppendXmlParam("setup",
- "Callback that receives the mock's setup surface and registers initial setups before the mock is returned, or to skip.");
- sb.AppendXmlParam("constructorParameters",
- "Values forwarded to a matching base-class constructor, or to use the parameterless constructor.");
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\t").Append(hasParameterizedConstructor ? "public" : "private").Append(" static ")
- .Append(@class.ClassFullName)
- .Append(" CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action<")
- .Append(setupType).Append(">? setup, object?[]? constructorParameters)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tif (mockBehavior is not null)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append(
- "\t\t\t\tIMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior;")
- .AppendLine();
- sb.Append("\t\t\t\tif (mockBehaviorAccess.TryGet?>(out var additionalSetup))").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tif (setup is null)").AppendLine();
- sb.Append("\t\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t\tsetup = additionalSetup;").AppendLine();
- sb.Append("\t\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\t\telse").AppendLine();
- sb.Append("\t\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t\tvar originalSetup = setup;").AppendLine();
- sb.Append("\t\t\t\t\t\tsetup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); };").AppendLine();
- sb.Append("\t\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- if (!@class.IsInterface && !hasStaticMembers)
+ if (hasProtectedEvents)
{
- sb.Append("\t\t\t\tif (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters<")
- .Append(@class.ClassFullName).Append(">(out object?[]? parameters))").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tconstructorParameters = parameters;").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockProtectedRaiseOn").Append(name).AppendLine();
+ sb.AppendLine();
+ ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockProtectedRaiseOn{name}", MemberType.Protected);
+ sb.Append("\t\t#endregion IMockProtectedRaiseOn").Append(name).AppendLine();
}
- sb.Append("\t\t\t}").AppendLine();
+ if (hasStaticEvents)
+ {
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockStaticRaiseOn").Append(name).AppendLine();
+ sb.AppendLine();
+ ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockStaticRaiseOn{name}", MemberType.Static);
+ sb.Append("\t\t#endregion IMockStaticRaiseOn").Append(name).AppendLine();
+ }
+
+ #endregion Mock.Raise
+
+ #region Mock.Verify
+
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockVerifyFor").Append(name).AppendLine();
sb.AppendLine();
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockVerifyFor").Append(name).AppendLine();
- if (@class is { ClassFullName: "global::System.Net.Http.HttpClient", })
+ if (hasProtectedMembers || hasProtectedEvents)
{
- sb.Append(
- "\t\t\tglobal::Mockolate.MockBehavior effectiveBehavior = mockBehavior ?? global::Mockolate.MockBehavior.Default;")
- .AppendLine();
- sb.Append(
- "\t\t\tglobal::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(effectiveBehavior, global::Mockolate.Mock.")
- .Append(name).Append(".CreateFastInteractions(effectiveBehavior), constructorParameters);")
- .AppendLine();
- sb.Append("\t\t\tif (constructorParameters is null)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tconstructorParameters = [new global::Mockolate.Mock.HttpMessageHandler(mockRegistry),];")
- .AppendLine();
- sb.Append("\t\t\t\tmockRegistry = new global::Mockolate.MockRegistry(mockRegistry, constructorParameters);")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append(
- "\t\t\telse if (constructorParameters.Length > 0 && constructorParameters[0] is global::Mockolate.Mock.HttpMessageHandler && constructorParameters[0] is global::Mockolate.IMock httpMessageHandlerMock)")
- .AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append(
- "\t\t\t\tif (mockBehavior is not null && httpMessageHandlerMock.MockRegistry.Behavior != mockBehavior)")
- .AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append(
- "\t\t\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Mock of type 'System.Net.Http.HttpClient' cannot be created with behavior '{mockBehavior}' because it shares its mock registry with a mock of type 'System.Net.Http.HttpMessageHandler' that has behavior '{httpMessageHandlerMock.MockRegistry.Behavior}'.\");")
- .AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append(
- "\t\t\t\tmockRegistry = new global::Mockolate.MockRegistry(httpMessageHandlerMock.MockRegistry, constructorParameters);")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockProtectedVerifyFor").Append(name).AppendLine();
+ sb.AppendLine();
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockProtectedVerifyFor{name}", MemberType.Protected, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockProtectedVerifyFor").Append(name).AppendLine();
}
- else
+
+ if (hasStaticMembers || hasStaticEvents)
{
- sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
- sb.Append(
- "\t\t\tglobal::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.")
- .Append(name).Append(".CreateFastInteractions(mockBehavior), constructorParameters);")
- .AppendLine();
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockStaticVerifyFor").Append(name).AppendLine();
+ sb.AppendLine();
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockStaticVerifyFor{name}", MemberType.Static, memberIds, memberIdPrefix);
+ sb.Append("\t\t#endregion IMockStaticVerifyFor").Append(name).AppendLine();
}
- sb.Append("\t\t\treturn CreateMockInstance(mockRegistry, constructorParameters, setup);").AppendLine();
- sb.Append("\t\t}").AppendLine();
-
- sb.AppendLine();
- sb.Append("\t\tprivate static ").Append(@class.ClassFullName)
- .Append(
- " CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action<")
- .Append(setupType).Append(">? setup)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- if (!@class.IsInterface && constructors?.Count > 0)
- {
- sb.Append("\t\t\tif (constructorParameters is null || constructorParameters.Length == 0)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- if (constructors.Value.Any(m => m.Parameters.Count == 0))
- {
- sb.Append("\t\t\t\tglobal::Mockolate.Mock.").Append(name)
- .Append(".MockRegistryProvider.Value = mockRegistry;").AppendLine();
- sb.Append("\t\t\t\tglobal::Mockolate.MockExtensionsFor").Append(name)
- .Append(".MockSetup? setupTarget = null;").AppendLine();
- sb.Append("\t\t\t\tif (setup is not null)").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tsetupTarget ??= new(mockRegistry);").AppendLine();
- sb.Append("\t\t\t\t\tsetup.Invoke(setupTarget);").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\treturn new global::Mockolate.Mock.").Append(name).Append("(mockRegistry);")
- .AppendLine();
- }
- else
- {
- sb.Append(
- "\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"No parameterless constructor found for '")
- .Append(@class.DisplayString).Append("'. Please provide constructor parameters.\");").AppendLine();
- }
-
- sb.Append("\t\t\t}").AppendLine();
- int constructorIndex = 0;
- bool useTryCast = false;
- bool useTryCastWithDefaultValue = false;
- foreach (EquatableArray constructorParameters in constructors.Value
- .Select(constructor => constructor.Parameters))
- {
- constructorIndex++;
- int requiredParameters = constructorParameters.Count(c => !c.HasExplicitDefaultValue);
- if (requiredParameters < constructorParameters.Count)
- {
- sb.Append("\t\t\telse if (constructorParameters.Length >= ")
- .Append(requiredParameters).Append(" && constructorParameters.Length <= ")
- .Append(constructorParameters.Count);
- }
- else
- {
- sb.Append("\t\t\telse if (constructorParameters.Length == ")
- .Append(constructorParameters.Count);
- }
-
- int constructorParameterIndex = 0;
- foreach (MethodParameter parameter in constructorParameters)
- {
- useTryCast = useTryCast || !parameter.HasExplicitDefaultValue;
- useTryCastWithDefaultValue = useTryCastWithDefaultValue || parameter.HasExplicitDefaultValue;
- sb.AppendLine().Append("\t\t\t && ")
- .Append(parameter.HasExplicitDefaultValue ? "TryCastWithDefaultValue" : "TryCast")
- .Append("(constructorParameters, ")
- .Append(constructorParameterIndex++)
- .Append(parameter.HasExplicitDefaultValue ? $", {parameter.ExplicitDefaultValue}" : "")
- .Append(", mockRegistry.Behavior, out ").Append(parameter.Type.Fullname).Append(" c")
- .Append(constructorIndex)
- .Append('p')
- .Append(constructorParameterIndex).Append(")");
- }
-
- sb.Append(")").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tglobal::Mockolate.Mock.").Append(name)
- .Append(".MockRegistryProvider.Value = mockRegistry;").AppendLine();
- sb.Append("\t\t\t\tglobal::Mockolate.MockExtensionsFor").Append(name)
- .Append(".MockSetup? setupTarget = null;").AppendLine();
- sb.Append("\t\t\t\tif (setup is not null)").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tsetupTarget ??= new(mockRegistry);").AppendLine();
- sb.Append("\t\t\t\t\tsetup.Invoke(setupTarget);").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\treturn new global::Mockolate.Mock.").Append(name)
- .Append("(mockRegistry");
- for (int i = 1; i <= constructorParameters.Count; i++)
- {
- sb.Append(", ").Append('c').Append(constructorIndex).Append('p').Append(i);
- }
-
- sb.Append(");").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- }
-
- sb.Append("\t\t\telse").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append(
- "\t\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Could not find any constructor for '")
- .Append(@class.DisplayString)
- .Append(
- "' that matches the {constructorParameters.Length} given parameters ({string.Join(\", \", constructorParameters)}).\");")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- if (useTryCast)
- {
- sb.Append("""
- static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
- {
- var value = values[index];
- if (value is TValue typedValue)
- {
- result = typedValue;
- return true;
- }
-
- result = default!;
- return value is null;
- }
- """).AppendLine();
- }
-
- if (useTryCastWithDefaultValue)
- {
- sb.Append("""
- static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
- {
- if (values.Length > index && values[index] is TValue typedValue)
- {
- result = typedValue;
- return true;
- }
-
- result = defaultValue;
- return true;
- }
- """).AppendLine();
- }
- }
- else
- {
- sb.Append("\t\t\tvar value = new global::Mockolate.Mock.").Append(name).Append("(mockRegistry);")
- .AppendLine();
- sb.Append("\t\t\tif (setup is not null)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tsetup.Invoke(value);").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t\treturn value;").AppendLine();
- }
-
- sb.Append("\t\t}").AppendLine();
-
- #endregion CreateMock
-
- sb.AppendXmlSummary("Creates a mock that wraps the given .");
- sb.AppendXmlRemarks(
- "Public members on the mock forward to unless overridden by a setup; protected members still go through the base-class implementation. All forwarded interactions are recorded and can be verified the same as on a plain mock.");
- sb.AppendXmlParam("instance",
- "The real object whose calls should be forwarded. Must not be .");
- sb.AppendXmlReturns(
- $"A new mock of that delegates to .");
- sb.Append("\t\tpublic ").Append(@class.ClassFullName).Append(" Wrapping(").Append(@class.ClassFullName)
- .Append(" instance)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tif (mock is global::Mockolate.IMock mockInterface)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append(
- "\t\t\t\tglobal::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance);")
- .AppendLine();
- sb.Append(
- "\t\t\t\twrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.")
- .Append(name).Append(".CreateFastInteractions(wrappingRegistry.Behavior));")
- .AppendLine();
- sb.Append(
- "\t\t\t\treturn CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null);")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");")
- .AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
-
- sb.Append("\t}").AppendLine();
-
- #endregion Type extensions
-
- sb.AppendLine();
-
- #region MockBehavior extensions
-
- sb.Append("\t/// ").AppendLine();
- sb.Append("\textension(global::Mockolate.MockBehavior behavior)").AppendLine();
- sb.Append("\t{").AppendLine();
-
- sb.AppendXmlSummary(
- "Initializes mocks of type with the given .");
- sb.AppendXmlRemarks(
- "The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones.");
- sb.AppendXmlTypeParam("T",
- $"The mockable type derived from that this setup should apply to.");
- sb.AppendXmlParam("setup", "Callback invoked when a new mock of is created.");
- sb.AppendXmlReturns(
- "A new with the registered initializer. The original instance is unchanged.");
- sb.Append("\t\tpublic global::Mockolate.MockBehavior Initialize(global::System.Action<").Append(setupType)
- .Append("> setup)").AppendLine();
- sb.Append("\t\t\twhere T : ").Append(@class.ClassFullName).AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tvar behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior;").AppendLine();
- sb.Append("\t\t\treturn behaviorAccess.Set(setup);").AppendLine();
- sb.Append("\t\t}").AppendLine();
-
- sb.Append("\t}").AppendLine();
-
- #endregion MockBehavior extensions
-
- #region Setup helpers
-
- if (!@class.IsInterface && constructors?.Count > 0)
- {
- string protectedName = @class.GetUniqueName("Protected", "SetupProtected");
- if (hasProtectedMembers)
- {
- sb.Append("\tinternal interface IMockSetupInitializationFor").Append(name)
- .Append(" : global::Mockolate.Mock.IMockSetupFor").Append(name).AppendLine();
- sb.Append("\t{").AppendLine();
- sb.AppendXmlSummary("Setup protected members");
- sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name).Append(' ')
- .Append(protectedName).Append(" { get; }").AppendLine();
- sb.Append("\t}").AppendLine();
- }
-
- sb.AppendLine();
-#if !DEBUG
- sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
-#endif
- sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append(
- "\tinternal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupFor")
- .Append(name);
- if (hasProtectedMembers)
- {
- sb.Append(", global::Mockolate.Mock.IMockProtectedSetupFor").Append(name)
- .Append(", IMockSetupInitializationFor").Append(name);
- }
-
- sb.AppendLine();
- sb.Append("\t{").AppendLine();
- if (hasProtectedMembers)
- {
- sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name)
- .Append(" IMockSetupInitializationFor").Append(name).Append('.').Append(protectedName)
- .Append(" => this;").AppendLine();
- }
-
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName)
- .Append(" { get; } = mockRegistry;").AppendLine();
- sb.AppendLine();
- sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public,
- memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
- if (hasProtectedMembers)
- {
- sb.AppendLine();
- sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}",
- MemberType.Protected, memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
- }
-
- sb.Append("\t}").AppendLine();
- }
-
- #endregion Setup helpers
-
- AppendNestedCovariantParameterAdapter(sb);
- sb.Append("}").AppendLine();
-
- #endregion MockForXXXExtensions
-
- sb.AppendLine();
-
- #region MockForXXX
-
- sb.Append("internal static partial class Mock").AppendLine();
- sb.Append("{").AppendLine();
- sb.AppendXmlSummary($"A mock implementation for .", "\t");
- sb.Append(
- "\t[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]")
- .AppendLine();
-#if !DEBUG
- sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
-#endif
- sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("\tinternal class ").Append(name).Append(" :").AppendLine();
- sb.Append("\t\t").Append(@class.ClassFullName);
- sb.Append(", IMockFor").Append(name).Append(", IMockSetupFor").Append(name);
- if (hasProtectedMembers)
- {
- sb.Append(", IMockProtectedSetupFor").Append(name);
- sb.Append(", global::Mockolate.MockExtensionsFor").Append(name).Append(".IMockSetupInitializationFor")
- .Append(name);
- }
-
- if (hasStaticMembers)
- {
- sb.Append(", IMockStaticSetupFor").Append(name);
- }
-
- if (hasEvents)
- {
- sb.Append(", IMockRaiseOn").Append(name);
- }
-
- if (hasProtectedEvents)
- {
- sb.Append(", IMockProtectedRaiseOn").Append(name);
- }
-
- if (hasStaticEvents)
- {
- sb.Append(", IMockStaticRaiseOn").Append(name);
- }
-
- sb.Append(", IMockVerifyFor").Append(name);
-
- if (hasProtectedMembers || hasProtectedEvents)
- {
- sb.Append(", IMockProtectedVerifyFor").Append(name);
- }
-
- if (hasStaticMembers || hasStaticEvents)
- {
- sb.Append(", IMockStaticVerifyFor").Append(name);
- }
-
- sb.Append(',').AppendLine();
-
- sb.Append("\t\tglobal::Mockolate.IMock").AppendLine();
- sb.Append("\t{").AppendLine();
-
- memberIds.Emit(sb, "\t\t");
- sb.AppendLine();
-
- AppendCreateFastInteractions(sb, "\t\t");
- sb.AppendLine();
-
- bool hasMockRegistryProvider = constructors?.Count > 0 || (@class.IsInterface && hasStaticMembers);
- AppendCreateRegistryFromBehavior(sb, "\t\t", hasMockRegistryProvider);
- sb.AppendLine();
-
- sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tglobal::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.")
- .Append(mockRegistryName).Append(';').AppendLine();
- if (constructors?.Count > 0)
- {
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tget => field ?? MockRegistryProvider.Value;").AppendLine();
- sb.Append("\t\t\tset;").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append(
- "\t\tinternal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();")
- .AppendLine();
- }
- else
- {
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }")
- .AppendLine();
- if (hasStaticMembers)
- {
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append(
- "\t\tinternal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();")
- .AppendLine();
- }
- }
-
- sb.AppendLine();
- AppendCachedFieldDeclarations(sb, "\t\t", @class, memberIds, memberIdPrefix, mockRegistryName);
- sb.AppendLine();
- ImplementMockForInterface(sb, mockRegistryName, name, hasEvents, hasProtectedMembers, hasProtectedEvents,
- hasStaticMembers, hasStaticEvents);
-
- sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tstring global::Mockolate.IMock.ToString()").AppendLine();
- sb.Append("\t\t\t=> \"").Append(@class.DisplayString).Append(" mock\";").AppendLine();
- sb.AppendLine();
-
- if (@class.IsInterface)
- {
- sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tpublic ").Append(name).Append("(global::Mockolate.MockRegistry mockRegistry)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tthis.").Append(mockRegistryName).Append(" = mockRegistry;").AppendLine();
- if (hasStaticMembers)
- {
- sb.Append("\t\t\tMockRegistryProvider.Value = mockRegistry;").AppendLine();
- }
-
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
- AppendMockSubject_BehaviorConstructor(sb, name);
- }
- else if (constructors is not null)
- {
- foreach (Method constructor in constructors)
- {
- AppendMockSubject_BaseClassConstructor(sb, mockRegistryName, name, constructor,
- @class.HasRequiredMembers);
- AppendMockSubject_BehaviorBaseClassConstructor(sb, name, constructor,
- @class.HasRequiredMembers);
- }
- }
-
- AppendMockSubject_ImplementClass(sb, @class, mockRegistryName, null, memberIds, memberIdPrefix);
- sb.AppendLine();
-
- #region IMockSetupForXXX
-
- sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public,
- memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
-
- if (hasProtectedMembers)
- {
- sb.AppendLine();
- sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}",
- MemberType.Protected, memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
- }
-
- if (hasStaticMembers)
- {
- sb.AppendLine();
- sb.Append("\t\t#region IMockStaticSetupFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockStaticSetupFor{name}", MemberType.Static,
- memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockStaticSetupFor").Append(name).AppendLine();
- }
-
- #endregion IMockSetupForXXX
-
- if (hasEvents)
- {
- #region IMockRaiseOnXXX
-
- sb.AppendLine();
- sb.Append("\t\t#region IMockRaiseOn").Append(name).AppendLine();
- sb.AppendLine();
- ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockRaiseOn{name}", MemberType.Public);
- sb.Append("\t\t#endregion IMockRaiseOn").Append(name).AppendLine();
-
- #endregion IMockRaiseOnXXX
- }
-
- if (hasProtectedEvents)
- {
- #region IMockProtectedRaiseOnXXX
-
- sb.AppendLine();
- sb.Append("\t\t#region IMockProtectedRaiseOn").Append(name).AppendLine();
- sb.AppendLine();
- ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockProtectedRaiseOn{name}", MemberType.Protected);
- sb.Append("\t\t#endregion IMockProtectedRaiseOn").Append(name).AppendLine();
+ #endregion Mock.Verify
- #endregion IMockProtectedRaiseOnXXX
- }
-
- if (hasStaticEvents)
- {
- #region IMockStaticRaiseOnXXX
-
- sb.AppendLine();
- sb.Append("\t\t#region IMockStaticRaiseOn").Append(name).AppendLine();
- sb.AppendLine();
- ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockStaticRaiseOn{name}", MemberType.Static);
- sb.Append("\t\t#endregion IMockStaticRaiseOn").Append(name).AppendLine();
-
- #endregion IMockStaticRaiseOnXXX
- }
-
- #region IMockVerifyForXXX
-
- sb.AppendLine();
- sb.Append("\t\t#region IMockVerifyFor").Append(name).AppendLine();
+ sb.AppendLine("\t}");
sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public,
- memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockVerifyFor").Append(name).AppendLine();
-
- if (hasProtectedMembers || hasProtectedEvents)
- {
- sb.AppendLine();
- sb.Append("\t\t#region IMockProtectedVerifyFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockProtectedVerifyFor{name}",
- MemberType.Protected, memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockProtectedVerifyFor").Append(name).AppendLine();
- }
- if (hasStaticMembers || hasStaticEvents)
- {
- sb.AppendLine();
- sb.Append("\t\t#region IMockStaticVerifyFor").Append(name).AppendLine();
- sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockStaticVerifyFor{name}", MemberType.Static,
- memberIds, memberIdPrefix);
- sb.Append("\t\t#endregion IMockStaticVerifyFor").Append(name).AppendLine();
- }
-
- #endregion IMockVerifyForXXX
-
- sb.AppendLine("\t}");
+ #endregion MockForXXX
- sb.AppendLine();
+ #region VerifyMonitor
+
#if !DEBUG
sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
#endif
sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("\tprivate sealed class VerifyMonitor").Append(name)
- .Append("(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyFor")
- .Append(name).AppendLine();
+ sb.Append("\tprivate sealed class VerifyMonitor").Append(name).Append("(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName)
- .Append(" { get; } = mockRegistry;").AppendLine();
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; } = mockRegistry;").AppendLine();
sb.AppendLine();
sb.Append("\t\t#region IMockVerifyFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public,
- memberIds, memberIdPrefix);
+
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockVerifyFor").Append(name).AppendLine();
sb.Append("\t}").AppendLine();
-
sb.AppendLine();
+
+ #endregion VerifyMonitor
+
+ #region MockInScenarioForXXX
+
#if !DEBUG
sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
#endif
sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("\tprivate sealed class MockInScenarioFor").Append(name)
- .Append(" : global::Mockolate.Mock.IMockInScenarioFor").Append(name)
- .Append(", global::Mockolate.Mock.IMockSetupFor").Append(name);
+ sb.Append("\tprivate sealed class MockInScenarioFor").Append(name).Append(" : global::Mockolate.Mock.IMockInScenarioFor").Append(name).Append(", global::Mockolate.Mock.IMockSetupFor").Append(name);
if (hasProtectedMembers)
{
sb.Append(", global::Mockolate.Mock.IMockProtectedSetupFor").Append(name);
@@ -879,66 +291,60 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t{").AppendLine();
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }")
- .AppendLine();
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }").AppendLine();
sb.Append("\t\tprivate string _scenarioName;").AppendLine();
sb.AppendLine();
- sb.Append("\t\tpublic MockInScenarioFor").Append(name)
- .Append("(global::Mockolate.MockRegistry mockRegistry, string scenario)").AppendLine();
+ sb.Append("\t\tpublic MockInScenarioFor").Append(name).Append("(global::Mockolate.MockRegistry mockRegistry, string scenario)").AppendLine();
sb.Append("\t\t{").AppendLine();
sb.Append("\t\t\tthis.").Append(mockRegistryName).Append(" = mockRegistry;").AppendLine();
sb.Append("\t\t\t_scenarioName = scenario;").AppendLine();
sb.Append("\t\t}").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Mock.IMockSetupFor").Append(name)
- .Append(" global::Mockolate.Mock.IMockInScenarioFor").Append(name).Append(".Setup").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Mock.IMockSetupFor").Append(name).Append(" global::Mockolate.Mock.IMockInScenarioFor").Append(name).Append(".Setup").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
sb.AppendLine();
if (hasProtectedMembers)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name)
- .Append(" global::Mockolate.Mock.IMockInScenarioFor").Append(name).Append(".SetupProtected")
- .AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name).Append(" global::Mockolate.Mock.IMockInScenarioFor").Append(name).Append(".SetupProtected").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
sb.AppendLine();
}
sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public,
- memberIds, memberIdPrefix, "_scenarioName");
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public, memberIds, memberIdPrefix, "_scenarioName");
+
sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
if (hasProtectedMembers)
{
sb.AppendLine();
sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected,
- memberIds, memberIdPrefix, "_scenarioName");
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected, memberIds, memberIdPrefix, "_scenarioName");
+
sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
}
sb.Append("\t}").AppendLine();
-
- #endregion MockForXXX
-
sb.AppendLine();
+
+ #endregion MockInScenarioForXXX
+ #region Mock Interfaces
+
#region IMockForXXX
- sb.AppendXmlSummary(
- $"The Mockolate accessor for a mock of , reached through .Mock on the mocked instance.",
- "\t");
- sb.AppendXmlRemarks([
- "Groups every operation that acts on the mock rather than on the mocked subject: setups, verifications, event raising, scenarios and monitoring.",
- ], "\t");
+ sb.AppendXmlSummary($"The Mockolate accessor for a mock of , reached through .Mock on the mocked instance.", "\t");
+ sb.AppendXmlRemarks(["Groups every operation that acts on the mock rather than on the mocked subject: setups, verifications, event raising, scenarios and monitoring.",], "\t");
sb.Append("\tinternal interface IMockFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
- sb.AppendXmlSummary(
- $"Configures how members of the mock of respond when invoked.");
- sb.AppendXmlRemarks([
+ sb.AppendXmlSummary($"Configures how members of the mock of respond when invoked.");
+ sb.AppendXmlRemarks(
+ [
"Each mocked member is available as a strongly-typed entry on this surface. Chain Returns, ReturnsAsync, Throws, ThrowsAsync or Do to control the response; chain InitializeWith/Register to initialize properties and indexers; chain multiple returns/throws to define a sequence; use .For(n), .Only(n), .Forever(), .When(predicate) to control when a callback runs.",
"When two setups overlap, the most recently defined one wins.",
]);
@@ -946,57 +352,37 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
if (hasProtectedMembers)
{
- sb.AppendXmlSummary(
- $"Configures how virtual members of the mock of respond when invoked.");
- sb.AppendXmlRemarks([
- "Only members declared as (or ) on the mocked class appear here. All setup chain operators (Returns, Throws, Do, sequences, .For/.Only/.Forever, ...) work identically to .",
- ]);
+ sb.AppendXmlSummary($"Configures how virtual members of the mock of respond when invoked.");
+ sb.AppendXmlRemarks(["Only members declared as (or ) on the mocked class appear here. All setup chain operators (Returns, Throws, Do, sequences, .For/.Only/.Forever, ...) work identically to .",]);
sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" SetupProtected { get; }").AppendLine();
sb.AppendLine();
}
if (hasStaticMembers)
{
- sb.AppendXmlSummary(
- $"Configures how members declared on respond when invoked.");
- sb.AppendXmlRemarks([
- "Static members are scoped per async/execution flow while the mock is alive; invocations from other flows are not intercepted.",
- ]);
+ sb.AppendXmlSummary($"Configures how members declared on respond when invoked.");
+ sb.AppendXmlRemarks(["Static members are scoped per async/execution flow while the mock is alive; invocations from other flows are not intercepted.",]);
sb.Append("\t\tIMockStaticSetupFor").Append(name).Append(" SetupStatic { get; }").AppendLine();
sb.AppendLine();
}
- sb.AppendXmlSummary(
- $"Opens a named scenario scope on the mock of so that additional setups can be registered for that scenario.");
- sb.AppendXmlRemarks([
- "Scenarios let you define per-state behavior. Setups registered inside the returned IMockInScenarioFor... scope only apply while the mock's current scenario matches ; switch scenarios with .",
- ]);
- sb.AppendXmlParam("scenario",
- "Name of the scenario to enter. Any non-null string acts as a key; the mock starts in an unnamed default scenario.");
- sb.AppendXmlReturns(
- "A scoped accessor whose Setup (and SetupProtected, where applicable) register scenario-specific setups.");
+ sb.AppendXmlSummary($"Opens a named scenario scope on the mock of so that additional setups can be registered for that scenario.");
+ sb.AppendXmlRemarks(["Scenarios let you define per-state behavior. Setups registered inside the returned IMockInScenarioFor... scope only apply while the mock's current scenario matches ; switch scenarios with .",]);
+ sb.AppendXmlParam("scenario", "Name of the scenario to enter. Any non-null string acts as a key; the mock starts in an unnamed default scenario.");
+ sb.AppendXmlReturns("A scoped accessor whose Setup (and SetupProtected, where applicable) register scenario-specific setups.");
sb.Append("\t\tIMockInScenarioFor").Append(name).Append(" InScenario(string scenario);").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- $"Opens a named scenario scope on the mock of and immediately invokes to register scenario-specific setups.");
- sb.AppendXmlRemarks([
- "Equivalent to InScenario(scenario) followed by the setup callback, but returns the original IMockFor... accessor so it chains nicely at mock-creation time.",
- ]);
+ sb.AppendXmlSummary($"Opens a named scenario scope on the mock of and immediately invokes to register scenario-specific setups.");
+ sb.AppendXmlRemarks(["Equivalent to InScenario(scenario) followed by the setup callback, but returns the original IMockFor... accessor so it chains nicely at mock-creation time.",]);
sb.AppendXmlParam("scenario", "Name of the scenario to enter.");
- sb.AppendXmlParam("setup",
- "Callback that receives the scenario-scoped setup surface and registers scenario-specific setups.");
+ sb.AppendXmlParam("setup", "Callback that receives the scenario-scoped setup surface and registers scenario-specific setups.");
sb.AppendXmlReturns("This accessor, to allow chaining.");
- sb.Append("\t\tIMockFor").Append(name)
- .Append(" InScenario(string scenario, global::System.Action setup);").AppendLine();
+ sb.Append("\t\tIMockFor").Append(name).Append(" InScenario(string scenario, global::System.Action setup);").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- $"Switches the active scenario of the mock of to .");
- sb.AppendXmlRemarks([
- "After the transition, setups registered via under that scenario take effect. Scenarios that have no matching setup for a given member fall back to the default (un-scoped) setups.",
- ]);
+ sb.AppendXmlSummary($"Switches the active scenario of the mock of to .");
+ sb.AppendXmlRemarks(["After the transition, setups registered via under that scenario take effect. Scenarios that have no matching setup for a given member fall back to the default (un-scoped) setups.",]);
sb.AppendXmlParam("scenario", "Name of the scenario to transition to.");
sb.AppendXmlReturns("This accessor, to allow chaining.");
sb.Append("\t\tIMockFor").Append(name).Append(" TransitionTo(string scenario);").AppendLine();
@@ -1004,40 +390,31 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
if (hasEvents)
{
- sb.AppendXmlSummary(
- $"Triggers events declared on so that currently subscribed handlers are invoked.");
- sb.AppendXmlRemarks([
- "One entry per event is generated; the signature matches the event's delegate. Only handlers that are subscribed at the moment of the Raise call are invoked - handlers subscribed later (or already removed) are skipped.",
- ]);
+ sb.AppendXmlSummary($"Triggers events declared on so that currently subscribed handlers are invoked.");
+ sb.AppendXmlRemarks(["One entry per event is generated; the signature matches the event's delegate. Only handlers that are subscribed at the moment of the Raise call are invoked - handlers subscribed later (or already removed) are skipped.",]);
sb.Append("\t\tIMockRaiseOn").Append(name).Append(" Raise { get; }").AppendLine();
sb.AppendLine();
}
if (hasProtectedEvents)
{
- sb.AppendXmlSummary(
- $"Triggers events declared on so that currently subscribed handlers are invoked.");
- sb.AppendXmlRemarks([
- "Same semantics as but for events whose accessibility prevents external subscription from outside the class. Useful when testing code that subclasses the mocked type.",
- ]);
+ sb.AppendXmlSummary($"Triggers events declared on so that currently subscribed handlers are invoked.");
+ sb.AppendXmlRemarks(["Same semantics as but for events whose accessibility prevents external subscription from outside the class. Useful when testing code that subclasses the mocked type.",]);
sb.Append("\t\tIMockProtectedRaiseOn").Append(name).Append(" RaiseProtected { get; }").AppendLine();
sb.AppendLine();
}
if (hasStaticEvents)
{
- sb.AppendXmlSummary(
- $"Triggers events declared on so that currently subscribed handlers are invoked.");
- sb.AppendXmlRemarks([
- "Static events are scoped per async/execution flow while the mock is alive.",
- ]);
+ sb.AppendXmlSummary($"Triggers events declared on so that currently subscribed handlers are invoked.");
+ sb.AppendXmlRemarks(["Static events are scoped per async/execution flow while the mock is alive.",]);
sb.Append("\t\tIMockStaticRaiseOn").Append(name).Append(" RaiseStatic { get; }").AppendLine();
sb.AppendLine();
}
- sb.AppendXmlSummary(
- $"Asserts how often, and in which order, members of the mock of were invoked.");
- sb.AppendXmlRemarks([
+ sb.AppendXmlSummary($"Asserts how often, and in which order, members of the mock of were invoked.");
+ sb.AppendXmlRemarks(
+ [
"Each call to a member here returns a VerificationResult that you terminate with a count assertion: Never(), Once(), Twice(), Exactly(n), AtLeast(n)/AtLeastOnce()/AtLeastTwice(), AtMost(n)/AtMostOnce()/AtMostTwice(), Between(min, max) or Times(predicate).",
"Use Within(TimeSpan) / WithCancellation(CancellationToken) before the terminator to wait for expected interactions that happen on background threads.",
"Chain Then(...) to assert an ordered sequence of calls. A failing assertion throws a .",
@@ -1046,80 +423,56 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
if (hasProtectedMembers || hasProtectedEvents)
{
- sb.AppendXmlSummary(
- $"Asserts how often, and in which order, members of the mock of were invoked.");
- sb.AppendXmlRemarks([
- "Same terminators and modifiers as (Once(), Exactly(n), Within(...), Then(...), ...); applies to members and events instead of public ones.",
- ]);
+ sb.AppendXmlSummary($"Asserts how often, and in which order, members of the mock of were invoked.");
+ sb.AppendXmlRemarks(["Same terminators and modifiers as (Once(), Exactly(n), Within(...), Then(...), ...); applies to members and events instead of public ones.",]);
sb.Append("\t\tIMockProtectedVerifyFor").Append(name).Append(" VerifyProtected { get; }").AppendLine();
sb.AppendLine();
}
if (hasStaticMembers || hasStaticEvents)
{
- sb.AppendXmlSummary(
- $"Asserts how often, and in which order, members declared on were invoked.");
- sb.AppendXmlRemarks([
- "Same terminators and modifiers as ; scoped per async/execution flow in the same way as .",
- ]);
+ sb.AppendXmlSummary($"Asserts how often, and in which order, members declared on were invoked.");
+ sb.AppendXmlRemarks(["Same terminators and modifiers as ; scoped per async/execution flow in the same way as .",]);
sb.Append("\t\tIMockStaticVerifyFor").Append(name).Append(" VerifyStatic { get; }").AppendLine();
sb.AppendLine();
}
sb.AppendXmlSummary("Verifies how often a specific method setup was matched by actual invocations.");
- sb.AppendXmlRemarks([
- "Useful when you want to verify "this particular setup was hit N times" without re-stating the matchers. Chain the usual count terminators (Once(), AtLeastOnce(), Exactly(n), ...) on the returned result.",
- ]);
- sb.AppendXmlParam("setup",
- "The setup previously registered through (typically returned from a Returns(...)/Throws(...) call).");
+ sb.AppendXmlRemarks(["Useful when you want to verify "this particular setup was hit N times" without re-stating the matchers. Chain the usual count terminators (Once(), AtLeastOnce(), Exactly(n), ...) on the returned result.",]);
+ sb.AppendXmlParam("setup", "The setup previously registered through (typically returned from a Returns(...)/Throws(...) call).");
sb.AppendXmlReturns("A VerificationResult that counts invocations matching the given setup.");
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult VerifySetup(global::Mockolate.Setup.IMethodSetup setup);").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult VerifySetup(global::Mockolate.Setup.IMethodSetup setup);").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- "Checks whether every recorded interaction on this mock has been observed by at least one Verify call.");
- sb.AppendXmlRemarks([
- "Useful in test teardown to catch unexpected interactions ("strict verification"): if any recorded call has never been matched by a verification, the method returns .",
- ]);
- sb.AppendXmlReturns(
- " if every recorded interaction was verified at least once; otherwise .");
+
+ sb.AppendXmlSummary("Checks whether every recorded interaction on this mock has been observed by at least one Verify call.");
+ sb.AppendXmlRemarks(["Useful in test teardown to catch unexpected interactions ("strict verification"): if any recorded call has never been matched by a verification, the method returns .",]);
+ sb.AppendXmlReturns(" if every recorded interaction was verified at least once; otherwise .");
sb.Append("\t\tbool VerifyThatAllInteractionsAreVerified();").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- "Checks whether every registered setup on this mock was matched by at least one actual invocation.");
- sb.AppendXmlRemarks([
- "Useful to catch unused setups that silently rot as the test subject evolves.",
- ]);
- sb.AppendXmlReturns(
- " if every registered setup was used at least once; otherwise .");
+
+ sb.AppendXmlSummary("Checks whether every registered setup on this mock was matched by at least one actual invocation.");
+ sb.AppendXmlRemarks(["Useful to catch unused setups that silently rot as the test subject evolves.",]);
+ sb.AppendXmlReturns(" if every registered setup was used at least once; otherwise .");
sb.Append("\t\tbool VerifyThatAllSetupsAreUsed();").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- "Removes every recorded interaction from this mock while keeping all registered setups intact.");
- sb.AppendXmlRemarks([
- "Handy when a single test exercises multiple logical phases and you only want to verify the interactions of the latest phase.",
- ]);
+
+ sb.AppendXmlSummary("Removes every recorded interaction from this mock while keeping all registered setups intact.");
+ sb.AppendXmlRemarks(["Handy when a single test exercises multiple logical phases and you only want to verify the interactions of the latest phase.",]);
sb.Append("\t\tvoid ClearAllInteractions();").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- "Creates a monitor whose Verify surface is scoped to interactions produced between monitor.Run() and the disposal of its scope.");
- sb.AppendXmlRemarks([
- "The underlying mock keeps recording all interactions as usual - only the monitor's Verify view is scoped. Useful to verify only the interactions produced by a specific block of test code without resetting the mock.",
- ]);
- sb.AppendXmlReturns(
- "A that exposes Verify over the monitored interactions and a Run() method that opens the recording scope.");
- sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor Monitor();")
- .AppendLine();
+
+ sb.AppendXmlSummary("Creates a monitor whose Verify surface is scoped to interactions produced between monitor.Run() and the disposal of its scope.");
+ sb.AppendXmlRemarks(["The underlying mock keeps recording all interactions as usual - only the monitor's Verify view is scoped. Useful to verify only the interactions produced by a specific block of test code without resetting the mock.",]);
+ sb.AppendXmlReturns("A that exposes Verify over the monitored interactions and a Run() method that opens the recording scope.");
+ sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor Monitor();").AppendLine();
sb.Append("\t}").AppendLine();
+ sb.AppendLine();
#endregion IMockForXXX
- sb.AppendLine();
-
#region IMockInScenarioForXXX
- sb.AppendXmlSummary(
- $"Scoped access to setups for a scenario on the mock of .", "\t");
+ sb.AppendXmlSummary($"Scoped access to setups for a scenario on the mock of .", "\t");
sb.Append("\tinternal interface IMockInScenarioFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
sb.AppendXmlSummary($"Set up the mock of within the scenario scope.");
@@ -1127,17 +480,15 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
if (hasProtectedMembers)
{
sb.AppendLine();
- sb.AppendXmlSummary(
- $"Set up protected members of the mock of within the scenario scope.");
+ sb.AppendXmlSummary($"Set up protected members of the mock of within the scenario scope.");
sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" SetupProtected { get; }").AppendLine();
}
sb.Append("\t}").AppendLine();
+ sb.AppendLine();
#endregion IMockInScenarioForXXX
- sb.AppendLine();
-
#region IMockSetupForXXX
sb.AppendXmlSummary($"Set up the mock of .", "\t");
@@ -1152,74 +503,94 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
}
sb.Append("\t{").AppendLine();
+
DefineSetupInterface(sb, @class, MemberType.Public, hasOverloadResolutionPriority);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
+ #endregion IMockSetupForXXX
+
+ #region IMockProtectedSetupForXXX
+
if (hasProtectedMembers)
{
sb.AppendXmlSummary($"Set up protected members for the mock of .", "\t");
sb.Append("\tinternal interface IMockProtectedSetupFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
+
DefineSetupInterface(sb, @class, MemberType.Protected, hasOverloadResolutionPriority);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
}
+ #endregion IMockProtectedSetupForXXX
+
+ #region IMockStaticSetupForXXX
+
if (hasStaticMembers)
{
sb.AppendXmlSummary($"Set up static members for the mock of .", "\t");
sb.Append("\tinternal interface IMockStaticSetupFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
+
DefineSetupInterface(sb, @class, MemberType.Static, hasOverloadResolutionPriority);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
}
- #endregion IMockSetupForXXX
+ #endregion IMockStaticSetupForXXX
+ #region IMockRaiseOnXXX
+
if (hasEvents)
{
- #region IMockRaiseOnXXX
-
sb.AppendXmlSummary($"Raise events on the mock of .", "\t");
sb.Append("\tinternal interface IMockRaiseOn").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
+
DefineRaiseInterface(sb, @class, MemberType.Public);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
-
- #endregion IMockRaiseOnXXX
}
+
+ #endregion IMockRaiseOnXXX
+
+ #region IMockProtectedRaiseOnXXX
if (hasProtectedEvents)
{
- #region IMockProtectedRaiseOnXXX
-
sb.AppendXmlSummary($"Raise protected events on the mock of .", "\t");
sb.Append("\tinternal interface IMockProtectedRaiseOn").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
+
DefineRaiseInterface(sb, @class, MemberType.Protected);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
-
- #endregion IMockProtectedRaiseOnXXX
}
+ #endregion IMockProtectedRaiseOnXXX
+
+ #region IMockStaticRaiseOnXXX
+
if (hasStaticEvents)
{
- #region IMockStaticRaiseOnXXX
-
sb.AppendXmlSummary($"Raise static events on the mock of .", "\t");
sb.Append("\tinternal interface IMockStaticRaiseOn").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
+
DefineRaiseInterface(sb, @class, MemberType.Static);
+
sb.Append("\t}").AppendLine();
sb.AppendLine();
-
- #endregion IMockStaticRaiseOnXXX
}
+ #endregion IMockStaticRaiseOnXXX
+
#region IMockVerifyForXXX
sb.AppendXmlSummary($"Verify interactions with the mock of .", "\t");
@@ -1234,9 +605,15 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
}
sb.Append("\t{").AppendLine();
+
DefineVerifyInterface(sb, @class, $"IMockVerifyFor{name}", MemberType.Public, hasOverloadResolutionPriority);
+
sb.Append("\t}").AppendLine();
+ #endregion IMockVerifyForXXX
+
+ #region IMockProtectedVerifyForXXX
+
if (hasProtectedMembers || hasProtectedEvents)
{
sb.AppendLine();
@@ -1249,6 +626,10 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.Append("\t}").AppendLine();
}
+ #endregion IMockProtectedVerifyForXXX
+
+ #region IMockStaticVerifyForXXX
+
if (hasStaticMembers || hasStaticEvents)
{
sb.AppendLine();
@@ -1261,262 +642,471 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.Append("\t}").AppendLine();
}
- #endregion IMockVerifyForXXX
+ #endregion IMockStaticVerifyForXXX
+
+ #endregion Mock Interfaces
sb.Append("}").AppendLine();
+
+ #endregion Mock
+
+ #region MockForXXXExtensions
+
+ sb.AppendXmlSummary($"Mock extensions for .", "");
+#if !DEBUG
+ sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
+#endif
+ sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
+ sb.Append("internal static partial class MockExtensionsFor").Append(name).AppendLine();
+ sb.Append("{").AppendLine();
+
+ #region Mock Type extensions
+
+ sb.Append("\t/// ").AppendLine();
+ sb.Append("\textension(").Append(@class.ClassFullName).Append(" mock)").AppendLine();
+ sb.Append("\t{").AppendLine();
+
+ #region Mock Property
+
+ string mockPropertyName = CreateUniquePropertyName(@class, "Mock");
+
+ List mockPropertyRemarks =
+ [
+ $"The accessor is the bridge between the strongly-typed instance of returned by CreateMock(...) and the underlying mock registry where setups and recorded interactions live.",
+ "Through it you can:",
+ "",
+ " - Setup - configure how members respond when invoked (Returns, Throws, Do, InitializeWith, ...).
",
+ " - Verify - assert how often (and in which order) members were invoked.
",
+ ];
+ if (hasEvents)
+ {
+ mockPropertyRemarks.Add(" - Raise - trigger events declared on the mocked type.
");
+ }
+
+ if (hasProtectedMembers || hasProtectedEvents)
+ {
+ mockPropertyRemarks.Add(" - SetupProtected / VerifyProtected / RaiseProtected - target members on class mocks.
");
+ }
+
+ if (hasStaticMembers || hasStaticEvents)
+ {
+ mockPropertyRemarks.Add(" - SetupStatic / VerifyStatic / RaiseStatic - target members on interface mocks.
");
+ }
+
+ mockPropertyRemarks.Add(" - InScenario / TransitionTo - scope setups and behavior to a named scenario and switch between scenarios.
");
+ mockPropertyRemarks.Add(" - Monitor, ClearAllInteractions, VerifyThatAllInteractionsAreVerified, VerifyThatAllSetupsAreUsed - manage recorded interactions.
");
+ mockPropertyRemarks.Add(" - VerifySetup - verify how often a specific setup matched.
");
+ mockPropertyRemarks.Add("
");
+
+ sb.AppendXmlSummary($"Gets the mock accessor for - the entry point for configuring setups, verifying interactions and raising events.");
+ sb.AppendXmlRemarks(mockPropertyRemarks.ToArray());
+ sb.AppendXmlException("global::Mockolate.Exceptions.MockException", $"The instance is not a Mockolate-generated mock of .");
+ sb.Append("\t\tpublic global::Mockolate.Mock.IMockFor").Append(name).Append(' ').Append(mockPropertyName).AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tget").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tif (mock is global::Mockolate.Mock.IMockFor").Append(name).Append(" mockInterface)").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\treturn mockInterface;").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
sb.AppendLine();
- sb.AppendLine("#nullable disable annotations");
- return sb.ToString();
- }
- private static void AppendCreateFastInteractions(StringBuilder sb, string indent)
- {
- sb.Append(indent).Append("/// ").AppendLine();
- sb.Append(indent)
- .Append("/// Creates a sized to ")
- .Append(" for use as the mock's interaction store.").AppendLine();
- sb.Append(indent)
- .Append("/// Per-member buffers are not allocated up-front: the recording hot paths call ")
- .Append("")
- .Append(" so a slot is materialized only when its member is first invoked.").AppendLine();
- sb.Append(indent).Append("/// ").AppendLine();
- sb.Append(indent)
- .Append(
- "internal static global::Mockolate.Interactions.FastMockInteractions CreateFastInteractions(global::Mockolate.MockBehavior behavior)")
- .AppendLine();
- sb.Append(indent)
- .Append(
- "\t=> new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);")
- .AppendLine();
- }
+ #endregion Mock Property
- ///
- /// Emits the declarations of the cached MockolateSkipRecording flag and per-member typed
- /// buffer fields. These mirror values that AppendCreateFastInteractions writes into the
- /// FastMockInteractions.Buffers array so the body emitters can read them as plain field
- /// accesses instead of paying the cast / array-index / property-chain on every invocation. Static
- /// members stay on the legacy path because the cached field would not flow through
- /// AsyncLocal-resolved registries.
- ///
- ///
- /// when the class has at least one fast-eligible non-static indexer or
- /// method, in which case the generator emits cached typed-buffer fields and a
- /// MockolateSkipRecording flag that the recording hot paths read instead of paying the
- /// per-call cast / array-index / property-chain.
- ///
- private static bool HasCachedBufferFields(Class @class)
- {
- foreach (Property property in @class.AllProperties())
+ #region CreateMock
+
+ string createMockReturns = $"A new mock instance of .";
+ List createMockRemarks =
+ [
+ $"The returned instance is a strongly-typed mock generated at compile time - it implements and exposes the Mockolate surface through .Mock:",
+ "",
+ " - .Mock.Setup configures how members respond (Returns, Throws, Do, InitializeWith, sequences, callbacks).
",
+ " - .Mock.Verify asserts how often and in which order members were invoked.
",
+ ];
+ if (hasEvents)
{
- if (property.IsIndexer && IsFastBufferEligibleIndexer(property))
+ createMockRemarks.Add(" - .Mock.Raise triggers events declared on the mocked type.
");
+ }
+
+ createMockRemarks.Add("
");
+ createMockRemarks.Add("With the default behavior, un-configured members return default values (empty collections / strings, completed tasks, otherwise) and base-class implementations are invoked for class mocks. Use one of the overloads that accepts a to customize this (for example to make un-configured calls throw or to skip the base class).");
+ createMockRemarks.Add("Overloads allow you to additionally pass constructor parameters (for class mocks), apply an initial setup callback before the instance is returned, or combine both.");
+
+ sb.AppendXmlSummary($"Creates a new mock of with the default .");
+ sb.AppendXmlRemarks(createMockRemarks.ToArray());
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock()").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, null, (object?[]?)null);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary($"Creates a new mock of with the default , applying the given immediately.");
+ sb.AppendXmlRemarks("The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
+ sb.AppendXmlParam("setup", "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::System.Action<").Append(setupType).Append("> setup)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, setup, (object?[]?)null);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary($"Creates a new mock of with the given .");
+ sb.AppendXmlParam("mockBehavior", "Controls how the mock responds when members are invoked without a matching setup; see .");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(mockBehavior, null, (object?[]?)null);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary($"Creates a new mock of with the given , applying the given immediately.");
+ sb.AppendXmlRemarks("The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
+ sb.AppendXmlParam("mockBehavior", "Controls how the mock responds when members are invoked without a matching setup; see .");
+ sb.AppendXmlParam("setup", "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action<").Append(setupType).Append("> setup)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(mockBehavior, setup, (object?[]?)null);").AppendLine();
+ sb.AppendLine();
+
+ if (hasParameterizedConstructor)
+ {
+ sb.AppendXmlSummary($"Creates a new mock of using the given to invoke the base-class constructor.");
+ sb.AppendXmlParam("constructorParameters", "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(object?[] constructorParameters)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, null, constructorParameters);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary($"Creates a new mock of using the given and .");
+ sb.AppendXmlParam("mockBehavior", "Controls how the mock responds when members are invoked without a matching setup; see .");
+ sb.AppendXmlParam("constructorParameters", "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(mockBehavior, null, constructorParameters);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary($"Creates a new mock of applying the given immediately, using the given .");
+ sb.AppendXmlRemarks("The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
+ sb.AppendXmlParam("setup", "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
+ sb.AppendXmlParam("constructorParameters", "Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(global::System.Action<").Append(setupType).Append("> setup, object?[] constructorParameters)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, setup, constructorParameters);").AppendLine();
+ sb.AppendLine();
+
+ AppendTypedCreateMockOverloads(sb, @class, constructors!.Value, setupType, escapedClassName, createMockReturns);
+ }
+
+ sb.AppendXmlSummary($"Creates a new mock of using the given , applying the given immediately, using the given .");
+ sb.AppendXmlRemarks("The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
+ sb.AppendXmlParam("mockBehavior", "Controls how the mock responds when members are invoked without a matching setup, or for MockBehavior.Default.");
+ sb.AppendXmlParam("setup", "Callback that receives the mock's setup surface and registers initial setups before the mock is returned, or to skip.");
+ sb.AppendXmlParam("constructorParameters", "Values forwarded to a matching base-class constructor, or to use the parameterless constructor.");
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\t").Append(hasParameterizedConstructor ? "public" : "private").Append(" static ").Append(@class.ClassFullName).Append(" CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action<").Append(setupType).Append(">? setup, object?[]? constructorParameters)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tif (mockBehavior is not null)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tIMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior;").AppendLine();
+ sb.Append("\t\t\t\tif (mockBehaviorAccess.TryGet?>(out var additionalSetup))").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tif (setup is null)").AppendLine();
+ sb.Append("\t\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\t\tsetup = additionalSetup;").AppendLine();
+ sb.Append("\t\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\t\telse").AppendLine();
+ sb.Append("\t\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\t\tvar originalSetup = setup;").AppendLine();
+ sb.Append("\t\t\t\t\t\tsetup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); };").AppendLine();
+ sb.Append("\t\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ if (!@class.IsInterface && !hasStaticMembers)
+ {
+ sb.Append("\t\t\t\tif (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters<").Append(@class.ClassFullName).Append(">(out object?[]? parameters))").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tconstructorParameters = parameters;").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ }
+
+ sb.Append("\t\t\t}").AppendLine();
+ sb.AppendLine();
+
+ if (@class is { ClassFullName: "global::System.Net.Http.HttpClient", })
+ {
+ sb.Append("\t\t\tglobal::Mockolate.MockBehavior effectiveBehavior = mockBehavior ?? global::Mockolate.MockBehavior.Default;").AppendLine();
+ sb.Append("\t\t\tglobal::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(effectiveBehavior, global::Mockolate.Mock.").Append(name).Append(".CreateFastInteractions(effectiveBehavior), constructorParameters);").AppendLine();
+ sb.Append("\t\t\tif (constructorParameters is null)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tconstructorParameters = [new global::Mockolate.Mock.HttpMessageHandler(mockRegistry),];").AppendLine();
+ sb.Append("\t\t\t\tmockRegistry = new global::Mockolate.MockRegistry(mockRegistry, constructorParameters);").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\telse if (constructorParameters.Length > 0 && constructorParameters[0] is global::Mockolate.Mock.HttpMessageHandler && constructorParameters[0] is global::Mockolate.IMock httpMessageHandlerMock)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tif (mockBehavior is not null && httpMessageHandlerMock.MockRegistry.Behavior != mockBehavior)").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Mock of type 'System.Net.Http.HttpClient' cannot be created with behavior '{mockBehavior}' because it shares its mock registry with a mock of type 'System.Net.Http.HttpMessageHandler' that has behavior '{httpMessageHandlerMock.MockRegistry.Behavior}'.\");").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\tmockRegistry = new global::Mockolate.MockRegistry(httpMessageHandlerMock.MockRegistry, constructorParameters);").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
+ }
+ else
+ {
+ sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
+ sb.Append("\t\t\tglobal::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.").Append(name).Append(".CreateFastInteractions(mockBehavior), constructorParameters);").AppendLine();
+ }
+
+ sb.Append("\t\t\treturn CreateMockInstance(mockRegistry, constructorParameters, setup);").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+
+ sb.AppendLine();
+ sb.Append("\t\tprivate static ").Append(@class.ClassFullName).Append(" CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action<").Append(setupType).Append(">? setup)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ if (!@class.IsInterface && constructors?.Count > 0)
+ {
+ sb.Append("\t\t\tif (constructorParameters is null || constructorParameters.Length == 0)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ if (constructors.Value.Any(m => m.Parameters.Count == 0))
+ {
+ sb.Append("\t\t\t\tglobal::Mockolate.Mock.").Append(name).Append(".MockRegistryProvider.Value = mockRegistry;").AppendLine();
+ sb.Append("\t\t\t\tglobal::Mockolate.MockExtensionsFor").Append(name).Append(".MockSetup? setupTarget = null;").AppendLine();
+ sb.Append("\t\t\t\tif (setup is not null)").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tsetupTarget ??= new(mockRegistry);").AppendLine();
+ sb.Append("\t\t\t\t\tsetup.Invoke(setupTarget);").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\treturn new global::Mockolate.Mock.").Append(name).Append("(mockRegistry);").AppendLine();
+ }
+ else
+ {
+ sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"No parameterless constructor found for '").Append(@class.DisplayString).Append("'. Please provide constructor parameters.\");").AppendLine();
+ }
+
+ sb.Append("\t\t\t}").AppendLine();
+ int constructorIndex = 0;
+ bool useTryCast = false;
+ bool useTryCastWithDefaultValue = false;
+ foreach (EquatableArray constructorParameters in constructors.Value.Select(constructor => constructor.Parameters))
+ {
+ constructorIndex++;
+ int requiredParameters = constructorParameters.Count(c => !c.HasExplicitDefaultValue);
+ if (requiredParameters < constructorParameters.Count)
+ {
+ sb.Append("\t\t\telse if (constructorParameters.Length >= ").Append(requiredParameters).Append(" && constructorParameters.Length <= ").Append(constructorParameters.Count);
+ }
+ else
+ {
+ sb.Append("\t\t\telse if (constructorParameters.Length == ").Append(constructorParameters.Count);
+ }
+
+ int constructorParameterIndex = 0;
+ foreach (MethodParameter parameter in constructorParameters)
+ {
+ useTryCast = useTryCast || !parameter.HasExplicitDefaultValue;
+ useTryCastWithDefaultValue = useTryCastWithDefaultValue || parameter.HasExplicitDefaultValue;
+ sb.AppendLine().Append("\t\t\t && ")
+ .Append(parameter.HasExplicitDefaultValue ? "TryCastWithDefaultValue" : "TryCast")
+ .Append("(constructorParameters, ")
+ .Append(constructorParameterIndex++)
+ .Append(parameter.HasExplicitDefaultValue ? $", {parameter.ExplicitDefaultValue}" : "")
+ .Append(", mockRegistry.Behavior, out ").Append(parameter.Type.Fullname).Append(" c")
+ .Append(constructorIndex)
+ .Append('p')
+ .Append(constructorParameterIndex).Append(")");
+ }
+
+ sb.Append(")").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tglobal::Mockolate.Mock.").Append(name).Append(".MockRegistryProvider.Value = mockRegistry;").AppendLine();
+ sb.Append("\t\t\t\tglobal::Mockolate.MockExtensionsFor").Append(name).Append(".MockSetup? setupTarget = null;").AppendLine();
+ sb.Append("\t\t\t\tif (setup is not null)").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tsetupTarget ??= new(mockRegistry);").AppendLine();
+ sb.Append("\t\t\t\t\tsetup.Invoke(setupTarget);").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\treturn new global::Mockolate.Mock.").Append(name).Append("(mockRegistry");
+ for (int i = 1; i <= constructorParameters.Count; i++)
+ {
+ sb.Append(", ").Append('c').Append(constructorIndex).Append('p').Append(i);
+ }
+
+ sb.Append(");").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ }
+
+ sb.Append("\t\t\telse").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Could not find any constructor for '").Append(@class.DisplayString).Append("' that matches the {constructorParameters.Length} given parameters ({string.Join(\", \", constructorParameters)}).\");").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ if (useTryCast)
{
- return true;
+ sb.Append("""
+ static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
+ {
+ var value = values[index];
+ if (value is TValue typedValue)
+ {
+ result = typedValue;
+ return true;
+ }
+
+ result = default!;
+ return value is null;
+ }
+ """).AppendLine();
}
- }
- foreach (Method method in @class.AllMethods())
- {
- if (!method.IsStatic && IsFastBufferEligibleMethod(method))
+ if (useTryCastWithDefaultValue)
{
- return true;
+ sb.Append("""
+ static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
+ {
+ if (values.Length > index && values[index] is TValue typedValue)
+ {
+ result = typedValue;
+ return true;
+ }
+
+ result = defaultValue;
+ return true;
+ }
+ """).AppendLine();
}
}
-
- return false;
- }
-
- private static void AppendCachedFieldDeclarations(StringBuilder sb, string indent, Class @class,
- MemberIdTable memberIds, string memberIdPrefix, string mockRegistryName)
- {
- if (!HasCachedBufferFields(@class))
+ else
{
- return;
+ sb.Append("\t\t\tvar value = new global::Mockolate.Mock.").Append(name).Append("(mockRegistry);").AppendLine();
+ sb.Append("\t\t\tif (setup is not null)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tsetup.Invoke(value);").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\treturn value;").AppendLine();
}
- string mockRegistryRef = "this." + mockRegistryName;
-
- foreach (Property indexer in @class.AllProperties().Where(p => p.IsIndexer))
- {
- if (!IsFastBufferEligibleIndexer(indexer))
- {
- continue;
- }
-
- string indexerKeyTypeArgs =
- string.Join(", ", indexer.IndexerParameters!.Value.Select(p => p.ToTypeOrWrapper()));
- string indexerValueType = indexer.Type.ToTypeOrWrapper();
- string getMemberIdRef = memberIdPrefix + memberIds.GetIndexerGetIdentifier(indexer);
- string setMemberIdRef = memberIdPrefix + memberIds.GetIndexerSetIdentifier(indexer);
- string getterBufferType = "global::Mockolate.Interactions.FastIndexerGetterBuffer<"
- + indexerKeyTypeArgs + ">";
- string setterBufferType = "global::Mockolate.Interactions.FastIndexerSetterBuffer<"
- + indexerKeyTypeArgs + ", " + indexerValueType + ">";
+ sb.Append("\t\t}").AppendLine();
- sb.Append(indent)
- .Append(
- "[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append(indent).Append("private ").Append(getterBufferType).Append(' ')
- .Append(memberIds.GetIndexerGetterBufferFieldName(indexer)).AppendLine();
- sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
- .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(getterBufferType)
- .Append(">(").Append(getMemberIdRef).Append(", static fast => new ").Append(getterBufferType)
- .Append("(fast)));").AppendLine();
+ #endregion CreateMock
+
+ #region Wrapping
- sb.Append(indent)
- .Append(
- "[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append(indent).Append("private ").Append(setterBufferType).Append(' ')
- .Append(memberIds.GetIndexerSetterBufferFieldName(indexer)).AppendLine();
- sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
- .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(setterBufferType)
- .Append(">(").Append(setMemberIdRef).Append(", static fast => new ").Append(setterBufferType)
- .Append("(fast)));").AppendLine();
- }
+ sb.AppendXmlSummary("Creates a mock that wraps the given .");
+ sb.AppendXmlRemarks("Public members on the mock forward to unless overridden by a setup; protected members still go through the base-class implementation. All forwarded interactions are recorded and can be verified the same as on a plain mock.");
+ sb.AppendXmlParam("instance", "The real object whose calls should be forwarded. Must not be .");
+ sb.AppendXmlReturns($"A new mock of that delegates to .");
+ sb.Append("\t\tpublic ").Append(@class.ClassFullName).Append(" Wrapping(").Append(@class.ClassFullName).Append(" instance)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tif (mock is global::Mockolate.IMock mockInterface)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tglobal::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance);").AppendLine();
+ sb.Append("\t\t\t\twrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.").Append(name).Append(".CreateFastInteractions(wrappingRegistry.Behavior));").AppendLine();
+ sb.Append("\t\t\t\treturn CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null);").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.AppendLine();
+
+ #endregion Wrapping
- foreach (Method method in @class.AllMethods())
- {
- if (method.IsStatic || !IsFastBufferEligibleMethod(method))
- {
- continue;
- }
+ sb.Append("\t}").AppendLine();
+ sb.AppendLine();
- int arity = method.Parameters.Count;
- string typeArgs = arity == 0
- ? string.Empty
- : "<" + string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper())) + ">";
- string memberIdRef = memberIdPrefix + memberIds.GetMethodIdentifier(method);
- string bufferType = "global::Mockolate.Interactions.FastMethod" + arity + "Buffer" + typeArgs;
- sb.Append(indent)
- .Append(
- "[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append(indent).Append("private ").Append(bufferType).Append(' ')
- .Append(memberIds.GetMethodBufferFieldName(method)).AppendLine();
- sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
- .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(bufferType)
- .Append(">(").Append(memberIdRef).Append(", static fast => new ").Append(bufferType)
- .Append("(fast)));").AppendLine();
- }
- }
+ #endregion Mock Type extensions
- ///
- /// Properties get a typed per-member buffer when they are not static. Static property recordings stay on
- /// the legacy RegisterInteraction path because their member id is shared across AsyncLocal
- /// contexts whereas the buffer instance is stored on a single registry, so per-context isolation breaks.
- ///
- private static bool IsFastBufferEligibleProperty(Property property)
- => !property.IsStatic;
+ #region MockBehavior extensions
- ///
- /// Indexers with up to four key parameters and a non-ref-struct signature get a typed per-member buffer.
- ///
- private static bool IsFastBufferEligibleIndexer(Property indexer)
- {
- if (indexer.IsStatic ||
- indexer.IndexerParameters is null ||
- indexer.IndexerParameters.Value.Count == 0 ||
- indexer.IndexerParameters.Value.Count > 4)
- {
- return false;
- }
+ sb.Append("\t/// ").AppendLine();
+ sb.Append("\textension(global::Mockolate.MockBehavior behavior)").AppendLine();
+ sb.Append("\t{").AppendLine();
- foreach (MethodParameter parameter in indexer.IndexerParameters.Value)
- {
- if (parameter.NeedsRefStructPipeline())
- {
- return false;
- }
- }
+ #region Initialize
+
+ sb.AppendXmlSummary("Initializes mocks of type with the given .");
+ sb.AppendXmlRemarks("The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones.");
+ sb.AppendXmlTypeParam("T", $"The mockable type derived from that this setup should apply to.");
+ sb.AppendXmlParam("setup", "Callback invoked when a new mock of is created.");
+ sb.AppendXmlReturns("A new with the registered initializer. The original instance is unchanged.");
+ sb.Append("\t\tpublic global::Mockolate.MockBehavior Initialize(global::System.Action<").Append(setupType).Append("> setup)").AppendLine();
+ sb.Append("\t\t\twhere T : ").Append(@class.ClassFullName).AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tvar behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior;").AppendLine();
+ sb.Append("\t\t\treturn behaviorAccess.Set(setup);").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+
+ #endregion Initialize
- return true;
- }
+ sb.Append("\t}").AppendLine();
- ///
- /// Events get a typed per-member buffer when they are not static (see
- /// for the rationale).
- ///
- private static bool IsFastBufferEligibleEvent(Event @event)
- => !@event.IsStatic;
+ #endregion MockBehavior extensions
- ///
- /// Methods with non-generic, non-ref-struct signatures get a typed per-member buffer; everything
- /// else (open generics, ref-struct params) records via the legacy RegisterInteraction fallback.
- ///
- private static bool IsFastBufferEligibleMethod(Method method)
- {
- if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
- {
- return false;
- }
+ #region Setup helpers
- foreach (MethodParameter parameter in method.Parameters)
+ if (!@class.IsInterface && constructors?.Count > 0)
{
- if (parameter.NeedsRefStructPipeline())
+ #region IMockSetupInitializationForXXX
+ string protectedName = @class.GetUniqueName("Protected", "SetupProtected");
+ if (hasProtectedMembers)
{
- return false;
+ sb.Append("\tinternal interface IMockSetupInitializationFor").Append(name).Append(" : global::Mockolate.Mock.IMockSetupFor").Append(name).AppendLine();
+ sb.Append("\t{").AppendLine();
+ sb.AppendXmlSummary("Setup protected members");
+ sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name).Append(' ').Append(protectedName).Append(" { get; }").AppendLine();
+ sb.Append("\t}").AppendLine();
}
- }
-
- return true;
- }
+ #endregion IMockSetupInitializationForXXX
- ///
- /// A T? return where T is one of the method's generic parameters and is
- /// constrained to a reference type (or any other non-value-type constraint such as
- /// class, class?, an interface, or notnull) cannot be expressed in
- /// the explicit setup-interface implementation: CS0460 forbids restating the inherited
- /// constraint, and where T : default (CS8822) conflicts with those constraints.
- /// Without a constraint clause the compiler resolves the bare T? as
- /// Nullable<T> and reports CS0453/CS9334/CS0738/CS0266.
- /// The fix is to drop the trailing ? from the setup-side return type
- /// (IReturnMethodSetup<T> instead of IReturnMethodSetup<T?>) and from
- /// the matching ReturnMethodSetup<T> construction. NRT annotations are erased at
- /// runtime, so the underlying setup object is identical and the fluent API still composes.
- /// The user-facing mock body keeps T? because the constraint is visible there.
- ///
- private static bool ShouldStripNullableGenericReturnAnnotation(Method method)
- {
- if (method.GenericParameters is null || method.GenericParameters.Value.Count == 0)
- {
- return false;
- }
+ sb.AppendLine();
+
+ #region MockSetup
+#if !DEBUG
+ sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
+#endif
+ sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
+ sb.Append("\tinternal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupFor").Append(name);
+ if (hasProtectedMembers)
+ {
+ sb.Append(", global::Mockolate.Mock.IMockProtectedSetupFor").Append(name).Append(", IMockSetupInitializationFor").Append(name);
+ }
- string fullname = method.ReturnType.Fullname;
- if (fullname.Length < 2 || fullname[fullname.Length - 1] != '?')
- {
- return false;
- }
+ sb.AppendLine();
+ sb.Append("\t{").AppendLine();
+ if (hasProtectedMembers)
+ {
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Mock.IMockProtectedSetupFor").Append(name).Append(" IMockSetupInitializationFor").Append(name).Append('.').Append(protectedName).Append(" => this;").AppendLine();
+ }
- string raw = fullname.Substring(0, fullname.Length - 1);
- foreach (GenericParameter gp in method.GenericParameters.Value)
- {
- if (gp.Name == raw)
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; } = mockRegistry;").AppendLine();
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
+ sb.AppendLine();
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public, memberIds, memberIdPrefix);
+
+ sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
+ if (hasProtectedMembers)
{
- return !gp.IsStruct && !gp.IsUnmanaged;
+ sb.AppendLine();
+ sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
+ sb.AppendLine();
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected, memberIds, memberIdPrefix);
+
+ sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
}
+
+ sb.Append("\t}").AppendLine();
+ #endregion MockSetup
}
- return false;
- }
+ #endregion Setup helpers
- ///
- /// Emits the method's return type as it should appear inside the setup-side surface
- /// (the IReturnMethodSetup<...> wrapper on the setup interface, the explicit
- /// impl, and the new ReturnMethodSetup<...> construction). Strips a trailing
- /// ? when applies.
- ///
- private static void AppendSetupReturnType(StringBuilder sb, Method method)
- {
- if (ShouldStripNullableGenericReturnAnnotation(method))
- {
- string fullname = method.ReturnType.Fullname;
- sb.Append(fullname, 0, fullname.Length - 1);
- return;
- }
+ AppendNestedCovariantParameterAdapter(sb);
+
+ sb.Append("}").AppendLine();
- sb.AppendTypeOrWrapper(method.ReturnType);
+ #endregion MockForXXXExtensions
+
+ sb.AppendLine();
+ sb.AppendLine("#nullable disable annotations");
+ return sb.ToString();
}
#pragma warning disable S107 // Methods should not have too many parameters
@@ -1524,63 +1114,46 @@ private static void ImplementMockForInterface(StringBuilder sb, string mockRegis
bool hasEvents, bool hasProtectedMembers, bool hasProtectedEvents, bool hasStaticMembers, bool hasStaticEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
sb.Append("\t\tIMockSetupFor").Append(name).Append(" IMockFor").Append(name).Append(".Setup").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
if (hasProtectedMembers)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" IMockFor").Append(name)
- .Append(".SetupProtected").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" IMockFor").Append(name).Append(".SetupProtected").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" global::Mockolate.MockExtensionsFor")
- .Append(name).Append(".IMockSetupInitializationFor").Append(name).Append(".Protected").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockProtectedSetupFor").Append(name).Append(" global::Mockolate.MockExtensionsFor").Append(name).Append(".IMockSetupInitializationFor").Append(name).Append(".Protected").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
if (hasStaticMembers)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockStaticSetupFor").Append(name).Append(" IMockFor").Append(name).Append(".SetupStatic")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockStaticSetupFor").Append(name).Append(" IMockFor").Append(name).Append(".SetupStatic").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tIMockInScenarioFor").Append(name).Append(" IMockFor").Append(name)
- .Append(".InScenario(string scenario)").AppendLine();
- sb.Append("\t\t\t=> new MockInScenarioFor").Append(name).Append("(this.").Append(mockRegistryName)
- .Append(", scenario);").AppendLine();
+ sb.Append("\t\tIMockInScenarioFor").Append(name).Append(" IMockFor").Append(name).Append(".InScenario(string scenario)").AppendLine();
+ sb.Append("\t\t\t=> new MockInScenarioFor").Append(name).Append("(this.").Append(mockRegistryName).Append(", scenario);").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tIMockFor").Append(name).Append(" IMockFor").Append(name)
- .Append(".InScenario(string scenario, global::System.Action setup)").AppendLine();
+ sb.Append("\t\tIMockFor").Append(name).Append(" IMockFor").Append(name).Append(".InScenario(string scenario, global::System.Action setup)").AppendLine();
sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tsetup.Invoke(new MockInScenarioFor").Append(name).Append("(this.").Append(mockRegistryName)
- .Append(", scenario));").AppendLine();
+ sb.Append("\t\t\tsetup.Invoke(new MockInScenarioFor").Append(name).Append("(this.").Append(mockRegistryName).Append(", scenario));").AppendLine();
sb.Append("\t\t\treturn this;").AppendLine();
sb.Append("\t\t}").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tIMockFor").Append(name).Append(" IMockFor").Append(name)
- .Append(".TransitionTo(string scenario)").AppendLine();
+ sb.Append("\t\tIMockFor").Append(name).Append(" IMockFor").Append(name).Append(".TransitionTo(string scenario)").AppendLine();
sb.Append("\t\t{").AppendLine();
sb.Append("\t\t\tthis.").Append(mockRegistryName).Append(".TransitionTo(scenario);").AppendLine();
sb.Append("\t\t\treturn this;").AppendLine();
@@ -1589,9 +1162,7 @@ private static void ImplementMockForInterface(StringBuilder sb, string mockRegis
if (hasEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
sb.Append("\t\tIMockRaiseOn").Append(name).Append(" IMockFor").Append(name).Append(".Raise").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
@@ -1599,308 +1170,62 @@ private static void ImplementMockForInterface(StringBuilder sb, string mockRegis
if (hasProtectedEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockProtectedRaiseOn").Append(name).Append(" IMockFor").Append(name)
- .Append(".RaiseProtected").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockProtectedRaiseOn").Append(name).Append(" IMockFor").Append(name).Append(".RaiseProtected").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
if (hasStaticEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockStaticRaiseOn").Append(name).Append(" IMockFor").Append(name).Append(".RaiseStatic")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockStaticRaiseOn").Append(name).Append(" IMockFor").Append(name).Append(".RaiseStatic").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
sb.Append("\t\tIMockVerifyFor").Append(name).Append(" IMockFor").Append(name).Append(".Verify").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
if (hasProtectedMembers || hasProtectedEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockProtectedVerifyFor").Append(name).Append(" IMockFor").Append(name)
- .Append(".VerifyProtected").AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockProtectedVerifyFor").Append(name).Append(" IMockFor").Append(name).Append(".VerifyProtected").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
if (hasStaticMembers || hasStaticEvents)
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tIMockStaticVerifyFor").Append(name).Append(" IMockFor").Append(name).Append(".VerifyStatic")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tIMockStaticVerifyFor").Append(name).Append(" IMockFor").Append(name).Append(".VerifyStatic").AppendLine();
sb.Append("\t\t\t=> this;").AppendLine();
}
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult IMockFor")
- .Append(name).Append(".VerifySetup(global::Mockolate.Setup.IMethodSetup setup)").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Method(this, setup);").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult IMockFor").Append(name).Append(".VerifySetup(global::Mockolate.Setup.IMethodSetup setup)").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Method(this, setup);").AppendLine();
sb.Append("\t\t/// ").AppendLine();
sb.Append("\t\tbool IMockFor").Append(name).Append(".VerifyThatAllInteractionsAreVerified()").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName)
- .Append(".Interactions.GetUnverifiedInteractions().Count == 0;").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Interactions.GetUnverifiedInteractions().Count == 0;").AppendLine();
sb.Append("\t\t/// ").AppendLine();
sb.Append("\t\tbool IMockFor").Append(name).Append(".VerifyThatAllSetupsAreUsed()").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".GetUnusedSetups(this.").Append(mockRegistryName)
- .Append(".Interactions).Count == 0;").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".GetUnusedSetups(this.").Append(mockRegistryName).Append(".Interactions).Count == 0;").AppendLine();
sb.Append("\t\t/// ").AppendLine();
sb.Append("\t\tvoid IMockFor").Append(name).Append(".ClearAllInteractions()").AppendLine();
sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".ClearAllInteractions();").AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor IMockFor")
- .Append(name).Append(".Monitor()").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor IMockFor").Append(name).Append(".Monitor()").AppendLine();
sb.Append("\t\t\t=> new global::Mockolate.Monitor.MockMonitor(this.")
- .Append(mockRegistryName).Append(".Interactions, interactions => new VerifyMonitor").Append(name)
- .Append("(new global::Mockolate.MockRegistry(this.").Append(mockRegistryName).Append(", interactions)));")
- .AppendLine();
- sb.AppendLine();
- }
-#pragma warning restore S107 // Methods should not have too many parameters
-
- private static void AppendTypedCreateMockOverloads(StringBuilder sb, Class @class,
- EquatableArray constructors, string setupType, string escapedClassName, string createMockReturns)
- {
- // Seeded signatures track the hand-written CreateMock overloads so typed overloads that
- // would collide with them are skipped. The key order mirrors the emitted C# signature:
- // "mockBehavior? | setup? | ctor-param-types...".
- HashSet emittedSignatures = new(StringComparer.Ordinal)
- {
- string.Empty,
- "global::Mockolate.MockBehavior",
- $"global::System.Action<{setupType}>",
- $"global::Mockolate.MockBehavior|global::System.Action<{setupType}>",
- "object?[]",
- "global::Mockolate.MockBehavior|object?[]",
- $"global::System.Action<{setupType}>|object?[]",
- $"global::Mockolate.MockBehavior|global::System.Action<{setupType}>|object?[]",
- };
-
- foreach (Method constructor in constructors)
- {
- if (constructor.Parameters.Count == 0)
- {
- continue;
- }
-
- if (constructor.Parameters.Any(p => p.RefKind != RefKind.None || p.IsParams))
- {
- continue;
- }
-
- string mockBehaviorName = CreateUniqueParameterName(constructor.Parameters, "mockBehavior");
- string setupName = CreateUniqueParameterName(constructor.Parameters, "setup");
- string baseSig = string.Join("|",
- constructor.Parameters.Select(p => p.Type.Fullname));
-
- TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
- false, false, mockBehaviorName, setupName, baseSig,
- emittedSignatures);
- TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
- true, false, mockBehaviorName, setupName, baseSig,
- emittedSignatures);
- TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
- false, true, mockBehaviorName, setupName, baseSig,
- emittedSignatures);
- TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
- true, true, mockBehaviorName, setupName, baseSig,
- emittedSignatures);
- }
- }
-
- ///
- /// Builds an XML-doc cref string and a matching short display text for the given
- /// on . The cref has the form
- /// {class-cref}({fully-qualified-param-types}); the display has the form
- /// {simple-name}({short-param-types}), intended as the inner text of
- /// <see cref="...">...</see> so the rendered prose reads
- /// the MyClass(int) constructor.
- /// Returns when no valid cref can be produced.
- ///
- ///
- /// Generic classes are skipped because the cref type-parameter-list syntax (e.g. {T})
- /// expects identifier tokens, not the concrete type arguments that closed generics carry —
- /// emitting MyClass{int}(int) would surface CS1584/CS1658 on the consumer side.
- ///
- private static (string Cref, string Display)? BuildConstructorCref(Class @class, Method constructor)
- {
- string fullName = @class.ClassFullName;
-
- if (fullName.IndexOf('<') >= 0)
- {
- return null;
- }
-
- int lastDot = fullName.LastIndexOf('.');
- string simpleName = lastDot >= 0 ? fullName.Substring(lastDot + 1) : fullName;
-
- StringBuilder cref = new();
- StringBuilder display = new();
- cref.Append(fullName).Append('(');
- display.Append(simpleName).Append('(');
- bool first = true;
- foreach (MethodParameter parameter in constructor.Parameters)
- {
- if (!first)
- {
- cref.Append(", ");
- display.Append(", ");
- }
-
- first = false;
- cref.Append(parameter.Type.Fullname.EscapeForXmlDoc());
- // Inner text of is XML content, so escape '<'/'>' as entities
- // (unlike cref attributes, which use the '{...}' shorthand).
- display.Append(parameter.Type.DisplayName.Replace("<", "<").Replace(">", ">"));
- }
-
- cref.Append(')');
- display.Append(')');
- return (cref.ToString(), display.ToString());
- }
-
-#pragma warning disable S107 // Methods should not have too many parameters
- private static void TryEmitTypedCreateMockOverload(StringBuilder sb, Class @class, Method constructor,
- string setupType, string escapedClassName, string createMockReturns,
- bool includeMockBehavior, bool includeSetup, string mockBehaviorName, string setupName, string baseSig,
- HashSet emittedSignatures)
- {
- // Build the signature key in the same order as the emitted method signature
- // (mockBehavior, setup, then ctor parameters) so it correctly detects collisions against
- // other typed overloads and against the hand-written seeded overloads.
- string sig = baseSig;
- if (includeSetup)
- {
- sig = $"global::System.Action<{setupType}>|{sig}";
- }
-
- if (includeMockBehavior)
- {
- sig = $"global::Mockolate.MockBehavior|{sig}";
- }
-
- if (!emittedSignatures.Add(sig))
- {
- return;
- }
-
- (string Cref, string Display)? constructorCref = BuildConstructorCref(@class, constructor);
- string ctorPhrase = constructorCref is null
- ? "the base-class constructor"
- : $"the {constructorCref.Value.Display} constructor";
-
- if (includeMockBehavior && includeSetup)
- {
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given , applying the given immediately, using the given constructor parameters to invoke {ctorPhrase}.");
- sb.AppendXmlRemarks(
- $"The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- }
- else if (includeMockBehavior)
- {
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given and the given constructor parameters to invoke {ctorPhrase}.");
- }
- else if (includeSetup)
- {
- sb.AppendXmlSummary(
- $"Creates a new mock of applying the given immediately, using the given constructor parameters to invoke {ctorPhrase}.");
- sb.AppendXmlRemarks(
- $"The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
- }
- else
- {
- sb.AppendXmlSummary(
- $"Creates a new mock of using the given constructor parameters to invoke {ctorPhrase}.");
- }
-
- if (includeMockBehavior)
- {
- sb.AppendXmlParam(mockBehaviorName,
- "Controls how the mock responds when members are invoked without a matching setup; see .");
- }
-
- if (includeSetup)
- {
- sb.AppendXmlParam(setupName,
- "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
- }
-
- foreach (MethodParameter parameter in constructor.Parameters)
- {
- sb.AppendXmlParam(parameter.Name, "Value forwarded to the base-class constructor.");
- }
-
- sb.AppendXmlReturns(createMockReturns);
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(");
- bool needsLeadingComma = false;
- if (includeMockBehavior)
- {
- sb.Append("global::Mockolate.MockBehavior ").Append(mockBehaviorName);
- needsLeadingComma = true;
- }
-
- if (includeSetup)
- {
- if (needsLeadingComma)
- {
- sb.Append(", ");
- }
-
- sb.Append("global::System.Action<").Append(setupType).Append("> ").Append(setupName);
- needsLeadingComma = true;
- }
-
- foreach (MethodParameter parameter in constructor.Parameters)
- {
- if (needsLeadingComma)
- {
- sb.Append(", ");
- }
-
- needsLeadingComma = true;
- sb.Append(parameter.Type.Fullname).Append(' ').Append(parameter.Name);
- if (parameter.HasExplicitDefaultValue)
- {
- sb.Append(" = ").Append(parameter.ExplicitDefaultValue);
- }
- }
-
- sb.Append(")").AppendLine();
- sb.Append("\t\t\t=> CreateMock(").Append(includeMockBehavior ? mockBehaviorName : "null").Append(", ")
- .Append(includeSetup ? setupName : "null").Append(", new object?[] { ");
- int argIndex = 0;
- foreach (MethodParameter parameter in constructor.Parameters)
- {
- if (argIndex++ > 0)
- {
- sb.Append(", ");
- }
-
- sb.Append(parameter.Name);
- }
-
- sb.Append(" });").AppendLine();
+ .Append(mockRegistryName).Append(".Interactions, interactions => new VerifyMonitor").Append(name)
+ .Append("(new global::Mockolate.MockRegistry(this.").Append(mockRegistryName).Append(", interactions)));")
+ .AppendLine();
sb.AppendLine();
}
#pragma warning restore S107 // Methods should not have too many parameters
@@ -1913,9 +1238,7 @@ private static void AppendMockSubject_BaseClassConstructor(StringBuilder sb, str
string mockRegistry = CreateUniqueParameterName(constructor.Parameters, "mockRegistry");
sb.Append("\t\t/// ").AppendLine();
sb.Append(constructor.Attributes, "\t\t");
- if (hasRequiredMembers &&
- constructor.Attributes?.Any(a => a.Name == "global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers") !=
- true)
+ if (hasRequiredMembers && constructor.Attributes?.Any(a => a.Name == "global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers") != true)
{
sb.Append("\t\t[global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]").AppendLine();
}
@@ -1973,21 +1296,11 @@ private static void AppendCreateRegistryFromBehavior(StringBuilder sb, string in
bool setsMockRegistryProvider)
{
sb.Append(indent).Append("/// ").AppendLine();
- sb.Append(indent)
- .Append("/// Builds a backed by a typed-buffer-sized ")
- .Append(
- " from .")
- .AppendLine();
+ sb.Append(indent).Append("/// Builds a backed by a typed-buffer-sized ").Append(" from .").AppendLine();
sb.Append(indent).Append("/// ").AppendLine();
- sb.Append(indent)
- .Append(
- "private static global::Mockolate.MockRegistry MockolateCreateRegistryFromBehavior(global::Mockolate.MockBehavior behavior)")
- .AppendLine();
+ sb.Append(indent).Append("private static global::Mockolate.MockRegistry MockolateCreateRegistryFromBehavior(global::Mockolate.MockBehavior behavior)").AppendLine();
sb.Append(indent).Append("{").AppendLine();
- sb.Append(indent)
- .Append(
- "\tglobal::Mockolate.MockRegistry registry = new global::Mockolate.MockRegistry(behavior, CreateFastInteractions(behavior));")
- .AppendLine();
+ sb.Append(indent).Append("\tglobal::Mockolate.MockRegistry registry = new global::Mockolate.MockRegistry(behavior, CreateFastInteractions(behavior));").AppendLine();
if (setsMockRegistryProvider)
{
sb.Append(indent).Append("\tMockRegistryProvider.Value = registry;").AppendLine();
@@ -2024,9 +1337,7 @@ private static void AppendMockSubject_BehaviorBaseClassConstructor(StringBuilder
string behavior = CreateUniqueParameterName(constructor.Parameters, "behavior");
sb.Append("\t\t/// ").AppendLine();
sb.Append(constructor.Attributes, "\t\t");
- if (hasRequiredMembers &&
- constructor.Attributes?.Any(a => a.Name == "global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers") !=
- true)
+ if (hasRequiredMembers && constructor.Attributes?.Any(a => a.Name == "global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers") != true)
{
sb.Append("\t\t[global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]").AppendLine();
}
@@ -2207,12 +1518,10 @@ private static void AppendMockSubject_ImplementClass_AddEvent(StringBuilder sb,
sb.Append("\t\t\t{").AppendLine();
sb.Append("\t\t\t\tif (value is not null)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(addCall).Append(@event.GetUniqueNameString())
- .Append(", value.Target, value.Method);").AppendLine();
+ sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(addCall).Append(@event.GetUniqueNameString()).Append(", value.Target, value.Method);").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
sb.Append("\t\t\t\t").Append(backingFieldAccess).Append(" += value;").AppendLine();
- sb.Append("\t\t\t\tif (").Append(mockRegistry).Append(".Wraps is ").Append(className).Append(" wraps)")
- .AppendLine();
+ sb.Append("\t\t\t\tif (").Append(mockRegistry).Append(".Wraps is ").Append(className).Append(" wraps)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
sb.Append("\t\t\t\t\twraps.").Append(@event.Name).Append(" += value;").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
@@ -2229,12 +1538,10 @@ private static void AppendMockSubject_ImplementClass_AddEvent(StringBuilder sb,
sb.Append("\t\t\t{").AppendLine();
sb.Append("\t\t\t\tif (value is not null)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(removeCall).Append(@event.GetUniqueNameString())
- .Append(", value.Target, value.Method);").AppendLine();
+ sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(removeCall).Append(@event.GetUniqueNameString()).Append(", value.Target, value.Method);").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
sb.Append("\t\t\t\t").Append(backingFieldAccess).Append(" -= value;").AppendLine();
- sb.Append("\t\t\t\tif (").Append(mockRegistry).Append(".Wraps is ").Append(className).Append(" wraps)")
- .AppendLine();
+ sb.Append("\t\t\t\tif (").Append(mockRegistry).Append(".Wraps is ").Append(className).Append(" wraps)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
sb.Append("\t\t\t\t\twraps.").Append(@event.Name).Append(" -= value;").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
@@ -2254,8 +1561,7 @@ private static void AppendMockSubject_ImplementClass_AddEvent(StringBuilder sb,
sb.Append("\t\t\t{").AppendLine();
sb.Append("\t\t\t\tif (value is not null)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(addCall).Append(@event.GetUniqueNameString())
- .Append(", value.Target, value.Method);").AppendLine();
+ sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(addCall).Append(@event.GetUniqueNameString()).Append(", value.Target, value.Method);").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
sb.Append("\t\t\t\t").Append(backingFieldAccess).Append(" += value;").AppendLine();
sb.Append("\t\t\t}").AppendLine();
@@ -2263,8 +1569,7 @@ private static void AppendMockSubject_ImplementClass_AddEvent(StringBuilder sb,
sb.Append("\t\t\t{").AppendLine();
sb.Append("\t\t\t\tif (value is not null)").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(removeCall).Append(@event.GetUniqueNameString())
- .Append(", value.Target, value.Method);").AppendLine();
+ sb.Append("\t\t\t\t\t").Append(mockRegistry).Append(removeCall).Append(@event.GetUniqueNameString()).Append(", value.Target, value.Method);").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
sb.Append("\t\t\t\t").Append(backingFieldAccess).Append(" -= value;").AppendLine();
sb.Append("\t\t\t}").AppendLine();
@@ -5437,10 +4742,277 @@ private static void DefineVerifyInterface(StringBuilder sb, Class @class, string
property.MemberType == memberType;
foreach (Property property in @class.AllProperties().Where(propertyPredicate))
{
- sb.AppendXmlSummary(
- $"Verify interactions with the {property.Type.Fullname.EscapeForXmlDoc()} property .");
+ sb.AppendXmlSummary(
+ $"Verify interactions with the {property.Type.Fullname.EscapeForXmlDoc()} property .");
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName).Append(", ")
+ .Append(property.Type.Fullname).Append("> ").Append(property.Name).Append(" { get; }").AppendLine();
+ sb.AppendLine();
+ }
+
+ #endregion
+
+ #region Indexers
+
+ Func indexerPredicate =
+ indexer => indexer.ExplicitImplementation is null && indexer is { IsIndexer: true, } &&
+ indexer.MemberType == memberType;
+ foreach (Property indexer in @class.AllProperties().Where(indexerPredicate))
+ {
+ AppendIndexerVerifyDefinition(sb, indexer, verifyName,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ if (indexer.IndexerParameters!.Value.Count <= MaxExplicitParameters)
+ {
+ foreach (bool[] valueFlags in GenerateValueFlagCombinations(indexer.IndexerParameters.Value))
+ {
+ AppendIndexerVerifyDefinition(sb, indexer, verifyName, valueFlags, hasOverloadResolutionPriority);
+ }
+ }
+ else
+ {
+ bool[] allValueFlags = indexer.IndexerParameters.Value.Select(p => p.CanUseNullableParameterOverload())
+ .ToArray();
+ if (allValueFlags.Any(f => f))
+ {
+ AppendIndexerVerifyDefinition(sb, indexer, verifyName, allValueFlags,
+ hasOverloadResolutionPriority);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ bool MethodPredicate(Method method)
+ {
+ return method.ExplicitImplementation is null && method.MemberType == memberType;
+ }
+
+ List> methodGroups =
+ @class.AllMethods().Where((Func)MethodPredicate).GroupBy(m => m.Name).ToList();
+ foreach (IGrouping? methodGroup in methodGroups)
+ {
+ if (methodGroup.Count() == 1)
+ {
+ Method? method = methodGroup.Single();
+ if (method.Parameters.Count > 0)
+ {
+ AppendMethodVerifyDefinition(sb, method, verifyName, true,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ }
+ }
+
+ foreach (Method? method in methodGroup)
+ {
+ if (method.Parameters.Count == 0)
+ {
+ AppendMethodVerifyDefinition(sb, method, verifyName, false,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ }
+ else
+ {
+ AppendMethodVerifyDefinition(sb, method, verifyName, false,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ if (method.Parameters.Count <= MaxExplicitParameters)
+ {
+ foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters))
+ {
+ AppendMethodVerifyDefinition(sb, method, verifyName, false, valueFlags: valueFlags,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ }
+ }
+ else
+ {
+ bool[] allValueFlags = method.Parameters.Select(p => p.CanUseNullableParameterOverload())
+ .ToArray();
+ if (allValueFlags.Any(f => f))
+ {
+ AppendMethodVerifyDefinition(sb, method, verifyName, false, valueFlags: allValueFlags,
+ hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ }
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Events
+
+ Func eventPredicate = @event => @event.ExplicitImplementation is null &&
+ @event.MemberType == memberType;
+ foreach (Event @event in @class.AllEvents().Where(eventPredicate))
+ {
+ sb.AppendXmlSummary(
+ $"Verify subscriptions on the {@event.Name} event of .");
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationEventResult<").Append(verifyName).Append("> ")
+ .Append(@event.Name).Append(" { get; }").AppendLine();
+ sb.AppendLine();
+ }
+
+ #endregion
+ }
+
+ private static void AppendMethodVerifyDefinition(StringBuilder sb, Method method, string verifyName,
+ bool useParameters, string? methodNameOverride = null, bool[]? valueFlags = null,
+ bool hasOverloadResolutionPriority = false)
+ {
+ // For methods with ref-struct parameters, skip Verify emission entirely. The
+ // VerificationResult pipeline takes IParameter? matchers that then feed into
+ // closures over the captured call values — incompatible with a ref-struct T. Callers
+ // fall back to reading `mock.Mock.Registry.Interactions.OfType()`
+ // for count-based verification. See brief's "verify count" guidance.
+ if (method.Parameters.Any(p => p.NeedsRefStructPipeline()))
+ {
+ return;
+ }
+
+ string methodName = methodNameOverride ?? method.Name;
+ sb.Append("\t\t/// ").AppendLine();
+ if (methodNameOverride is null)
+ {
+ sb.Append("\t\t/// Verify invocations for the method p.RefKind.GetString() + p.Type.Fullname.EscapeForXmlDoc())));
+ sb.Append(")\"/>");
+ }
+ else
+ {
+ sb.Append("\t\t/// Verify invocations for the delegate ");
+ }
+
+ sb.Append(method.Parameters.Count > 0 ? " with the given " : "");
+ if (useParameters)
+ {
+ sb.Append("");
+ }
+ else
+ {
+ sb.Append(string.Join(", ", method.Parameters.Select(p => $"")));
+ }
+
+ sb.Append(".").AppendLine();
+ sb.Append("\t\t/// ").AppendLine();
+ AppendOverloadDifferentiatorRemark(sb, method.Parameters.Select(p => p.Name).ToArray(), useParameters,
+ valueFlags, true);
+ if (valueFlags?.All(x => x) == true || (method.Parameters.Count == 0 && !useParameters))
+ {
+ if (hasOverloadResolutionPriority && method.Parameters.Count > 0 && valueFlags is not null &&
+ !ParametersBlockAllValuesPromotion(method.Parameters, valueFlags))
+ {
+ sb.Append("\t\t[global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)]")
+ .AppendLine();
+ }
+
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<").Append(verifyName)
+ .Append(">.IgnoreParameters ").Append(methodName).Append("(");
+ }
+ else
+ {
+ if (hasOverloadResolutionPriority)
+ {
+ sb.Append("\t\t[global::System.Runtime.CompilerServices.OverloadResolutionPriority(")
+ .Append(ComputeMethodOverloadPriority(useParameters, valueFlags, method.Parameters.Count))
+ .Append(")]").AppendLine();
+ }
+
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<").Append(verifyName).Append("> ")
+ .Append(methodName).Append("(");
+ }
+
+ if (useParameters)
+ {
+ sb.Append("global::Mockolate.Parameters.IParameters parameters");
+ }
+ else
+ {
+ ReadOnlySpan paramSpan = method.Parameters.AsSpan();
+ bool[] hasTrailingDefault = ComputeTrailingDefaults(paramSpan, valueFlags);
+
+ int i = 0;
+ foreach (MethodParameter parameter in method.Parameters)
+ {
+ if (i > 0)
+ {
+ sb.Append(", ");
+ }
+
+ bool isValueParam = valueFlags?[i] == true;
+ if (isValueParam)
+ {
+ sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name);
+ }
+ else
+ {
+ sb.AppendVerifyParameter(parameter);
+ if (parameter.CanUseNullableParameterOverload())
+ {
+ sb.Append('?');
+ }
+
+ sb.Append(' ').Append(parameter.Name);
+ if (hasTrailingDefault[i])
+ {
+ sb.Append(" = null");
+ }
+ }
+
+ i++;
+ }
+ }
+
+ sb.Append(")");
+ if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
+ {
+ foreach (GenericParameter gp in method.GenericParameters.Value)
+ {
+ gp.AppendWhereConstraint(sb, "\t\t\t");
+ }
+ }
+
+ sb.Append(";").AppendLine();
+ sb.AppendLine();
+ }
+
+#pragma warning disable S107 // Methods should not have too many parameters
+ private static void ImplementVerifyInterface(StringBuilder sb, Class @class, string mockRegistryName,
+ string verifyName, MemberType memberType, MemberIdTable memberIds, string memberIdPrefix,
+ bool useFastBuffers = true)
+#pragma warning restore S107
+ {
+ #region Properties
+
+ Func propertyPredicate = property
+ => property.ExplicitImplementation is null && property is { IsIndexer: false, } &&
+ property.MemberType == memberType;
+ foreach (Property property in @class.AllProperties().Where(propertyPredicate))
+ {
+ bool useFastForProperty = useFastBuffers && IsFastBufferEligibleProperty(property);
+ string propertyGetMemberId = useFastForProperty
+ ? memberIdPrefix + memberIds.GetPropertyGetIdentifier(property)
+ : "-1";
+ string propertySetMemberId = useFastForProperty
+ ? memberIdPrefix + memberIds.GetPropertySetIdentifier(property)
+ : "-1";
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append(
+ "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
+ .AppendLine();
sb.Append("\t\tglobal::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName).Append(", ")
- .Append(property.Type.Fullname).Append("> ").Append(property.Name).Append(" { get; }").AppendLine();
+ .Append(property.Type.Fullname).Append("> ").Append(verifyName).Append('.').Append(property.Name)
+ .AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tget").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\treturn new global::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName)
+ .Append(", ").Append(property.Type.Fullname).Append(">(this, this.").Append(mockRegistryName)
+ .Append(", ").Append(propertyGetMemberId).Append(", ").Append(propertySetMemberId).Append(", ")
+ .Append(property.GetUniqueNameString()).Append(");").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
sb.AppendLine();
}
@@ -5448,18 +5020,19 @@ private static void DefineVerifyInterface(StringBuilder sb, Class @class, string
#region Indexers
- Func indexerPredicate =
- indexer => indexer.ExplicitImplementation is null && indexer is { IsIndexer: true, } &&
- indexer.MemberType == memberType;
+ Func indexerPredicate = indexer
+ => indexer.ExplicitImplementation is null && indexer is { IsIndexer: true, IndexerParameters: not null, } &&
+ indexer.MemberType == memberType;
foreach (Property indexer in @class.AllProperties().Where(indexerPredicate))
{
- AppendIndexerVerifyDefinition(sb, indexer, verifyName,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds, memberIdPrefix,
+ useFastBuffers);
if (indexer.IndexerParameters!.Value.Count <= MaxExplicitParameters)
{
foreach (bool[] valueFlags in GenerateValueFlagCombinations(indexer.IndexerParameters.Value))
{
- AppendIndexerVerifyDefinition(sb, indexer, verifyName, valueFlags, hasOverloadResolutionPriority);
+ AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds,
+ memberIdPrefix, useFastBuffers, valueFlags);
}
}
else
@@ -5468,8 +5041,8 @@ private static void DefineVerifyInterface(StringBuilder sb, Class @class, string
.ToArray();
if (allValueFlags.Any(f => f))
{
- AppendIndexerVerifyDefinition(sb, indexer, verifyName, allValueFlags,
- hasOverloadResolutionPriority);
+ AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds,
+ memberIdPrefix, useFastBuffers, allValueFlags);
}
}
}
@@ -5480,532 +5053,710 @@ private static void DefineVerifyInterface(StringBuilder sb, Class @class, string
bool MethodPredicate(Method method)
{
- return method.ExplicitImplementation is null && method.MemberType == memberType;
+ return method.ExplicitImplementation is null && method.MemberType == memberType;
+ }
+
+ List> methodGroups =
+ @class.AllMethods().Where((Func)MethodPredicate).GroupBy(m => m.Name).ToList();
+ foreach (IGrouping? methodGroup in methodGroups)
+ {
+ if (methodGroup.Count() == 1)
+ {
+ Method? method = methodGroup.Single();
+ if (method.Parameters.Count > 0)
+ {
+ AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, true,
+ memberIds, memberIdPrefix, useFastBuffers);
+ }
+ }
+
+ foreach (Method? method in methodGroup)
+ {
+ if (method.Parameters.Count == 0)
+ {
+ AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
+ memberIds, memberIdPrefix, useFastBuffers);
+ }
+ else
+ {
+ AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
+ memberIds, memberIdPrefix, useFastBuffers);
+ if (method.Parameters.Count <= MaxExplicitParameters)
+ {
+ foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters))
+ {
+ AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
+ memberIds, memberIdPrefix, useFastBuffers, valueFlags: valueFlags);
+ }
+ }
+ else
+ {
+ bool[] allValueFlags = method.Parameters.Select(p => p.CanUseNullableParameterOverload())
+ .ToArray();
+ if (allValueFlags.Any(f => f))
+ {
+ AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
+ memberIds, memberIdPrefix, useFastBuffers, valueFlags: allValueFlags);
+ }
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Events
+
+ Func eventPredicate = @event => @event.ExplicitImplementation is null &&
+ @event.MemberType == memberType;
+ foreach (Event @event in @class.AllEvents().Where(eventPredicate))
+ {
+ bool useFastForEvent = useFastBuffers && IsFastBufferEligibleEvent(@event);
+ string subMemberId = useFastForEvent
+ ? memberIdPrefix + memberIds.GetEventSubscribeIdentifier(@event)
+ : "-1";
+ string unsubMemberId = useFastForEvent
+ ? memberIdPrefix + memberIds.GetEventUnsubscribeIdentifier(@event)
+ : "-1";
+ sb.AppendXmlSummary(
+ $"Verify subscriptions on the {@event.Name} event .");
+ sb.Append(
+ "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
+ .AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationEventResult<").Append(verifyName).Append("> ")
+ .Append(verifyName).Append('.').Append(@event.Name).AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tget").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\treturn new global::Mockolate.Verify.VerificationEventResult<").Append(verifyName)
+ .Append(">(this, this.").Append(mockRegistryName).Append(", ").Append(subMemberId).Append(", ")
+ .Append(unsubMemberId).Append(", ").Append(@event.GetUniqueNameString()).Append(");").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.AppendLine();
+ }
+
+ #endregion
+ }
+
+#pragma warning disable S107 // Methods should not have too many parameters
+ private static void AppendMethodVerifyImplementation(StringBuilder sb, Method method, string mockRegistryName,
+ string verifyName,
+ bool useParameters, MemberIdTable memberIds, string memberIdPrefix, bool useFastBuffers,
+ string? methodNameOverride = null, bool[]? valueFlags = null)
+#pragma warning restore S107
+ {
+ // Mirror the AppendMethodVerifyDefinition short-circuit for ref-struct signatures.
+ if (method.Parameters.Any(p => p.NeedsRefStructPipeline()))
+ {
+ return;
+ }
+
+ bool useFastForMethod = useFastBuffers && IsFastBufferEligibleMethod(method);
+ string methodMemberId = useFastForMethod
+ ? memberIdPrefix + memberIds.GetMethodIdentifier(method)
+ : "-1";
+ string methodName = methodNameOverride ?? method.Name;
+ sb.Append("\t\t/// ").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<");
+ sb.Append(verifyName).Append('>');
+ if (valueFlags?.All(x => x) == true || (method.Parameters.Count == 0 && !useParameters))
+ {
+ sb.Append(".IgnoreParameters");
+ }
+
+ sb.Append(' ').Append(verifyName).Append('.').Append(methodName).Append("(");
+ if (useParameters)
+ {
+ sb.Append("global::Mockolate.Parameters.IParameters parameters");
+ }
+ else
+ {
+ int i = 0;
+ foreach (MethodParameter parameter in method.Parameters)
+ {
+ if (i > 0)
+ {
+ sb.Append(", ");
+ }
+
+ bool isValueParam = valueFlags?[i] == true;
+ if (isValueParam)
+ {
+ sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name);
+ }
+ else
+ {
+ sb.AppendVerifyParameter(parameter);
+ if (parameter.CanUseNullableParameterOverload())
+ {
+ sb.Append('?');
+ }
+
+ sb.Append(' ').Append(parameter.Name);
+ }
+
+ i++;
+ }
+ }
+
+ sb.Append(")");
+ if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
+ {
+ foreach (GenericParameter gp in method.GenericParameters.Value)
+ {
+ gp.AppendWhereConstraint(sb, "\t\t\t", true, true);
+ }
+ }
+
+ sb.AppendLine();
+
+ bool canUseTypedVerify = useFastForMethod
+ && !useParameters
+ && method.Parameters.Count <= 4
+ && (method.GenericParameters is null || method.GenericParameters.Value.Count == 0)
+ && (valueFlags is null || !valueFlags.Any(x => x))
+ && !method.Parameters.Any(p
+ => p.RefKind == RefKind.Out || p.RefKind == RefKind.Ref ||
+ p.RefKind == RefKind.RefReadOnlyParameter);
+
+ if (canUseTypedVerify)
+ {
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".VerifyMethod<").Append(verifyName);
+ foreach (MethodParameter parameter in method.Parameters)
+ {
+ sb.Append(", ").Append(parameter.ToTypeOrWrapper());
+ }
+
+ sb.Append(">(this, ").Append(methodMemberId).Append(", ").Append(method.GetUniqueNameString());
+ foreach (MethodParameter parameter in method.Parameters)
+ {
+ string paramType = parameter.ToTypeOrWrapper();
+ sb.Append(", ").Append(parameter.Name).Append(" is null ? ")
+ .Append("(global::Mockolate.Parameters.IParameterMatch<").Append(paramType)
+ .Append(">)global::Mockolate.It.Is<").Append(paramType).Append(">(default!) : ")
+ .Append("CovariantParameterAdapter<").Append(paramType).Append(">.Wrap(").Append(parameter.Name)
+ .Append(")");
+ }
+
+ sb.Append(", () => $\"").Append(method.Name).Append("(")
+ .Append(string.Join(", ", method.Parameters.Select(p => $"{{{p.Name}}}"))).Append(")\");").AppendLine();
+ return;
+ }
+
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".VerifyMethod<").Append(verifyName)
+ .Append(", global::Mockolate.Interactions.MethodInvocation");
+ if (method.Parameters.Count > 0)
+ {
+ sb.Append("<").Append(string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper()))).Append(">");
+ }
+
+ sb.Append(">(this, ").Append(methodMemberId).Append(", ").Append(method.GetUniqueNameString());
+ if (useParameters)
+ {
+ sb.Append(", __i => parameters switch").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tglobal::Mockolate.Parameters.IParametersMatch m => m.Matches([")
+ .Append(string.Join(", ", Enumerable.Range(1, method.Parameters.Count).Select(i => $"__i.Parameter{i}")))
+ .Append("]),").AppendLine();
+ sb.Append("\t\t\t\t\tglobal::Mockolate.Parameters.INamedParametersMatch m => m.Matches([")
+ .Append(string.Join(", ", method.Parameters.Select((p, i) => $"(\"{p.Name}\", __i.Parameter{i + 1})")))
+ .Append("]),").AppendLine();
+ sb.Append("\t\t\t\t\t_ => true").AppendLine();
+ sb.Append("\t\t\t\t}");
+ }
+ else if (method.Parameters.Count == 0)
+ {
+ sb.Append(", __i => true");
}
-
- List> methodGroups =
- @class.AllMethods().Where((Func)MethodPredicate).GroupBy(m => m.Name).ToList();
- foreach (IGrouping? methodGroup in methodGroups)
+ else
{
- if (methodGroup.Count() == 1)
+ sb.Append(", __i => ");
+
+ int i = 0;
+ foreach (MethodParameter parameter in method.Parameters)
{
- Method? method = methodGroup.Single();
- if (method.Parameters.Count > 0)
+ if (i > 0)
{
- AppendMethodVerifyDefinition(sb, method, verifyName, true,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ sb.Append(" && ");
}
- }
- foreach (Method? method in methodGroup)
- {
- if (method.Parameters.Count == 0)
+ sb.AppendLine().Append("\t\t\t\t");
+
+ bool isValueParam = valueFlags?[i] == true;
+ if (isValueParam)
{
- AppendMethodVerifyDefinition(sb, method, verifyName, false,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
+ sb.Append(
+ $"(global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals({parameter.Name}, __i.Parameter{i + 1}))");
+ }
+ else if (parameter.RefKind == RefKind.Out || parameter.RefKind == RefKind.Ref ||
+ parameter.RefKind == RefKind.RefReadOnlyParameter)
+ {
+ // out/ref verify parameters use IVerifyOutParameter / IVerifyRefParameter, which don't inherit
+ // from IParameter — covariance isn't applicable, so keep the direct IParameterMatch check.
+ sb.Append(
+ $"({parameter.Name} is global::Mockolate.Parameters.IParameterMatch<{parameter.ToTypeOrWrapper()}> {parameter.Name}Match ? {parameter.Name}Match.Matches(__i.Parameter{i + 1}) : global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals(__i.Parameter{i + 1}, default({parameter.ToTypeOrWrapper()})))");
}
else
{
- AppendMethodVerifyDefinition(sb, method, verifyName, false,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
- if (method.Parameters.Count <= MaxExplicitParameters)
- {
- foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters))
- {
- AppendMethodVerifyDefinition(sb, method, verifyName, false, valueFlags: valueFlags,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
- }
- }
- else
- {
- bool[] allValueFlags = method.Parameters.Select(p => p.CanUseNullableParameterOverload())
- .ToArray();
- if (allValueFlags.Any(f => f))
- {
- AppendMethodVerifyDefinition(sb, method, verifyName, false, valueFlags: allValueFlags,
- hasOverloadResolutionPriority: hasOverloadResolutionPriority);
- }
- }
+ sb.Append(
+ $"({parameter.Name} is not null ? CovariantParameterAdapter<{parameter.ToTypeOrWrapper()}>.Wrap({parameter.Name}).Matches(__i.Parameter{i + 1}) : global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals(__i.Parameter{i + 1}, default({parameter.ToTypeOrWrapper()})))");
}
+
+ i++;
}
}
- #endregion
-
- #region Events
+ sb.Append(", () => $\"").Append(method.Name).Append("(")
+ .Append(useParameters ? "{parameters}" : string.Join(", ", method.Parameters.Select(p => $"{{{p.Name}}}")))
+ .Append(")\");").AppendLine();
+ }
- Func eventPredicate = @event => @event.ExplicitImplementation is null &&
- @event.MemberType == memberType;
- foreach (Event @event in @class.AllEvents().Where(eventPredicate))
- {
- sb.AppendXmlSummary(
- $"Verify subscriptions on the {@event.Name} event of .");
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationEventResult<").Append(verifyName).Append("> ")
- .Append(@event.Name).Append(" { get; }").AppendLine();
- sb.AppendLine();
- }
+ #endregion Verify Helpers
- #endregion
+ private static void AppendCreateFastInteractions(StringBuilder sb, string indent)
+ {
+ sb.Append(indent).Append("/// ").AppendLine();
+ sb.Append(indent).Append("/// Creates a sized to ").Append(" for use as the mock's interaction store.").AppendLine();
+ sb.Append(indent).Append("/// Per-member buffers are not allocated up-front: the recording hot paths call ").Append("").Append(" so a slot is materialized only when its member is first invoked.").AppendLine();
+ sb.Append(indent).Append("/// ").AppendLine();
+ sb.Append(indent).Append("internal static global::Mockolate.Interactions.FastMockInteractions CreateFastInteractions(global::Mockolate.MockBehavior behavior)").AppendLine();
+ sb.Append(indent).Append("\t=> new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);").AppendLine();
}
- private static void AppendMethodVerifyDefinition(StringBuilder sb, Method method, string verifyName,
- bool useParameters, string? methodNameOverride = null, bool[]? valueFlags = null,
- bool hasOverloadResolutionPriority = false)
+ ///
+ /// Emits the declarations of the cached MockolateSkipRecording flag and per-member typed
+ /// buffer fields. These mirror values that AppendCreateFastInteractions writes into the
+ /// FastMockInteractions.Buffers array so the body emitters can read them as plain field
+ /// accesses instead of paying the cast / array-index / property-chain on every invocation. Static
+ /// members stay on the legacy path because the cached field would not flow through
+ /// AsyncLocal-resolved registries.
+ ///
+ ///
+ /// when the class has at least one fast-eligible non-static indexer or
+ /// method, in which case the generator emits cached typed-buffer fields and a
+ /// MockolateSkipRecording flag that the recording hot paths read instead of paying the
+ /// per-call cast / array-index / property-chain.
+ ///
+ private static bool HasCachedBufferFields(Class @class)
{
- // For methods with ref-struct parameters, skip Verify emission entirely. The
- // VerificationResult pipeline takes IParameter? matchers that then feed into
- // closures over the captured call values — incompatible with a ref-struct T. Callers
- // fall back to reading `mock.Mock.Registry.Interactions.OfType()`
- // for count-based verification. See brief's "verify count" guidance.
- if (method.Parameters.Any(p => p.NeedsRefStructPipeline()))
+ foreach (Property property in @class.AllProperties())
{
- return;
+ if (property.IsIndexer && IsFastBufferEligibleIndexer(property))
+ {
+ return true;
+ }
}
- string methodName = methodNameOverride ?? method.Name;
- sb.Append("\t\t/// ").AppendLine();
- if (methodNameOverride is null)
- {
- sb.Append("\t\t/// Verify invocations for the method p.RefKind.GetString() + p.Type.Fullname.EscapeForXmlDoc())));
- sb.Append(")\"/>");
- }
- else
+ foreach (Method method in @class.AllMethods())
{
- sb.Append("\t\t/// Verify invocations for the delegate ");
+ if (!method.IsStatic && IsFastBufferEligibleMethod(method))
+ {
+ return true;
+ }
}
- sb.Append(method.Parameters.Count > 0 ? " with the given " : "");
- if (useParameters)
- {
- sb.Append("");
- }
- else
+ return false;
+ }
+
+ private static void AppendCachedFieldDeclarations(StringBuilder sb, string indent, Class @class,
+ MemberIdTable memberIds, string memberIdPrefix, string mockRegistryName)
+ {
+ if (!HasCachedBufferFields(@class))
{
- sb.Append(string.Join(", ", method.Parameters.Select(p => $"")));
+ return;
}
- sb.Append(".").AppendLine();
- sb.Append("\t\t/// ").AppendLine();
- AppendOverloadDifferentiatorRemark(sb, method.Parameters.Select(p => p.Name).ToArray(), useParameters,
- valueFlags, true);
- if (valueFlags?.All(x => x) == true || (method.Parameters.Count == 0 && !useParameters))
+ string mockRegistryRef = "this." + mockRegistryName;
+
+ foreach (Property indexer in @class.AllProperties().Where(p => p.IsIndexer))
{
- if (hasOverloadResolutionPriority && method.Parameters.Count > 0 && valueFlags is not null &&
- !ParametersBlockAllValuesPromotion(method.Parameters, valueFlags))
+ if (!IsFastBufferEligibleIndexer(indexer))
{
- sb.Append("\t\t[global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)]")
- .AppendLine();
+ continue;
}
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<").Append(verifyName)
- .Append(">.IgnoreParameters ").Append(methodName).Append("(");
+ string indexerKeyTypeArgs =
+ string.Join(", ", indexer.IndexerParameters!.Value.Select(p => p.ToTypeOrWrapper()));
+ string indexerValueType = indexer.Type.ToTypeOrWrapper();
+ string getMemberIdRef = memberIdPrefix + memberIds.GetIndexerGetIdentifier(indexer);
+ string setMemberIdRef = memberIdPrefix + memberIds.GetIndexerSetIdentifier(indexer);
+ string getterBufferType = "global::Mockolate.Interactions.FastIndexerGetterBuffer<"
+ + indexerKeyTypeArgs + ">";
+ string setterBufferType = "global::Mockolate.Interactions.FastIndexerSetterBuffer<"
+ + indexerKeyTypeArgs + ", " + indexerValueType + ">";
+
+ sb.Append(indent).Append("[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append(indent).Append("private ").Append(getterBufferType).Append(' ').Append(memberIds.GetIndexerGetterBufferFieldName(indexer)).AppendLine();
+ sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
+ .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(getterBufferType)
+ .Append(">(").Append(getMemberIdRef).Append(", static fast => new ").Append(getterBufferType)
+ .Append("(fast)));").AppendLine();
+
+ sb.Append(indent).Append("[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append(indent).Append("private ").Append(setterBufferType).Append(' ').Append(memberIds.GetIndexerSetterBufferFieldName(indexer)).AppendLine();
+ sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
+ .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(setterBufferType)
+ .Append(">(").Append(setMemberIdRef).Append(", static fast => new ").Append(setterBufferType)
+ .Append("(fast)));").AppendLine();
}
- else
+
+ foreach (Method method in @class.AllMethods())
{
- if (hasOverloadResolutionPriority)
+ if (method.IsStatic || !IsFastBufferEligibleMethod(method))
{
- sb.Append("\t\t[global::System.Runtime.CompilerServices.OverloadResolutionPriority(")
- .Append(ComputeMethodOverloadPriority(useParameters, valueFlags, method.Parameters.Count))
- .Append(")]").AppendLine();
+ continue;
}
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<").Append(verifyName).Append("> ")
- .Append(methodName).Append("(");
+ int arity = method.Parameters.Count;
+ string typeArgs = arity == 0
+ ? string.Empty
+ : "<" + string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper())) + ">";
+ string memberIdRef = memberIdPrefix + memberIds.GetMethodIdentifier(method);
+ string bufferType = "global::Mockolate.Interactions.FastMethod" + arity + "Buffer" + typeArgs;
+ sb.Append(indent).Append("[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append(indent).Append("private ").Append(bufferType).Append(' ').Append(memberIds.GetMethodBufferFieldName(method)).AppendLine();
+ sb.Append(indent).Append("\t=> field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)")
+ .Append(mockRegistryRef).Append(".Interactions).GetOrCreateBuffer<").Append(bufferType)
+ .Append(">(").Append(memberIdRef).Append(", static fast => new ").Append(bufferType)
+ .Append("(fast)));").AppendLine();
}
+ }
- if (useParameters)
+ ///
+ /// Properties get a typed per-member buffer when they are not static. Static property recordings stay on
+ /// the legacy RegisterInteraction path because their member id is shared across AsyncLocal
+ /// contexts whereas the buffer instance is stored on a single registry, so per-context isolation breaks.
+ ///
+ private static bool IsFastBufferEligibleProperty(Property property)
+ => !property.IsStatic;
+
+ ///
+ /// Indexers with up to four key parameters and a non-ref-struct signature get a typed per-member buffer.
+ ///
+ private static bool IsFastBufferEligibleIndexer(Property indexer)
+ {
+ if (indexer.IsStatic ||
+ indexer.IndexerParameters is null ||
+ indexer.IndexerParameters.Value.Count == 0 ||
+ indexer.IndexerParameters.Value.Count > 4)
{
- sb.Append("global::Mockolate.Parameters.IParameters parameters");
+ return false;
}
- else
+
+ foreach (MethodParameter parameter in indexer.IndexerParameters.Value)
{
- ReadOnlySpan paramSpan = method.Parameters.AsSpan();
- bool[] hasTrailingDefault = ComputeTrailingDefaults(paramSpan, valueFlags);
+ if (parameter.NeedsRefStructPipeline())
+ {
+ return false;
+ }
+ }
- int i = 0;
- foreach (MethodParameter parameter in method.Parameters)
+ return true;
+ }
+
+ ///
+ /// Events get a typed per-member buffer when they are not static (see
+ /// for the rationale).
+ ///
+ private static bool IsFastBufferEligibleEvent(Event @event)
+ => !@event.IsStatic;
+
+ ///
+ /// Methods with non-generic, non-ref-struct signatures get a typed per-member buffer; everything
+ /// else (open generics, ref-struct params) records via the legacy RegisterInteraction fallback.
+ ///
+ private static bool IsFastBufferEligibleMethod(Method method)
+ {
+ if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
+ {
+ return false;
+ }
+
+ foreach (MethodParameter parameter in method.Parameters)
+ {
+ if (parameter.NeedsRefStructPipeline())
{
- if (i > 0)
- {
- sb.Append(", ");
- }
+ return false;
+ }
+ }
- bool isValueParam = valueFlags?[i] == true;
- if (isValueParam)
- {
- sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name);
- }
- else
- {
- sb.AppendVerifyParameter(parameter);
- if (parameter.CanUseNullableParameterOverload())
- {
- sb.Append('?');
- }
+ return true;
+ }
- sb.Append(' ').Append(parameter.Name);
- if (hasTrailingDefault[i])
- {
- sb.Append(" = null");
- }
- }
+ ///
+ /// A T? return where T is one of the method's generic parameters and is
+ /// constrained to a reference type (or any other non-value-type constraint such as
+ /// class, class?, an interface, or notnull) cannot be expressed in
+ /// the explicit setup-interface implementation: CS0460 forbids restating the inherited
+ /// constraint, and where T : default (CS8822) conflicts with those constraints.
+ /// Without a constraint clause the compiler resolves the bare T? as
+ /// Nullable<T> and reports CS0453/CS9334/CS0738/CS0266.
+ /// The fix is to drop the trailing ? from the setup-side return type
+ /// (IReturnMethodSetup<T> instead of IReturnMethodSetup<T?>) and from
+ /// the matching ReturnMethodSetup<T> construction. NRT annotations are erased at
+ /// runtime, so the underlying setup object is identical and the fluent API still composes.
+ /// The user-facing mock body keeps T? because the constraint is visible there.
+ ///
+ private static bool ShouldStripNullableGenericReturnAnnotation(Method method)
+ {
+ if (method.GenericParameters is null || method.GenericParameters.Value.Count == 0)
+ {
+ return false;
+ }
- i++;
- }
+ string fullname = method.ReturnType.Fullname;
+ if (fullname.Length < 2 || fullname[fullname.Length - 1] != '?')
+ {
+ return false;
}
- sb.Append(")");
- if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
+ string raw = fullname.Substring(0, fullname.Length - 1);
+ foreach (GenericParameter gp in method.GenericParameters.Value)
{
- foreach (GenericParameter gp in method.GenericParameters.Value)
+ if (gp.Name == raw)
{
- gp.AppendWhereConstraint(sb, "\t\t\t");
+ return !gp.IsStruct && !gp.IsUnmanaged;
}
}
- sb.Append(";").AppendLine();
- sb.AppendLine();
+ return false;
}
-#pragma warning disable S107 // Methods should not have too many parameters
- private static void ImplementVerifyInterface(StringBuilder sb, Class @class, string mockRegistryName,
- string verifyName, MemberType memberType, MemberIdTable memberIds, string memberIdPrefix,
- bool useFastBuffers = true)
-#pragma warning restore S107
+ ///
+ /// Emits the method's return type as it should appear inside the setup-side surface
+ /// (the IReturnMethodSetup<...> wrapper on the setup interface, the explicit
+ /// impl, and the new ReturnMethodSetup<...> construction). Strips a trailing
+ /// ? when applies.
+ ///
+ private static void AppendSetupReturnType(StringBuilder sb, Method method)
{
- #region Properties
-
- Func propertyPredicate = property
- => property.ExplicitImplementation is null && property is { IsIndexer: false, } &&
- property.MemberType == memberType;
- foreach (Property property in @class.AllProperties().Where(propertyPredicate))
+ if (ShouldStripNullableGenericReturnAnnotation(method))
{
- bool useFastForProperty = useFastBuffers && IsFastBufferEligibleProperty(property);
- string propertyGetMemberId = useFastForProperty
- ? memberIdPrefix + memberIds.GetPropertyGetIdentifier(property)
- : "-1";
- string propertySetMemberId = useFastForProperty
- ? memberIdPrefix + memberIds.GetPropertySetIdentifier(property)
- : "-1";
- sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName).Append(", ")
- .Append(property.Type.Fullname).Append("> ").Append(verifyName).Append('.').Append(property.Name)
- .AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tget").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\treturn new global::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName)
- .Append(", ").Append(property.Type.Fullname).Append(">(this, this.").Append(mockRegistryName)
- .Append(", ").Append(propertyGetMemberId).Append(", ").Append(propertySetMemberId).Append(", ")
- .Append(property.GetUniqueNameString()).Append(");").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
+ string fullname = method.ReturnType.Fullname;
+ sb.Append(fullname, 0, fullname.Length - 1);
+ return;
}
- #endregion
+ sb.AppendTypeOrWrapper(method.ReturnType);
+ }
- #region Indexers
+ private static void AppendTypedCreateMockOverloads(StringBuilder sb, Class @class,
+ EquatableArray constructors, string setupType, string escapedClassName, string createMockReturns)
+ {
+ // Seeded signatures track the hand-written CreateMock overloads so typed overloads that
+ // would collide with them are skipped. The key order mirrors the emitted C# signature:
+ // "mockBehavior? | setup? | ctor-param-types...".
+ HashSet emittedSignatures = new(StringComparer.Ordinal)
+ {
+ string.Empty,
+ "global::Mockolate.MockBehavior",
+ $"global::System.Action<{setupType}>",
+ $"global::Mockolate.MockBehavior|global::System.Action<{setupType}>",
+ "object?[]",
+ "global::Mockolate.MockBehavior|object?[]",
+ $"global::System.Action<{setupType}>|object?[]",
+ $"global::Mockolate.MockBehavior|global::System.Action<{setupType}>|object?[]",
+ };
- Func indexerPredicate = indexer
- => indexer.ExplicitImplementation is null && indexer is { IsIndexer: true, IndexerParameters: not null, } &&
- indexer.MemberType == memberType;
- foreach (Property indexer in @class.AllProperties().Where(indexerPredicate))
+ foreach (Method constructor in constructors)
{
- AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds, memberIdPrefix,
- useFastBuffers);
- if (indexer.IndexerParameters!.Value.Count <= MaxExplicitParameters)
+ if (constructor.Parameters.Count == 0)
{
- foreach (bool[] valueFlags in GenerateValueFlagCombinations(indexer.IndexerParameters.Value))
- {
- AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds,
- memberIdPrefix, useFastBuffers, valueFlags);
- }
+ continue;
}
- else
+
+ if (constructor.Parameters.Any(p => p.RefKind != RefKind.None || p.IsParams))
{
- bool[] allValueFlags = indexer.IndexerParameters.Value.Select(p => p.CanUseNullableParameterOverload())
- .ToArray();
- if (allValueFlags.Any(f => f))
- {
- AppendIndexerVerifyImplementation(sb, indexer, mockRegistryName, verifyName, memberIds,
- memberIdPrefix, useFastBuffers, allValueFlags);
- }
+ continue;
}
- }
- #endregion
+ string mockBehaviorName = CreateUniqueParameterName(constructor.Parameters, "mockBehavior");
+ string setupName = CreateUniqueParameterName(constructor.Parameters, "setup");
+ string baseSig = string.Join("|",
+ constructor.Parameters.Select(p => p.Type.Fullname));
- #region Methods
+ TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
+ false, false, mockBehaviorName, setupName, baseSig,
+ emittedSignatures);
+ TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
+ true, false, mockBehaviorName, setupName, baseSig,
+ emittedSignatures);
+ TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
+ false, true, mockBehaviorName, setupName, baseSig,
+ emittedSignatures);
+ TryEmitTypedCreateMockOverload(sb, @class, constructor, setupType, escapedClassName, createMockReturns,
+ true, true, mockBehaviorName, setupName, baseSig,
+ emittedSignatures);
+ }
+ }
- bool MethodPredicate(Method method)
+ ///
+ /// Builds an XML-doc cref string and a matching short display text for the given
+ /// on . The cref has the form
+ /// {class-cref}({fully-qualified-param-types}); the display has the form
+ /// {simple-name}({short-param-types}), intended as the inner text of
+ /// <see cref="...">...</see> so the rendered prose reads
+ /// the MyClass(int) constructor.
+ /// Returns when no valid cref can be produced.
+ ///
+ ///
+ /// Generic classes are skipped because the cref type-parameter-list syntax (e.g. {T})
+ /// expects identifier tokens, not the concrete type arguments that closed generics carry —
+ /// emitting MyClass{int}(int) would surface CS1584/CS1658 on the consumer side.
+ ///
+ private static (string Cref, string Display)? BuildConstructorCref(Class @class, Method constructor)
+ {
+ string fullName = @class.ClassFullName;
+
+ if (fullName.IndexOf('<') >= 0)
{
- return method.ExplicitImplementation is null && method.MemberType == memberType;
+ return null;
}
- List> methodGroups =
- @class.AllMethods().Where((Func)MethodPredicate).GroupBy(m => m.Name).ToList();
- foreach (IGrouping? methodGroup in methodGroups)
- {
- if (methodGroup.Count() == 1)
- {
- Method? method = methodGroup.Single();
- if (method.Parameters.Count > 0)
- {
- AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, true,
- memberIds, memberIdPrefix, useFastBuffers);
- }
- }
+ int lastDot = fullName.LastIndexOf('.');
+ string simpleName = lastDot >= 0 ? fullName.Substring(lastDot + 1) : fullName;
- foreach (Method? method in methodGroup)
- {
- if (method.Parameters.Count == 0)
- {
- AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
- memberIds, memberIdPrefix, useFastBuffers);
- }
- else
- {
- AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
- memberIds, memberIdPrefix, useFastBuffers);
- if (method.Parameters.Count <= MaxExplicitParameters)
- {
- foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters))
- {
- AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
- memberIds, memberIdPrefix, useFastBuffers, valueFlags: valueFlags);
- }
- }
- else
- {
- bool[] allValueFlags = method.Parameters.Select(p => p.CanUseNullableParameterOverload())
- .ToArray();
- if (allValueFlags.Any(f => f))
- {
- AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false,
- memberIds, memberIdPrefix, useFastBuffers, valueFlags: allValueFlags);
- }
- }
- }
+ StringBuilder cref = new();
+ StringBuilder display = new();
+ cref.Append(fullName).Append('(');
+ display.Append(simpleName).Append('(');
+ bool first = true;
+ foreach (MethodParameter parameter in constructor.Parameters)
+ {
+ if (!first)
+ {
+ cref.Append(", ");
+ display.Append(", ");
}
- }
-
- #endregion
-
- #region Events
- Func eventPredicate = @event => @event.ExplicitImplementation is null &&
- @event.MemberType == memberType;
- foreach (Event @event in @class.AllEvents().Where(eventPredicate))
- {
- bool useFastForEvent = useFastBuffers && IsFastBufferEligibleEvent(@event);
- string subMemberId = useFastForEvent
- ? memberIdPrefix + memberIds.GetEventSubscribeIdentifier(@event)
- : "-1";
- string unsubMemberId = useFastForEvent
- ? memberIdPrefix + memberIds.GetEventUnsubscribeIdentifier(@event)
- : "-1";
- sb.AppendXmlSummary(
- $"Verify subscriptions on the {@event.Name} event .");
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationEventResult<").Append(verifyName).Append("> ")
- .Append(verifyName).Append('.').Append(@event.Name).AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tget").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\treturn new global::Mockolate.Verify.VerificationEventResult<").Append(verifyName)
- .Append(">(this, this.").Append(mockRegistryName).Append(", ").Append(subMemberId).Append(", ")
- .Append(unsubMemberId).Append(", ").Append(@event.GetUniqueNameString()).Append(");").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
+ first = false;
+ cref.Append(parameter.Type.Fullname.EscapeForXmlDoc());
+ // Inner text of is XML content, so escape '<'/'>' as entities
+ // (unlike cref attributes, which use the '{...}' shorthand).
+ display.Append(parameter.Type.DisplayName.Replace("<", "<").Replace(">", ">"));
}
- #endregion
+ cref.Append(')');
+ display.Append(')');
+ return (cref.ToString(), display.ToString());
}
#pragma warning disable S107 // Methods should not have too many parameters
- private static void AppendMethodVerifyImplementation(StringBuilder sb, Method method, string mockRegistryName,
- string verifyName,
- bool useParameters, MemberIdTable memberIds, string memberIdPrefix, bool useFastBuffers,
- string? methodNameOverride = null, bool[]? valueFlags = null)
-#pragma warning restore S107
+ private static void TryEmitTypedCreateMockOverload(StringBuilder sb, Class @class, Method constructor,
+ string setupType, string escapedClassName, string createMockReturns,
+ bool includeMockBehavior, bool includeSetup, string mockBehaviorName, string setupName, string baseSig,
+ HashSet emittedSignatures)
{
- // Mirror the AppendMethodVerifyDefinition short-circuit for ref-struct signatures.
- if (method.Parameters.Any(p => p.NeedsRefStructPipeline()))
+ // Build the signature key in the same order as the emitted method signature
+ // (mockBehavior, setup, then ctor parameters) so it correctly detects collisions against
+ // other typed overloads and against the hand-written seeded overloads.
+ string sig = baseSig;
+ if (includeSetup)
{
- return;
+ sig = $"global::System.Action<{setupType}>|{sig}";
}
- bool useFastForMethod = useFastBuffers && IsFastBufferEligibleMethod(method);
- string methodMemberId = useFastForMethod
- ? memberIdPrefix + memberIds.GetMethodIdentifier(method)
- : "-1";
- string methodName = methodNameOverride ?? method.Name;
- sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult<");
- sb.Append(verifyName).Append('>');
- if (valueFlags?.All(x => x) == true || (method.Parameters.Count == 0 && !useParameters))
+ if (includeMockBehavior)
{
- sb.Append(".IgnoreParameters");
+ sig = $"global::Mockolate.MockBehavior|{sig}";
}
- sb.Append(' ').Append(verifyName).Append('.').Append(methodName).Append("(");
- if (useParameters)
+ if (!emittedSignatures.Add(sig))
{
- sb.Append("global::Mockolate.Parameters.IParameters parameters");
+ return;
+ }
+
+ (string Cref, string Display)? constructorCref = BuildConstructorCref(@class, constructor);
+ string ctorPhrase = constructorCref is null
+ ? "the base-class constructor"
+ : $"the {constructorCref.Value.Display} constructor";
+
+ if (includeMockBehavior && includeSetup)
+ {
+ sb.AppendXmlSummary($"Creates a new mock of using the given , applying the given immediately, using the given constructor parameters to invoke {ctorPhrase}.");
+ sb.AppendXmlRemarks($"The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
+ }
+ else if (includeMockBehavior)
+ {
+ sb.AppendXmlSummary($"Creates a new mock of using the given and the given constructor parameters to invoke {ctorPhrase}.");
+ }
+ else if (includeSetup)
+ {
+ sb.AppendXmlSummary($"Creates a new mock of applying the given immediately, using the given constructor parameters to invoke {ctorPhrase}.");
+ sb.AppendXmlRemarks($"The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.");
}
else
{
- int i = 0;
- foreach (MethodParameter parameter in method.Parameters)
- {
- if (i > 0)
- {
- sb.Append(", ");
- }
+ sb.AppendXmlSummary($"Creates a new mock of using the given constructor parameters to invoke {ctorPhrase}.");
+ }
- bool isValueParam = valueFlags?[i] == true;
- if (isValueParam)
- {
- sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name);
- }
- else
- {
- sb.AppendVerifyParameter(parameter);
- if (parameter.CanUseNullableParameterOverload())
- {
- sb.Append('?');
- }
+ if (includeMockBehavior)
+ {
+ sb.AppendXmlParam(mockBehaviorName, "Controls how the mock responds when members are invoked without a matching setup; see .");
+ }
- sb.Append(' ').Append(parameter.Name);
- }
+ if (includeSetup)
+ {
+ sb.AppendXmlParam(setupName, "Callback that receives the mock's setup surface and registers initial setups before the mock is returned.");
+ }
- i++;
- }
+ foreach (MethodParameter parameter in constructor.Parameters)
+ {
+ sb.AppendXmlParam(parameter.Name, "Value forwarded to the base-class constructor.");
}
- sb.Append(")");
- if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0)
+ sb.AppendXmlReturns(createMockReturns);
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock(");
+ bool needsLeadingComma = false;
+ if (includeMockBehavior)
{
- foreach (GenericParameter gp in method.GenericParameters.Value)
- {
- gp.AppendWhereConstraint(sb, "\t\t\t", true, true);
- }
+ sb.Append("global::Mockolate.MockBehavior ").Append(mockBehaviorName);
+ needsLeadingComma = true;
}
- sb.AppendLine();
+ if (includeSetup)
+ {
+ if (needsLeadingComma)
+ {
+ sb.Append(", ");
+ }
- bool canUseTypedVerify = useFastForMethod
- && !useParameters
- && method.Parameters.Count <= 4
- && (method.GenericParameters is null || method.GenericParameters.Value.Count == 0)
- && (valueFlags is null || !valueFlags.Any(x => x))
- && !method.Parameters.Any(p
- => p.RefKind == RefKind.Out || p.RefKind == RefKind.Ref ||
- p.RefKind == RefKind.RefReadOnlyParameter);
+ sb.Append("global::System.Action<").Append(setupType).Append("> ").Append(setupName);
+ needsLeadingComma = true;
+ }
- if (canUseTypedVerify)
+ foreach (MethodParameter parameter in constructor.Parameters)
{
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".VerifyMethod<").Append(verifyName);
- foreach (MethodParameter parameter in method.Parameters)
+ if (needsLeadingComma)
{
- sb.Append(", ").Append(parameter.ToTypeOrWrapper());
+ sb.Append(", ");
}
- sb.Append(">(this, ").Append(methodMemberId).Append(", ").Append(method.GetUniqueNameString());
- foreach (MethodParameter parameter in method.Parameters)
+ needsLeadingComma = true;
+ sb.Append(parameter.Type.Fullname).Append(' ').Append(parameter.Name);
+ if (parameter.HasExplicitDefaultValue)
{
- string paramType = parameter.ToTypeOrWrapper();
- sb.Append(", ").Append(parameter.Name).Append(" is null ? ")
- .Append("(global::Mockolate.Parameters.IParameterMatch<").Append(paramType)
- .Append(">)global::Mockolate.It.Is<").Append(paramType).Append(">(default!) : ")
- .Append("CovariantParameterAdapter<").Append(paramType).Append(">.Wrap(").Append(parameter.Name)
- .Append(")");
+ sb.Append(" = ").Append(parameter.ExplicitDefaultValue);
}
-
- sb.Append(", () => $\"").Append(method.Name).Append("(")
- .Append(string.Join(", ", method.Parameters.Select(p => $"{{{p.Name}}}"))).Append(")\");").AppendLine();
- return;
- }
-
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".VerifyMethod<").Append(verifyName)
- .Append(", global::Mockolate.Interactions.MethodInvocation");
- if (method.Parameters.Count > 0)
- {
- sb.Append("<").Append(string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper()))).Append(">");
}
- sb.Append(">(this, ").Append(methodMemberId).Append(", ").Append(method.GetUniqueNameString());
- if (useParameters)
- {
- sb.Append(", __i => parameters switch").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tglobal::Mockolate.Parameters.IParametersMatch m => m.Matches([")
- .Append(string.Join(", ", Enumerable.Range(1, method.Parameters.Count).Select(i => $"__i.Parameter{i}")))
- .Append("]),").AppendLine();
- sb.Append("\t\t\t\t\tglobal::Mockolate.Parameters.INamedParametersMatch m => m.Matches([")
- .Append(string.Join(", ", method.Parameters.Select((p, i) => $"(\"{p.Name}\", __i.Parameter{i + 1})")))
- .Append("]),").AppendLine();
- sb.Append("\t\t\t\t\t_ => true").AppendLine();
- sb.Append("\t\t\t\t}");
- }
- else if (method.Parameters.Count == 0)
- {
- sb.Append(", __i => true");
- }
- else
+ sb.Append(")").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(").Append(includeMockBehavior ? mockBehaviorName : "null").Append(", ")
+ .Append(includeSetup ? setupName : "null").Append(", new object?[] { ");
+ int argIndex = 0;
+ foreach (MethodParameter parameter in constructor.Parameters)
{
- sb.Append(", __i => ");
-
- int i = 0;
- foreach (MethodParameter parameter in method.Parameters)
+ if (argIndex++ > 0)
{
- if (i > 0)
- {
- sb.Append(" && ");
- }
-
- sb.AppendLine().Append("\t\t\t\t");
-
- bool isValueParam = valueFlags?[i] == true;
- if (isValueParam)
- {
- sb.Append(
- $"(global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals({parameter.Name}, __i.Parameter{i + 1}))");
- }
- else if (parameter.RefKind == RefKind.Out || parameter.RefKind == RefKind.Ref ||
- parameter.RefKind == RefKind.RefReadOnlyParameter)
- {
- // out/ref verify parameters use IVerifyOutParameter / IVerifyRefParameter, which don't inherit
- // from IParameter — covariance isn't applicable, so keep the direct IParameterMatch check.
- sb.Append(
- $"({parameter.Name} is global::Mockolate.Parameters.IParameterMatch<{parameter.ToTypeOrWrapper()}> {parameter.Name}Match ? {parameter.Name}Match.Matches(__i.Parameter{i + 1}) : global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals(__i.Parameter{i + 1}, default({parameter.ToTypeOrWrapper()})))");
- }
- else
- {
- sb.Append(
- $"({parameter.Name} is not null ? CovariantParameterAdapter<{parameter.ToTypeOrWrapper()}>.Wrap({parameter.Name}).Matches(__i.Parameter{i + 1}) : global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals(__i.Parameter{i + 1}, default({parameter.ToTypeOrWrapper()})))");
- }
-
- i++;
+ sb.Append(", ");
}
+
+ sb.Append(parameter.Name);
}
- sb.Append(", () => $\"").Append(method.Name).Append("(")
- .Append(useParameters ? "{parameters}" : string.Join(", ", method.Parameters.Select(p => $"{{{p.Name}}}")))
- .Append(")\");").AppendLine();
+ sb.Append(" });").AppendLine();
+ sb.AppendLine();
}
-
- #endregion Verify Helpers
+#pragma warning restore S107 // Methods should not have too many parameters
}
diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockCombination.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockCombination.cs
index 7200a415..00476aa8 100644
--- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockCombination.cs
+++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockCombination.cs
@@ -44,182 +44,13 @@ public static string MockCombinationClass(
sb.Append("namespace Mockolate;").AppendLine();
sb.AppendLine();
- #region Extensions
-
- sb.AppendXmlSummary($"Mock extensions for that also implements
\n/// - {string.Join("
\n/// - ", additionalInterfaces.Select(x => $""))}.", "");
-#if !DEBUG
- sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
-#endif
- sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("internal static partial class MockExtensionsFor").Append(fileName).AppendLine();
- sb.Append("{").AppendLine();
-
- #region Implementing
-
- (string Name, Class Class) lastInterface = additionalInterfaces[additionalInterfaces.Length - 1];
- sb.AppendXmlSummary($"Extends this mock so the returned instance also implements .");
- sb.AppendXmlRemarks([
- $"The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to to exercise the extra surface or use .Mock.As<{lastInterface.Class.ClassName}>() to reach the Setup/Verify surface of the additional interface.",
- ]);
- sb.AppendXmlParam("sut", "The mock instance to extend.");
- sb.AppendXmlParam("setups", "Optional setup callbacks registered on the additional interface before the mock is returned.");
- sb.AppendXmlReturns($"A mock of the original type that additionally implements .");
- sb.Append("\tpublic static ").Append(@class.ClassFullName).Append(" Implementing(this ").Append(@class.ClassFullName).Append(" sut, params global::System.Action[] setups)").AppendLine();
- sb.Append("\t\twhere TInterface : ").Append(lastInterface.Class.ClassFullName).AppendLine();
- sb.Append("\t{").AppendLine();
- sb.Append("\t\tif (sut is not global::Mockolate.IMock mock)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Mock.").Append(fileName).Append(" value;").AppendLine();
-
- bool useTryCast = false;
- bool useTryCastWithDefaultValue = false;
- if (!@class.IsInterface && constructors?.Count > 0)
- {
- sb.Append("\t\tif (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- if (constructors.Value.Any(m => m.Parameters.Count == 0))
- {
- sb.Append("\t\t\tvalue = new global::Mockolate.Mock.").Append(fileName).Append("(mock.MockRegistry);").AppendLine();
- }
- else
- {
- sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"No parameterless constructor found for '").Append(@class.DisplayString).Append("'. Please provide constructor parameters.\");").AppendLine();
- }
-
- sb.Append("\t\t}").AppendLine();
- int constructorIndex = 0;
- foreach (EquatableArray constructorParameters in constructors.Value
- .Select(constructor => constructor.Parameters))
- {
- constructorIndex++;
- int requiredParameters = constructorParameters.Count(c => !c.HasExplicitDefaultValue);
- if (requiredParameters < constructorParameters.Count)
- {
- sb.Append("\t\telse if (mock.MockRegistry.ConstructorParameters.Length >= ")
- .Append(requiredParameters).Append(" && mock.MockRegistry.ConstructorParameters.Length <= ")
- .Append(constructorParameters.Count);
- }
- else
- {
- sb.Append("\t\telse if (mock.MockRegistry.ConstructorParameters.Length == ")
- .Append(constructorParameters.Count);
- }
-
- int constructorParameterIndex = 0;
- foreach (MethodParameter parameter in constructorParameters)
- {
- useTryCast = useTryCast || !parameter.HasExplicitDefaultValue;
- useTryCastWithDefaultValue = useTryCastWithDefaultValue || parameter.HasExplicitDefaultValue;
- sb.AppendLine().Append("\t\t && ")
- .Append(parameter.HasExplicitDefaultValue ? "TryCastWithDefaultValue" : "TryCast")
- .Append("(mock.MockRegistry.ConstructorParameters, ")
- .Append(constructorParameterIndex++)
- .Append(parameter.HasExplicitDefaultValue ? $", {parameter.ExplicitDefaultValue}" : "")
- .Append(", mock.MockRegistry.Behavior, out ").Append(parameter.Type.Fullname).Append(" c")
- .Append(constructorIndex)
- .Append('p')
- .Append(constructorParameterIndex).Append(")");
- }
-
- sb.Append(")").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tvalue = new global::Mockolate.Mock.").Append(fileName)
- .Append("(mock.MockRegistry");
- for (int j = 1; j <= constructorParameters.Count; j++)
- {
- sb.Append(", ").Append('c').Append(constructorIndex).Append('p').Append(j);
- }
-
- sb.Append(");").AppendLine();
- sb.Append("\t\t}").AppendLine();
- }
-
- sb.Append("\t\telse").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append(
- "\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Could not find any constructor for '")
- .Append(@class.DisplayString).Append("' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(\", \", mock.MockRegistry.ConstructorParameters)}).\");")
- .AppendLine();
- sb.Append("\t\t}").AppendLine();
- }
- else
- {
- sb.Append("\t\tvalue = new global::Mockolate.Mock.").Append(fileName).Append("(mock.MockRegistry);").AppendLine();
- }
-
- sb.Append("\t\tIMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior;").AppendLine();
- sb.Append("\t\tif (mockBehaviorAccess.TryGet[]?>(out var additionalSetups))").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tif (setups.Length > 0)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tvar concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length];").AppendLine();
- sb.Append("\t\t\t\tadditionalSetups.CopyTo(concatenatedSetups, 0);").AppendLine();
- sb.Append("\t\t\t\tsetups.CopyTo(concatenatedSetups, additionalSetups.Length);").AppendLine();
- sb.Append("\t\t\t\tsetups = concatenatedSetups;").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t\telse").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tsetups = additionalSetups;").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.Append("\t\tif (setups.Length > 0)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tforeach (var setup in setups)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tsetup.Invoke(value);").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.Append("\t\treturn value;").AppendLine();
- if (useTryCast)
- {
- sb.Append("""
- static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
- {
- var value = values[index];
- if (value is TValue typedValue)
- {
- result = typedValue;
- return true;
- }
-
- result = default!;
- return value is null;
- }
- """).AppendLine();
- }
-
- if (useTryCastWithDefaultValue)
- {
- sb.Append("""
- static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
- {
- if (values.Length > index && values[index] is TValue typedValue)
- {
- result = typedValue;
- return true;
- }
-
- result = defaultValue;
- return true;
- }
- """).AppendLine();
- }
-
- sb.Append("\t}").AppendLine();
-
- #endregion Implementing
-
- sb.Append("}").AppendLine();
- sb.AppendLine();
-
- #endregion Extensions
-
- #region MockForXXX
+ #region Mock
sb.Append("internal static partial class Mock").AppendLine();
sb.Append("{").AppendLine();
+
+ #region MockForXXX
+
sb.AppendXmlSummary($"A mock implementation for that also implements
\n\t/// - {string.Join("
\n\t/// - ", additionalInterfaces.Select(x => $""))}.", "\t");
sb.Append("\t[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]").AppendLine();
#if !DEBUG
@@ -341,8 +172,7 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
else
{
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tpublic ").Append(fileName).Append("(global::Mockolate.MockRegistry mockRegistry)")
- .AppendLine();
+ sb.Append("\t\tpublic ").Append(fileName).Append("(global::Mockolate.MockRegistry mockRegistry)").AppendLine();
sb.Append("\t\t{").AppendLine();
sb.Append("\t\t\tthis.").Append(mockRegistryName).Append(" = mockRegistry;").AppendLine();
if (hasAnyStaticMembers || hasAnyStaticEvents)
@@ -356,35 +186,37 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
Dictionary signatureIndices = new();
int[] nextSignatureIndex = [0,];
+
// Combined mocks reuse the base mock's MockRegistry (and thus its FastMockInteractions sized
// to the base MemberCount). Combined member ids would index past those buffers, so emit the
// legacy RegisterInteraction path instead — recordings still flow through FastMockInteractions'
// fallback buffer and remain shared with the base mock.
- AppendMockSubject_ImplementClass(sb, @class, mockRegistryName, null, memberIds, memberIdPrefix,
- signatureIndices, nextSignatureIndex, false);
+ AppendMockSubject_ImplementClass(sb, @class, mockRegistryName, null, memberIds, memberIdPrefix, signatureIndices, nextSignatureIndex, false);
+
foreach ((string Name, Class Class) item in additionalInterfaces)
{
sb.AppendLine();
- AppendMockSubject_ImplementClass(sb, item.Class, mockRegistryName, @class as MockClass,
- memberIds, memberIdPrefix, signatureIndices, nextSignatureIndex, false);
+ AppendMockSubject_ImplementClass(sb, item.Class, mockRegistryName, @class as MockClass, memberIds, memberIdPrefix, signatureIndices, nextSignatureIndex, false);
}
sb.AppendLine();
- #region IMockSetupForXXX
+ #region Setup implementations
sb.Append("\t\t#region IMockSetupFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public,
- memberIds, memberIdPrefix);
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockSetupFor{name}", MemberType.Public, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockSetupFor").Append(name).AppendLine();
if (hasProtectedMembers)
{
sb.AppendLine();
sb.Append("\t\t#region IMockProtectedSetupFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected,
- memberIds, memberIdPrefix);
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockProtectedSetupFor{name}", MemberType.Protected, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockProtectedSetupFor").Append(name).AppendLine();
}
@@ -393,8 +225,9 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockStaticSetupFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockStaticSetupFor{name}", MemberType.Static,
- memberIds, memberIdPrefix);
+
+ ImplementSetupInterface(sb, @class, mockRegistryName, $"IMockStaticSetupFor{name}", MemberType.Static, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockStaticSetupFor").Append(name).AppendLine();
}
@@ -403,8 +236,9 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockSetupFor").Append(item.Name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, item.Class, mockRegistryName, $"IMockSetupFor{item.Name}", MemberType.Public,
- memberIds, memberIdPrefix);
+
+ ImplementSetupInterface(sb, item.Class, mockRegistryName, $"IMockSetupFor{item.Name}", MemberType.Public, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockSetupFor").Append(item.Name).AppendLine();
if (item.Class.AllMethods().Any(x => x.IsStatic) || item.Class.AllProperties().Any(x => x.IsStatic))
@@ -412,51 +246,50 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockStaticSetupFor").Append(item.Name).AppendLine();
sb.AppendLine();
- ImplementSetupInterface(sb, item.Class, mockRegistryName, $"IMockStaticSetupFor{item.Name}", MemberType.Static,
- memberIds, memberIdPrefix);
+
+ ImplementSetupInterface(sb, item.Class, mockRegistryName, $"IMockStaticSetupFor{item.Name}", MemberType.Static, memberIds, memberIdPrefix);
+
sb.Append("\t\t#endregion IMockStaticSetupFor").Append(item.Name).AppendLine();
}
}
- #endregion IMockSetupForXXX
+ #endregion Setup implementations
- #region IMockRaiseOnXXX
+ #region Raise implementations
if (hasEvents)
{
sb.AppendLine();
sb.Append("\t\t#region IMockRaiseOn").Append(name).AppendLine();
sb.AppendLine();
+
ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockRaiseOn{name}", MemberType.Public);
+
sb.Append("\t\t#endregion IMockRaiseOn").Append(name).AppendLine();
}
if (hasProtectedEvents)
{
- #region IMockProtectedRaiseOnXXX
-
sb.AppendLine();
sb.Append("\t\t#region IMockProtectedRaiseOn").Append(name).AppendLine();
sb.AppendLine();
+
ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockProtectedRaiseOn{name}", MemberType.Protected);
+
sb.Append("\t\t#endregion IMockProtectedRaiseOn").Append(name).AppendLine();
-
- #endregion IMockProtectedRaiseOnXXX
}
if (hasStaticEvents)
{
- #region IMockStaticRaiseOnXXX
-
sb.AppendLine();
sb.Append("\t\t#region IMockStaticRaiseOn").Append(name).AppendLine();
sb.AppendLine();
+
ImplementRaiseInterface(sb, @class, mockRegistryName, $"IMockStaticRaiseOn{name}", MemberType.Static);
+
sb.Append("\t\t#endregion IMockStaticRaiseOn").Append(name).AppendLine();
-
- #endregion IMockStaticRaiseOnXXX
}
-#pragma warning disable S3267 // Loops should be simplified using the "Where" LINQ method
+
foreach ((string Name, Class Class) item in additionalInterfaces)
{
if (item.Class.AllEvents().Any(x => !x.IsStatic))
@@ -464,7 +297,9 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockRaiseOn").Append(item.Name).AppendLine();
sb.AppendLine();
+
ImplementRaiseInterface(sb, item.Class, mockRegistryName, $"IMockRaiseOn{item.Name}", MemberType.Public);
+
sb.Append("\t\t#endregion IMockRaiseOn").Append(item.Name).AppendLine();
}
@@ -473,15 +308,16 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockStaticRaiseOn").Append(item.Name).AppendLine();
sb.AppendLine();
+
ImplementRaiseInterface(sb, item.Class, mockRegistryName, $"IMockStaticRaiseOn{item.Name}", MemberType.Static);
+
sb.Append("\t\t#endregion IMockStaticRaiseOn").Append(item.Name).AppendLine();
}
}
-#pragma warning restore S3267 // Loops should be simplified using the "Where" LINQ method
- #endregion IMockRaiseOnXXX
+ #endregion Raise implementations
- #region IMockVerifyForXXX
+ #region Verify implementation
sb.AppendLine();
sb.Append("\t\t#region IMockVerifyFor").Append(name).AppendLine();
@@ -491,16 +327,16 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
// memberIds enumerate a different (typically larger) set, so they cannot be used to fetch the
// base buffers — emit the slow Verify path here instead. Recordings flow through the
// FastMockInteractions fallback buffer (see AppendMockSubject_ImplementClass useFastBuffers: false).
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public,
- memberIds, memberIdPrefix, false);
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockVerifyFor{name}", MemberType.Public, memberIds, memberIdPrefix, false);
sb.Append("\t\t#endregion IMockVerifyFor").Append(name).AppendLine();
if (hasProtectedMembers || hasProtectedEvents)
{
sb.AppendLine();
sb.Append("\t\t#region IMockProtectedVerifyFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockProtectedVerifyFor{name}",
- MemberType.Protected, memberIds, memberIdPrefix, false);
+
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockProtectedVerifyFor{name}", MemberType.Protected, memberIds, memberIdPrefix, false);
+
sb.Append("\t\t#endregion IMockProtectedVerifyFor").Append(name).AppendLine();
}
@@ -509,8 +345,9 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockStaticVerifyFor").Append(name).AppendLine();
sb.AppendLine();
- ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockStaticVerifyFor{name}", MemberType.Static,
- memberIds, memberIdPrefix, false);
+
+ ImplementVerifyInterface(sb, @class, mockRegistryName, $"IMockStaticVerifyFor{name}", MemberType.Static, memberIds, memberIdPrefix, false);
+
sb.Append("\t\t#endregion IMockStaticVerifyFor").Append(name).AppendLine();
}
@@ -519,8 +356,9 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockVerifyFor").Append(item.Name).AppendLine();
sb.AppendLine();
- ImplementVerifyInterface(sb, item.Class, mockRegistryName, $"IMockVerifyFor{item.Name}", MemberType.Public,
- memberIds, memberIdPrefix, false);
+
+ ImplementVerifyInterface(sb, item.Class, mockRegistryName, $"IMockVerifyFor{item.Name}", MemberType.Public, memberIds, memberIdPrefix, false);
+
sb.Append("\t\t#endregion IMockVerifyFor").Append(item.Name).AppendLine();
if (item.Class.AllMethods().Any(x => x.IsStatic) || item.Class.AllProperties().Any(x => x.IsStatic) ||
@@ -529,20 +367,190 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue
sb.AppendLine();
sb.Append("\t\t#region IMockStaticVerifyFor").Append(item.Name).AppendLine();
sb.AppendLine();
- ImplementVerifyInterface(sb, item.Class, mockRegistryName, $"IMockStaticVerifyFor{item.Name}", MemberType.Static,
- memberIds, memberIdPrefix, false);
+
+ ImplementVerifyInterface(sb, item.Class, mockRegistryName, $"IMockStaticVerifyFor{item.Name}", MemberType.Static, memberIds, memberIdPrefix, false);
+
sb.Append("\t\t#endregion IMockStaticVerifyFor").Append(item.Name).AppendLine();
}
}
- #endregion IMockVerifyForXXX
+ #endregion Verify implementation
sb.AppendLine("\t}");
-
+
#endregion MockForXXX
+
+ sb.Append("}").AppendLine();
+ sb.AppendLine();
+
+ #endregion Mock
+
+ #region Extensions
+
+ sb.AppendXmlSummary($"Mock extensions for that also implements
\n/// - {string.Join("
\n/// - ", additionalInterfaces.Select(x => $""))}.", "");
+#if !DEBUG
+ sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
+#endif
+ sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
+ sb.Append("internal static partial class MockExtensionsFor").Append(fileName).AppendLine();
+ sb.Append("{").AppendLine();
+
+ #region Implementing
+
+ (string Name, Class Class) lastInterface = additionalInterfaces[additionalInterfaces.Length - 1];
+ sb.AppendXmlSummary($"Extends this mock so the returned instance also implements .");
+ sb.AppendXmlRemarks([$"The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to to exercise the extra surface or use .Mock.As<{lastInterface.Class.ClassName}>() to reach the Setup/Verify surface of the additional interface.",]);
+ sb.AppendXmlParam("sut", "The mock instance to extend.");
+ sb.AppendXmlParam("setups", "Optional setup callbacks registered on the additional interface before the mock is returned.");
+ sb.AppendXmlReturns($"A mock of the original type that additionally implements .");
+ sb.Append("\tpublic static ").Append(@class.ClassFullName).Append(" Implementing(this ").Append(@class.ClassFullName).Append(" sut, params global::System.Action[] setups)").AppendLine();
+ sb.Append("\t\twhere TInterface : ").Append(lastInterface.Class.ClassFullName).AppendLine();
+ sb.Append("\t{").AppendLine();
+ sb.Append("\t\tif (sut is not global::Mockolate.IMock mock)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Mock.").Append(fileName).Append(" value;").AppendLine();
+
+ bool useTryCast = false;
+ bool useTryCastWithDefaultValue = false;
+ if (!@class.IsInterface && constructors?.Count > 0)
+ {
+ sb.Append("\t\tif (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ if (constructors.Value.Any(m => m.Parameters.Count == 0))
+ {
+ sb.Append("\t\t\tvalue = new global::Mockolate.Mock.").Append(fileName).Append("(mock.MockRegistry);").AppendLine();
+ }
+ else
+ {
+ sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"No parameterless constructor found for '").Append(@class.DisplayString).Append("'. Please provide constructor parameters.\");").AppendLine();
+ }
+
+ sb.Append("\t\t}").AppendLine();
+ int constructorIndex = 0;
+ foreach (EquatableArray constructorParameters in constructors.Value
+ .Select(constructor => constructor.Parameters))
+ {
+ constructorIndex++;
+ int requiredParameters = constructorParameters.Count(c => !c.HasExplicitDefaultValue);
+ if (requiredParameters < constructorParameters.Count)
+ {
+ sb.Append("\t\telse if (mock.MockRegistry.ConstructorParameters.Length >= ")
+ .Append(requiredParameters).Append(" && mock.MockRegistry.ConstructorParameters.Length <= ")
+ .Append(constructorParameters.Count);
+ }
+ else
+ {
+ sb.Append("\t\telse if (mock.MockRegistry.ConstructorParameters.Length == ")
+ .Append(constructorParameters.Count);
+ }
+
+ int constructorParameterIndex = 0;
+ foreach (MethodParameter parameter in constructorParameters)
+ {
+ useTryCast = useTryCast || !parameter.HasExplicitDefaultValue;
+ useTryCastWithDefaultValue = useTryCastWithDefaultValue || parameter.HasExplicitDefaultValue;
+ sb.AppendLine().Append("\t\t && ")
+ .Append(parameter.HasExplicitDefaultValue ? "TryCastWithDefaultValue" : "TryCast")
+ .Append("(mock.MockRegistry.ConstructorParameters, ")
+ .Append(constructorParameterIndex++)
+ .Append(parameter.HasExplicitDefaultValue ? $", {parameter.ExplicitDefaultValue}" : "")
+ .Append(", mock.MockRegistry.Behavior, out ").Append(parameter.Type.Fullname).Append(" c")
+ .Append(constructorIndex)
+ .Append('p')
+ .Append(constructorParameterIndex).Append(")");
+ }
+
+ sb.Append(")").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tvalue = new global::Mockolate.Mock.").Append(fileName).Append("(mock.MockRegistry");
+ for (int j = 1; j <= constructorParameters.Count; j++)
+ {
+ sb.Append(", ").Append('c').Append(constructorIndex).Append('p').Append(j);
+ }
+
+ sb.Append(");").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ }
+
+ sb.Append("\t\telse").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tthrow new global::Mockolate.Exceptions.MockException($\"Could not find any constructor for '").Append(@class.DisplayString).Append("' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(\", \", mock.MockRegistry.ConstructorParameters)}).\");").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ }
+ else
+ {
+ sb.Append("\t\tvalue = new global::Mockolate.Mock.").Append(fileName).Append("(mock.MockRegistry);").AppendLine();
+ }
+
+ sb.Append("\t\tIMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior;").AppendLine();
+ sb.Append("\t\tif (mockBehaviorAccess.TryGet[]?>(out var additionalSetups))").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tif (setups.Length > 0)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tvar concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length];").AppendLine();
+ sb.Append("\t\t\t\tadditionalSetups.CopyTo(concatenatedSetups, 0);").AppendLine();
+ sb.Append("\t\t\t\tsetups.CopyTo(concatenatedSetups, additionalSetups.Length);").AppendLine();
+ sb.Append("\t\t\t\tsetups = concatenatedSetups;").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\telse").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tsetups = additionalSetups;").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.Append("\t\tif (setups.Length > 0)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tforeach (var setup in setups)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tsetup.Invoke(value);").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.Append("\t\treturn value;").AppendLine();
+ if (useTryCast)
+ {
+ sb.Append("""
+ static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
+ {
+ var value = values[index];
+ if (value is TValue typedValue)
+ {
+ result = typedValue;
+ return true;
+ }
+
+ result = default!;
+ return value is null;
+ }
+ """).AppendLine();
+ }
+
+ if (useTryCastWithDefaultValue)
+ {
+ sb.Append("""
+ static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
+ {
+ if (values.Length > index && values[index] is TValue typedValue)
+ {
+ result = typedValue;
+ return true;
+ }
+
+ result = defaultValue;
+ return true;
+ }
+ """).AppendLine();
+ }
+
+ sb.Append("\t}").AppendLine();
+
+ #endregion Implementing
sb.Append("}").AppendLine();
sb.AppendLine();
+
+ #endregion Extensions
+
sb.AppendLine("#nullable disable annotations");
return sb.ToString();
}
diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockDelegate.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockDelegate.cs
index c91a7822..6d053ee9 100644
--- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockDelegate.cs
+++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockDelegate.cs
@@ -19,101 +19,17 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.Append("namespace Mockolate;").AppendLine();
sb.AppendLine();
- #region MockForXXXExtensions
+ #region Mock
- sb.AppendXmlSummary($"Mock extensions for .", "");
-#if !DEBUG
- sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
-#endif
- sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("internal static partial class MockExtensionsFor").Append(name).AppendLine();
+ sb.Append("internal static partial class Mock").AppendLine();
sb.Append("{").AppendLine();
-
- sb.Append("\t/// ").AppendLine();
- sb.Append("\textension(").Append(@class.ClassFullName).Append(" mock)").AppendLine();
- sb.Append("\t{").AppendLine();
-
- #region Mock Property
-
- sb.AppendXmlSummary($"Get access to the mock of .");
- sb.Append("\t\tpublic global::Mockolate.Mock.IMockFor").Append(name).Append(" Mock").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tget").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tif (mock.Target is global::Mockolate.Mock.IMockFor").Append(name).Append(" mockInterface)")
- .AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\treturn mockInterface;").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");")
- .AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.AppendLine();
-
- #endregion Mock Property
-
- #region CreateMock
-
- sb.AppendXmlSummary(
- $"Create a new mock of with the default .");
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock()").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, []);").AppendLine();
- sb.AppendLine();
-
- sb.AppendXmlSummary(
- $"Create a new mock of with the default .");
- sb.AppendXmlRemarks("All provided are immediately applied to the mock.");
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(" CreateMock(params global::System.Action[] setups)").AppendLine();
- sb.Append("\t\t\t=> CreateMock(null, setups);").AppendLine();
- sb.AppendLine();
-
- sb.AppendXmlSummary(
- $"Create a new mock of with the given .");
- sb.AppendXmlRemarks("All provided are immediately applied to the mock.");
- sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
- .Append(
- " CreateMock(global::Mockolate.MockBehavior? mockBehavior = null, params global::System.Action[] setups)").AppendLine();
- sb.Append("\t\t{").AppendLine();
- sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
- sb.Append(
- "\t\t\tvar mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, new global::Mockolate.Interactions.FastMockInteractions(0, mockBehavior.SkipInteractionRecording));")
- .AppendLine();
- sb.Append("\t\t\tglobal::Mockolate.Mock.").Append(name).Append(" mockTarget = new global::Mockolate.Mock.")
- .Append(name).Append("(mockRegistry);")
- .AppendLine();
- sb.Append("\t\t\tif (setups.Length > 0)").AppendLine();
- sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tforeach (var setup in setups)").AppendLine();
- sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\tsetup.Invoke(mockTarget);").AppendLine();
- sb.Append("\t\t\t\t}").AppendLine();
- sb.Append("\t\t\t}").AppendLine();
- sb.Append("\t\t\treturn mockTarget.Object;").AppendLine();
- sb.Append("\t\t}").AppendLine();
- sb.Append("\t}").AppendLine();
- sb.Append("}").AppendLine();
-
- #endregion MockForXXXExtensions
-
- #endregion MockForXXXExtensions
-
- sb.AppendLine();
-
+
#region MockForXXX
- sb.Append("internal static partial class Mock").AppendLine();
- sb.Append("{").AppendLine();
sb.Append("\t/// ").AppendLine();
- sb.Append("\t/// A mock implementation for .")
- .AppendLine();
+ sb.Append("\t/// A mock implementation for .").AppendLine();
sb.Append("\t/// ").AppendLine();
- sb.Append(
- "\t[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]")
- .AppendLine();
+ sb.Append("\t[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]").AppendLine();
#if !DEBUG
sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
#endif
@@ -126,13 +42,9 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append(
- "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]")
- .AppendLine();
- sb.Append("\t\tglobal::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.")
- .Append(mockRegistryName).Append(';').AppendLine();
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }")
- .AppendLine();
+ sb.Append("\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.").Append(mockRegistryName).Append(';').AppendLine();
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; }").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
@@ -143,24 +55,16 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.AppendLine();
sb.AppendXmlSummary("Returns the actual delegate with the mock as target.");
sb.Append("\t\tpublic ").Append(@class.ClassFullName).Append(" Object => new(Invoke);").AppendLine();
- sb.Append("\t\tprivate ")
- .Append(delegateMethod.ReturnType == Type.Void
- ? "void"
- : delegateMethod.ReturnType.Fullname)
- .Append(" Invoke(")
- .Append(string.Join(", ",
- delegateMethod.Parameters.Select(p => $"{p.RefKind.GetString()}{p.Type.Fullname} {p.Name}")))
- .Append(')').AppendLine();
+ sb.Append("\t\tprivate ").Append(delegateMethod.ReturnType == Type.Void ? "void" : delegateMethod.ReturnType.Fullname).Append(" Invoke(")
+ .Append(string.Join(", ", delegateMethod.Parameters.Select(p => $"{p.RefKind.GetString()}{p.Type.Fullname} {p.Name}"))).Append(')').AppendLine();
sb.Append("\t\t{").AppendLine();
string methodSetup = Helpers.GetUniqueLocalVariableName("methodSetup", delegateMethod.Parameters);
string methodSetupType = (delegateMethod.ReturnType == Type.Void, delegateMethod.Parameters.Count) switch
{
(true, 0) => "global::Mockolate.Setup.VoidMethodSetup",
- (true, _) =>
- $"global::Mockolate.Setup.VoidMethodSetup<{string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper()))}>",
+ (true, _) => $"global::Mockolate.Setup.VoidMethodSetup<{string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper()))}>",
(_, 0) => $"global::Mockolate.Setup.ReturnMethodSetup<{delegateMethod.ReturnType.ToTypeOrWrapper()}>",
- (_, _) =>
- $"global::Mockolate.Setup.ReturnMethodSetup<{delegateMethod.ReturnType.ToTypeOrWrapper()}, {string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper()))}>",
+ (_, _) => $"global::Mockolate.Setup.ReturnMethodSetup<{delegateMethod.ReturnType.ToTypeOrWrapper()}, {string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper()))}>",
};
bool hasOutParams = delegateMethod.Parameters.Any(p => p.RefKind is RefKind.Out);
bool hasRefParams = delegateMethod.Parameters.Any(p => p.RefKind is RefKind.Ref);
@@ -187,14 +91,12 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
{
string paramRef = Helpers.GetUniqueLocalVariableName($"ref_{p.Name}", delegateMethod.Parameters);
- sb.Append("\t\t\tvar ").Append(paramRef).Append(" = ").Append(p.ToNameOrWrapper()).Append(';')
- .AppendLine();
+ sb.Append("\t\t\tvar ").Append(paramRef).Append(" = ").Append(p.ToNameOrWrapper()).Append(';').AppendLine();
sb2.Append(paramRef);
}
else
{
- sb2.Append(
- p.RefKind switch
+ sb2.Append(p.RefKind switch
{
RefKind.Out => "default",
_ => p.ToNameOrWrapper(),
@@ -220,8 +122,7 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
{
string outParamBase = Helpers.GetUniqueIndexedLocalVariableBase("outParam", delegateMethod.Parameters);
string refParamBase = Helpers.GetUniqueIndexedLocalVariableBase("refParam", delegateMethod.Parameters);
- sb.Append("\t\t\tif (").Append(methodSetup).Append(" is ").Append(methodSetupType)
- .Append(".WithParameterCollection ").Append(wpc).Append(')').AppendLine();
+ sb.Append("\t\t\tif (").Append(methodSetup).Append(" is ").Append(methodSetupType).Append(".WithParameterCollection ").Append(wpc).Append(')').AppendLine();
sb.Append("\t\t\t{").AppendLine();
int parameterIndex = 0;
foreach (MethodParameter parameter in delegateMethod.Parameters)
@@ -236,23 +137,14 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
.Append(" || !").Append(outParamBase).Append(parameterIndex).Append(".TryGetValue(out ")
.Append(parameter.Name).Append("))").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(parameter.Name).Append(" = ")
- .AppendDefaultValueGeneratorFor(parameter.Type,
- $"this.{mockRegistryName}.Behavior.DefaultValue")
- .Append(';').AppendLine();
+ sb.Append("\t\t\t\t\t").Append(parameter.Name).Append(" = ").AppendDefaultValueGeneratorFor(parameter.Type, $"this.{mockRegistryName}.Behavior.DefaultValue").Append(';').AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
}
else if (parameter.RefKind == RefKind.Ref)
{
- sb.Append("\t\t\t\tif (").Append(wpc).Append(".Parameter").Append(parameterIndex)
- .Append(" is global::Mockolate.Parameters.IRefParameter<")
- .Append(parameter.Type.ToTypeOrWrapper()).Append("> ").Append(refParamBase)
- .Append(parameterIndex)
- .Append(")").AppendLine();
+ sb.Append("\t\t\t\tif (").Append(wpc).Append(".Parameter").Append(parameterIndex).Append(" is global::Mockolate.Parameters.IRefParameter<").Append(parameter.Type.ToTypeOrWrapper()).Append("> ").Append(refParamBase).Append(parameterIndex).Append(")").AppendLine();
sb.Append("\t\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t\t").Append(parameter.Name).Append(" = ").Append(refParamBase)
- .Append(parameterIndex)
- .Append(".GetValue(").Append(parameter.Name).Append(");").AppendLine();
+ sb.Append("\t\t\t\t\t").Append(parameter.Name).Append(" = ").Append(refParamBase).Append(parameterIndex).Append(".GetValue(").Append(parameter.Name).Append(");").AppendLine();
sb.Append("\t\t\t\t}").AppendLine();
}
}
@@ -260,15 +152,12 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.Append("\t\t\t}").AppendLine();
}
- sb.Append("\t\t\tif (").Append(mockRegistryName).Append(".Behavior.SkipInteractionRecording == false)")
- .AppendLine();
+ sb.Append("\t\t\tif (").Append(mockRegistryName).Append(".Behavior.SkipInteractionRecording == false)").AppendLine();
sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\t").Append(mockRegistryName)
- .Append(".RegisterInteraction(new global::Mockolate.Interactions.MethodInvocation");
+ sb.Append("\t\t\t\t").Append(mockRegistryName).Append(".RegisterInteraction(new global::Mockolate.Interactions.MethodInvocation");
if (delegateMethod.Parameters.Count > 0)
{
- sb.Append('<').Append(string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper())))
- .Append('>');
+ sb.Append('<').Append(string.Join(", ", delegateMethod.Parameters.Select(p => p.ToTypeOrWrapper()))).Append('>');
}
sb.Append("(").Append(delegateMethod.GetUniqueNameString());
@@ -282,11 +171,9 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
string displayDelegateName =
$"{delegateMethod.ContainingType}.{delegateMethod.Name}({string.Join(", ", delegateMethod.Parameters.Select(p => p.Type.DisplayName))})";
- sb.Append("\t\t\tif (").Append(methodSetup).Append(" is null && this.").Append(mockRegistryName)
- .Append(".Behavior.ThrowWhenNotSetup)").AppendLine();
+ sb.Append("\t\t\tif (").Append(methodSetup).Append(" is null && this.").Append(mockRegistryName).Append(".Behavior.ThrowWhenNotSetup)").AppendLine();
sb.Append("\t\t\t{").AppendLine();
- sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockNotSetupException(\"The method '")
- .Append(displayDelegateName).Append("' was invoked without prior setup.\");").AppendLine();
+ sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockNotSetupException(\"The method '").Append(displayDelegateName).Append("' was invoked without prior setup.\");").AppendLine();
sb.Append("\t\t\t}").AppendLine();
AppendTriggerCallbacks(sb, "\t\t\t", methodSetup, delegateMethod.Parameters);
@@ -301,8 +188,7 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
}
sb.Append("out var ").Append(returnValue).Append(") == true ? ").Append(returnValue).Append(" : ")
- .AppendDefaultValueGeneratorFor(delegateMethod.ReturnType,
- $"this.{mockRegistryName}.Behavior.DefaultValue")
+ .AppendDefaultValueGeneratorFor(delegateMethod.ReturnType, $"this.{mockRegistryName}.Behavior.DefaultValue")
.Append(';').AppendLine();
}
@@ -314,20 +200,18 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.Append("\t\t\t=> \"").Append(@class.DisplayString).Append(" mock\";").AppendLine();
sb.AppendLine();
- AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false,
- memberIds, memberIdPrefix, "Setup");
+ AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false, memberIds, memberIdPrefix, "Setup");
+
if (delegateMethod.Parameters.Count > 0)
{
- AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", true,
- memberIds, memberIdPrefix, "Setup");
+ AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", true, memberIds, memberIdPrefix, "Setup");
}
if (delegateMethod.Parameters.Count is > 0 and <= MaxExplicitParameters)
{
foreach (bool[] valueFlags in GenerateValueFlagCombinations(delegateMethod.Parameters))
{
- AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false,
- memberIds, memberIdPrefix, "Setup", valueFlags);
+ AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false, memberIds, memberIdPrefix, "Setup", valueFlags);
}
}
else if (delegateMethod.Parameters.Count > MaxExplicitParameters)
@@ -335,26 +219,22 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
bool[] allValueFlags = delegateMethod.Parameters.Select(p => p.CanUseNullableParameterOverload()).ToArray();
if (allValueFlags.Any(f => f))
{
- AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false,
- memberIds, memberIdPrefix, "Setup", allValueFlags);
+ AppendMethodSetupImplementation(sb, delegateMethod, mockRegistryName, $"IMockSetupFor{name}", false, memberIds, memberIdPrefix, "Setup", allValueFlags);
}
}
// Delegate mocks use a plain MockRegistry (no FastMockInteractions), so emit the slow Verify path.
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false,
- memberIds, memberIdPrefix, false, "Verify");
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false, memberIds, memberIdPrefix, false, "Verify");
if (delegateMethod.Parameters.Count > 0)
{
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", true,
- memberIds, memberIdPrefix, false, "Verify");
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", true, memberIds, memberIdPrefix, false, "Verify");
}
if (delegateMethod.Parameters.Count is > 0 and <= MaxExplicitParameters)
{
foreach (bool[] valueFlags in GenerateValueFlagCombinations(delegateMethod.Parameters))
{
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false,
- memberIds, memberIdPrefix, false, "Verify", valueFlags);
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false, memberIds, memberIdPrefix, false, "Verify", valueFlags);
}
}
else if (delegateMethod.Parameters.Count > MaxExplicitParameters)
@@ -368,22 +248,18 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
}
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult IMockFor")
- .Append(name).Append(".VerifySetup(global::Mockolate.Setup.IMethodSetup setup)").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Method(this, setup);").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult IMockFor").Append(name).Append(".VerifySetup(global::Mockolate.Setup.IMethodSetup setup)").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Method(this, setup);").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
sb.Append("\t\tbool IMockFor").Append(name).Append(".VerifyThatAllInteractionsAreVerified()").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName)
- .Append(".Interactions.GetUnverifiedInteractions().Count == 0;").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".Interactions.GetUnverifiedInteractions().Count == 0;").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
sb.Append("\t\tbool IMockFor").Append(name).Append(".VerifyThatAllSetupsAreUsed()").AppendLine();
- sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".GetUnusedSetups(this.").Append(mockRegistryName)
- .Append(".Interactions).Count == 0;").AppendLine();
+ sb.Append("\t\t\t=> this.").Append(mockRegistryName).Append(".GetUnusedSetups(this.").Append(mockRegistryName).Append(".Interactions).Count == 0;").AppendLine();
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
@@ -392,43 +268,38 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.AppendLine();
sb.Append("\t\t/// ").AppendLine();
- sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor IMockFor")
- .Append(name).Append(".Monitor()").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor IMockFor").Append(name).Append(".Monitor()").AppendLine();
sb.Append("\t\t\t=> new global::Mockolate.Monitor.MockMonitor(this.")
.Append(mockRegistryName).Append(".Interactions, interactions => new VerifyMonitor").Append(name)
- .Append("(new global::Mockolate.MockRegistry(this.").Append(mockRegistryName).Append(", interactions)));")
- .AppendLine();
+ .Append("(new global::Mockolate.MockRegistry(this.").Append(mockRegistryName).Append(", interactions)));").AppendLine();
sb.AppendLine("\t}");
-
sb.AppendLine();
+
#if !DEBUG
sb.Append("\t[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
#endif
sb.Append("\t[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
- sb.Append("\tprivate sealed class VerifyMonitor").Append(name)
- .Append("(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyFor")
- .Append(name).AppendLine();
+ sb.Append("\tprivate sealed class VerifyMonitor").Append(name).Append("(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
- sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName)
- .Append(" { get; } = mockRegistry;").AppendLine();
+ sb.Append("\t\tprivate global::Mockolate.MockRegistry ").Append(mockRegistryName).Append(" { get; } = mockRegistry;").AppendLine();
sb.AppendLine();
+
sb.Append("\t\t#region IMockVerifyFor").Append(name).AppendLine();
sb.AppendLine();
+
// Delegate mocks use a plain MockRegistry (no FastMockInteractions), so emit the slow Verify path.
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false,
- memberIds, memberIdPrefix, false, "Verify");
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false, memberIds, memberIdPrefix, false, "Verify");
+
if (delegateMethod.Parameters.Count > 0)
{
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", true,
- memberIds, memberIdPrefix, false, "Verify");
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", true, memberIds, memberIdPrefix, false, "Verify");
}
if (delegateMethod.Parameters.Count is > 0 and <= MaxExplicitParameters)
{
foreach (bool[] valueFlags in GenerateValueFlagCombinations(delegateMethod.Parameters))
{
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false,
- memberIds, memberIdPrefix, false, "Verify", valueFlags);
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false, memberIds, memberIdPrefix, false, "Verify", valueFlags);
}
}
else if (delegateMethod.Parameters.Count > MaxExplicitParameters)
@@ -436,17 +307,17 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
bool[] allValueFlags = delegateMethod.Parameters.Select(p => p.CanUseNullableParameterOverload()).ToArray();
if (allValueFlags.Any(f => f))
{
- AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false,
- memberIds, memberIdPrefix, false, "Verify", allValueFlags);
+ AppendMethodVerifyImplementation(sb, delegateMethod, mockRegistryName, $"IMockVerifyFor{name}", false, memberIds, memberIdPrefix, false, "Verify", allValueFlags);
}
}
sb.Append("\t\t#endregion IMockVerifyFor").Append(name).AppendLine();
sb.Append("\t}").AppendLine();
+ sb.AppendLine();
#endregion MockForXXX
- sb.AppendLine();
+ #region Mock Interfaces
#region IMockForXXX
@@ -455,8 +326,7 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.Append("\t\t IMockSetupFor").Append(name).Append(", IMockVerifyFor").Append(name).AppendLine();
sb.Append("\t{").AppendLine();
sb.AppendXmlSummary("Verifies the method invocations for the on the mock.");
- sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult VerifySetup(global::Mockolate.Setup.IMethodSetup setup);").AppendLine();
+ sb.Append("\t\tglobal::Mockolate.Verify.VerificationResult VerifySetup(global::Mockolate.Setup.IMethodSetup setup);").AppendLine();
sb.AppendLine();
sb.AppendXmlSummary("Gets a value indicating whether all expected interactions have been verified.");
sb.Append("\t\tbool VerifyThatAllInteractionsAreVerified();").AppendLine();
@@ -467,23 +337,21 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
sb.AppendXmlSummary("Clears all interactions recorded by the mock object.");
sb.Append("\t\tvoid ClearAllInteractions();").AppendLine();
sb.AppendLine();
- sb.AppendXmlSummary(
- "Provides monitoring capabilities for a mocked instance of the specified type, allowing inspection of accessed properties, invoked methods, and event subscriptions.");
- sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor Monitor();")
- .AppendLine();
+ sb.AppendXmlSummary("Provides monitoring capabilities for a mocked instance of the specified type, allowing inspection of accessed properties, invoked methods, and event subscriptions.");
+ sb.Append("\t\tglobal::Mockolate.Monitor.MockMonitor Monitor();").AppendLine();
sb.Append("\t}").AppendLine();
+ sb.AppendLine();
#endregion IMockForXXX
- sb.AppendLine();
-
#region IMockSetupForXXX
sb.AppendXmlSummary($"Set up the mock of .", "\t");
- sb.Append("\tinternal interface IMockSetupFor").Append(name).Append(" : global::Mockolate.Setup.IMockSetup<")
- .Append(@class.ClassFullName).Append(">").AppendLine();
+ sb.Append("\tinternal interface IMockSetupFor").Append(name).Append(" : global::Mockolate.Setup.IMockSetup<").Append(@class.ClassFullName).Append(">").AppendLine();
sb.Append("\t{").AppendLine();
+
AppendMethodSetupDefinition(sb, @class, delegateMethod, false, "Setup");
+
if (delegateMethod.Parameters.Count > 0)
{
AppendMethodSetupDefinition(sb, @class, delegateMethod, true, "Setup");
@@ -506,18 +374,18 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
}
sb.Append("\t}").AppendLine();
+ sb.AppendLine();
#endregion IMockSetupForXXX
- sb.AppendLine();
-
#region IMockVerifyForXXX
sb.AppendXmlSummary($"Verify interactions with the mock of .", "\t");
- sb.Append("\tinternal interface IMockVerifyFor").Append(name).Append(" : global::Mockolate.Verify.IMockVerify<")
- .Append(@class.ClassFullName).Append(">").AppendLine();
+ sb.Append("\tinternal interface IMockVerifyFor").Append(name).Append(" : global::Mockolate.Verify.IMockVerify<").Append(@class.ClassFullName).Append(">").AppendLine();
sb.Append("\t{").AppendLine();
+
AppendMethodVerifyDefinition(sb, delegateMethod, $"IMockVerifyFor{name}", false, "Verify");
+
if (delegateMethod.Parameters.Count > 0)
{
AppendMethodVerifyDefinition(sb, delegateMethod, $"IMockVerifyFor{name}", true, "Verify");
@@ -544,7 +412,95 @@ public static string MockDelegate(string name, MockClass @class, Method delegate
#endregion IMockVerifyForXXX
+ #endregion Mock Interfaces
+
sb.Append("}").AppendLine();
+ sb.AppendLine();
+
+ #endregion Mock
+
+ #region MockForXXXExtensions
+
+ sb.AppendXmlSummary($"Mock extensions for .", "");
+#if !DEBUG
+ sb.Append("[global::System.Diagnostics.DebuggerNonUserCode]").AppendLine();
+#endif
+ sb.Append("[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]").AppendLine();
+ sb.Append("internal static partial class MockExtensionsFor").Append(name).AppendLine();
+ sb.Append("{").AppendLine();
+
+ sb.Append("\t/// ").AppendLine();
+ sb.Append("\textension(").Append(@class.ClassFullName).Append(" mock)").AppendLine();
+ sb.Append("\t{").AppendLine();
+
+ #region Mock Property
+
+ sb.AppendXmlSummary($"Get access to the mock of .");
+ sb.Append("\t\tpublic global::Mockolate.Mock.IMockFor").Append(name).Append(" Mock").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tget").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tif (mock.Target is global::Mockolate.Mock.IMockFor").Append(name).Append(" mockInterface)")
+ .AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\treturn mockInterface;").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t\tthrow new global::Mockolate.Exceptions.MockException(\"The subject is no mock.\");")
+ .AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.AppendLine();
+
+ #endregion Mock Property
+
+ #region CreateMock
+
+ sb.AppendXmlSummary(
+ $"Create a new mock of with the default .");
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName).Append(" CreateMock()").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, []);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary(
+ $"Create a new mock of with the default .");
+ sb.AppendXmlRemarks("All provided are immediately applied to the mock.");
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
+ .Append(" CreateMock(params global::System.Action[] setups)").AppendLine();
+ sb.Append("\t\t\t=> CreateMock(null, setups);").AppendLine();
+ sb.AppendLine();
+
+ sb.AppendXmlSummary(
+ $"Create a new mock of with the given .");
+ sb.AppendXmlRemarks("All provided are immediately applied to the mock.");
+ sb.Append("\t\tpublic static ").Append(@class.ClassFullName)
+ .Append(
+ " CreateMock(global::Mockolate.MockBehavior? mockBehavior = null, params global::System.Action[] setups)").AppendLine();
+ sb.Append("\t\t{").AppendLine();
+ sb.Append("\t\t\tmockBehavior ??= global::Mockolate.MockBehavior.Default;").AppendLine();
+ sb.Append(
+ "\t\t\tvar mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, new global::Mockolate.Interactions.FastMockInteractions(0, mockBehavior.SkipInteractionRecording));")
+ .AppendLine();
+ sb.Append("\t\t\tglobal::Mockolate.Mock.").Append(name).Append(" mockTarget = new global::Mockolate.Mock.")
+ .Append(name).Append("(mockRegistry);")
+ .AppendLine();
+ sb.Append("\t\t\tif (setups.Length > 0)").AppendLine();
+ sb.Append("\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\tforeach (var setup in setups)").AppendLine();
+ sb.Append("\t\t\t\t{").AppendLine();
+ sb.Append("\t\t\t\t\tsetup.Invoke(mockTarget);").AppendLine();
+ sb.Append("\t\t\t\t}").AppendLine();
+ sb.Append("\t\t\t}").AppendLine();
+ sb.Append("\t\t\treturn mockTarget.Object;").AppendLine();
+ sb.Append("\t\t}").AppendLine();
+ sb.Append("\t}").AppendLine();
+ sb.Append("}").AppendLine();
+
+ #endregion MockForXXXExtensions
+
+ #endregion MockForXXXExtensions
+
sb.AppendLine("#nullable disable annotations");
return sb.ToString();
}
diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs
index 6665ca37..731eb0c4 100644
--- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs
+++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs
@@ -10,435 +10,320 @@
#nullable enable annotations
namespace Mockolate;
-///
-/// Mock extensions for ComprehensiveAbstractClass.
-///
-[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
-internal static partial class MockExtensionsForComprehensiveAbstractClass
+internal static partial class Mock
{
- ///
- extension(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass mock)
+ ///
+ /// A mock implementation for ComprehensiveAbstractClass.
+ ///
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal class ComprehensiveAbstractClass :
+ global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass, IMockForComprehensiveAbstractClass, IMockSetupForComprehensiveAbstractClass, IMockProtectedSetupForComprehensiveAbstractClass, global::Mockolate.MockExtensionsForComprehensiveAbstractClass.IMockSetupInitializationForComprehensiveAbstractClass, IMockVerifyForComprehensiveAbstractClass, IMockProtectedVerifyForComprehensiveAbstractClass,
+ global::Mockolate.IMock
{
- ///
- /// Gets the mock accessor for ComprehensiveAbstractClass - the entry point for configuring setups, verifying interactions and raising events.
- ///
- ///
- /// The accessor is the bridge between the strongly-typed instance of ComprehensiveAbstractClass returned by CreateMock(...) and the underlying mock registry where setups and recorded interactions live.
- /// Through it you can:
- ///
- /// - Setup - configure how members respond when invoked (Returns, Throws, Do, InitializeWith, ...).
- /// - Verify - assert how often (and in which order) members were invoked.
- /// - SetupProtected / VerifyProtected / RaiseProtected - target members on class mocks.
- /// - InScenario / TransitionTo - scope setups and behavior to a named scenario and switch between scenarios.
- /// - Monitor, ClearAllInteractions, VerifyThatAllInteractionsAreVerified, VerifyThatAllSetupsAreUsed - manage recorded interactions.
- /// - VerifySetup - verify how often a specific setup matched.
- ///
- ///
- /// The instance is not a Mockolate-generated mock of ComprehensiveAbstractClass.
- public global::Mockolate.Mock.IMockForComprehensiveAbstractClass Mock
- {
- get
- {
- if (mock is global::Mockolate.Mock.IMockForComprehensiveAbstractClass mockInterface)
- {
- return mockInterface;
- }
- throw new global::Mockolate.Exceptions.MockException("The subject is no mock.");
- }
- }
+ internal const int MemberId_V_Get = 0;
+ internal const int MemberId_V_Set = 1;
+ internal const int MemberId_A = 2;
+ internal const int MemberId_P = 3;
+ internal const int MemberCount = 4;
+ internal static readonly global::Mockolate.Interactions.PropertyGetterAccess PropertyAccess_V_Get = new global::Mockolate.Interactions.PropertyGetterAccess("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
///
- /// Creates a new mock of ComprehensiveAbstractClass with the default MockBehavior.
+ /// Creates a FastMockInteractions sized to MemberCount for use as the mock's interaction store.
+ /// Per-member buffers are not allocated up-front: the recording hot paths call GetOrCreateBuffer<TBuffer>(int, Func<FastMockInteractions, TBuffer>) so a slot is materialized only when its member is first invoked.
///
- ///
- /// The returned instance is a strongly-typed mock generated at compile time - it implements ComprehensiveAbstractClass and exposes the Mockolate surface through .Mock:
- ///
- /// - .Mock.Setup configures how members respond (Returns, Throws, Do, InitializeWith, sequences, callbacks).
- /// - .Mock.Verify asserts how often and in which order members were invoked.
- ///
- /// With the default behavior, un-configured members return default values (empty collections / strings, completed tasks, otherwise) and base-class implementations are invoked for class mocks. Use one of the overloads that accepts a MockBehavior to customize this (for example to make un-configured calls throw or to skip the base class).
- /// Overloads allow you to additionally pass constructor parameters (for class mocks), apply an initial setup callback before the instance is returned, or combine both.
- ///
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock()
- => CreateMock(null, null, (object?[]?)null);
+ internal static global::Mockolate.Interactions.FastMockInteractions CreateFastInteractions(global::Mockolate.MockBehavior behavior)
+ => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);
///
- /// Creates a new mock of ComprehensiveAbstractClass with the default MockBehavior, applying the given immediately.
+ /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from .
///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup)
- => CreateMock(null, setup, (object?[]?)null);
+ private static global::Mockolate.MockRegistry MockolateCreateRegistryFromBehavior(global::Mockolate.MockBehavior behavior)
+ {
+ global::Mockolate.MockRegistry registry = new global::Mockolate.MockRegistry(behavior, CreateFastInteractions(behavior));
+ MockRegistryProvider.Value = registry;
+ return registry;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass with the given .
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior)
- => CreateMock(mockBehavior, null, (object?[]?)null);
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ global::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.MockRegistry;
+ private global::Mockolate.MockRegistry MockRegistry
+ {
+ get => field ?? MockRegistryProvider.Value;
+ set;
+ }
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ internal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();
- ///
- /// Creates a new mock of ComprehensiveAbstractClass with the given , applying the given immediately.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup)
- => CreateMock(mockBehavior, setup, (object?[]?)null);
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_A
+ => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)));
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_P
+ => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)));
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given to invoke the base-class constructor.
- ///
- /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(object?[] constructorParameters)
- => CreateMock(null, null, constructorParameters);
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ IMockSetupForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.Setup
+ => this;
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ IMockProtectedSetupForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.SetupProtected
+ => this;
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ IMockProtectedSetupForComprehensiveAbstractClass global::Mockolate.MockExtensionsForComprehensiveAbstractClass.IMockSetupInitializationForComprehensiveAbstractClass.Protected
+ => this;
+ ///
+ IMockInScenarioForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.InScenario(string scenario)
+ => new MockInScenarioForComprehensiveAbstractClass(this.MockRegistry, scenario);
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given and .
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters)
- => CreateMock(mockBehavior, null, constructorParameters);
+ ///
+ IMockForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.InScenario(string scenario, global::System.Action setup)
+ {
+ setup.Invoke(new MockInScenarioForComprehensiveAbstractClass(this.MockRegistry, scenario));
+ return this;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given .
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, object?[] constructorParameters)
- => CreateMock(null, setup, constructorParameters);
+ ///
+ IMockForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.TransitionTo(string scenario)
+ {
+ this.MockRegistry.TransitionTo(scenario);
+ return this;
+ }
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ IMockVerifyForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.Verify
+ => this;
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ IMockProtectedVerifyForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.VerifyProtected
+ => this;
+ ///
+ global::Mockolate.Verify.VerificationResult IMockForComprehensiveAbstractClass.VerifySetup(global::Mockolate.Setup.IMethodSetup setup)
+ => this.MockRegistry.Method(this, setup);
+ ///
+ bool IMockForComprehensiveAbstractClass.VerifyThatAllInteractionsAreVerified()
+ => this.MockRegistry.Interactions.GetUnverifiedInteractions().Count == 0;
+ ///
+ bool IMockForComprehensiveAbstractClass.VerifyThatAllSetupsAreUsed()
+ => this.MockRegistry.GetUnusedSetups(this.MockRegistry.Interactions).Count == 0;
+ ///
+ void IMockForComprehensiveAbstractClass.ClearAllInteractions()
+ => this.MockRegistry.ClearAllInteractions();
+ ///
+ global::Mockolate.Monitor.MockMonitor IMockForComprehensiveAbstractClass.Monitor()
+ => new global::Mockolate.Monitor.MockMonitor(this.MockRegistry.Interactions, interactions => new VerifyMonitorComprehensiveAbstractClass(new global::Mockolate.MockRegistry(this.MockRegistry, interactions)));
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
- ///
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(int v, string text = "x")
- => CreateMock(null, null, new object?[] { v, text });
+ ///
+ string global::Mockolate.IMock.ToString()
+ => "Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass mock";
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, int v, string text = "x")
- => CreateMock(mockBehavior, null, new object?[] { v, text });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry)
+ : base()
+ {
+ this.MockRegistry = mockRegistry;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, int v, string text = "x")
- => CreateMock(null, setup, new object?[] { v, text });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior)
+ : this(MockolateCreateRegistryFromBehavior(behavior))
+ {
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, int v, string text = "x")
- => CreateMock(mockBehavior, setup, new object?[] { v, text });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, int v, string text = "x")
+ : base(v, text)
+ {
+ this.MockRegistry = mockRegistry;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
- ///
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(int mockRegistry, bool _)
- => CreateMock(null, null, new object?[] { mockRegistry, _ });
-
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, int mockRegistry, bool _)
- => CreateMock(mockBehavior, null, new object?[] { mockRegistry, _ });
-
- ///
- /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, int mockRegistry, bool _)
- => CreateMock(null, setup, new object?[] { mockRegistry, _ });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, int v, string text = "x")
+ : this(MockolateCreateRegistryFromBehavior(behavior), v, text)
+ {
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, int mockRegistry, bool _)
- => CreateMock(mockBehavior, setup, new object?[] { mockRegistry, _ });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry_1, int mockRegistry, bool _)
+ : base(mockRegistry, _)
+ {
+ this.MockRegistry = mockRegistry_1;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
- ///
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(string name)
- => CreateMock(null, null, new object?[] { name });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, int mockRegistry, bool _)
+ : this(MockolateCreateRegistryFromBehavior(behavior), mockRegistry, _)
+ {
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, string name)
- => CreateMock(mockBehavior, null, new object?[] { name });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, string name)
+ : base(name)
+ {
+ this.MockRegistry = mockRegistry;
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, string name)
- => CreateMock(null, setup, new object?[] { name });
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
+ public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, string name)
+ : this(MockolateCreateRegistryFromBehavior(behavior), name)
+ {
+ }
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
- /// Value forwarded to the base-class constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, string name)
- => CreateMock(mockBehavior, setup, new object?[] { name });
+ #region Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
- ///
- /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given .
- ///
- ///
- /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
- ///
- /// Controls how the mock responds when members are invoked without a matching setup, or for MockBehavior.Default.
- /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned, or to skip.
- /// Values forwarded to a matching base-class constructor, or to use the parameterless constructor.
- /// A new mock instance of ComprehensiveAbstractClass.
- public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters)
+ ///
+ public override int V
{
- if (mockBehavior is not null)
+ get
{
- IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior;
- if (mockBehaviorAccess.TryGet?>(out var additionalSetup))
+ return this.MockRegistry.GetPropertyFast(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.PropertyAccess_V_Get, static b => b.DefaultValue.Generate(default(int)!), this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps ? () => wraps.V : () => base.V);
+ }
+ set
+ {
+ if (!this.MockRegistry.SetPropertyFast(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V", value))
{
- if (setup is null)
+ if (this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps)
{
- setup = additionalSetup;
+ wraps.V = value;
}
else
{
- var originalSetup = setup;
- setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); };
+ base.V = value;
}
}
- if (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters(out object?[]? parameters))
- {
- constructorParameters = parameters;
- }
}
-
- mockBehavior ??= global::Mockolate.MockBehavior.Default;
- global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ComprehensiveAbstractClass.CreateFastInteractions(mockBehavior), constructorParameters);
- return CreateMockInstance(mockRegistry, constructorParameters, setup);
}
- private static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup)
+ ///
+ public override int A()
{
- if (constructorParameters is null || constructorParameters.Length == 0)
+ global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null;
+ if (string.IsNullOrEmpty(this.MockRegistry.Scenario))
{
- global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
- global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
- if (setup is not null)
+ global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A);
+ if (snapshot_methodSetup is not null)
{
- setupTarget ??= new(mockRegistry);
- setup.Invoke(setupTarget);
+ for (int i_methodSetup = snapshot_methodSetup.Length - 1; i_methodSetup >= 0; i_methodSetup--)
+ {
+ if (snapshot_methodSetup[i_methodSetup] is global::Mockolate.Setup.ReturnMethodSetup s_methodSetup && s_methodSetup.Matches())
+ {
+ methodSetup = s_methodSetup;
+ break;
+ }
+ }
}
- return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry);
}
- else if (constructorParameters.Length == 0)
+ if (methodSetup is null)
{
- global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
- global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
- if (setup is not null)
+ foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A"))
{
- setupTarget ??= new(mockRegistry);
- setup.Invoke(setupTarget);
+ if (s_methodSetup.Matches())
+ {
+ methodSetup = s_methodSetup;
+ break;
+ }
}
- return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry);
}
- else if (constructorParameters.Length >= 1 && constructorParameters.Length <= 2
- && TryCast(constructorParameters, 0, mockRegistry.Behavior, out int c2p1)
- && TryCastWithDefaultValue(constructorParameters, 1, "x", mockRegistry.Behavior, out string c2p2))
+ bool hasWrappedResult = false;
+ int wrappedResult = default!;
+ if (this.MockRegistry.Behavior.SkipInteractionRecording == false)
{
- global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
- global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
- if (setup is not null)
- {
- setupTarget ??= new(mockRegistry);
- setup.Invoke(setupTarget);
- }
- return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c2p1, c2p2);
+ this.MockolateBuffer_A.Append("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A");
}
- else if (constructorParameters.Length == 2
- && TryCast(constructorParameters, 0, mockRegistry.Behavior, out int c3p1)
- && TryCast(constructorParameters, 1, mockRegistry.Behavior, out bool c3p2))
+ try
{
- global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
- global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
- if (setup is not null)
+ if (this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps)
{
- setupTarget ??= new(mockRegistry);
- setup.Invoke(setupTarget);
+ wrappedResult = wraps.A();
+ hasWrappedResult = true;
}
- return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c3p1, c3p2);
}
- else if (constructorParameters.Length == 1
- && TryCast(constructorParameters, 0, mockRegistry.Behavior, out string c4p1))
+ finally
{
- global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
- global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
- if (setup is not null)
- {
- setupTarget ??= new(mockRegistry);
- setup.Invoke(setupTarget);
- }
- return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c4p1);
+ methodSetup?.TriggerCallbacks();
}
- else
+ if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup)
{
- throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)}).");
+ throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A()' was invoked without prior setup.");
}
- static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
+ if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult)
{
- var value = values[index];
- if (value is TValue typedValue)
- {
- result = typedValue;
- return true;
- }
-
- result = default!;
- return value is null;
+ return wrappedResult;
}
- static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
+ return methodSetup?.TryGetReturnValue(out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(int)!);
+ }
+
+ ///
+ protected override int P()
+ {
+ global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null;
+ if (string.IsNullOrEmpty(this.MockRegistry.Scenario))
{
- if (values.Length > index && values[index] is TValue typedValue)
+ global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P);
+ if (snapshot_methodSetup is not null)
{
- result = typedValue;
- return true;
+ for (int i_methodSetup = snapshot_methodSetup.Length - 1; i_methodSetup >= 0; i_methodSetup--)
+ {
+ if (snapshot_methodSetup[i_methodSetup] is global::Mockolate.Setup.ReturnMethodSetup s_methodSetup && s_methodSetup.Matches())
+ {
+ methodSetup = s_methodSetup;
+ break;
+ }
+ }
}
-
- result = defaultValue;
- return true;
}
- }
- ///
- /// Creates a mock that wraps the given .
- ///
- ///
- /// Public members on the mock forward to unless overridden by a setup; protected members still go through the base-class implementation. All forwarded interactions are recorded and can be verified the same as on a plain mock.
- ///
- /// The real object whose calls should be forwarded. Must not be .
- /// A new mock of ComprehensiveAbstractClass that delegates to .
- public global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Wrapping(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass instance)
- {
- if (mock is global::Mockolate.IMock mockInterface)
+ if (methodSetup is null)
{
- global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance);
- wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.CreateFastInteractions(wrappingRegistry.Behavior));
- return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null);
+ foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P"))
+ {
+ if (s_methodSetup.Matches())
+ {
+ methodSetup = s_methodSetup;
+ break;
+ }
+ }
}
- throw new global::Mockolate.Exceptions.MockException("The subject is no mock.");
- }
-
- }
-
- ///
- extension(global::Mockolate.MockBehavior behavior)
- {
- ///
- /// Initializes mocks of type with the given .
- ///
- ///
- /// The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones.
- ///
- /// The mockable type derived from ComprehensiveAbstractClass that this setup should apply to.
- /// Callback invoked when a new mock of is created.
- /// A new MockBehavior with the registered initializer. The original instance is unchanged.
- public global::Mockolate.MockBehavior Initialize(global::System.Action setup)
- where T : global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
- {
- var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior;
- return behaviorAccess.Set(setup);
+ bool hasWrappedResult = false;
+ int wrappedResult = default!;
+ if (this.MockRegistry.Behavior.SkipInteractionRecording == false)
+ {
+ this.MockolateBuffer_P.Append("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P");
+ }
+ try
+ {
+ if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass))
+ {
+ wrappedResult = base.P();
+ hasWrappedResult = true;
+ }
+ }
+ finally
+ {
+ methodSetup?.TriggerCallbacks();
+ }
+ if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup)
+ {
+ throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P()' was invoked without prior setup.");
+ }
+ if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult)
+ {
+ return wrappedResult;
+ }
+ return methodSetup?.TryGetReturnValue(out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(int)!);
}
- }
- internal interface IMockSetupInitializationForComprehensiveAbstractClass : global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass
- {
- ///
- /// Setup protected members
- ///
- global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass Protected { get; }
- }
- [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
- internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass, global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass, IMockSetupInitializationForComprehensiveAbstractClass
- {
- ///
- global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass IMockSetupInitializationForComprehensiveAbstractClass.Protected => this;
- private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry;
+ #endregion Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
#region IMockSetupForComprehensiveAbstractClass
@@ -475,440 +360,737 @@ internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : g
}
#endregion IMockProtectedSetupForComprehensiveAbstractClass
- }
- [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
- private sealed class CovariantParameterAdapter(global::Mockolate.Parameters.IParameter inner) : global::Mockolate.Parameters.IParameterMatch
- {
- public bool Matches(T value) => inner.Matches(value);
- public void InvokeCallbacks(T value) => inner.InvokeCallbacks(value);
- public override string? ToString() => inner.ToString();
+ #region IMockVerifyForComprehensiveAbstractClass
- public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter)
- => parameter is global::Mockolate.Parameters.IParameterMatch direct
- ? direct
- : new CovariantParameterAdapter(parameter);
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForComprehensiveAbstractClass.V
+ {
+ get
+ {
+ return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ }
+ }
+
+ ///
+ global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForComprehensiveAbstractClass.A()
+ => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A", () => $"A()");
+ #endregion IMockVerifyForComprehensiveAbstractClass
+
+ #region IMockProtectedVerifyForComprehensiveAbstractClass
+
+ ///
+ global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForComprehensiveAbstractClass.P()
+ => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P", () => $"P()");
+ #endregion IMockProtectedVerifyForComprehensiveAbstractClass
}
-}
-internal static partial class Mock
-{
- ///
- /// A mock implementation for ComprehensiveAbstractClass.
- ///
- [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
- internal class ComprehensiveAbstractClass :
- global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass, IMockForComprehensiveAbstractClass, IMockSetupForComprehensiveAbstractClass, IMockProtectedSetupForComprehensiveAbstractClass, global::Mockolate.MockExtensionsForComprehensiveAbstractClass.IMockSetupInitializationForComprehensiveAbstractClass, IMockVerifyForComprehensiveAbstractClass, IMockProtectedVerifyForComprehensiveAbstractClass,
- global::Mockolate.IMock
+ private sealed class VerifyMonitorComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyForComprehensiveAbstractClass
{
- internal const int MemberId_V_Get = 0;
- internal const int MemberId_V_Set = 1;
- internal const int MemberId_A = 2;
- internal const int MemberId_P = 3;
- internal const int MemberCount = 4;
- internal static readonly global::Mockolate.Interactions.PropertyGetterAccess PropertyAccess_V_Get = new global::Mockolate.Interactions.PropertyGetterAccess("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry;
- ///
- /// Creates a FastMockInteractions sized to MemberCount for use as the mock's interaction store.
- /// Per-member buffers are not allocated up-front: the recording hot paths call GetOrCreateBuffer<TBuffer>(int, Func<FastMockInteractions, TBuffer>) so a slot is materialized only when its member is first invoked.
- ///
- internal static global::Mockolate.Interactions.FastMockInteractions CreateFastInteractions(global::Mockolate.MockBehavior behavior)
- => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);
+ #region IMockVerifyForComprehensiveAbstractClass
- ///
- /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from .
- ///
- private static global::Mockolate.MockRegistry MockolateCreateRegistryFromBehavior(global::Mockolate.MockBehavior behavior)
+ ///
+ [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
+ global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForComprehensiveAbstractClass.V
{
- global::Mockolate.MockRegistry registry = new global::Mockolate.MockRegistry(behavior, CreateFastInteractions(behavior));
- MockRegistryProvider.Value = registry;
- return registry;
+ get
+ {
+ return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ }
}
///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- global::Mockolate.MockRegistry global::Mockolate.IMock.MockRegistry => this.MockRegistry;
- private global::Mockolate.MockRegistry MockRegistry
+ global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForComprehensiveAbstractClass.A()
+ => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A", () => $"A()");
+ #endregion IMockVerifyForComprehensiveAbstractClass
+ }
+
+ [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ private sealed class MockInScenarioForComprehensiveAbstractClass : global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass, global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass, global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass
+ {
+ private global::Mockolate.MockRegistry MockRegistry { get; }
+ private string _scenarioName;
+
+ public MockInScenarioForComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, string scenario)
{
- get => field ?? MockRegistryProvider.Value;
- set;
+ this.MockRegistry = mockRegistry;
+ _scenarioName = scenario;
}
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- internal static readonly global::System.Threading.AsyncLocal MockRegistryProvider = new global::System.Threading.AsyncLocal();
-
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_A
- => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)));
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_P
- => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)));
///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- IMockSetupForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.Setup
+ global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass.Setup
=> this;
+
///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- IMockProtectedSetupForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.SetupProtected
+ global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass.SetupProtected
=> this;
+
+ #region IMockSetupForComprehensiveAbstractClass
+
///
[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- IMockProtectedSetupForComprehensiveAbstractClass global::Mockolate.MockExtensionsForComprehensiveAbstractClass.IMockSetupInitializationForComprehensiveAbstractClass.Protected
- => this;
- ///
- IMockInScenarioForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.InScenario(string scenario)
- => new MockInScenarioForComprehensiveAbstractClass(this.MockRegistry, scenario);
+ global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass.V
+ {
+ get
+ {
+ var propertySetup = new global::Mockolate.Setup.PropertySetup(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ this.MockRegistry.SetupProperty(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, _scenarioName, propertySetup);
+ return propertySetup;
+ }
+ }
///
- IMockForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.InScenario(string scenario, global::System.Action setup)
+ global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass.A()
{
- setup.Invoke(new MockInScenarioForComprehensiveAbstractClass(this.MockRegistry, scenario));
- return this;
+ var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A");
+ this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, _scenarioName, methodSetup);
+ return methodSetup;
}
+ #endregion IMockSetupForComprehensiveAbstractClass
+
+ #region IMockProtectedSetupForComprehensiveAbstractClass
+
///
- IMockForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.TransitionTo(string scenario)
+ global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass.P()
{
- this.MockRegistry.TransitionTo(scenario);
- return this;
+ var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P");
+ this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, _scenarioName, methodSetup);
+ return methodSetup;
}
- ///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- IMockVerifyForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.Verify
- => this;
- ///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- IMockProtectedVerifyForComprehensiveAbstractClass IMockForComprehensiveAbstractClass.VerifyProtected
- => this;
- ///
- global::Mockolate.Verify.VerificationResult IMockForComprehensiveAbstractClass.VerifySetup(global::Mockolate.Setup.IMethodSetup setup)
- => this.MockRegistry.Method(this, setup);
- ///
- bool IMockForComprehensiveAbstractClass.VerifyThatAllInteractionsAreVerified()
- => this.MockRegistry.Interactions.GetUnverifiedInteractions().Count == 0;
- ///
- bool IMockForComprehensiveAbstractClass.VerifyThatAllSetupsAreUsed()
- => this.MockRegistry.GetUnusedSetups(this.MockRegistry.Interactions).Count == 0;
- ///
- void IMockForComprehensiveAbstractClass.ClearAllInteractions()
- => this.MockRegistry.ClearAllInteractions();
- ///
- global::Mockolate.Monitor.MockMonitor IMockForComprehensiveAbstractClass.Monitor()
- => new global::Mockolate.Monitor.MockMonitor(this.MockRegistry.Interactions, interactions => new VerifyMonitorComprehensiveAbstractClass(new global::Mockolate.MockRegistry(this.MockRegistry, interactions)));
- ///
- string global::Mockolate.IMock.ToString()
- => "Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass mock";
+ #endregion IMockProtectedSetupForComprehensiveAbstractClass
+ }
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry)
- : base()
- {
- this.MockRegistry = mockRegistry;
- }
+ ///
+ /// The Mockolate accessor for a mock of ComprehensiveAbstractClass, reached through .Mock on the mocked instance.
+ ///
+ ///
+ /// Groups every operation that acts on the mock rather than on the mocked subject: setups, verifications, event raising, scenarios and monitoring.
+ ///
+ internal interface IMockForComprehensiveAbstractClass
+ {
+ ///
+ /// Configures how members of the mock of ComprehensiveAbstractClass respond when invoked.
+ ///
+ ///
+ /// Each mocked member is available as a strongly-typed entry on this surface. Chain Returns, ReturnsAsync, Throws, ThrowsAsync or Do to control the response; chain InitializeWith/Register to initialize properties and indexers; chain multiple returns/throws to define a sequence; use .For(n), .Only(n), .Forever(), .When(predicate) to control when a callback runs.
+ /// When two setups overlap, the most recently defined one wins.
+ ///
+ IMockSetupForComprehensiveAbstractClass Setup { get; }
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior)
- : this(MockolateCreateRegistryFromBehavior(behavior))
- {
- }
+ ///
+ /// Configures how virtual members of the mock of ComprehensiveAbstractClass respond when invoked.
+ ///
+ ///
+ /// Only members declared as (or ) on the mocked class appear here. All setup chain operators (Returns, Throws, Do, sequences, .For/.Only/.Forever, ...) work identically to Setup.
+ ///
+ IMockProtectedSetupForComprehensiveAbstractClass SetupProtected { get; }
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, int v, string text = "x")
- : base(v, text)
- {
- this.MockRegistry = mockRegistry;
- }
+ ///
+ /// Opens a named scenario scope on the mock of ComprehensiveAbstractClass so that additional setups can be registered for that scenario.
+ ///
+ ///
+ /// Scenarios let you define per-state behavior. Setups registered inside the returned IMockInScenarioFor... scope only apply while the mock's current scenario matches ; switch scenarios with TransitionTo.
+ ///
+ /// Name of the scenario to enter. Any non-null string acts as a key; the mock starts in an unnamed default scenario.
+ /// A scoped accessor whose Setup (and SetupProtected, where applicable) register scenario-specific setups.
+ IMockInScenarioForComprehensiveAbstractClass InScenario(string scenario);
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, int v, string text = "x")
- : this(MockolateCreateRegistryFromBehavior(behavior), v, text)
- {
- }
+ ///
+ /// Opens a named scenario scope on the mock of ComprehensiveAbstractClass and immediately invokes to register scenario-specific setups.
+ ///
+ ///
+ /// Equivalent to InScenario(scenario) followed by the setup callback, but returns the original IMockFor... accessor so it chains nicely at mock-creation time.
+ ///
+ /// Name of the scenario to enter.
+ /// Callback that receives the scenario-scoped setup surface and registers scenario-specific setups.
+ /// This accessor, to allow chaining.
+ IMockForComprehensiveAbstractClass InScenario(string scenario, global::System.Action setup);
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry_1, int mockRegistry, bool _)
- : base(mockRegistry, _)
- {
- this.MockRegistry = mockRegistry_1;
- }
+ ///
+ /// Switches the active scenario of the mock of ComprehensiveAbstractClass to .
+ ///
+ ///
+ /// After the transition, setups registered via InScenario(string) under that scenario take effect. Scenarios that have no matching setup for a given member fall back to the default (un-scoped) setups.
+ ///
+ /// Name of the scenario to transition to.
+ /// This accessor, to allow chaining.
+ IMockForComprehensiveAbstractClass TransitionTo(string scenario);
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, int mockRegistry, bool _)
- : this(MockolateCreateRegistryFromBehavior(behavior), mockRegistry, _)
- {
- }
+ ///
+ /// Asserts how often, and in which order, members of the mock of ComprehensiveAbstractClass were invoked.
+ ///
+ ///
+ /// Each call to a member here returns a VerificationResult that you terminate with a count assertion: Never(), Once(), Twice(), Exactly(n), AtLeast(n)/AtLeastOnce()/AtLeastTwice(), AtMost(n)/AtMostOnce()/AtMostTwice(), Between(min, max) or Times(predicate).
+ /// Use Within(TimeSpan) / WithCancellation(CancellationToken) before the terminator to wait for expected interactions that happen on background threads.
+ /// Chain Then(...) to assert an ordered sequence of calls. A failing assertion throws a MockVerificationException.
+ ///
+ IMockVerifyForComprehensiveAbstractClass Verify { get; }
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, string name)
- : base(name)
- {
- this.MockRegistry = mockRegistry;
- }
+ ///
+ /// Asserts how often, and in which order, members of the mock of ComprehensiveAbstractClass were invoked.
+ ///
+ ///
+ /// Same terminators and modifiers as Verify (Once(), Exactly(n), Within(...), Then(...), ...); applies to members and events instead of public ones.
+ ///
+ IMockProtectedVerifyForComprehensiveAbstractClass VerifyProtected { get; }
- ///
- [global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
- public ComprehensiveAbstractClass(global::Mockolate.MockBehavior behavior, string name)
- : this(MockolateCreateRegistryFromBehavior(behavior), name)
- {
- }
+ ///
+ /// Verifies how often a specific method setup was matched by actual invocations.
+ ///
+ ///
+ /// Useful when you want to verify "this particular setup was hit N times" without re-stating the matchers. Chain the usual count terminators (Once(), AtLeastOnce(), Exactly(n), ...) on the returned result.
+ ///
+ /// The setup previously registered through Setup (typically returned from a Returns(...)/Throws(...) call).
+ /// A VerificationResult that counts invocations matching the given setup.
+ global::Mockolate.Verify.VerificationResult VerifySetup(global::Mockolate.Setup.IMethodSetup setup);
- #region Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
+ ///
+ /// Checks whether every recorded interaction on this mock has been observed by at least one Verify call.
+ ///
+ ///
+ /// Useful in test teardown to catch unexpected interactions ("strict verification"): if any recorded call has never been matched by a verification, the method returns .
+ ///
+ /// if every recorded interaction was verified at least once; otherwise .
+ bool VerifyThatAllInteractionsAreVerified();
- ///
- public override int V
+ ///
+ /// Checks whether every registered setup on this mock was matched by at least one actual invocation.
+ ///
+ ///
+ /// Useful to catch unused setups that silently rot as the test subject evolves.
+ ///
+ /// if every registered setup was used at least once; otherwise .
+ bool VerifyThatAllSetupsAreUsed();
+
+ ///
+ /// Removes every recorded interaction from this mock while keeping all registered setups intact.
+ ///
+ ///
+ /// Handy when a single test exercises multiple logical phases and you only want to verify the interactions of the latest phase.
+ ///
+ void ClearAllInteractions();
+
+ ///
+ /// Creates a monitor whose Verify surface is scoped to interactions produced between monitor.Run() and the disposal of its IDisposable scope.
+ ///
+ ///
+ /// The underlying mock keeps recording all interactions as usual - only the monitor's Verify view is scoped. Useful to verify only the interactions produced by a specific block of test code without resetting the mock.
+ ///
+ /// A MockMonitor<T> that exposes Verify over the monitored interactions and a Run() method that opens the recording scope.
+ global::Mockolate.Monitor.MockMonitor Monitor();
+ }
+
+ ///
+ /// Scoped access to setups for a scenario on the mock of ComprehensiveAbstractClass.
+ ///
+ internal interface IMockInScenarioForComprehensiveAbstractClass
+ {
+ ///
+ /// Set up the mock of ComprehensiveAbstractClass within the scenario scope.
+ ///
+ IMockSetupForComprehensiveAbstractClass Setup { get; }
+
+ ///
+ /// Set up protected members of the mock of ComprehensiveAbstractClass within the scenario scope.
+ ///
+ IMockProtectedSetupForComprehensiveAbstractClass SetupProtected { get; }
+ }
+
+ ///
+ /// Set up the mock of ComprehensiveAbstractClass.
+ ///
+ internal interface IMockSetupForComprehensiveAbstractClass : global::Mockolate.Setup.IMockSetup
+ {
+ ///
+ /// Setup for the int property V.
+ ///
+ global::Mockolate.Setup.PropertySetup V { get; }
+
+ ///
+ /// Setup for the method A().
+ ///
+ [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)]
+ global::Mockolate.Setup.IReturnMethodSetup A();
+
+ }
+
+ ///
+ /// Set up protected members for the mock of ComprehensiveAbstractClass.
+ ///
+ internal interface IMockProtectedSetupForComprehensiveAbstractClass
+ {
+ ///
+ /// Setup for the method P().
+ ///
+ [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)]
+ global::Mockolate.Setup.IReturnMethodSetup P();
+
+ }
+
+ ///
+ /// Verify interactions with the mock of ComprehensiveAbstractClass.
+ ///
+ internal interface IMockVerifyForComprehensiveAbstractClass : global::Mockolate.Verify.IMockVerify
+ {
+ ///
+ /// Verify interactions with the int property V.
+ ///
+ global::Mockolate.Verify.VerificationPropertyResult V { get; }
+
+ ///
+ /// Verify invocations for the method A().
+ ///
+ global::Mockolate.Verify.VerificationResult.IgnoreParameters A();
+
+ }
+
+ ///
+ /// Verify protected interactions with the mock of ComprehensiveAbstractClass.
+ ///
+ internal interface IMockProtectedVerifyForComprehensiveAbstractClass
+ {
+ ///
+ /// Verify invocations for the method P().
+ ///
+ global::Mockolate.Verify.VerificationResult.IgnoreParameters P();
+
+ }
+}
+///
+/// Mock extensions for ComprehensiveAbstractClass.
+///
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+internal static partial class MockExtensionsForComprehensiveAbstractClass
+{
+ ///
+ extension(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass mock)
+ {
+ ///
+ /// Gets the mock accessor for ComprehensiveAbstractClass - the entry point for configuring setups, verifying interactions and raising events.
+ ///
+ ///
+ /// The accessor is the bridge between the strongly-typed instance of ComprehensiveAbstractClass returned by CreateMock(...) and the underlying mock registry where setups and recorded interactions live.
+ /// Through it you can:
+ ///
+ /// - Setup - configure how members respond when invoked (Returns, Throws, Do, InitializeWith, ...).
+ /// - Verify - assert how often (and in which order) members were invoked.
+ /// - SetupProtected / VerifyProtected / RaiseProtected - target members on class mocks.
+ /// - InScenario / TransitionTo - scope setups and behavior to a named scenario and switch between scenarios.
+ /// - Monitor, ClearAllInteractions, VerifyThatAllInteractionsAreVerified, VerifyThatAllSetupsAreUsed - manage recorded interactions.
+ /// - VerifySetup - verify how often a specific setup matched.
+ ///
+ ///
+ /// The instance is not a Mockolate-generated mock of ComprehensiveAbstractClass.
+ public global::Mockolate.Mock.IMockForComprehensiveAbstractClass Mock
{
get
{
- return this.MockRegistry.GetPropertyFast(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.PropertyAccess_V_Get, static b => b.DefaultValue.Generate(default(int)!), this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps ? () => wraps.V : () => base.V);
+ if (mock is global::Mockolate.Mock.IMockForComprehensiveAbstractClass mockInterface)
+ {
+ return mockInterface;
+ }
+ throw new global::Mockolate.Exceptions.MockException("The subject is no mock.");
}
- set
+ }
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass with the default MockBehavior.
+ ///
+ ///
+ /// The returned instance is a strongly-typed mock generated at compile time - it implements ComprehensiveAbstractClass and exposes the Mockolate surface through .Mock:
+ ///
+ /// - .Mock.Setup configures how members respond (Returns, Throws, Do, InitializeWith, sequences, callbacks).
+ /// - .Mock.Verify asserts how often and in which order members were invoked.
+ ///
+ /// With the default behavior, un-configured members return default values (empty collections / strings, completed tasks, otherwise) and base-class implementations are invoked for class mocks. Use one of the overloads that accepts a MockBehavior to customize this (for example to make un-configured calls throw or to skip the base class).
+ /// Overloads allow you to additionally pass constructor parameters (for class mocks), apply an initial setup callback before the instance is returned, or combine both.
+ ///
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock()
+ => CreateMock(null, null, (object?[]?)null);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass with the default MockBehavior, applying the given immediately.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup)
+ => CreateMock(null, setup, (object?[]?)null);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass with the given .
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior)
+ => CreateMock(mockBehavior, null, (object?[]?)null);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass with the given , applying the given immediately.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup)
+ => CreateMock(mockBehavior, setup, (object?[]?)null);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given to invoke the base-class constructor.
+ ///
+ /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(object?[] constructorParameters)
+ => CreateMock(null, null, constructorParameters);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given and .
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters)
+ => CreateMock(mockBehavior, null, constructorParameters);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given .
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Values forwarded to a matching base-class constructor. Required when no parameterless constructor exists.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, object?[] constructorParameters)
+ => CreateMock(null, setup, constructorParameters);
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
+ ///
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(int v, string text = "x")
+ => CreateMock(null, null, new object?[] { v, text });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, int v, string text = "x")
+ => CreateMock(mockBehavior, null, new object?[] { v, text });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, int v, string text = "x")
+ => CreateMock(null, setup, new object?[] { v, text });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, string) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, int v, string text = "x")
+ => CreateMock(mockBehavior, setup, new object?[] { v, text });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
+ ///
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(int mockRegistry, bool _)
+ => CreateMock(null, null, new object?[] { mockRegistry, _ });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, int mockRegistry, bool _)
+ => CreateMock(mockBehavior, null, new object?[] { mockRegistry, _ });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, int mockRegistry, bool _)
+ => CreateMock(null, setup, new object?[] { mockRegistry, _ });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(int, bool) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, int mockRegistry, bool _)
+ => CreateMock(mockBehavior, setup, new object?[] { mockRegistry, _ });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
+ ///
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(string name)
+ => CreateMock(null, null, new object?[] { name });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given and the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, string name)
+ => CreateMock(mockBehavior, null, new object?[] { name });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::System.Action setup, string name)
+ => CreateMock(null, setup, new object?[] { name });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given constructor parameters to invoke the ComprehensiveAbstractClass(string) constructor.
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior.
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned.
+ /// Value forwarded to the base-class constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, string name)
+ => CreateMock(mockBehavior, setup, new object?[] { name });
+
+ ///
+ /// Creates a new mock of ComprehensiveAbstractClass using the given , applying the given immediately, using the given .
+ ///
+ ///
+ /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor.
+ ///
+ /// Controls how the mock responds when members are invoked without a matching setup, or for MockBehavior.Default.
+ /// Callback that receives the mock's setup surface and registers initial setups before the mock is returned, or to skip.
+ /// Values forwarded to a matching base-class constructor, or to use the parameterless constructor.
+ /// A new mock instance of ComprehensiveAbstractClass.
+ public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters)
+ {
+ if (mockBehavior is not null)
{
- if (!this.MockRegistry.SetPropertyFast(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V", value))
+ IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior;
+ if (mockBehaviorAccess.TryGet?>(out var additionalSetup))
{
- if (this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps)
+ if (setup is null)
{
- wraps.V = value;
+ setup = additionalSetup;
}
else
{
- base.V = value;
+ var originalSetup = setup;
+ setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); };
}
}
+ if (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters(out object?[]? parameters))
+ {
+ constructorParameters = parameters;
+ }
}
+
+ mockBehavior ??= global::Mockolate.MockBehavior.Default;
+ global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ComprehensiveAbstractClass.CreateFastInteractions(mockBehavior), constructorParameters);
+ return CreateMockInstance(mockRegistry, constructorParameters, setup);
}
- ///
- public override int A()
+ private static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup)
{
- global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null;
- if (string.IsNullOrEmpty(this.MockRegistry.Scenario))
+ if (constructorParameters is null || constructorParameters.Length == 0)
{
- global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A);
- if (snapshot_methodSetup is not null)
+ global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
+ global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
+ if (setup is not null)
{
- for (int i_methodSetup = snapshot_methodSetup.Length - 1; i_methodSetup >= 0; i_methodSetup--)
- {
- if (snapshot_methodSetup[i_methodSetup] is global::Mockolate.Setup.ReturnMethodSetup s_methodSetup && s_methodSetup.Matches())
- {
- methodSetup = s_methodSetup;
- break;
- }
- }
+ setupTarget ??= new(mockRegistry);
+ setup.Invoke(setupTarget);
}
+ return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry);
}
- if (methodSetup is null)
+ else if (constructorParameters.Length == 0)
{
- foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A"))
+ global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
+ global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
+ if (setup is not null)
{
- if (s_methodSetup.Matches())
- {
- methodSetup = s_methodSetup;
- break;
- }
+ setupTarget ??= new(mockRegistry);
+ setup.Invoke(setupTarget);
}
+ return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry);
}
- bool hasWrappedResult = false;
- int wrappedResult = default!;
- if (this.MockRegistry.Behavior.SkipInteractionRecording == false)
- {
- this.MockolateBuffer_A.Append("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A");
- }
- try
+ else if (constructorParameters.Length >= 1 && constructorParameters.Length <= 2
+ && TryCast(constructorParameters, 0, mockRegistry.Behavior, out int c2p1)
+ && TryCastWithDefaultValue(constructorParameters, 1, "x", mockRegistry.Behavior, out string c2p2))
{
- if (this.MockRegistry.Wraps is global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass wraps)
+ global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
+ global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
+ if (setup is not null)
{
- wrappedResult = wraps.A();
- hasWrappedResult = true;
+ setupTarget ??= new(mockRegistry);
+ setup.Invoke(setupTarget);
}
+ return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c2p1, c2p2);
}
- finally
- {
- methodSetup?.TriggerCallbacks();
- }
- if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup)
- {
- throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A()' was invoked without prior setup.");
- }
- if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult)
- {
- return wrappedResult;
- }
- return methodSetup?.TryGetReturnValue(out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(int)!);
- }
-
- ///
- protected override int P()
- {
- global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null;
- if (string.IsNullOrEmpty(this.MockRegistry.Scenario))
+ else if (constructorParameters.Length == 2
+ && TryCast(constructorParameters, 0, mockRegistry.Behavior, out int c3p1)
+ && TryCast(constructorParameters, 1, mockRegistry.Behavior, out bool c3p2))
{
- global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P);
- if (snapshot_methodSetup is not null)
+ global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
+ global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
+ if (setup is not null)
{
- for (int i_methodSetup = snapshot_methodSetup.Length - 1; i_methodSetup >= 0; i_methodSetup--)
- {
- if (snapshot_methodSetup[i_methodSetup] is global::Mockolate.Setup.ReturnMethodSetup s_methodSetup && s_methodSetup.Matches())
- {
- methodSetup = s_methodSetup;
- break;
- }
- }
+ setupTarget ??= new(mockRegistry);
+ setup.Invoke(setupTarget);
}
+ return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c3p1, c3p2);
}
- if (methodSetup is null)
+ else if (constructorParameters.Length == 1
+ && TryCast(constructorParameters, 0, mockRegistry.Behavior, out string c4p1))
{
- foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P"))
+ global::Mockolate.Mock.ComprehensiveAbstractClass.MockRegistryProvider.Value = mockRegistry;
+ global::Mockolate.MockExtensionsForComprehensiveAbstractClass.MockSetup? setupTarget = null;
+ if (setup is not null)
{
- if (s_methodSetup.Matches())
- {
- methodSetup = s_methodSetup;
- break;
- }
+ setupTarget ??= new(mockRegistry);
+ setup.Invoke(setupTarget);
}
+ return new global::Mockolate.Mock.ComprehensiveAbstractClass(mockRegistry, c4p1);
}
- bool hasWrappedResult = false;
- int wrappedResult = default!;
- if (this.MockRegistry.Behavior.SkipInteractionRecording == false)
+ else
{
- this.MockolateBuffer_P.Append("global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P");
+ throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)}).");
}
- try
+ static bool TryCast(object?[] values, int index, global::Mockolate.MockBehavior behavior, out TValue result)
{
- if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass))
+ var value = values[index];
+ if (value is TValue typedValue)
{
- wrappedResult = base.P();
- hasWrappedResult = true;
+ result = typedValue;
+ return true;
}
+
+ result = default!;
+ return value is null;
}
- finally
- {
- methodSetup?.TriggerCallbacks();
- }
- if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup)
- {
- throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P()' was invoked without prior setup.");
- }
- if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult)
- {
- return wrappedResult;
- }
- return methodSetup?.TryGetReturnValue(out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(int)!);
- }
-
- #endregion Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
-
- #region IMockSetupForComprehensiveAbstractClass
-
- ///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass.V
- {
- get
- {
- var propertySetup = new global::Mockolate.Setup.PropertySetup(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
- this.MockRegistry.SetupProperty(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, propertySetup);
- return propertySetup;
- }
- }
-
- ///
- global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass.A()
- {
- var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A");
- this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, methodSetup);
- return methodSetup;
- }
-
- #endregion IMockSetupForComprehensiveAbstractClass
-
- #region IMockProtectedSetupForComprehensiveAbstractClass
-
- ///
- global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass.P()
- {
- var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P");
- this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, methodSetup);
- return methodSetup;
- }
-
- #endregion IMockProtectedSetupForComprehensiveAbstractClass
-
- #region IMockVerifyForComprehensiveAbstractClass
-
- ///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForComprehensiveAbstractClass.V
- {
- get
+ static bool TryCastWithDefaultValue(object?[] values, int index, TValue defaultValue, global::Mockolate.MockBehavior behavior, out TValue result)
{
- return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ if (values.Length > index && values[index] is TValue typedValue)
+ {
+ result = typedValue;
+ return true;
+ }
+
+ result = defaultValue;
+ return true;
}
}
-
- ///
- global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForComprehensiveAbstractClass.A()
- => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A", () => $"A()");
- #endregion IMockVerifyForComprehensiveAbstractClass
-
- #region IMockProtectedVerifyForComprehensiveAbstractClass
-
- ///
- global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForComprehensiveAbstractClass.P()
- => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P", () => $"P()");
- #endregion IMockProtectedVerifyForComprehensiveAbstractClass
- }
-
- [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
- private sealed class VerifyMonitorComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyForComprehensiveAbstractClass
- {
- private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry;
-
- #region IMockVerifyForComprehensiveAbstractClass
-
- ///
- [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
- global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForComprehensiveAbstractClass.V
+ ///
+ /// Creates a mock that wraps the given .
+ ///
+ ///
+ /// Public members on the mock forward to unless overridden by a setup; protected members still go through the base-class implementation. All forwarded interactions are recorded and can be verified the same as on a plain mock.
+ ///
+ /// The real object whose calls should be forwarded. Must not be .
+ /// A new mock of ComprehensiveAbstractClass that delegates to .
+ public global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Wrapping(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass instance)
{
- get
+ if (mock is global::Mockolate.IMock mockInterface)
{
- return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
+ global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance);
+ wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ComprehensiveAbstractClass.CreateFastInteractions(wrappingRegistry.Behavior));
+ return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null);
}
+ throw new global::Mockolate.Exceptions.MockException("The subject is no mock.");
}
- ///
- global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForComprehensiveAbstractClass.A()
- => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A", () => $"A()");
- #endregion IMockVerifyForComprehensiveAbstractClass
}
- [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
- private sealed class MockInScenarioForComprehensiveAbstractClass : global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass, global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass, global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass
+ ///
+ extension(global::Mockolate.MockBehavior behavior)
{
- private global::Mockolate.MockRegistry MockRegistry { get; }
- private string _scenarioName;
-
- public MockInScenarioForComprehensiveAbstractClass(global::Mockolate.MockRegistry mockRegistry, string scenario)
+ ///
+ /// Initializes mocks of type with the given .
+ ///
+ ///
+ /// The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones.
+ ///
+ /// The mockable type derived from ComprehensiveAbstractClass that this setup should apply to.
+ /// Callback invoked when a new mock of is created.
+ /// A new MockBehavior with the registered initializer. The original instance is unchanged.
+ public global::Mockolate.MockBehavior Initialize(global::System.Action setup)
+ where T : global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass
{
- this.MockRegistry = mockRegistry;
- _scenarioName = scenario;
+ var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior;
+ return behaviorAccess.Set(setup);
}
+ }
+ internal interface IMockSetupInitializationForComprehensiveAbstractClass : global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass
+ {
+ ///
+ /// Setup protected members
+ ///
+ global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass Protected { get; }
+ }
+ [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass, global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass, IMockSetupInitializationForComprehensiveAbstractClass
+ {
///
- global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass.Setup
- => this;
-
- ///
- global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass global::Mockolate.Mock.IMockInScenarioForComprehensiveAbstractClass.SetupProtected
- => this;
+ global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass IMockSetupInitializationForComprehensiveAbstractClass.Protected => this;
+ private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry;
#region IMockSetupForComprehensiveAbstractClass
@@ -919,7 +1101,7 @@ public MockInScenarioForComprehensiveAbstractClass(global::Mockolate.MockRegistr
get
{
var propertySetup = new global::Mockolate.Setup.PropertySetup(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.V");
- this.MockRegistry.SetupProperty(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, _scenarioName, propertySetup);
+ this.MockRegistry.SetupProperty(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, propertySetup);
return propertySetup;
}
}
@@ -928,7 +1110,7 @@ public MockInScenarioForComprehensiveAbstractClass(global::Mockolate.MockRegistr
global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForComprehensiveAbstractClass.A()
{
var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.A");
- this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, _scenarioName, methodSetup);
+ this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A, methodSetup);
return methodSetup;
}
@@ -940,207 +1122,24 @@ public MockInScenarioForComprehensiveAbstractClass(global::Mockolate.MockRegistr
global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockProtectedSetupForComprehensiveAbstractClass.P()
{
var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass.P");
- this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, _scenarioName, methodSetup);
+ this.MockRegistry.SetupMethod(global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P, methodSetup);
return methodSetup;
}
#endregion IMockProtectedSetupForComprehensiveAbstractClass
}
- ///
- /// The Mockolate accessor for a mock of