From e0233809cfe9fa0975739fe04dc4463cf7da32ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sat, 2 May 2026 07:17:36 +0200 Subject: [PATCH] refactor: move source-generated mock to top of file --- .../Sources/Sources.MockClass.cs | 3517 ++++++++--------- .../Sources/Sources.MockCombination.cs | 440 ++- .../Sources/Sources.MockDelegate.cs | 342 +- .../Mock.ComprehensiveAbstractClass.g.cs | 1791 +++++---- ...nsiveAbstractClass__ICombinationMockA.g.cs | 204 +- ..._ICombinationMockA__ICombinationMockB.g.cs | 206 +- .../Mock.ICombinationMockA.g.cs | 361 +- .../Mock.ICombinationMockB.g.cs | 361 +- .../Mock.ComprehensiveAbstractClass.g.cs | 1791 +++++---- .../Mock.ComprehensiveDelegate.g.cs | 124 +- .../Mock.IComprehensiveInterface.g.cs | 367 +- .../Mock.HttpClient.g.cs | 1493 ++++--- .../Mock.HttpMessageHandler.g.cs | 1809 +++++---- .../Mock.IKeywordEdgeCases.g.cs | 365 +- .../Mock.IRefStructConsumer.g.cs | 361 +- .../Mock.IStaticAbstractMembers.g.cs | 363 +- 16 files changed, 6800 insertions(+), 7095 deletions(-) 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 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; } - - /// - /// 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; } - - /// - /// 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); - - /// - /// 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); - - /// - /// 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); - - /// - /// 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; } - - /// - /// 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; } - - /// - /// 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); - - /// - /// 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(); - - /// - /// 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 + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private sealed class CovariantParameterAdapter(global::Mockolate.Parameters.IParameter inner) : global::Mockolate.Parameters.IParameterMatch { - /// - /// Verify invocations for the method P(). - /// - global::Mockolate.Verify.VerificationResult.IgnoreParameters P(); + public bool Matches(T value) => inner.Matches(value); + public void InvokeCallbacks(T value) => inner.InvokeCallbacks(value); + public override string? ToString() => inner.ToString(); + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs index 347e4ba1..1d96ce08 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs @@ -10,108 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for ComprehensiveAbstractClass that also implements
-/// - ICombinationMockA. -///
-[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForComprehensiveAbstractClass__ICombinationMockA -{ - /// - /// Extends this mock so the returned instance also implements ICombinationMockA. - /// - /// - /// The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to ICombinationMockA to exercise the extra surface or use .Mock.As<ICombinationMockA>() to reach the Setup/Verify surface of the additional interface. - /// - /// The mock instance to extend. - /// Optional setup callbacks registered on the additional interface before the mock is returned. - /// A mock of the original type that additionally implements ICombinationMockA. - public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Implementing(this global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass sut, params global::System.Action[] setups) - where TInterface : global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA - { - if (sut is not global::Mockolate.IMock mock) - { - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA value; - if (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 0) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry); - } - else if (mock.MockRegistry.ConstructorParameters.Length >= 1 && mock.MockRegistry.ConstructorParameters.Length <= 2 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c2p1) - && TryCastWithDefaultValue(mock.MockRegistry.ConstructorParameters, 1, "x", mock.MockRegistry.Behavior, out string c2p2)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c2p1, c2p2); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 2 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c3p1) - && TryCast(mock.MockRegistry.ConstructorParameters, 1, mock.MockRegistry.Behavior, out bool c3p2)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c3p1, c3p2); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 1 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out string c4p1)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c4p1); - } - else - { - throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(", ", mock.MockRegistry.ConstructorParameters)})."); - } - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior; - if (mockBehaviorAccess.TryGet[]?>(out var additionalSetups)) - { - if (setups.Length > 0) - { - var concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length]; - additionalSetups.CopyTo(concatenatedSetups, 0); - setups.CopyTo(concatenatedSetups, additionalSetups.Length); - setups = concatenatedSetups; - } - else - { - setups = additionalSetups; - } - } - if (setups.Length > 0) - { - foreach (var setup in setups) - { - setup.Invoke(value); - } - } - return value; - 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; - } - 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; - } - } -} - internal static partial class Mock { /// @@ -580,4 +478,106 @@ protected override int P() } } +/// +/// Mock extensions for ComprehensiveAbstractClass that also implements
+/// - ICombinationMockA. +///
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForComprehensiveAbstractClass__ICombinationMockA +{ + /// + /// Extends this mock so the returned instance also implements ICombinationMockA. + /// + /// + /// The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to ICombinationMockA to exercise the extra surface or use .Mock.As<ICombinationMockA>() to reach the Setup/Verify surface of the additional interface. + /// + /// The mock instance to extend. + /// Optional setup callbacks registered on the additional interface before the mock is returned. + /// A mock of the original type that additionally implements ICombinationMockA. + public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Implementing(this global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass sut, params global::System.Action[] setups) + where TInterface : global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA + { + if (sut is not global::Mockolate.IMock mock) + { + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA value; + if (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 0) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry); + } + else if (mock.MockRegistry.ConstructorParameters.Length >= 1 && mock.MockRegistry.ConstructorParameters.Length <= 2 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c2p1) + && TryCastWithDefaultValue(mock.MockRegistry.ConstructorParameters, 1, "x", mock.MockRegistry.Behavior, out string c2p2)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c2p1, c2p2); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 2 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c3p1) + && TryCast(mock.MockRegistry.ConstructorParameters, 1, mock.MockRegistry.Behavior, out bool c3p2)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c3p1, c3p2); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 1 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out string c4p1)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA(mock.MockRegistry, c4p1); + } + else + { + throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(", ", mock.MockRegistry.ConstructorParameters)})."); + } + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior; + if (mockBehaviorAccess.TryGet[]?>(out var additionalSetups)) + { + if (setups.Length > 0) + { + var concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length]; + additionalSetups.CopyTo(concatenatedSetups, 0); + setups.CopyTo(concatenatedSetups, additionalSetups.Length); + setups = concatenatedSetups; + } + else + { + setups = additionalSetups; + } + } + if (setups.Length > 0) + { + foreach (var setup in setups) + { + setup.Invoke(value); + } + } + return value; + 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; + } + 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; + } + } +} + #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs index c8af595a..4dc71c33 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs @@ -10,109 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for ComprehensiveAbstractClass that also implements
-/// - ICombinationMockA
-/// - ICombinationMockB. -///
-[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB -{ - /// - /// Extends this mock so the returned instance also implements ICombinationMockB. - /// - /// - /// The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to ICombinationMockB to exercise the extra surface or use .Mock.As<ICombinationMockB>() to reach the Setup/Verify surface of the additional interface. - /// - /// The mock instance to extend. - /// Optional setup callbacks registered on the additional interface before the mock is returned. - /// A mock of the original type that additionally implements ICombinationMockB. - public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Implementing(this global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass sut, params global::System.Action[] setups) - where TInterface : global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB - { - if (sut is not global::Mockolate.IMock mock) - { - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB value; - if (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 0) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry); - } - else if (mock.MockRegistry.ConstructorParameters.Length >= 1 && mock.MockRegistry.ConstructorParameters.Length <= 2 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c2p1) - && TryCastWithDefaultValue(mock.MockRegistry.ConstructorParameters, 1, "x", mock.MockRegistry.Behavior, out string c2p2)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c2p1, c2p2); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 2 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c3p1) - && TryCast(mock.MockRegistry.ConstructorParameters, 1, mock.MockRegistry.Behavior, out bool c3p2)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c3p1, c3p2); - } - else if (mock.MockRegistry.ConstructorParameters.Length == 1 - && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out string c4p1)) - { - value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c4p1); - } - else - { - throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(", ", mock.MockRegistry.ConstructorParameters)})."); - } - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior; - if (mockBehaviorAccess.TryGet[]?>(out var additionalSetups)) - { - if (setups.Length > 0) - { - var concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length]; - additionalSetups.CopyTo(concatenatedSetups, 0); - setups.CopyTo(concatenatedSetups, additionalSetups.Length); - setups = concatenatedSetups; - } - else - { - setups = additionalSetups; - } - } - if (setups.Length > 0) - { - foreach (var setup in setups) - { - setup.Invoke(value); - } - } - return value; - 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; - } - 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; - } - } -} - internal static partial class Mock { /// @@ -730,4 +627,107 @@ protected override int P() } } +/// +/// Mock extensions for ComprehensiveAbstractClass that also implements
+/// - ICombinationMockA
+/// - ICombinationMockB. +///
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB +{ + /// + /// Extends this mock so the returned instance also implements ICombinationMockB. + /// + /// + /// The returned instance is a brand-new mock that shares the mock registry (recorded interactions, scenario state, setups) of this one. Cast it to ICombinationMockB to exercise the extra surface or use .Mock.As<ICombinationMockB>() to reach the Setup/Verify surface of the additional interface. + /// + /// The mock instance to extend. + /// Optional setup callbacks registered on the additional interface before the mock is returned. + /// A mock of the original type that additionally implements ICombinationMockB. + public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass Implementing(this global::Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass sut, params global::System.Action[] setups) + where TInterface : global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB + { + if (sut is not global::Mockolate.IMock mock) + { + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB value; + if (mock.MockRegistry.ConstructorParameters is null || mock.MockRegistry.ConstructorParameters.Length == 0) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 0) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry); + } + else if (mock.MockRegistry.ConstructorParameters.Length >= 1 && mock.MockRegistry.ConstructorParameters.Length <= 2 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c2p1) + && TryCastWithDefaultValue(mock.MockRegistry.ConstructorParameters, 1, "x", mock.MockRegistry.Behavior, out string c2p2)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c2p1, c2p2); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 2 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out int c3p1) + && TryCast(mock.MockRegistry.ConstructorParameters, 1, mock.MockRegistry.Behavior, out bool c3p2)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c3p1, c3p2); + } + else if (mock.MockRegistry.ConstructorParameters.Length == 1 + && TryCast(mock.MockRegistry.ConstructorParameters, 0, mock.MockRegistry.Behavior, out string c4p1)) + { + value = new global::Mockolate.Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB(mock.MockRegistry, c4p1); + } + else + { + throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'Mockolate.Tests.GeneratorCoverage.ComprehensiveAbstractClass' that matches the {mock.MockRegistry.ConstructorParameters.Length} given parameters ({string.Join(", ", mock.MockRegistry.ConstructorParameters)})."); + } + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mock.MockRegistry.Behavior; + if (mockBehaviorAccess.TryGet[]?>(out var additionalSetups)) + { + if (setups.Length > 0) + { + var concatenatedSetups = new global::System.Action[additionalSetups.Length + setups.Length]; + additionalSetups.CopyTo(concatenatedSetups, 0); + setups.CopyTo(concatenatedSetups, additionalSetups.Length); + setups = concatenatedSetups; + } + else + { + setups = additionalSetups; + } + } + if (setups.Length > 0) + { + foreach (var setup in setups) + { + setup.Invoke(value); + } + } + return value; + 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; + } + 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; + } + } +} + #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockA.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockA.g.cs index 9a934d04..07c4f063 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockA.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockA.g.cs @@ -10,187 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for ICombinationMockA. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForICombinationMockA -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA mock) - { - /// - /// Gets the mock accessor for ICombinationMockA - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of ICombinationMockA 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.
- /// 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 ICombinationMockA. - public global::Mockolate.Mock.IMockForICombinationMockA Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForICombinationMockA mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of ICombinationMockA with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements ICombinationMockA 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 ICombinationMockA. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockA with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of ICombinationMockA. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. - private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ICombinationMockA.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.ICombinationMockA(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 ICombinationMockA that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA Wrapping(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ICombinationMockA.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 ICombinationMockA 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.ICombinationMockA - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -612,5 +431,185 @@ internal interface IMockVerifyForICombinationMockA : global::Mockolate.Verify.IM } } +/// +/// Mock extensions for ICombinationMockA. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForICombinationMockA +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA mock) + { + /// + /// Gets the mock accessor for ICombinationMockA - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of ICombinationMockA 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.
+ /// 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 ICombinationMockA. + public global::Mockolate.Mock.IMockForICombinationMockA Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForICombinationMockA mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of ICombinationMockA with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements ICombinationMockA 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 ICombinationMockA. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockA with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of ICombinationMockA. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockA 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 ICombinationMockA. + private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ICombinationMockA.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.ICombinationMockA(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 ICombinationMockA that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA Wrapping(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ICombinationMockA.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 ICombinationMockA 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.ICombinationMockA + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockB.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockB.g.cs index 88ffb1e0..a3701df5 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockB.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ICombinationMockB.g.cs @@ -10,187 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for ICombinationMockB. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForICombinationMockB -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB mock) - { - /// - /// Gets the mock accessor for ICombinationMockB - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of ICombinationMockB 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.
- /// 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 ICombinationMockB. - public global::Mockolate.Mock.IMockForICombinationMockB Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForICombinationMockB mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of ICombinationMockB with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements ICombinationMockB 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 ICombinationMockB. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockB with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of ICombinationMockB. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. - public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. - private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ICombinationMockB.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.ICombinationMockB(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 ICombinationMockB that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB Wrapping(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ICombinationMockB.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 ICombinationMockB 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.ICombinationMockB - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -612,5 +431,185 @@ internal interface IMockVerifyForICombinationMockB : global::Mockolate.Verify.IM } } +/// +/// Mock extensions for ICombinationMockB. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForICombinationMockB +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB mock) + { + /// + /// Gets the mock accessor for ICombinationMockB - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of ICombinationMockB 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.
+ /// 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 ICombinationMockB. + public global::Mockolate.Mock.IMockForICombinationMockB Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForICombinationMockB mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of ICombinationMockB with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements ICombinationMockB 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 ICombinationMockB. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockB with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of ICombinationMockB. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. + public static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of ICombinationMockB 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 ICombinationMockB. + private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.ICombinationMockB.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.ICombinationMockB(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 ICombinationMockB that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB Wrapping(global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.ICombinationMockB.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 ICombinationMockB 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.ICombinationMockB + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveAbstractClass_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveAbstractClass_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs index 6665ca37..731eb0c4 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveAbstractClass_CanBeCreated/Mock.ComprehensiveAbstractClass.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveAbstractClass_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 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; } - - /// - /// 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; } - - /// - /// 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); - - /// - /// 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); - - /// - /// 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); - - /// - /// 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; } - - /// - /// 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; } - - /// - /// 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); - - /// - /// 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(); - - /// - /// 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 + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private sealed class CovariantParameterAdapter(global::Mockolate.Parameters.IParameter inner) : global::Mockolate.Parameters.IParameterMatch { - /// - /// Verify invocations for the method P(). - /// - global::Mockolate.Verify.VerificationResult.IgnoreParameters P(); + public bool Matches(T value) => inner.Matches(value); + public void InvokeCallbacks(T value) => inner.InvokeCallbacks(value); + public override string? ToString() => inner.ToString(); + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveDelegate_CanBeCreated/Mock.ComprehensiveDelegate.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveDelegate_CanBeCreated/Mock.ComprehensiveDelegate.g.cs index 3b5fa951..db893751 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveDelegate_CanBeCreated/Mock.ComprehensiveDelegate.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveDelegate_CanBeCreated/Mock.ComprehensiveDelegate.g.cs @@ -10,68 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for ComprehensiveDelegate. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForComprehensiveDelegate -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate mock) - { - /// - /// Get access to the mock of ComprehensiveDelegate. - /// - public global::Mockolate.Mock.IMockForComprehensiveDelegate Mock - { - get - { - if (mock.Target is global::Mockolate.Mock.IMockForComprehensiveDelegate mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Create a new mock of ComprehensiveDelegate with the default MockBehavior. - /// - public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock() - => CreateMock(null, []); - - /// - /// Create a new mock of ComprehensiveDelegate with the default MockBehavior. - /// - /// - /// All provided are immediately applied to the mock. - /// - public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock(params global::System.Action[] setups) - => CreateMock(null, setups); - - /// - /// Create a new mock of ComprehensiveDelegate with the given . - /// - /// - /// All provided are immediately applied to the mock. - /// - public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock(global::Mockolate.MockBehavior? mockBehavior = null, params global::System.Action[] setups) - { - mockBehavior ??= global::Mockolate.MockBehavior.Default; - var mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, new global::Mockolate.Interactions.FastMockInteractions(0, mockBehavior.SkipInteractionRecording)); - global::Mockolate.Mock.ComprehensiveDelegate mockTarget = new global::Mockolate.Mock.ComprehensiveDelegate(mockRegistry); - if (setups.Length > 0) - { - foreach (var setup in setups) - { - setup.Invoke(mockTarget); - } - } - return mockTarget.Object; - } - } -} - internal static partial class Mock { /// @@ -428,4 +366,66 @@ internal interface IMockVerifyForComprehensiveDelegate : global::Mockolate.Verif } } + +/// +/// Mock extensions for ComprehensiveDelegate. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForComprehensiveDelegate +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate mock) + { + /// + /// Get access to the mock of ComprehensiveDelegate. + /// + public global::Mockolate.Mock.IMockForComprehensiveDelegate Mock + { + get + { + if (mock.Target is global::Mockolate.Mock.IMockForComprehensiveDelegate mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Create a new mock of ComprehensiveDelegate with the default MockBehavior. + /// + public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock() + => CreateMock(null, []); + + /// + /// Create a new mock of ComprehensiveDelegate with the default MockBehavior. + /// + /// + /// All provided are immediately applied to the mock. + /// + public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock(params global::System.Action[] setups) + => CreateMock(null, setups); + + /// + /// Create a new mock of ComprehensiveDelegate with the given . + /// + /// + /// All provided are immediately applied to the mock. + /// + public static global::Mockolate.Tests.GeneratorCoverage.ComprehensiveDelegate CreateMock(global::Mockolate.MockBehavior? mockBehavior = null, params global::System.Action[] setups) + { + mockBehavior ??= global::Mockolate.MockBehavior.Default; + var mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, new global::Mockolate.Interactions.FastMockInteractions(0, mockBehavior.SkipInteractionRecording)); + global::Mockolate.Mock.ComprehensiveDelegate mockTarget = new global::Mockolate.Mock.ComprehensiveDelegate(mockRegistry); + if (setups.Length > 0) + { + foreach (var setup in setups) + { + setup.Invoke(mockTarget); + } + } + return mockTarget.Object; + } + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveInterface_CanBeCreated/Mock.IComprehensiveInterface.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveInterface_CanBeCreated/Mock.IComprehensiveInterface.g.cs index 2b44a34e..f38ea9b2 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveInterface_CanBeCreated/Mock.IComprehensiveInterface.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/ComprehensiveInterface_CanBeCreated/Mock.IComprehensiveInterface.g.cs @@ -10,190 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for IComprehensiveInterface. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForIComprehensiveInterface -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface mock) - { - /// - /// Gets the mock accessor for IComprehensiveInterface - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of IComprehensiveInterface 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.
- /// Raise - trigger events declared on the mocked type.
- /// SetupStatic / VerifyStatic / RaiseStatic - target members on interface 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 IComprehensiveInterface. - public global::Mockolate.Mock.IMockForIComprehensiveInterface Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForIComprehensiveInterface mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of IComprehensiveInterface with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements IComprehensiveInterface 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.
- /// .Mock.Raise triggers events declared on the mocked type.
- ///

- /// 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 IComprehensiveInterface. - public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. - public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of IComprehensiveInterface with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of IComprehensiveInterface. - public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. - public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. - private static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IComprehensiveInterface.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.IComprehensiveInterface(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 IComprehensiveInterface that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface Wrapping(global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IComprehensiveInterface.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 IComprehensiveInterface 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.IComprehensiveInterface - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -6021,5 +5837,188 @@ internal interface IMockStaticVerifyForIComprehensiveInterface } } +/// +/// Mock extensions for IComprehensiveInterface. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForIComprehensiveInterface +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface mock) + { + /// + /// Gets the mock accessor for IComprehensiveInterface - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of IComprehensiveInterface 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.
+ /// Raise - trigger events declared on the mocked type.
+ /// SetupStatic / VerifyStatic / RaiseStatic - target members on interface 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 IComprehensiveInterface. + public global::Mockolate.Mock.IMockForIComprehensiveInterface Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForIComprehensiveInterface mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of IComprehensiveInterface with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements IComprehensiveInterface 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.
+ /// .Mock.Raise triggers events declared on the mocked type.
+ ///

+ /// 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 IComprehensiveInterface. + public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. + public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of IComprehensiveInterface with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of IComprehensiveInterface. + public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. + public static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of IComprehensiveInterface 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 IComprehensiveInterface. + private static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IComprehensiveInterface.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.IComprehensiveInterface(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 IComprehensiveInterface that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface Wrapping(global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IComprehensiveInterface.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 IComprehensiveInterface 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.IComprehensiveInterface + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpClient.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpClient.g.cs index 12b85acc..6e9e48fc 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpClient.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpClient.g.cs @@ -10,507 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for HttpClient. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForHttpClient -{ - /// - extension(global::System.Net.Http.HttpClient mock) - { - /// - /// Gets the mock accessor for HttpClient - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of HttpClient 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 HttpClient. - public global::Mockolate.Mock.IMockForHttpClient Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForHttpClient mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of HttpClient with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of HttpClient with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(object?[] constructorParameters) - => CreateMock(null, null, constructorParameters); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters) - => CreateMock(mockBehavior, null, constructorParameters); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, object?[] constructorParameters) - => CreateMock(null, setup, constructorParameters); - - /// - /// Creates a new mock of HttpClient using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) constructor. - /// - /// Value forwarded to the base-class constructor. - /// A new mock instance of HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Net.Http.HttpMessageHandler handler) - => CreateMock(null, null, new object?[] { handler }); - - /// - /// Creates a new mock of HttpClient using the given and the given constructor parameters to invoke the HttpClient(HttpMessageHandler) 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Net.Http.HttpMessageHandler handler) - => CreateMock(mockBehavior, null, new object?[] { handler }); - - /// - /// Creates a new mock of HttpClient applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler) - => CreateMock(null, setup, new object?[] { handler }); - - /// - /// Creates a new mock of HttpClient using the given , applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler) - => CreateMock(mockBehavior, setup, new object?[] { handler }); - - /// - /// Creates a new mock of HttpClient using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, bool) constructor. - /// - /// Value forwarded to the base-class constructor. - /// Value forwarded to the base-class constructor. - /// A new mock instance of HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) - => CreateMock(null, null, new object?[] { handler, disposeHandler }); - - /// - /// Creates a new mock of HttpClient using the given and the given constructor parameters to invoke the HttpClient(HttpMessageHandler, 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) - => CreateMock(mockBehavior, null, new object?[] { handler, disposeHandler }); - - /// - /// Creates a new mock of HttpClient applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) - => CreateMock(null, setup, new object?[] { handler, disposeHandler }); - - /// - /// Creates a new mock of HttpClient using the given , applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) - => CreateMock(mockBehavior, setup, new object?[] { handler, disposeHandler }); - - /// - /// Creates a new mock of HttpClient 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 HttpClient. - public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - if (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters(out object?[]? parameters)) - { - constructorParameters = parameters; - } - } - - global::Mockolate.MockBehavior effectiveBehavior = mockBehavior ?? global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(effectiveBehavior, global::Mockolate.Mock.HttpClient.CreateFastInteractions(effectiveBehavior), constructorParameters); - if (constructorParameters is null) - { - constructorParameters = [new global::Mockolate.Mock.HttpMessageHandler(mockRegistry),]; - mockRegistry = new global::Mockolate.MockRegistry(mockRegistry, constructorParameters); - } - else if (constructorParameters.Length > 0 && constructorParameters[0] is global::Mockolate.Mock.HttpMessageHandler && constructorParameters[0] is global::Mockolate.IMock httpMessageHandlerMock) - { - if (mockBehavior is not null && httpMessageHandlerMock.MockRegistry.Behavior != mockBehavior) - { - throw 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}'."); - } - mockRegistry = new global::Mockolate.MockRegistry(httpMessageHandlerMock.MockRegistry, constructorParameters); - } - mockBehavior ??= global::Mockolate.MockBehavior.Default; - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::System.Net.Http.HttpClient CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - if (constructorParameters is null || constructorParameters.Length == 0) - { - global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; - if (setup is not null) - { - setupTarget ??= new(mockRegistry); - setup.Invoke(setupTarget); - } - return new global::Mockolate.Mock.HttpClient(mockRegistry); - } - else if (constructorParameters.Length == 0) - { - global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; - if (setup is not null) - { - setupTarget ??= new(mockRegistry); - setup.Invoke(setupTarget); - } - return new global::Mockolate.Mock.HttpClient(mockRegistry); - } - else if (constructorParameters.Length == 1 - && TryCast(constructorParameters, 0, mockRegistry.Behavior, out global::System.Net.Http.HttpMessageHandler c2p1)) - { - global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; - if (setup is not null) - { - setupTarget ??= new(mockRegistry); - setup.Invoke(setupTarget); - } - return new global::Mockolate.Mock.HttpClient(mockRegistry, c2p1); - } - else if (constructorParameters.Length == 2 - && TryCast(constructorParameters, 0, mockRegistry.Behavior, out global::System.Net.Http.HttpMessageHandler c3p1) - && TryCast(constructorParameters, 1, mockRegistry.Behavior, out bool c3p2)) - { - global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; - if (setup is not null) - { - setupTarget ??= new(mockRegistry); - setup.Invoke(setupTarget); - } - return new global::Mockolate.Mock.HttpClient(mockRegistry, c3p1, c3p2); - } - else - { - throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'System.Net.Http.HttpClient' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)})."); - } - 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; - } - } - /// - /// 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 HttpClient that delegates to . - public global::System.Net.Http.HttpClient Wrapping(global::System.Net.Http.HttpClient instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.HttpClient.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 HttpClient 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::System.Net.Http.HttpClient - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - internal interface IMockSetupInitializationForHttpClient : global::Mockolate.Mock.IMockSetupForHttpClient - { - /// - /// Setup protected members - /// - global::Mockolate.Mock.IMockProtectedSetupForHttpClient Protected { get; } - } - - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForHttpClient, global::Mockolate.Mock.IMockProtectedSetupForHttpClient, IMockSetupInitializationForHttpClient - { - /// - global::Mockolate.Mock.IMockProtectedSetupForHttpClient IMockSetupInitializationForHttpClient.Protected => this; - private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; - - #region IMockSetupForHttpClient - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - #endregion IMockSetupForHttpClient - - #region IMockProtectedSetupForHttpClient - - /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", parameters, "disposing"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(global::Mockolate.Parameters.IParameter? disposing) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", CovariantParameterAdapter.Wrap(disposing ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(bool disposing) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(disposing)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); - return methodSetup; - } - - #endregion IMockProtectedSetupForHttpClient - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -1251,405 +750,905 @@ public MockInScenarioForHttpClient(global::Mockolate.MockRegistry mockRegistry, return methodSetup; } - #endregion IMockProtectedSetupForHttpClient + #endregion IMockProtectedSetupForHttpClient + } + + /// + /// The Mockolate accessor for a mock of HttpClient, 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 IMockForHttpClient + { + /// + /// Configures how members of the mock of HttpClient 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. + ///
+ IMockSetupForHttpClient Setup { get; } + + /// + /// Configures how virtual members of the mock of HttpClient 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. + /// + IMockProtectedSetupForHttpClient SetupProtected { get; } + + /// + /// Opens a named scenario scope on the mock of HttpClient 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. + IMockInScenarioForHttpClient InScenario(string scenario); + + /// + /// Opens a named scenario scope on the mock of HttpClient 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. + IMockForHttpClient InScenario(string scenario, global::System.Action setup); + + /// + /// Switches the active scenario of the mock of HttpClient 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. + IMockForHttpClient TransitionTo(string scenario); + + /// + /// Asserts how often, and in which order, members of the mock of HttpClient 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. + ///
+ IMockVerifyForHttpClient Verify { get; } + + /// + /// Asserts how often, and in which order, members of the mock of HttpClient were invoked. + /// + /// + /// Same terminators and modifiers as Verify (Once(), Exactly(n), Within(...), Then(...), ...); applies to members and events instead of public ones. + /// + IMockProtectedVerifyForHttpClient VerifyProtected { get; } + + /// + /// 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); + + /// + /// 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(); + + /// + /// 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 HttpClient. + /// + internal interface IMockInScenarioForHttpClient + { + /// + /// Set up the mock of HttpClient within the scenario scope. + /// + IMockSetupForHttpClient Setup { get; } + + /// + /// Set up protected members of the mock of HttpClient within the scenario scope. + /// + IMockProtectedSetupForHttpClient SetupProtected { get; } + } + + /// + /// Set up the mock of HttpClient. + /// + internal interface IMockSetupForHttpClient : global::Mockolate.Setup.IMockSetup + { + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given . + /// + /// + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameters parameters); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . + /// + /// + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameters parameters); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + } /// - /// The Mockolate accessor for a mock of HttpClient, reached through .Mock on the mocked instance. + /// Set up protected members for the mock of HttpClient. /// - /// - /// Groups every operation that acts on the mock rather than on the mocked subject: setups, verifications, event raising, scenarios and monitoring. - /// - internal interface IMockForHttpClient + internal interface IMockProtectedSetupForHttpClient { /// - /// Configures how members of the mock of HttpClient respond when invoked. + /// Setup for the method Dispose(bool) with the given . /// /// - /// 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. + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. ///
- IMockSetupForHttpClient Setup { get; } + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameters parameters); /// - /// Configures how virtual members of the mock of HttpClient respond when invoked. + /// Setup for the method Dispose(bool) with the given . /// /// - /// 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. + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// - IMockProtectedSetupForHttpClient SetupProtected { get; } + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameter? disposing); /// - /// Opens a named scenario scope on the mock of HttpClient so that additional setups can be registered for that scenario. + /// Setup for the method Dispose(bool) with the given . /// /// - /// 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. + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). /// - /// 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. - IMockInScenarioForHttpClient InScenario(string scenario); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer Dispose(bool disposing); + + } + /// + /// Verify interactions with the mock of HttpClient. + /// + internal interface IMockVerifyForHttpClient : global::Mockolate.Verify.IMockVerify + { /// - /// Opens a named scenario scope on the mock of HttpClient and immediately invokes to register scenario-specific setups. + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given . /// /// - /// Equivalent to InScenario(scenario) followed by the setup callback, but returns the original IMockFor... accessor so it chains nicely at mock-creation time. + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. /// - /// Name of the scenario to enter. - /// Callback that receives the scenario-scoped setup surface and registers scenario-specific setups. - /// This accessor, to allow chaining. - IMockForHttpClient InScenario(string scenario, global::System.Action setup); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameters parameters); /// - /// Switches the active scenario of the mock of HttpClient to . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// 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. + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// - /// Name of the scenario to transition to. - /// This accessor, to allow chaining. - IMockForHttpClient TransitionTo(string scenario); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Asserts how often, and in which order, members of the mock of HttpClient were invoked. + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// 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. + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . ///
- IMockVerifyForHttpClient Verify { get; } + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Verify.VerificationResult Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Asserts how often, and in which order, members of the mock of HttpClient were invoked. + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// Same terminators and modifiers as Verify (Once(), Exactly(n), Within(...), Then(...), ...); applies to members and events instead of public ones. + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// - IMockProtectedVerifyForHttpClient VerifyProtected { get; } + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); /// - /// Verifies how often a specific method setup was matched by actual invocations. + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// 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. + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. /// - /// 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); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Verify.VerificationResult.IgnoreParameters Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); /// - /// Checks whether every recorded interaction on this mock has been observed by at least one Verify call. + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . /// /// - /// Useful in test teardown to catch unexpected interactions ("strict verification"): if any recorded call has never been matched by a verification, the method returns . + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. /// - /// if every recorded interaction was verified at least once; otherwise . - bool VerifyThatAllInteractionsAreVerified(); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameters parameters); /// - /// Checks whether every registered setup on this mock was matched by at least one actual invocation. + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// Useful to catch unused setups that silently rot as the test subject evolves. + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// - /// if every registered setup was used at least once; otherwise . - bool VerifyThatAllSetupsAreUsed(); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Removes every recorded interaction from this mock while keeping all registered setups intact. + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// Handy when a single test exercises multiple logical phases and you only want to verify the interactions of the latest phase. + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// - void ClearAllInteractions(); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Verify.VerificationResult SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Creates a monitor whose Verify surface is scoped to interactions produced between monitor.Run() and the disposal of its IDisposable scope. + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// 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. + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// - /// A MockMonitor<T> that exposes Verify over the monitored interactions and a Run() method that opens the recording scope. - global::Mockolate.Monitor.MockMonitor Monitor(); + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Verify.VerificationResult.IgnoreParameters SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + } /// - /// Scoped access to setups for a scenario on the mock of HttpClient. + /// Verify protected interactions with the mock of HttpClient. /// - internal interface IMockInScenarioForHttpClient + internal interface IMockProtectedVerifyForHttpClient { /// - /// Set up the mock of HttpClient within the scenario scope. + /// Verify invocations for the method Dispose(bool) with the given . /// - IMockSetupForHttpClient Setup { get; } + /// + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameters parameters); /// - /// Set up protected members of the mock of HttpClient within the scenario scope. + /// Verify invocations for the method Dispose(bool) with the given . /// - IMockProtectedSetupForHttpClient SetupProtected { get; } - } + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameter? disposing); - /// - /// Set up the mock of HttpClient. - /// - internal interface IMockSetupForHttpClient : global::Mockolate.Setup.IMockSetup + /// + /// Verify invocations for the method Dispose(bool) with the given . + /// + /// + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Verify.VerificationResult.IgnoreParameters Dispose(bool disposing); + + } +} +/// +/// Mock extensions for HttpClient. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForHttpClient +{ + /// + extension(global::System.Net.Http.HttpClient mock) { /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given . + /// Gets the mock accessor for HttpClient - the entry point for configuring setups, verifying interactions and raising events. /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// The accessor is the bridge between the strongly-typed instance of HttpClient 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.
+ ///
///
- [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameters parameters); + /// The instance is not a Mockolate-generated mock of HttpClient. + public global::Mockolate.Mock.IMockForHttpClient Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForHttpClient mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of HttpClient with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements HttpClient 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of HttpClient 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of HttpClient with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of HttpClient 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of HttpClient 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(object?[] constructorParameters) + => CreateMock(null, null, constructorParameters); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given and . /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, object?[] constructorParameters) + => CreateMock(mockBehavior, null, constructorParameters); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient applying the given immediately, using the given . /// /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, object?[] constructorParameters) + => CreateMock(null, setup, constructorParameters); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) constructor. /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + /// Value forwarded to the base-class constructor. + /// A new mock instance of HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Net.Http.HttpMessageHandler handler) + => CreateMock(null, null, new object?[] { handler }); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given and the given constructor parameters to invoke the HttpClient(HttpMessageHandler) constructor. /// - /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Net.Http.HttpMessageHandler handler) + => CreateMock(mockBehavior, null, new object?[] { handler }); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . + /// Creates a new mock of HttpClient applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) constructor. /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameters parameters); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler) + => CreateMock(null, setup, new object?[] { handler }); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given , applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler) constructor. /// /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler) + => CreateMock(mockBehavior, setup, new object?[] { handler }); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, bool) constructor. /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// Value forwarded to the base-class constructor. + /// Value forwarded to the base-class constructor. + /// A new mock instance of HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) + => CreateMock(null, null, new object?[] { handler, disposeHandler }); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient using the given and the given constructor parameters to invoke the HttpClient(HttpMessageHandler, bool) constructor. /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) + => CreateMock(mockBehavior, null, new object?[] { handler, disposeHandler }); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Creates a new mock of HttpClient applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, bool) constructor. /// /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); - - } + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) + => CreateMock(null, setup, new object?[] { handler, disposeHandler }); - /// - /// Set up protected members for the mock of HttpClient. - /// - internal interface IMockProtectedSetupForHttpClient - { /// - /// Setup for the method Dispose(bool) with the given . + /// Creates a new mock of HttpClient using the given , applying the given immediately, using the given constructor parameters to invoke the HttpClient(HttpMessageHandler, bool) constructor. /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameters parameters); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup, global::System.Net.Http.HttpMessageHandler handler, bool disposeHandler) + => CreateMock(mockBehavior, setup, new object?[] { handler, disposeHandler }); /// - /// Setup for the method Dispose(bool) with the given . + /// Creates a new mock of HttpClient using the given , applying the given immediately, using the given . /// /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// The provided is immediately applied to the mock. Use this overload when you want setups to cover virtual interactions triggered inside the constructor. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameter? disposing); + /// 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 HttpClient. + public static global::System.Net.Http.HttpClient CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + if (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters(out object?[]? parameters)) + { + constructorParameters = parameters; + } + } + + global::Mockolate.MockBehavior effectiveBehavior = mockBehavior ?? global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(effectiveBehavior, global::Mockolate.Mock.HttpClient.CreateFastInteractions(effectiveBehavior), constructorParameters); + if (constructorParameters is null) + { + constructorParameters = [new global::Mockolate.Mock.HttpMessageHandler(mockRegistry),]; + mockRegistry = new global::Mockolate.MockRegistry(mockRegistry, constructorParameters); + } + else if (constructorParameters.Length > 0 && constructorParameters[0] is global::Mockolate.Mock.HttpMessageHandler && constructorParameters[0] is global::Mockolate.IMock httpMessageHandlerMock) + { + if (mockBehavior is not null && httpMessageHandlerMock.MockRegistry.Behavior != mockBehavior) + { + throw 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}'."); + } + mockRegistry = new global::Mockolate.MockRegistry(httpMessageHandlerMock.MockRegistry, constructorParameters); + } + mockBehavior ??= global::Mockolate.MockBehavior.Default; + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + private static global::System.Net.Http.HttpClient CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + if (constructorParameters is null || constructorParameters.Length == 0) + { + global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpClient(mockRegistry); + } + else if (constructorParameters.Length == 0) + { + global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpClient(mockRegistry); + } + else if (constructorParameters.Length == 1 + && TryCast(constructorParameters, 0, mockRegistry.Behavior, out global::System.Net.Http.HttpMessageHandler c2p1)) + { + global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpClient(mockRegistry, c2p1); + } + else if (constructorParameters.Length == 2 + && TryCast(constructorParameters, 0, mockRegistry.Behavior, out global::System.Net.Http.HttpMessageHandler c3p1) + && TryCast(constructorParameters, 1, mockRegistry.Behavior, out bool c3p2)) + { + global::Mockolate.Mock.HttpClient.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpClient.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpClient(mockRegistry, c3p1, c3p2); + } + else + { + throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'System.Net.Http.HttpClient' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)})."); + } + 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; + } + } /// - /// Setup for the method Dispose(bool) with the given . + /// Creates a mock that wraps the given . /// /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// 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. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer Dispose(bool disposing); + /// The real object whose calls should be forwarded. Must not be . + /// A new mock of HttpClient that delegates to . + public global::System.Net.Http.HttpClient Wrapping(global::System.Net.Http.HttpClient instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.HttpClient.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } } - /// - /// Verify interactions with the mock of HttpClient. - /// - internal interface IMockVerifyForHttpClient : global::Mockolate.Verify.IMockVerify + /// + extension(global::Mockolate.MockBehavior behavior) { /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given . + /// Initializes mocks of type with the given . /// /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameters parameters); - + /// The mockable type derived from HttpClient 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::System.Net.Http.HttpClient + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + internal interface IMockSetupInitializationForHttpClient : global::Mockolate.Mock.IMockSetupForHttpClient + { /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Setup protected members /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + global::Mockolate.Mock.IMockProtectedSetupForHttpClient Protected { get; } + } - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForHttpClient, global::Mockolate.Mock.IMockProtectedSetupForHttpClient, IMockSetupInitializationForHttpClient + { + /// + global::Mockolate.Mock.IMockProtectedSetupForHttpClient IMockSetupInitializationForHttpClient.Protected => this; + private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + #region IMockSetupForHttpClient - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . - /// - /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameters parameters); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockSetupForHttpClient.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); + return methodSetup; + } - } + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify protected interactions with the mock of HttpClient. - /// - internal interface IMockProtectedVerifyForHttpClient - { - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameters parameters); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameter? disposing); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters Dispose(bool disposing); + /// + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockSetupForHttpClient.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_SendAsync, methodSetup); + return methodSetup; + } + + #endregion IMockSetupForHttpClient + + #region IMockProtectedSetupForHttpClient + + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", parameters, "disposing"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(global::Mockolate.Parameters.IParameter? disposing) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", CovariantParameterAdapter.Wrap(disposing ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpClient.Dispose(bool disposing) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageInvoker.Dispose", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(disposing)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpClient.MemberId_Dispose, methodSetup); + return methodSetup; + } + + #endregion IMockProtectedSetupForHttpClient + } + + [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(); + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpMessageHandler.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpMessageHandler.g.cs index 97b30562..7c137cf9 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpMessageHandler.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/HttpClient_CanBeCreated/Mock.HttpMessageHandler.g.cs @@ -10,211 +10,299 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for HttpMessageHandler. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForHttpMessageHandler +internal static partial class Mock { - /// - extension(global::System.Net.Http.HttpMessageHandler mock) + /// + /// A mock implementation for HttpMessageHandler. + /// + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal class HttpMessageHandler : + global::System.Net.Http.HttpMessageHandler, IMockForHttpMessageHandler, IMockSetupForHttpMessageHandler, IMockProtectedSetupForHttpMessageHandler, global::Mockolate.MockExtensionsForHttpMessageHandler.IMockSetupInitializationForHttpMessageHandler, IMockVerifyForHttpMessageHandler, IMockProtectedVerifyForHttpMessageHandler, + global::Mockolate.IMock { - /// - /// Gets the mock accessor for HttpMessageHandler - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of HttpMessageHandler 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 HttpMessageHandler. - public global::Mockolate.Mock.IMockForHttpMessageHandler Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForHttpMessageHandler mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } + internal const int MemberId_Send = 0; + internal const int MemberId_SendAsync = 1; + internal const int MemberId_Dispose = 2; + internal const int MemberCount = 3; /// - /// Creates a new mock of HttpMessageHandler 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 HttpMessageHandler 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 HttpMessageHandler. - public static global::System.Net.Http.HttpMessageHandler 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 HttpMessageHandler 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 HttpMessageHandler. - public static global::System.Net.Http.HttpMessageHandler 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 HttpMessageHandler with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of HttpMessageHandler. - public static global::System.Net.Http.HttpMessageHandler 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 HttpMessageHandler 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 HttpMessageHandler. - public static global::System.Net.Http.HttpMessageHandler 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.FastMethod2Buffer MockolateBuffer_Send + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, static fast => new global::Mockolate.Interactions.FastMethod2Buffer(fast))); + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + private global::Mockolate.Interactions.FastMethod2Buffer MockolateBuffer_SendAsync + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, static fast => new global::Mockolate.Interactions.FastMethod2Buffer(fast))); + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer_Dispose + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); - /// - /// Creates a new mock of HttpMessageHandler 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 HttpMessageHandler. - private static global::System.Net.Http.HttpMessageHandler CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + /// + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + IMockSetupForHttpMessageHandler IMockForHttpMessageHandler.Setup + => this; + /// + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + IMockProtectedSetupForHttpMessageHandler IMockForHttpMessageHandler.SetupProtected + => this; + /// + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + IMockProtectedSetupForHttpMessageHandler global::Mockolate.MockExtensionsForHttpMessageHandler.IMockSetupInitializationForHttpMessageHandler.Protected + => this; + /// + IMockInScenarioForHttpMessageHandler IMockForHttpMessageHandler.InScenario(string scenario) + => new MockInScenarioForHttpMessageHandler(this.MockRegistry, scenario); + + /// + IMockForHttpMessageHandler IMockForHttpMessageHandler.InScenario(string scenario, global::System.Action setup) { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - if (constructorParameters is null && mockBehaviorAccess.TryGetConstructorParameters(out object?[]? parameters)) - { - constructorParameters = parameters; - } - } + setup.Invoke(new MockInScenarioForHttpMessageHandler(this.MockRegistry, scenario)); + return this; + } - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.HttpMessageHandler.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); + /// + IMockForHttpMessageHandler IMockForHttpMessageHandler.TransitionTo(string scenario) + { + this.MockRegistry.TransitionTo(scenario); + return this; + } + /// + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + IMockVerifyForHttpMessageHandler IMockForHttpMessageHandler.Verify + => this; + /// + [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] + IMockProtectedVerifyForHttpMessageHandler IMockForHttpMessageHandler.VerifyProtected + => this; + /// + global::Mockolate.Verify.VerificationResult IMockForHttpMessageHandler.VerifySetup(global::Mockolate.Setup.IMethodSetup setup) + => this.MockRegistry.Method(this, setup); + /// + bool IMockForHttpMessageHandler.VerifyThatAllInteractionsAreVerified() + => this.MockRegistry.Interactions.GetUnverifiedInteractions().Count == 0; + /// + bool IMockForHttpMessageHandler.VerifyThatAllSetupsAreUsed() + => this.MockRegistry.GetUnusedSetups(this.MockRegistry.Interactions).Count == 0; + /// + void IMockForHttpMessageHandler.ClearAllInteractions() + => this.MockRegistry.ClearAllInteractions(); + /// + global::Mockolate.Monitor.MockMonitor IMockForHttpMessageHandler.Monitor() + => new global::Mockolate.Monitor.MockMonitor(this.MockRegistry.Interactions, interactions => new VerifyMonitorHttpMessageHandler(new global::Mockolate.MockRegistry(this.MockRegistry, interactions))); + + /// + string global::Mockolate.IMock.ToString() + => "System.Net.Http.HttpMessageHandler mock"; + + /// + public HttpMessageHandler(global::Mockolate.MockRegistry mockRegistry) + : base() + { + this.MockRegistry = mockRegistry; } - private static global::System.Net.Http.HttpMessageHandler CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + /// + public HttpMessageHandler(global::Mockolate.MockBehavior behavior) + : this(MockolateCreateRegistryFromBehavior(behavior)) { - if (constructorParameters is null || constructorParameters.Length == 0) + } + + #region System.Net.Http.HttpMessageHandler + + /// + protected override global::System.Net.Http.HttpResponseMessage Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null; + if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) { - global::Mockolate.Mock.HttpMessageHandler.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpMessageHandler.MockSetup? setupTarget = null; - if (setup is not null) + global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send); + 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(request, cancellationToken)) + { + methodSetup = s_methodSetup; + break; + } + } } - return new global::Mockolate.Mock.HttpMessageHandler(mockRegistry); } - else if (constructorParameters.Length == 0) + if (methodSetup is null) { - global::Mockolate.Mock.HttpMessageHandler.MockRegistryProvider.Value = mockRegistry; - global::Mockolate.MockExtensionsForHttpMessageHandler.MockSetup? setupTarget = null; - if (setup is not null) + foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::System.Net.Http.HttpMessageHandler.Send")) { - setupTarget ??= new(mockRegistry); - setup.Invoke(setupTarget); + if (s_methodSetup.Matches(request, cancellationToken)) + { + methodSetup = s_methodSetup; + break; + } } - return new global::Mockolate.Mock.HttpMessageHandler(mockRegistry); } - else - { - throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'System.Net.Http.HttpMessageHandler' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)})."); + bool hasWrappedResult = false; + global::System.Net.Http.HttpResponseMessage wrappedResult = default!; + if (this.MockRegistry.Behavior.SkipInteractionRecording == false) + { + this.MockolateBuffer_Send.Append("global::System.Net.Http.HttpMessageHandler.Send", request, cancellationToken); + } + try + { + if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass)) + { + wrappedResult = base.Send(request, cancellationToken); + hasWrappedResult = true; + } + } + finally + { + methodSetup?.TriggerCallbacks(request, cancellationToken); + } + if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) + { + throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.Send(HttpRequestMessage, CancellationToken)' was invoked without prior setup."); + } + if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult) + { + return wrappedResult; } + return methodSetup?.TryGetReturnValue(request, cancellationToken, out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Net.Http.HttpResponseMessage)!, request, cancellationToken); } - /// - /// 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 HttpMessageHandler that delegates to . - public global::System.Net.Http.HttpMessageHandler Wrapping(global::System.Net.Http.HttpMessageHandler instance) + + /// + protected override global::System.Threading.Tasks.Task SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) { - if (mock is global::Mockolate.IMock mockInterface) + global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>? methodSetup = null; + if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.HttpMessageHandler.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync); + if (snapshot_methodSetup 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, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> s_methodSetup && s_methodSetup.Matches(request, cancellationToken)) + { + methodSetup = s_methodSetup; + break; + } + } + } } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + if (methodSetup is null) + { + foreach (global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> s_methodSetup in this.MockRegistry.GetMethodSetups, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>>("global::System.Net.Http.HttpMessageHandler.SendAsync")) + { + if (s_methodSetup.Matches(request, cancellationToken)) + { + methodSetup = s_methodSetup; + break; + } + } + } + bool hasWrappedResult = false; + global::System.Threading.Tasks.Task wrappedResult = default!; + if (this.MockRegistry.Behavior.SkipInteractionRecording == false) + { + this.MockolateBuffer_SendAsync.Append("global::System.Net.Http.HttpMessageHandler.SendAsync", request, cancellationToken); + } + try + { + } + finally + { + methodSetup?.TriggerCallbacks(request, cancellationToken); + } + if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) + { + throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.SendAsync(HttpRequestMessage, CancellationToken)' was invoked without prior setup."); + } + if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult) + { + return wrappedResult; + } + return methodSetup?.TryGetReturnValue(request, cancellationToken, out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Threading.Tasks.Task)!, this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Net.Http.HttpResponseMessage)!, request, cancellationToken), request, cancellationToken); } - } - - /// - 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 HttpMessageHandler 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::System.Net.Http.HttpMessageHandler + /// + protected override void Dispose(bool disposing) { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); + global::Mockolate.Setup.VoidMethodSetup? methodSetup = null; + if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) + { + global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose); + if (snapshot_methodSetup 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.VoidMethodSetup s_methodSetup && s_methodSetup.Matches(disposing)) + { + methodSetup = s_methodSetup; + break; + } + } + } + } + if (methodSetup is null) + { + foreach (global::Mockolate.Setup.VoidMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::System.Net.Http.HttpMessageHandler.Dispose")) + { + if (s_methodSetup.Matches(disposing)) + { + methodSetup = s_methodSetup; + break; + } + } + } + bool hasWrappedResult = false; + if (this.MockRegistry.Behavior.SkipInteractionRecording == false) + { + this.MockolateBuffer_Dispose.Append("global::System.Net.Http.HttpMessageHandler.Dispose", disposing); + } + try + { + if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass)) + { + base.Dispose(disposing); + hasWrappedResult = true; + } + } + finally + { + methodSetup?.TriggerCallbacks(disposing); + } + if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) + { + throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.Dispose(bool)' was invoked without prior setup."); + } } - } - internal interface IMockSetupInitializationForHttpMessageHandler : global::Mockolate.Mock.IMockSetupForHttpMessageHandler - { - /// - /// Setup protected members - /// - global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler Protected { get; } - } - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForHttpMessageHandler, global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler, IMockSetupInitializationForHttpMessageHandler - { - /// - global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler IMockSetupInitializationForHttpMessageHandler.Protected => this; - private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; + #endregion System.Net.Http.HttpMessageHandler #region IMockSetupForHttpMessageHandler @@ -327,622 +415,201 @@ internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : g } #endregion IMockProtectedSetupForHttpMessageHandler - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} -internal static partial class Mock -{ - /// - /// A mock implementation for HttpMessageHandler. - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - internal class HttpMessageHandler : - global::System.Net.Http.HttpMessageHandler, IMockForHttpMessageHandler, IMockSetupForHttpMessageHandler, IMockProtectedSetupForHttpMessageHandler, global::Mockolate.MockExtensionsForHttpMessageHandler.IMockSetupInitializationForHttpMessageHandler, IMockVerifyForHttpMessageHandler, IMockProtectedVerifyForHttpMessageHandler, - global::Mockolate.IMock - { - internal const int MemberId_Send = 0; - internal const int MemberId_SendAsync = 1; - internal const int MemberId_Dispose = 2; - internal const int MemberCount = 3; + #region IMockVerifyForHttpMessageHandler - /// - /// 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); + #endregion IMockVerifyForHttpMessageHandler - /// - /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . - /// - 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; - } + #region IMockProtectedVerifyForHttpMessageHandler /// - [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(); - - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - private global::Mockolate.Interactions.FastMethod2Buffer MockolateBuffer_Send - => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, static fast => new global::Mockolate.Interactions.FastMethod2Buffer(fast))); - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - private global::Mockolate.Interactions.FastMethod2Buffer MockolateBuffer_SendAsync - => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, static fast => new global::Mockolate.Interactions.FastMethod2Buffer(fast))); - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer_Dispose - => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); - + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => parameters switch + { + global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1, __i.Parameter2]), + global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("request", __i.Parameter1), ("cancellationToken", __i.Parameter2)]), + _ => true + }, () => $"Send({parameters})"); /// - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - IMockSetupForHttpMessageHandler IMockForHttpMessageHandler.Setup - => this; + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", request is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(request), cancellationToken is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(cancellationToken), () => $"Send({request}, {cancellationToken})"); /// - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - IMockProtectedSetupForHttpMessageHandler IMockForHttpMessageHandler.SetupProtected - => this; + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => + (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && + (cancellationToken is not null ? CovariantParameterAdapter.Wrap(cancellationToken).Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(global::System.Threading.CancellationToken))), () => $"Send({request}, {cancellationToken})"); /// - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - IMockProtectedSetupForHttpMessageHandler global::Mockolate.MockExtensionsForHttpMessageHandler.IMockSetupInitializationForHttpMessageHandler.Protected - => this; + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => + (request is not null ? CovariantParameterAdapter.Wrap(request).Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(global::System.Net.Http.HttpRequestMessage))) && + (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"Send({request}, {cancellationToken})"); /// - IMockInScenarioForHttpMessageHandler IMockForHttpMessageHandler.InScenario(string scenario) - => new MockInScenarioForHttpMessageHandler(this.MockRegistry, scenario); - + global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => + (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && + (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"Send({request}, {cancellationToken})"); /// - IMockForHttpMessageHandler IMockForHttpMessageHandler.InScenario(string scenario, global::System.Action setup) - { - setup.Invoke(new MockInScenarioForHttpMessageHandler(this.MockRegistry, scenario)); - return this; - } - + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => parameters switch + { + global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1, __i.Parameter2]), + global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("request", __i.Parameter1), ("cancellationToken", __i.Parameter2)]), + _ => true + }, () => $"SendAsync({parameters})"); /// - IMockForHttpMessageHandler IMockForHttpMessageHandler.TransitionTo(string scenario) + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", request is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(request), cancellationToken is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(cancellationToken), () => $"SendAsync({request}, {cancellationToken})"); + /// + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => + (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && + (cancellationToken is not null ? CovariantParameterAdapter.Wrap(cancellationToken).Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(global::System.Threading.CancellationToken))), () => $"SendAsync({request}, {cancellationToken})"); + /// + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => + (request is not null ? CovariantParameterAdapter.Wrap(request).Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(global::System.Net.Http.HttpRequestMessage))) && + (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"SendAsync({request}, {cancellationToken})"); + /// + global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => + (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && + (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"SendAsync({request}, {cancellationToken})"); + /// + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", __i => parameters switch + { + global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1]), + global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("disposing", __i.Parameter1)]), + _ => true + }, () => $"Dispose({parameters})"); + /// + global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameter? disposing) + => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", disposing is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(disposing), () => $"Dispose({disposing})"); + /// + global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.Dispose(bool disposing) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", __i => + (global::System.Collections.Generic.EqualityComparer.Default.Equals(disposing, __i.Parameter1)), () => $"Dispose({disposing})"); + #endregion IMockProtectedVerifyForHttpMessageHandler + } + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private sealed class VerifyMonitorHttpMessageHandler(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyForHttpMessageHandler + { + private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; + + #region IMockVerifyForHttpMessageHandler + + #endregion IMockVerifyForHttpMessageHandler + } + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private sealed class MockInScenarioForHttpMessageHandler : global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler, global::Mockolate.Mock.IMockSetupForHttpMessageHandler, global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler + { + private global::Mockolate.MockRegistry MockRegistry { get; } + private string _scenarioName; + + public MockInScenarioForHttpMessageHandler(global::Mockolate.MockRegistry mockRegistry, string scenario) { - this.MockRegistry.TransitionTo(scenario); - return this; + this.MockRegistry = mockRegistry; + _scenarioName = scenario; } + /// - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - IMockVerifyForHttpMessageHandler IMockForHttpMessageHandler.Verify + global::Mockolate.Mock.IMockSetupForHttpMessageHandler global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler.Setup => this; + /// - [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - IMockProtectedVerifyForHttpMessageHandler IMockForHttpMessageHandler.VerifyProtected + global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler.SetupProtected => this; + + #region IMockSetupForHttpMessageHandler + + #endregion IMockSetupForHttpMessageHandler + + #region IMockProtectedSetupForHttpMessageHandler + /// - global::Mockolate.Verify.VerificationResult IMockForHttpMessageHandler.VerifySetup(global::Mockolate.Setup.IMethodSetup setup) - => this.MockRegistry.Method(this, setup); + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); + return methodSetup; + } + /// - bool IMockForHttpMessageHandler.VerifyThatAllInteractionsAreVerified() - => this.MockRegistry.Interactions.GetUnverifiedInteractions().Count == 0; + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); + return methodSetup; + } + /// - bool IMockForHttpMessageHandler.VerifyThatAllSetupsAreUsed() - => this.MockRegistry.GetUnusedSetups(this.MockRegistry.Interactions).Count == 0; + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); + return methodSetup; + } + /// - void IMockForHttpMessageHandler.ClearAllInteractions() - => this.MockRegistry.ClearAllInteractions(); + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); + return methodSetup; + } + /// - global::Mockolate.Monitor.MockMonitor IMockForHttpMessageHandler.Monitor() - => new global::Mockolate.Monitor.MockMonitor(this.MockRegistry.Interactions, interactions => new VerifyMonitorHttpMessageHandler(new global::Mockolate.MockRegistry(this.MockRegistry, interactions))); + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); + return methodSetup; + } /// - string global::Mockolate.IMock.ToString() - => "System.Net.Http.HttpMessageHandler mock"; + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); + return methodSetup; + } - /// - public HttpMessageHandler(global::Mockolate.MockRegistry mockRegistry) - : base() + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) { - this.MockRegistry = mockRegistry; + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); + return methodSetup; } - /// - public HttpMessageHandler(global::Mockolate.MockBehavior behavior) - : this(MockolateCreateRegistryFromBehavior(behavior)) + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); + return methodSetup; } - #region System.Net.Http.HttpMessageHandler + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); + return methodSetup; + } - /// - protected override global::System.Net.Http.HttpResponseMessage Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + /// + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) { - global::Mockolate.Setup.ReturnMethodSetup? methodSetup = null; - if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) - { - global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send); - if (snapshot_methodSetup 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(request, cancellationToken)) - { - methodSetup = s_methodSetup; - break; - } - } - } - } - if (methodSetup is null) - { - foreach (global::Mockolate.Setup.ReturnMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::System.Net.Http.HttpMessageHandler.Send")) - { - if (s_methodSetup.Matches(request, cancellationToken)) - { - methodSetup = s_methodSetup; - break; - } - } - } - bool hasWrappedResult = false; - global::System.Net.Http.HttpResponseMessage wrappedResult = default!; - if (this.MockRegistry.Behavior.SkipInteractionRecording == false) - { - this.MockolateBuffer_Send.Append("global::System.Net.Http.HttpMessageHandler.Send", request, cancellationToken); - } - try - { - if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass)) - { - wrappedResult = base.Send(request, cancellationToken); - hasWrappedResult = true; - } - } - finally - { - methodSetup?.TriggerCallbacks(request, cancellationToken); - } - if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) - { - throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.Send(HttpRequestMessage, CancellationToken)' was invoked without prior setup."); - } - if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult) - { - return wrappedResult; - } - return methodSetup?.TryGetReturnValue(request, cancellationToken, out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Net.Http.HttpResponseMessage)!, request, cancellationToken); + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); + return methodSetup; } - /// - protected override global::System.Threading.Tasks.Task SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>? methodSetup = null; - if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) - { - global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync); - if (snapshot_methodSetup 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, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> s_methodSetup && s_methodSetup.Matches(request, cancellationToken)) - { - methodSetup = s_methodSetup; - break; - } - } - } - } - if (methodSetup is null) - { - foreach (global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> s_methodSetup in this.MockRegistry.GetMethodSetups, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>>("global::System.Net.Http.HttpMessageHandler.SendAsync")) - { - if (s_methodSetup.Matches(request, cancellationToken)) - { - methodSetup = s_methodSetup; - break; - } - } - } - bool hasWrappedResult = false; - global::System.Threading.Tasks.Task wrappedResult = default!; - if (this.MockRegistry.Behavior.SkipInteractionRecording == false) - { - this.MockolateBuffer_SendAsync.Append("global::System.Net.Http.HttpMessageHandler.SendAsync", request, cancellationToken); - } - try - { - } - finally - { - methodSetup?.TriggerCallbacks(request, cancellationToken); - } - if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) - { - throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.SendAsync(HttpRequestMessage, CancellationToken)' was invoked without prior setup."); - } - if (methodSetup?.HasReturnCallbacks != true && hasWrappedResult) - { - return wrappedResult; - } - return methodSetup?.TryGetReturnValue(request, cancellationToken, out var returnValue) == true ? returnValue : this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Threading.Tasks.Task)!, this.MockRegistry.Behavior.DefaultValue.Generate(default(global::System.Net.Http.HttpResponseMessage)!, request, cancellationToken), request, cancellationToken); - } - - /// - protected override void Dispose(bool disposing) - { - global::Mockolate.Setup.VoidMethodSetup? methodSetup = null; - if (string.IsNullOrEmpty(this.MockRegistry.Scenario)) - { - global::Mockolate.Setup.MethodSetup[]? snapshot_methodSetup = this.MockRegistry.GetMethodSetupSnapshot(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose); - if (snapshot_methodSetup 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.VoidMethodSetup s_methodSetup && s_methodSetup.Matches(disposing)) - { - methodSetup = s_methodSetup; - break; - } - } - } - } - if (methodSetup is null) - { - foreach (global::Mockolate.Setup.VoidMethodSetup s_methodSetup in this.MockRegistry.GetMethodSetups>("global::System.Net.Http.HttpMessageHandler.Dispose")) - { - if (s_methodSetup.Matches(disposing)) - { - methodSetup = s_methodSetup; - break; - } - } - } - bool hasWrappedResult = false; - if (this.MockRegistry.Behavior.SkipInteractionRecording == false) - { - this.MockolateBuffer_Dispose.Append("global::System.Net.Http.HttpMessageHandler.Dispose", disposing); - } - try - { - if (!(methodSetup?.SkipBaseClass(this.MockRegistry.Behavior) ?? this.MockRegistry.Behavior.SkipBaseClass)) - { - base.Dispose(disposing); - hasWrappedResult = true; - } - } - finally - { - methodSetup?.TriggerCallbacks(disposing); - } - if (methodSetup is null && !hasWrappedResult && this.MockRegistry.Behavior.ThrowWhenNotSetup) - { - throw new global::Mockolate.Exceptions.MockNotSetupException("The method 'global::System.Net.Http.HttpMessageHandler.Dispose(bool)' was invoked without prior setup."); - } - } - - #endregion System.Net.Http.HttpMessageHandler - - #region IMockSetupForHttpMessageHandler - - #endregion IMockSetupForHttpMessageHandler - - #region IMockProtectedSetupForHttpMessageHandler - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", parameters, "disposing"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameter? disposing) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", CovariantParameterAdapter.Wrap(disposing ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(bool disposing) - { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(disposing)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); - return methodSetup; - } - - #endregion IMockProtectedSetupForHttpMessageHandler - - #region IMockVerifyForHttpMessageHandler - - #endregion IMockVerifyForHttpMessageHandler - - #region IMockProtectedVerifyForHttpMessageHandler - - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => parameters switch - { - global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1, __i.Parameter2]), - global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("request", __i.Parameter1), ("cancellationToken", __i.Parameter2)]), - _ => true - }, () => $"Send({parameters})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", request is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(request), cancellationToken is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(cancellationToken), () => $"Send({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => - (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && - (cancellationToken is not null ? CovariantParameterAdapter.Wrap(cancellationToken).Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(global::System.Threading.CancellationToken))), () => $"Send({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => - (request is not null ? CovariantParameterAdapter.Wrap(request).Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(global::System.Net.Http.HttpRequestMessage))) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"Send({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, "global::System.Net.Http.HttpMessageHandler.Send", __i => - (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"Send({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => parameters switch - { - global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1, __i.Parameter2]), - global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("request", __i.Parameter1), ("cancellationToken", __i.Parameter2)]), - _ => true - }, () => $"SendAsync({parameters})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", request is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(request), cancellationToken is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(cancellationToken), () => $"SendAsync({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => - (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && - (cancellationToken is not null ? CovariantParameterAdapter.Wrap(cancellationToken).Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(global::System.Threading.CancellationToken))), () => $"SendAsync({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => - (request is not null ? CovariantParameterAdapter.Wrap(request).Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(global::System.Net.Http.HttpRequestMessage))) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"SendAsync({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, "global::System.Net.Http.HttpMessageHandler.SendAsync", __i => - (global::System.Collections.Generic.EqualityComparer.Default.Equals(request, __i.Parameter1)) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(cancellationToken, __i.Parameter2)), () => $"SendAsync({request}, {cancellationToken})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", __i => parameters switch - { - global::Mockolate.Parameters.IParametersMatch m => m.Matches([__i.Parameter1]), - global::Mockolate.Parameters.INamedParametersMatch m => m.Matches([("disposing", __i.Parameter1)]), - _ => true - }, () => $"Dispose({parameters})"); - /// - global::Mockolate.Verify.VerificationResult IMockProtectedVerifyForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameter? disposing) - => this.MockRegistry.VerifyMethod(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", disposing is null ? (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.Is(default!) : CovariantParameterAdapter.Wrap(disposing), () => $"Dispose({disposing})"); - /// - global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockProtectedVerifyForHttpMessageHandler.Dispose(bool disposing) - => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, "global::System.Net.Http.HttpMessageHandler.Dispose", __i => - (global::System.Collections.Generic.EqualityComparer.Default.Equals(disposing, __i.Parameter1)), () => $"Dispose({disposing})"); - #endregion IMockProtectedVerifyForHttpMessageHandler - } - - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - private sealed class VerifyMonitorHttpMessageHandler(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockVerifyForHttpMessageHandler - { - private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; - - #region IMockVerifyForHttpMessageHandler - - #endregion IMockVerifyForHttpMessageHandler - } - - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - private sealed class MockInScenarioForHttpMessageHandler : global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler, global::Mockolate.Mock.IMockSetupForHttpMessageHandler, global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler - { - private global::Mockolate.MockRegistry MockRegistry { get; } - private string _scenarioName; - - public MockInScenarioForHttpMessageHandler(global::Mockolate.MockRegistry mockRegistry, string scenario) - { - this.MockRegistry = mockRegistry; - _scenarioName = scenario; - } - - /// - global::Mockolate.Mock.IMockSetupForHttpMessageHandler global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler.Setup - => this; - - /// - global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler global::Mockolate.Mock.IMockInScenarioForHttpMessageHandler.SetupProtected - => this; - - #region IMockSetupForHttpMessageHandler - - #endregion IMockSetupForHttpMessageHandler - - #region IMockProtectedSetupForHttpMessageHandler - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", parameters, "request", "cancellationToken"); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) - { - var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); - this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, _scenarioName, methodSetup); - return methodSetup; - } - - /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) { var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", parameters, "disposing"); this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, _scenarioName, methodSetup); @@ -1099,271 +766,603 @@ internal interface IMockInScenarioForHttpMessageHandler IMockSetupForHttpMessageHandler Setup { get; } /// - /// Set up protected members of the mock of HttpMessageHandler within the scenario scope. + /// Set up protected members of the mock of HttpMessageHandler within the scenario scope. + /// + IMockProtectedSetupForHttpMessageHandler SetupProtected { get; } + } + + /// + /// Set up the mock of HttpMessageHandler. + /// + internal interface IMockSetupForHttpMessageHandler : global::Mockolate.Setup.IMockSetup + { + } + + /// + /// Set up protected members for the mock of HttpMessageHandler. + /// + internal interface IMockProtectedSetupForHttpMessageHandler + { + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given . + /// + /// + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameters parameters); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . + /// + /// + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameters parameters); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// + /// + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + + /// + /// Setup for the method Dispose(bool) with the given . + /// + /// + /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] + global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameters parameters); + + /// + /// Setup for the method Dispose(bool) with the given . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameter? disposing); + + /// + /// Setup for the method Dispose(bool) with the given . /// - IMockProtectedSetupForHttpMessageHandler SetupProtected { get; } + /// + /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer Dispose(bool disposing); + } /// - /// Set up the mock of HttpMessageHandler. + /// Verify interactions with the mock of HttpMessageHandler. /// - internal interface IMockSetupForHttpMessageHandler : global::Mockolate.Setup.IMockSetup + internal interface IMockVerifyForHttpMessageHandler : global::Mockolate.Verify.IMockVerify { } /// - /// Set up protected members for the mock of HttpMessageHandler. + /// Verify protected interactions with the mock of HttpMessageHandler. /// - internal interface IMockProtectedSetupForHttpMessageHandler + internal interface IMockProtectedVerifyForHttpMessageHandler { /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given . /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameters parameters); + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameters parameters); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + global::Mockolate.Verify.VerificationResult Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); /// - /// Setup for the method Send(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + global::Mockolate.Verify.VerificationResult.IgnoreParameters Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameters parameters); + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameters parameters); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + global::Mockolate.Verify.VerificationResult SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); /// - /// Setup for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . + /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . /// /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + global::Mockolate.Verify.VerificationResult.IgnoreParameters SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); /// - /// Setup for the method Dispose(bool) with the given . + /// Verify invocations for the method Dispose(bool) with the given . /// /// - /// This overload configures the setup via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. + /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameters parameters); + global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameters parameters); /// - /// Setup for the method Dispose(bool) with the given . + /// Verify invocations for the method Dispose(bool) with the given . /// /// /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback Dispose(global::Mockolate.Parameters.IParameter? disposing); + global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameter? disposing); + + /// + /// Verify invocations for the method Dispose(bool) with the given . + /// + /// + /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] + global::Mockolate.Verify.VerificationResult.IgnoreParameters Dispose(bool disposing); + + } +} +/// +/// Mock extensions for HttpMessageHandler. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForHttpMessageHandler +{ + /// + extension(global::System.Net.Http.HttpMessageHandler mock) + { + /// + /// Gets the mock accessor for HttpMessageHandler - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of HttpMessageHandler 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 HttpMessageHandler. + public global::Mockolate.Mock.IMockForHttpMessageHandler Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForHttpMessageHandler mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of HttpMessageHandler with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements HttpMessageHandler 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 HttpMessageHandler. + public static global::System.Net.Http.HttpMessageHandler CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of HttpMessageHandler 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 HttpMessageHandler. + public static global::System.Net.Http.HttpMessageHandler CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of HttpMessageHandler with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of HttpMessageHandler. + public static global::System.Net.Http.HttpMessageHandler CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of HttpMessageHandler 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 HttpMessageHandler. + public static global::System.Net.Http.HttpMessageHandler CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of HttpMessageHandler 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 HttpMessageHandler. + private static global::System.Net.Http.HttpMessageHandler CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + 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.HttpMessageHandler.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::System.Net.Http.HttpMessageHandler CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + if (constructorParameters is null || constructorParameters.Length == 0) + { + global::Mockolate.Mock.HttpMessageHandler.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpMessageHandler.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpMessageHandler(mockRegistry); + } + else if (constructorParameters.Length == 0) + { + global::Mockolate.Mock.HttpMessageHandler.MockRegistryProvider.Value = mockRegistry; + global::Mockolate.MockExtensionsForHttpMessageHandler.MockSetup? setupTarget = null; + if (setup is not null) + { + setupTarget ??= new(mockRegistry); + setup.Invoke(setupTarget); + } + return new global::Mockolate.Mock.HttpMessageHandler(mockRegistry); + } + else + { + throw new global::Mockolate.Exceptions.MockException($"Could not find any constructor for 'System.Net.Http.HttpMessageHandler' that matches the {constructorParameters.Length} given parameters ({string.Join(", ", constructorParameters)})."); + } + } + /// + /// 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 HttpMessageHandler that delegates to . + public global::System.Net.Http.HttpMessageHandler Wrapping(global::System.Net.Http.HttpMessageHandler instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.HttpMessageHandler.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + extension(global::Mockolate.MockBehavior behavior) + { /// - /// Setup for the method Dispose(bool) with the given . + /// Initializes mocks of type with the given . /// /// - /// This overload accepts direct values for every parameter; each is treated as It.Is<T>(value). + /// The is applied to the mock before the constructor is executed. Calling Initialize again overlays additional setups on top of any previously registered ones. /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer Dispose(bool disposing); - + /// The mockable type derived from HttpMessageHandler 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::System.Net.Http.HttpMessageHandler + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } } - - /// - /// Verify interactions with the mock of HttpMessageHandler. - /// - internal interface IMockVerifyForHttpMessageHandler : global::Mockolate.Verify.IMockVerify + internal interface IMockSetupInitializationForHttpMessageHandler : global::Mockolate.Mock.IMockSetupForHttpMessageHandler { + /// + /// Setup protected members + /// + global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler Protected { get; } } - /// - /// Verify protected interactions with the mock of HttpMessageHandler. - /// - internal interface IMockProtectedVerifyForHttpMessageHandler + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal sealed class MockSetup(global::Mockolate.MockRegistry mockRegistry) : global::Mockolate.Mock.IMockSetupForHttpMessageHandler, global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler, IMockSetupInitializationForHttpMessageHandler { - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given . - /// - /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameters parameters); + /// + global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler IMockSetupInitializationForHttpMessageHandler.Protected => this; + private global::Mockolate.MockRegistry MockRegistry { get; } = mockRegistry; - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + #region IMockSetupForHttpMessageHandler - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + #endregion IMockSetupForHttpMessageHandler - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + #region IMockProtectedSetupForHttpMessageHandler - /// - /// Verify invocations for the method Send(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given . - /// - /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameters parameters); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for . - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Send(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Send", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Send, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method SendAsync(HttpRequestMessage, CancellationToken) with the given , . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", parameters, "request", "cancellationToken"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload matches invocations via a custom Match predicate (for example AnyParameters() or Parameters(Func<object?[], bool>, string)) rather than per-parameter matchers. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue - 1)] - global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameters parameters); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - global::Mockolate.Verify.VerificationResult Dispose(global::Mockolate.Parameters.IParameter? disposing); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::Mockolate.Parameters.IParameter? cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), CovariantParameterAdapter.Wrap(cancellationToken ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); + return methodSetup; + } - /// - /// Verify invocations for the method Dispose(bool) with the given . - /// - /// - /// This overload accepts direct values for every parameter and returns a VerificationResult<TVerify>.IgnoreParameters whose VerificationResult<TVerify>.AnyParameters() drops per-parameter matching entirely. - /// - [global::System.Runtime.CompilerServices.OverloadResolutionPriority(int.MaxValue)] - global::Mockolate.Verify.VerificationResult.IgnoreParameters Dispose(bool disposing); + /// + global::Mockolate.Setup.IReturnMethodSetupWithCallback, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::Mockolate.Parameters.IParameter? request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", CovariantParameterAdapter.Wrap(request ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IReturnMethodSetupParameterIgnorer, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken> global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.SendAsync(global::System.Net.Http.HttpRequestMessage request, global::System.Threading.CancellationToken cancellationToken) + { + var methodSetup = new global::Mockolate.Setup.ReturnMethodSetup, global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken>.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.SendAsync", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(request), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(cancellationToken)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameters parameters) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameters(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", parameters, "disposing"); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(global::Mockolate.Parameters.IParameter? disposing) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", CovariantParameterAdapter.Wrap(disposing ?? global::Mockolate.It.IsNull("null"))); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); + return methodSetup; + } + + /// + global::Mockolate.Setup.IVoidMethodSetupParameterIgnorer global::Mockolate.Mock.IMockProtectedSetupForHttpMessageHandler.Dispose(bool disposing) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::System.Net.Http.HttpMessageHandler.Dispose", (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(disposing)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose, methodSetup); + return methodSetup; + } + + #endregion IMockProtectedSetupForHttpMessageHandler + } + + [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(); + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/KeywordEdgeCases_CanBeCreated/Mock.IKeywordEdgeCases.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/KeywordEdgeCases_CanBeCreated/Mock.IKeywordEdgeCases.g.cs index 69267456..743cb1a9 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/KeywordEdgeCases_CanBeCreated/Mock.IKeywordEdgeCases.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/KeywordEdgeCases_CanBeCreated/Mock.IKeywordEdgeCases.g.cs @@ -10,189 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for IKeywordEdgeCases. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForIKeywordEdgeCases -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases mock) - { - /// - /// Gets the mock accessor for IKeywordEdgeCases - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of IKeywordEdgeCases 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.
- /// Raise - trigger events declared on the mocked type.
- /// 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 IKeywordEdgeCases. - public global::Mockolate.Mock.IMockForIKeywordEdgeCases Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForIKeywordEdgeCases mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of IKeywordEdgeCases with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements IKeywordEdgeCases 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.
- /// .Mock.Raise triggers events declared on the mocked type.
- ///

- /// 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 IKeywordEdgeCases. - public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. - public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of IKeywordEdgeCases with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of IKeywordEdgeCases. - public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. - public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. - private static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IKeywordEdgeCases.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.IKeywordEdgeCases(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 IKeywordEdgeCases that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases Wrapping(global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IKeywordEdgeCases.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 IKeywordEdgeCases 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.IKeywordEdgeCases - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -1500,5 +1317,187 @@ internal interface IMockVerifyForIKeywordEdgeCases : global::Mockolate.Verify.IM } } +/// +/// Mock extensions for IKeywordEdgeCases. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForIKeywordEdgeCases +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases mock) + { + /// + /// Gets the mock accessor for IKeywordEdgeCases - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of IKeywordEdgeCases 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.
+ /// Raise - trigger events declared on the mocked type.
+ /// 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 IKeywordEdgeCases. + public global::Mockolate.Mock.IMockForIKeywordEdgeCases Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForIKeywordEdgeCases mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of IKeywordEdgeCases with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements IKeywordEdgeCases 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.
+ /// .Mock.Raise triggers events declared on the mocked type.
+ ///

+ /// 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 IKeywordEdgeCases. + public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. + public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of IKeywordEdgeCases with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of IKeywordEdgeCases. + public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. + public static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of IKeywordEdgeCases 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 IKeywordEdgeCases. + private static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IKeywordEdgeCases.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.IKeywordEdgeCases(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 IKeywordEdgeCases that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases Wrapping(global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IKeywordEdgeCases.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 IKeywordEdgeCases 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.IKeywordEdgeCases + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/RefStructConsumer_CanBeCreated/Mock.IRefStructConsumer.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/RefStructConsumer_CanBeCreated/Mock.IRefStructConsumer.g.cs index a9a3e5a6..76840834 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/RefStructConsumer_CanBeCreated/Mock.IRefStructConsumer.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/RefStructConsumer_CanBeCreated/Mock.IRefStructConsumer.g.cs @@ -10,187 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for IRefStructConsumer. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForIRefStructConsumer -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer mock) - { - /// - /// Gets the mock accessor for IRefStructConsumer - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of IRefStructConsumer 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.
- /// 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 IRefStructConsumer. - public global::Mockolate.Mock.IMockForIRefStructConsumer Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForIRefStructConsumer mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of IRefStructConsumer with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements IRefStructConsumer 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 IRefStructConsumer. - public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. - public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of IRefStructConsumer with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of IRefStructConsumer. - public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. - public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. - private static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IRefStructConsumer.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.IRefStructConsumer(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 IRefStructConsumer that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer Wrapping(global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IRefStructConsumer.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 IRefStructConsumer 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.IRefStructConsumer - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -601,5 +420,185 @@ internal interface IMockVerifyForIRefStructConsumer : global::Mockolate.Verify.I { } } +/// +/// Mock extensions for IRefStructConsumer. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForIRefStructConsumer +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer mock) + { + /// + /// Gets the mock accessor for IRefStructConsumer - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of IRefStructConsumer 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.
+ /// 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 IRefStructConsumer. + public global::Mockolate.Mock.IMockForIRefStructConsumer Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForIRefStructConsumer mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of IRefStructConsumer with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements IRefStructConsumer 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 IRefStructConsumer. + public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. + public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of IRefStructConsumer with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of IRefStructConsumer. + public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. + public static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of IRefStructConsumer 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 IRefStructConsumer. + private static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IRefStructConsumer.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.IRefStructConsumer(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 IRefStructConsumer that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer Wrapping(global::Mockolate.Tests.GeneratorCoverage.IRefStructConsumer instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IRefStructConsumer.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 IRefStructConsumer 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.IRefStructConsumer + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/StaticAbstractMembers_CanBeCreated/Mock.IStaticAbstractMembers.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/StaticAbstractMembers_CanBeCreated/Mock.IStaticAbstractMembers.g.cs index e0a26c5e..56747f5e 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/StaticAbstractMembers_CanBeCreated/Mock.IStaticAbstractMembers.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/StaticAbstractMembers_CanBeCreated/Mock.IStaticAbstractMembers.g.cs @@ -10,188 +10,6 @@ #nullable enable annotations namespace Mockolate; -/// -/// Mock extensions for IStaticAbstractMembers. -/// -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -internal static partial class MockExtensionsForIStaticAbstractMembers -{ - /// - extension(global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers mock) - { - /// - /// Gets the mock accessor for IStaticAbstractMembers - the entry point for configuring setups, verifying interactions and raising events. - /// - /// - /// The accessor is the bridge between the strongly-typed instance of IStaticAbstractMembers 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.
- /// SetupStatic / VerifyStatic / RaiseStatic - target members on interface 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 IStaticAbstractMembers. - public global::Mockolate.Mock.IMockForIStaticAbstractMembers Mock - { - get - { - if (mock is global::Mockolate.Mock.IMockForIStaticAbstractMembers mockInterface) - { - return mockInterface; - } - throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); - } - } - - /// - /// Creates a new mock of IStaticAbstractMembers with the default MockBehavior. - /// - /// - /// The returned instance is a strongly-typed mock generated at compile time - it implements IStaticAbstractMembers 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 IStaticAbstractMembers. - public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock() - => CreateMock(null, null, (object?[]?)null); - - /// - /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. - public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::System.Action setup) - => CreateMock(null, setup, (object?[]?)null); - - /// - /// Creates a new mock of IStaticAbstractMembers with the given . - /// - /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. - /// A new mock instance of IStaticAbstractMembers. - public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior mockBehavior) - => CreateMock(mockBehavior, null, (object?[]?)null); - - /// - /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. - public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) - => CreateMock(mockBehavior, setup, (object?[]?)null); - - /// - /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. - private static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) - { - if (mockBehavior is not null) - { - IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; - if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) - { - if (setup is null) - { - setup = additionalSetup; - } - else - { - var originalSetup = setup; - setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; - } - } - } - - mockBehavior ??= global::Mockolate.MockBehavior.Default; - global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IStaticAbstractMembers.CreateFastInteractions(mockBehavior), constructorParameters); - return CreateMockInstance(mockRegistry, constructorParameters, setup); - } - - private static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) - { - var value = new global::Mockolate.Mock.IStaticAbstractMembers(mockRegistry); - if (setup is not null) - { - setup.Invoke(value); - } - return value; - } - /// - /// 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 IStaticAbstractMembers that delegates to . - public global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers Wrapping(global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers instance) - { - if (mock is global::Mockolate.IMock mockInterface) - { - global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); - wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IStaticAbstractMembers.CreateFastInteractions(wrappingRegistry.Behavior)); - return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); - } - 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 IStaticAbstractMembers 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.IStaticAbstractMembers - { - var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; - return behaviorAccess.Set(setup); - } - } - - [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(); - - public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) - => parameter is global::Mockolate.Parameters.IParameterMatch direct - ? direct - : new CovariantParameterAdapter(parameter); - } -} - internal static partial class Mock { /// @@ -857,5 +675,186 @@ internal interface IMockStaticVerifyForIStaticAbstractMembers } } +/// +/// Mock extensions for IStaticAbstractMembers. +/// +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static partial class MockExtensionsForIStaticAbstractMembers +{ + /// + extension(global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers mock) + { + /// + /// Gets the mock accessor for IStaticAbstractMembers - the entry point for configuring setups, verifying interactions and raising events. + /// + /// + /// The accessor is the bridge between the strongly-typed instance of IStaticAbstractMembers 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.
+ /// SetupStatic / VerifyStatic / RaiseStatic - target members on interface 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 IStaticAbstractMembers. + public global::Mockolate.Mock.IMockForIStaticAbstractMembers Mock + { + get + { + if (mock is global::Mockolate.Mock.IMockForIStaticAbstractMembers mockInterface) + { + return mockInterface; + } + throw new global::Mockolate.Exceptions.MockException("The subject is no mock."); + } + } + + /// + /// Creates a new mock of IStaticAbstractMembers with the default MockBehavior. + /// + /// + /// The returned instance is a strongly-typed mock generated at compile time - it implements IStaticAbstractMembers 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 IStaticAbstractMembers. + public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock() + => CreateMock(null, null, (object?[]?)null); + + /// + /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. + public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::System.Action setup) + => CreateMock(null, setup, (object?[]?)null); + + /// + /// Creates a new mock of IStaticAbstractMembers with the given . + /// + /// Controls how the mock responds when members are invoked without a matching setup; see MockBehavior. + /// A new mock instance of IStaticAbstractMembers. + public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior mockBehavior) + => CreateMock(mockBehavior, null, (object?[]?)null); + + /// + /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. + public static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior mockBehavior, global::System.Action setup) + => CreateMock(mockBehavior, setup, (object?[]?)null); + + /// + /// Creates a new mock of IStaticAbstractMembers 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 IStaticAbstractMembers. + private static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMock(global::Mockolate.MockBehavior? mockBehavior, global::System.Action? setup, object?[]? constructorParameters) + { + if (mockBehavior is not null) + { + IMockBehaviorAccess mockBehaviorAccess = (global::Mockolate.IMockBehaviorAccess)mockBehavior; + if (mockBehaviorAccess.TryGet?>(out var additionalSetup)) + { + if (setup is null) + { + setup = additionalSetup; + } + else + { + var originalSetup = setup; + setup = s => { additionalSetup.Invoke(s); originalSetup.Invoke(s); }; + } + } + } + + mockBehavior ??= global::Mockolate.MockBehavior.Default; + global::Mockolate.MockRegistry mockRegistry = new global::Mockolate.MockRegistry(mockBehavior, global::Mockolate.Mock.IStaticAbstractMembers.CreateFastInteractions(mockBehavior), constructorParameters); + return CreateMockInstance(mockRegistry, constructorParameters, setup); + } + + private static global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers CreateMockInstance(global::Mockolate.MockRegistry mockRegistry, object?[]? constructorParameters, global::System.Action? setup) + { + var value = new global::Mockolate.Mock.IStaticAbstractMembers(mockRegistry); + if (setup is not null) + { + setup.Invoke(value); + } + return value; + } + /// + /// 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 IStaticAbstractMembers that delegates to . + public global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers Wrapping(global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers instance) + { + if (mock is global::Mockolate.IMock mockInterface) + { + global::Mockolate.MockRegistry wrappingRegistry = new global::Mockolate.MockRegistry(mockInterface.MockRegistry, instance); + wrappingRegistry = new global::Mockolate.MockRegistry(wrappingRegistry, global::Mockolate.Mock.IStaticAbstractMembers.CreateFastInteractions(wrappingRegistry.Behavior)); + return CreateMockInstance(wrappingRegistry, mockInterface.MockRegistry.ConstructorParameters, null); + } + 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 IStaticAbstractMembers 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.IStaticAbstractMembers + { + var behaviorAccess = (global::Mockolate.IMockBehaviorAccess)behavior; + return behaviorAccess.Set(setup); + } + } + + [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(); + + public static global::Mockolate.Parameters.IParameterMatch Wrap(global::Mockolate.Parameters.IParameter parameter) + => parameter is global::Mockolate.Parameters.IParameterMatch direct + ? direct + : new CovariantParameterAdapter(parameter); + } +} #nullable disable annotations