diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs index df1c5cbb..ba5977eb 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs @@ -661,7 +661,7 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue memberIds.Emit(sb, "\t\t"); sb.AppendLine(); - AppendCreateFastInteractions(sb, "\t\t", @class, memberIds, memberIdPrefix); + AppendCreateFastInteractions(sb, "\t\t"); sb.AppendLine(); bool hasMockRegistryProvider = constructors?.Count > 0 || (@class.IsInterface && hasStaticMembers); @@ -1269,110 +1269,25 @@ static bool TryCastWithDefaultValue(object?[] values, int index, TValue return sb.ToString(); } - private static void AppendCreateFastInteractions(StringBuilder sb, string indent, Class @class, - MemberIdTable memberIds, string memberIdPrefix) + 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("{").AppendLine(); sb.Append(indent) .Append( - "\tglobal::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);") + "\t=> new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording);") .AppendLine(); - - foreach (Method method in @class.AllMethods()) - { - if (!IsFastBufferEligibleMethod(method)) - { - continue; - } - - string memberIdRef = memberIdPrefix + memberIds.GetMethodIdentifier(method); - int arity = method.Parameters.Count; - string typeArgs = arity == 0 - ? string.Empty - : "<" + string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper())) + ">"; - - if (arity <= 4) - { - sb.Append(indent).Append("\tglobal::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod") - .Append(typeArgs).Append("(fast, ").Append(memberIdRef).Append(");").AppendLine(); - } - else - { - sb.Append(indent) - .Append("\tfast.InstallBuffer(").Append(memberIdRef) - .Append(", new global::Mockolate.Interactions.FastMethod").Append(arity) - .Append("Buffer").Append(typeArgs).Append("(fast));").AppendLine(); - } - } - - foreach (Property property in @class.AllProperties().Where(p => !p.IsIndexer)) - { - if (!IsFastBufferEligibleProperty(property)) - { - continue; - } - - string getMemberIdRef = memberIdPrefix + memberIds.GetPropertyGetIdentifier(property); - string accessFieldRef = memberIdPrefix + memberIds.GetPropertyGetterAccessFieldName(property); - sb.Append(indent) - .Append("\tglobal::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, ") - .Append(getMemberIdRef).Append(", ").Append(accessFieldRef).Append(");").AppendLine(); - - string setMemberIdRef = memberIdPrefix + memberIds.GetPropertySetIdentifier(property); - string propertyType = property.Type.ToTypeOrWrapper(); - sb.Append(indent) - .Append("\tglobal::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter<") - .Append(propertyType).Append(">(fast, ").Append(setMemberIdRef).Append(");").AppendLine(); - } - - foreach (Property indexer in @class.AllProperties().Where(p => p.IsIndexer)) - { - if (!IsFastBufferEligibleIndexer(indexer)) - { - continue; - } - - string getMemberIdRef = memberIdPrefix + memberIds.GetIndexerGetIdentifier(indexer); - string setMemberIdRef = memberIdPrefix + memberIds.GetIndexerSetIdentifier(indexer); - string indexerKeyTypeArgs = - string.Join(", ", indexer.IndexerParameters!.Value.Select(p => p.ToTypeOrWrapper())); - string indexerValueType = indexer.Type.ToTypeOrWrapper(); - - sb.Append(indent).Append("\tglobal::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerGetter<") - .Append(indexerKeyTypeArgs).Append(">(fast, ").Append(getMemberIdRef).Append(");").AppendLine(); - sb.Append(indent).Append("\tglobal::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerSetter<") - .Append(indexerKeyTypeArgs).Append(", ").Append(indexerValueType).Append(">(fast, ") - .Append(setMemberIdRef).Append(");").AppendLine(); - } - - foreach (Event @event in @class.AllEvents()) - { - if (!IsFastBufferEligibleEvent(@event)) - { - continue; - } - - string subMemberIdRef = memberIdPrefix + memberIds.GetEventSubscribeIdentifier(@event); - string unsubMemberIdRef = memberIdPrefix + memberIds.GetEventUnsubscribeIdentifier(@event); - sb.Append(indent) - .Append("\tglobal::Mockolate.Interactions.FastEventBufferFactory.InstallEventSubscribe(fast, ") - .Append(subMemberIdRef).Append(");").AppendLine(); - sb.Append(indent) - .Append("\tglobal::Mockolate.Interactions.FastEventBufferFactory.InstallEventUnsubscribe(fast, ") - .Append(unsubMemberIdRef).Append(");").AppendLine(); - } - - sb.Append(indent).Append("\treturn fast;").AppendLine(); - sb.Append(indent).Append("}").AppendLine(); } /// @@ -1432,30 +1347,32 @@ private static void AppendCachedFieldDeclarations(StringBuilder sb, string inden 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 global::Mockolate.Interactions.FastIndexerGetterBuffer<") - .Append(indexerKeyTypeArgs).Append("> ") + sb.Append(indent).Append("private ").Append(getterBufferType).Append(' ') .Append(memberIds.GetIndexerGetterBufferFieldName(indexer)).AppendLine(); - sb.Append(indent).Append("\t=> field ?? (field = (global::Mockolate.Interactions.FastIndexerGetterBuffer<") - .Append(indexerKeyTypeArgs).Append(">)((global::Mockolate.Interactions.FastMockInteractions)") - .Append(mockRegistryRef).Append(".Interactions).Buffers[").Append(getMemberIdRef).Append("]!);") - .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 global::Mockolate.Interactions.FastIndexerSetterBuffer<") - .Append(indexerKeyTypeArgs).Append(", ").Append(indexerValueType).Append("> ") + sb.Append(indent).Append("private ").Append(setterBufferType).Append(' ') .Append(memberIds.GetIndexerSetterBufferFieldName(indexer)).AppendLine(); - sb.Append(indent).Append("\t=> field ?? (field = (global::Mockolate.Interactions.FastIndexerSetterBuffer<") - .Append(indexerKeyTypeArgs).Append(", ").Append(indexerValueType) - .Append(">)((global::Mockolate.Interactions.FastMockInteractions)").Append(mockRegistryRef) - .Append(".Interactions).Buffers[").Append(setMemberIdRef).Append("]!);").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(); } foreach (Method method in @class.AllMethods()) @@ -1470,17 +1387,17 @@ private static void AppendCachedFieldDeclarations(StringBuilder sb, string inden ? 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 global::Mockolate.Interactions.FastMethod").Append(arity) - .Append("Buffer").Append(typeArgs).Append(' ') + sb.Append(indent).Append("private ").Append(bufferType).Append(' ') .Append(memberIds.GetMethodBufferFieldName(method)).AppendLine(); - sb.Append(indent).Append("\t=> field ?? (field = (global::Mockolate.Interactions.FastMethod").Append(arity) - .Append("Buffer").Append(typeArgs).Append(")((global::Mockolate.Interactions.FastMockInteractions)") - .Append(mockRegistryRef).Append(".Interactions).Buffers[").Append(memberIdRef).Append("]!);") - .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(); } } @@ -1553,7 +1470,6 @@ private static bool IsFastBufferEligibleMethod(Method method) /// 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 @@ -3109,8 +3025,10 @@ private static void AppendMockSubject_ImplementClass_AddMethod(StringBuilder sb, : "<" + string.Join(", ", method.Parameters.Select(p => p.ToTypeOrWrapper())) + ">"; string bufferType = $"global::Mockolate.Interactions.FastMethod{arity}Buffer{typeArgs}"; - sb.Append("\t\t\t\t((").Append(bufferType).Append(")((global::Mockolate.Interactions.FastMockInteractions)") - .Append(mockRegistry).Append(".Interactions).Buffers[").Append(memberIdRef).Append("]!).Append(") + sb.Append("\t\t\t\t((global::Mockolate.Interactions.FastMockInteractions)") + .Append(mockRegistry).Append(".Interactions).GetOrCreateBuffer<").Append(bufferType) + .Append(">(").Append(memberIdRef).Append(", static fast => new ").Append(bufferType) + .Append("(fast)).Append(") .Append(method.GetUniqueNameString()); if (arity > 0) { diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.cs index be487fbc..6c891623 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.cs @@ -149,11 +149,14 @@ private static void EmitIndexerGetterAccessAndSetup(StringBuilder sb, string ind } else if (useFastBuffers && memberIdRef is not null) { - sb.Append(indent).Append("\t((global::Mockolate.Interactions.FastIndexerGetterBuffer<"); - AppendIndexerParameterTypes(sb, parameters); - sb.Append(">)((global::Mockolate.Interactions.FastMockInteractions)").Append(mockRegistry) - .Append(".Interactions).Buffers[").Append(memberIdRef).Append("]!).Append(") - .Append(accessVarName).Append(");").AppendLine(); + StringBuilder bufferType = new("global::Mockolate.Interactions.FastIndexerGetterBuffer<"); + AppendIndexerParameterTypes(bufferType, parameters); + bufferType.Append('>'); + string bufferTypeName = bufferType.ToString(); + sb.Append(indent).Append("\t((global::Mockolate.Interactions.FastMockInteractions)").Append(mockRegistry) + .Append(".Interactions).GetOrCreateBuffer<").Append(bufferTypeName).Append(">(") + .Append(memberIdRef).Append(", static fast => new ").Append(bufferTypeName) + .Append("(fast)).Append(").Append(accessVarName).Append(");").AppendLine(); } else { @@ -241,12 +244,14 @@ private static void EmitIndexerSetterAccessAndSetup(StringBuilder sb, string ind } else if (useFastBuffers && memberIdRef is not null) { - sb.Append(indent).Append("\t((global::Mockolate.Interactions.FastIndexerSetterBuffer<"); - AppendIndexerParameterTypes(sb, parameters); - sb.Append(", ").AppendTypeOrWrapper(propertyType) - .Append(">)((global::Mockolate.Interactions.FastMockInteractions)").Append(mockRegistry) - .Append(".Interactions).Buffers[").Append(memberIdRef).Append("]!).Append(") - .Append(accessVarName).Append(");").AppendLine(); + StringBuilder bufferType = new("global::Mockolate.Interactions.FastIndexerSetterBuffer<"); + AppendIndexerParameterTypes(bufferType, parameters); + bufferType.Append(", ").AppendTypeOrWrapper(propertyType).Append('>'); + string bufferTypeName = bufferType.ToString(); + sb.Append(indent).Append("\t((global::Mockolate.Interactions.FastMockInteractions)").Append(mockRegistry) + .Append(".Interactions).GetOrCreateBuffer<").Append(bufferTypeName).Append(">(") + .Append(memberIdRef).Append(", static fast => new ").Append(bufferTypeName) + .Append("(fast)).Append(").Append(accessVarName).Append(");").AppendLine(); } else { diff --git a/Source/Mockolate/Interactions/FastEventBuffer.cs b/Source/Mockolate/Interactions/FastEventBuffer.cs index 9ca71f01..46cc749b 100644 --- a/Source/Mockolate/Interactions/FastEventBuffer.cs +++ b/Source/Mockolate/Interactions/FastEventBuffer.cs @@ -31,7 +31,12 @@ public sealed class FastEventBuffer : IFastMemberBuffer private readonly FastEventBufferKind _kind; private readonly ChunkedSlotStorage _storage = new(); - internal FastEventBuffer(FastMockInteractions owner, FastEventBufferKind kind) + /// + /// Creates a new event buffer of the given attached to . + /// + /// The mock-wide the buffer publishes records into. + /// Distinguishes a subscribe-recording buffer from an unsubscribe-recording buffer. + public FastEventBuffer(FastMockInteractions owner, FastEventBufferKind kind) { _owner = owner; _kind = kind; @@ -132,28 +137,3 @@ internal struct Record } } -/// -/// Factory helpers for event buffers. -/// -public static class FastEventBufferFactory -{ - /// - /// Creates and installs an event subscribe buffer at the given . - /// - public static FastEventBuffer InstallEventSubscribe(this FastMockInteractions interactions, int memberId) - { - FastEventBuffer buffer = new(interactions, FastEventBufferKind.Subscribe); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an event unsubscribe buffer at the given . - /// - public static FastEventBuffer InstallEventUnsubscribe(this FastMockInteractions interactions, int memberId) - { - FastEventBuffer buffer = new(interactions, FastEventBufferKind.Unsubscribe); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } -} diff --git a/Source/Mockolate/Interactions/FastIndexerBuffer.cs b/Source/Mockolate/Interactions/FastIndexerBuffer.cs index 676d3386..3ba3871b 100644 --- a/Source/Mockolate/Interactions/FastIndexerBuffer.cs +++ b/Source/Mockolate/Interactions/FastIndexerBuffer.cs @@ -16,7 +16,11 @@ public sealed class FastIndexerGetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerGetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-getter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerGetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -146,7 +150,11 @@ public sealed class FastIndexerGetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerGetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-getter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerGetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -275,7 +283,11 @@ public sealed class FastIndexerGetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerGetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-getter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerGetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -407,7 +419,11 @@ public sealed class FastIndexerGetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerGetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-getter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerGetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -542,7 +558,11 @@ public sealed class FastIndexerSetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerSetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-setter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerSetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -672,7 +692,11 @@ public sealed class FastIndexerSetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerSetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-setter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerSetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -805,7 +829,11 @@ public sealed class FastIndexerSetterBuffer : IFastMemberBuf private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerSetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-setter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerSetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -941,7 +969,11 @@ public sealed class FastIndexerSetterBuffer : IFastMembe private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastIndexerSetterBuffer(FastMockInteractions owner) + /// + /// Creates a new indexer-setter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastIndexerSetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -1068,88 +1100,3 @@ internal struct Record } } -/// -/// Factory helpers for indexer buffers. -/// -public static class FastIndexerBufferFactory -{ - /// - /// Creates and installs an indexer getter buffer at the given . - /// - public static FastIndexerGetterBuffer InstallIndexerGetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerGetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer getter buffer at the given . - /// - public static FastIndexerGetterBuffer InstallIndexerGetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerGetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer getter buffer at the given . - /// - public static FastIndexerGetterBuffer InstallIndexerGetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerGetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer getter buffer at the given . - /// - public static FastIndexerGetterBuffer InstallIndexerGetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerGetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer setter buffer at the given . - /// - public static FastIndexerSetterBuffer InstallIndexerSetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerSetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer setter buffer at the given . - /// - public static FastIndexerSetterBuffer InstallIndexerSetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerSetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer setter buffer at the given . - /// - public static FastIndexerSetterBuffer InstallIndexerSetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerSetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs an indexer setter buffer at the given . - /// - public static FastIndexerSetterBuffer InstallIndexerSetter(this FastMockInteractions interactions, int memberId) - { - FastIndexerSetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } -} diff --git a/Source/Mockolate/Interactions/FastMethodBuffer.cs b/Source/Mockolate/Interactions/FastMethodBuffer.cs index 6a64010f..5e37107b 100644 --- a/Source/Mockolate/Interactions/FastMethodBuffer.cs +++ b/Source/Mockolate/Interactions/FastMethodBuffer.cs @@ -16,7 +16,11 @@ public sealed class FastMethod0Buffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastMethod0Buffer(FastMockInteractions owner) + /// + /// Creates a new parameterless method buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastMethod0Buffer(FastMockInteractions owner) { _owner = owner; } @@ -122,7 +126,11 @@ public sealed class FastMethod1Buffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastMethod1Buffer(FastMockInteractions owner) + /// + /// Creates a new 1-parameter method buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastMethod1Buffer(FastMockInteractions owner) { _owner = owner; } @@ -248,7 +256,11 @@ public sealed class FastMethod2Buffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastMethod2Buffer(FastMockInteractions owner) + /// + /// Creates a new 2-parameter method buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastMethod2Buffer(FastMockInteractions owner) { _owner = owner; } @@ -374,7 +386,11 @@ public sealed class FastMethod3Buffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastMethod3Buffer(FastMockInteractions owner) + /// + /// Creates a new 3-parameter method buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastMethod3Buffer(FastMockInteractions owner) { _owner = owner; } @@ -501,7 +517,11 @@ public sealed class FastMethod4Buffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastMethod4Buffer(FastMockInteractions owner) + /// + /// Creates a new 4-parameter method buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastMethod4Buffer(FastMockInteractions owner) { _owner = owner; } @@ -618,59 +638,3 @@ internal struct Record } } -/// -/// Factory helpers that hide the per-arity buffer constructors behind the -/// API. -/// -public static class FastMethodBufferFactory -{ - /// - /// Creates and installs a parameterless method buffer at the given . - /// - public static FastMethod0Buffer InstallMethod(this FastMockInteractions interactions, int memberId) - { - FastMethod0Buffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a 1-parameter method buffer at the given . - /// - public static FastMethod1Buffer InstallMethod(this FastMockInteractions interactions, int memberId) - { - FastMethod1Buffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a 2-parameter method buffer at the given . - /// - public static FastMethod2Buffer InstallMethod(this FastMockInteractions interactions, int memberId) - { - FastMethod2Buffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a 3-parameter method buffer at the given . - /// - public static FastMethod3Buffer InstallMethod(this FastMockInteractions interactions, int memberId) - { - FastMethod3Buffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a 4-parameter method buffer at the given . - /// - public static FastMethod4Buffer InstallMethod(this FastMockInteractions interactions, int memberId) - { - FastMethod4Buffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } -} diff --git a/Source/Mockolate/Interactions/FastMockInteractions.cs b/Source/Mockolate/Interactions/FastMockInteractions.cs index 1f529614..522e3a82 100644 --- a/Source/Mockolate/Interactions/FastMockInteractions.cs +++ b/Source/Mockolate/Interactions/FastMockInteractions.cs @@ -29,8 +29,8 @@ public class FastMockInteractions : IMockInteractions /// /// Creates a new sized to . - /// Each mockable member is later assigned its own per-member buffer at the matching index via - /// . + /// Each mockable member's buffer slot starts empty and is materialized lazily on first access via + /// . /// /// The number of distinct mockable members the buffer array should hold. /// Mirrors . @@ -70,13 +70,59 @@ public FastMockInteractions(int memberCount, bool skipInteractionRecording = fal public int Count => (int)Interlocked.Read(ref _globalSequence); /// - /// Installs at the slot matching . - /// Called once at mock construction by the source generator. + /// Returns the buffer at , materializing it via + /// under a lock-free CAS on first touch. The factory must be a static lambda so the runtime never + /// allocates a closure on the lazy path. /// + /// The concrete buffer type at the slot. /// The generator-emitted member id for the buffer's target member. - /// The per-member buffer to install. - public void InstallBuffer(int memberId, IFastMemberBuffer buffer) - => Buffers[memberId] = buffer; + /// + /// Builds a new buffer when the slot is still empty. Invoked at most once per slot in the absence + /// of a race; under contention the loser's allocation is discarded and the winner is returned. + /// + public TBuffer GetOrCreateBuffer(int memberId, Func factory) + where TBuffer : class, IFastMemberBuffer + { + IFastMemberBuffer?[] buffers = Buffers; + IFastMemberBuffer? existing = Volatile.Read(ref buffers[memberId]); + if (existing is TBuffer typed) + { + return typed; + } + + TBuffer created = factory(this); + IFastMemberBuffer? prev = Interlocked.CompareExchange(ref buffers[memberId], created, null); + return prev is TBuffer winner ? winner : created; + } + + /// + /// -passing variant of + /// that lets + /// callers supply the buffer's construction parameter without allocating a closure. + /// + /// The concrete buffer type at the slot. + /// Type of the construction parameter forwarded to . + /// The generator-emitted member id for the buffer's target member. + /// + /// Builds a new buffer from when the slot is still empty. Must be a + /// static lambda; is the only flow path so closures are unnecessary. + /// + /// Forwarded to on construction. + public TBuffer GetOrCreateBuffer(int memberId, + Func factory, TState state) + where TBuffer : class, IFastMemberBuffer + { + IFastMemberBuffer?[] buffers = Buffers; + IFastMemberBuffer? existing = Volatile.Read(ref buffers[memberId]); + if (existing is TBuffer typed) + { + return typed; + } + + TBuffer created = factory(this, state); + IFastMemberBuffer? prev = Interlocked.CompareExchange(ref buffers[memberId], created, null); + return prev is TBuffer winner ? winner : created; + } /// /// Reserves the next sequence number for a recording. Buffer implementations call this once diff --git a/Source/Mockolate/Interactions/FastPropertyBuffer.cs b/Source/Mockolate/Interactions/FastPropertyBuffer.cs index 4180acd0..d2920980 100644 --- a/Source/Mockolate/Interactions/FastPropertyBuffer.cs +++ b/Source/Mockolate/Interactions/FastPropertyBuffer.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Diagnostics; using Mockolate.Parameters; @@ -24,14 +23,15 @@ public sealed class FastPropertyGetterBuffer : IFastMemberBuffer { private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - private PropertyGetterAccess? _access; + private readonly PropertyGetterAccess _access; - internal FastPropertyGetterBuffer(FastMockInteractions owner) - { - _owner = owner; - } - - internal FastPropertyGetterBuffer(FastMockInteractions owner, PropertyGetterAccess access) + /// + /// Creates a new property-getter buffer pre-seeded with the shared + /// singleton. + /// + /// The mock-wide the buffer publishes records into. + /// The shared singleton emitted by the source generator. + public FastPropertyGetterBuffer(FastMockInteractions owner, PropertyGetterAccess access) { _owner = owner; _access = access; @@ -42,18 +42,10 @@ internal FastPropertyGetterBuffer(FastMockInteractions owner, PropertyGetterAcce /// /// Records a property getter access using the buffer's pre-seeded - /// singleton. Throws when the singleton has not been - /// installed — callers must use in that case. + /// singleton. /// - /// No singleton was supplied at install time. public void Append() { - if (_access is null) - { - throw new InvalidOperationException( - $"{nameof(Append)}() requires the buffer to be installed with a {nameof(PropertyGetterAccess)} singleton via {nameof(FastPropertyBufferFactory)}.{nameof(FastPropertyBufferFactory.InstallPropertyGetter)}(memberId, access). Use {nameof(Append)}(string) when no singleton is available."); - } - long seq = _owner.NextSequence(); int slot = _storage.Reserve(); ref Record r = ref _storage.SlotForWrite(slot); @@ -66,22 +58,6 @@ public void Append() } } - /// - /// Records a property getter access. Lazily installs the buffer's - /// singleton from on first - /// call so legacy callers (generated code that does not pass a pre-built singleton) keep - /// working without allocating one access object per record. - /// - public void Append(string name) - { - // Lazy init: the buffer is bound to a single property, so one singleton covers every - // record. The benign race here is acceptable — both instances are equivalent because - // PropertyGetterAccess is identified solely by Name; whichever assignment wins still - // satisfies the contract. - _access ??= new PropertyGetterAccess(name); - Append(); - } - /// public void Clear() => _storage.Clear(); @@ -95,7 +71,7 @@ void IFastMemberBuffer.AppendBoxed(List<(long Seq, IInteraction Interaction)> de return; } - PropertyGetterAccess access = _access!; + PropertyGetterAccess access = _access; for (int slot = 0; slot < n; slot++) { ref Record r = ref _storage.SlotUnderLock(slot); @@ -114,7 +90,7 @@ void IFastMemberBuffer.AppendBoxedUnverified(List<(long Seq, IInteraction Intera return; } - PropertyGetterAccess access = _access!; + PropertyGetterAccess access = _access; for (int slot = 0; slot < n; slot++) { if (_storage.VerifiedUnderLock(slot)) @@ -167,7 +143,11 @@ public sealed class FastPropertySetterBuffer : IFastMemberBuffer private readonly FastMockInteractions _owner; private readonly ChunkedSlotStorage _storage = new(); - internal FastPropertySetterBuffer(FastMockInteractions owner) + /// + /// Creates a new property-setter buffer attached to . + /// + /// The mock-wide the buffer publishes records into. + public FastPropertySetterBuffer(FastMockInteractions owner) { _owner = owner; } @@ -266,42 +246,3 @@ internal struct Record } } -/// -/// Factory helpers for property buffers. -/// -public static class FastPropertyBufferFactory -{ - /// - /// Creates and installs a property getter buffer at the given . - /// - public static FastPropertyGetterBuffer InstallPropertyGetter(this FastMockInteractions interactions, int memberId) - { - FastPropertyGetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a property getter buffer at the given with - /// a pre-built shared singleton. Used by the source generator so the - /// buffer never has to allocate a on the first record or on - /// verification. - /// - public static FastPropertyGetterBuffer InstallPropertyGetter(this FastMockInteractions interactions, - int memberId, PropertyGetterAccess access) - { - FastPropertyGetterBuffer buffer = new(interactions, access); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } - - /// - /// Creates and installs a property setter buffer at the given . - /// - public static FastPropertySetterBuffer InstallPropertySetter(this FastMockInteractions interactions, int memberId) - { - FastPropertySetterBuffer buffer = new(interactions); - interactions.InstallBuffer(memberId, buffer); - return buffer; - } -} diff --git a/Source/Mockolate/MockRegistry.Interactions.cs b/Source/Mockolate/MockRegistry.Interactions.cs index 37f3f7ea..bc379d0a 100644 --- a/Source/Mockolate/MockRegistry.Interactions.cs +++ b/Source/Mockolate/MockRegistry.Interactions.cs @@ -94,7 +94,7 @@ public void ClearAllInteractions() /// , or when no setup has been registered. /// /// - /// Property dispatch reads the snapshot via + /// Property dispatch reads the snapshot via /// and falls back to the cold path when the snapshot is empty, so this accessor is intended for /// diagnostics and tests that need to verify the fast-path table directly. /// @@ -601,38 +601,18 @@ public TResult GetProperty(PropertyGetterAccess access, Func d } /// - /// Allocation-free fast-path overload of . - /// Avoids the per-call closure allocation by accepting a static that takes the - /// active as its argument — the source generator emits a static lambda so - /// the C# compiler caches the delegate in a static field. - /// - /// The property's value type. - /// The generator-emitted member id for the property getter. - /// The simple property name. - /// Cached factory invoked with the active when a default value is needed. - /// Optional accessor for the base-class getter; when only the default/initial value is considered. Pass for the no-wrapping fast path. - /// The resolved getter value. - /// No setup exists for the property and is . - public TResult GetPropertyFast(int memberId, string propertyName, - Func defaultValueGenerator, Func? baseValueAccessor = null) - { - if (!Behavior.SkipInteractionRecording) - { - RecordPropertyGetter(memberId, propertyName); - } - - return ResolvePropertyFast(memberId, propertyName, defaultValueGenerator, baseValueAccessor); - } - - /// - /// Singleton-aware overload of - /// + /// Allocation-free fast-path overload of /// that records the shared singleton emitted by the source generator, /// avoiding the per-call allocation. The /// stores only a sequence number per call and emits the /// same singleton for every recorded record on verification; the cold-path fall-through likewise /// registers the singleton. /// + /// + /// Avoids the per-call closure allocation by accepting a static that takes + /// the active as its argument — the source generator emits a static + /// lambda so the C# compiler caches the delegate in a static field. + /// /// The property's value type. /// The generator-emitted member id for the property getter. /// The shared singleton for the property. @@ -684,33 +664,14 @@ private TResult ResolvePropertyFast(int memberId, string propertyName, return ResolveGetterInternal(propertyName, bridge, baseValueAccessor, null); } - private void RecordPropertyGetter(int memberId, string propertyName) - { - if (Interactions is FastMockInteractions fast) - { - IFastMemberBuffer?[] buffers = fast.Buffers; - if ((uint)memberId < (uint)buffers.Length && - buffers[memberId] is FastPropertyGetterBuffer buffer) - { - buffer.Append(propertyName); - return; - } - } - - Interactions.RegisterInteraction(new PropertyGetterAccess(propertyName)); - } - private void RecordPropertyGetter(int memberId, PropertyGetterAccess access) { - if (Interactions is FastMockInteractions fast) + if (Interactions is FastMockInteractions fast && (uint)memberId < (uint)fast.Buffers.Length) { - IFastMemberBuffer?[] buffers = fast.Buffers; - if ((uint)memberId < (uint)buffers.Length && - buffers[memberId] is FastPropertyGetterBuffer buffer) - { - buffer.Append(); - return; - } + FastPropertyGetterBuffer buffer = fast.GetOrCreateBuffer( + memberId, static (f, a) => new FastPropertyGetterBuffer(f, a), access); + buffer.Append(); + return; } Interactions.RegisterInteraction(access); @@ -853,15 +814,12 @@ public bool SetPropertyFast(int memberId, int setterMemberId, string property private void RecordPropertySetter(int memberId, string propertyName, T value) { - if (Interactions is FastMockInteractions fast) + if (Interactions is FastMockInteractions fast && (uint)memberId < (uint)fast.Buffers.Length) { - IFastMemberBuffer?[] buffers = fast.Buffers; - if ((uint)memberId < (uint)buffers.Length && - buffers[memberId] is FastPropertySetterBuffer buffer) - { - buffer.Append(propertyName, value); - return; - } + FastPropertySetterBuffer buffer = fast.GetOrCreateBuffer( + memberId, static f => new FastPropertySetterBuffer(f)); + buffer.Append(propertyName, value); + return; } Interactions.RegisterInteraction(new PropertySetterAccess(propertyName, value)); @@ -1075,15 +1033,15 @@ public void RemoveEvent(int memberId, string name, object? target, MethodInfo? m private void RecordEvent(int memberId, string name, object? target, MethodInfo method, bool isSubscribe) { - if (Interactions is FastMockInteractions fast) - { - IFastMemberBuffer?[] buffers = fast.Buffers; - if ((uint)memberId < (uint)buffers.Length && - buffers[memberId] is FastEventBuffer buffer) - { - buffer.Append(name, target, method); - return; - } + if (Interactions is FastMockInteractions fast && (uint)memberId < (uint)fast.Buffers.Length) + { + FastEventBuffer buffer = isSubscribe + ? fast.GetOrCreateBuffer(memberId, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)) + : fast.GetOrCreateBuffer(memberId, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); + buffer.Append(name, target, method); + return; } if (isSubscribe) diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt index f88e7262..3c90f6e0 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt @@ -222,7 +222,6 @@ namespace Mockolate public TResult GetProperty(Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetProperty(string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetPropertyFast(int memberId, Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } - public TResult GetPropertyFast(int memberId, string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } public System.Collections.Generic.IReadOnlyCollection GetUnusedSetups(Mockolate.Interactions.IMockInteractions interactions) { } public Mockolate.Verify.VerificationResult IndexerGot(T subject, int memberId, System.Func gotPredicate, System.Func parametersDescription) { } public Mockolate.Verify.VerificationResult IndexerGotTyped(T subject, int memberId, Mockolate.Parameters.IParameterMatch match1, System.Func parametersDescription) { } @@ -653,35 +652,21 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} event {_kind}s")] public sealed class FastEventBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastEventBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.FastEventBufferKind kind) { } public int Count { get; } public void Append(string name, object? target, System.Reflection.MethodInfo method) { } public void Clear() { } public int ConsumeMatching() { } } - public static class FastEventBufferFactory - { - public static Mockolate.Interactions.FastEventBuffer InstallEventSubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastEventBuffer InstallEventUnsubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } public enum FastEventBufferKind { Subscribe = 0, Unsubscribe = 1, } - public static class FastIndexerBufferFactory - { - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1) { } @@ -691,6 +676,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2) { } @@ -700,6 +686,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3) { } @@ -709,6 +696,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } @@ -718,6 +706,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, TValue value) { } @@ -727,6 +716,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, TValue value) { } @@ -736,6 +726,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, TValue value) { } @@ -745,6 +736,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4, TValue value) { } @@ -754,6 +746,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod0Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod0Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name) { } public void Clear() { } @@ -762,6 +755,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod1Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod1Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1) { } public void Clear() { } @@ -770,6 +764,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod2Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod2Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2) { } public void Clear() { } @@ -778,6 +773,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod3Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod3Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3) { } public void Clear() { } @@ -786,19 +782,12 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod4Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod4Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } public void Clear() { } public int ConsumeMatching(Mockolate.Parameters.IParameterMatch match1, Mockolate.Parameters.IParameterMatch match2, Mockolate.Parameters.IParameterMatch match3, Mockolate.Parameters.IParameterMatch match4) { } } - public static class FastMethodBufferFactory - { - public static Mockolate.Interactions.FastMethod0Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod1Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod2Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod3Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod4Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} interactions")] public class FastMockInteractions : Mockolate.Interactions.IMockInteractions, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.IEnumerable { @@ -811,29 +800,27 @@ namespace Mockolate.Interactions public event System.EventHandler? OnClearing; public void Clear() { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory, TState state) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } public System.Collections.Generic.IReadOnlyCollection GetUnverifiedInteractions() { } - public void InstallBuffer(int memberId, Mockolate.Interactions.IFastMemberBuffer buffer) { } public long NextSequence() { } public void RaiseAdded() { } } - public static class FastPropertyBufferFactory - { - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId, Mockolate.Interactions.PropertyGetterAccess access) { } - public static Mockolate.Interactions.FastPropertySetterBuffer InstallPropertySetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} property gets")] public sealed class FastPropertyGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertyGetterBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.PropertyGetterAccess access) { } public int Count { get; } public void Append() { } - public void Append(string name) { } public void Clear() { } public int ConsumeMatching() { } } [System.Diagnostics.DebuggerDisplay("{Count} property sets")] public sealed class FastPropertySetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertySetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T value) { } public void Clear() { } diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt index f577d8d7..6337ffb5 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt @@ -215,7 +215,6 @@ namespace Mockolate public TResult GetProperty(Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetProperty(string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetPropertyFast(int memberId, Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } - public TResult GetPropertyFast(int memberId, string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } public System.Collections.Generic.IReadOnlyCollection GetUnusedSetups(Mockolate.Interactions.IMockInteractions interactions) { } public Mockolate.Verify.VerificationResult IndexerGot(T subject, int memberId, System.Func gotPredicate, System.Func parametersDescription) { } public Mockolate.Verify.VerificationResult IndexerGotTyped(T subject, int memberId, Mockolate.Parameters.IParameterMatch match1, System.Func parametersDescription) { } @@ -644,35 +643,21 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} event {_kind}s")] public sealed class FastEventBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastEventBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.FastEventBufferKind kind) { } public int Count { get; } public void Append(string name, object? target, System.Reflection.MethodInfo method) { } public void Clear() { } public int ConsumeMatching() { } } - public static class FastEventBufferFactory - { - public static Mockolate.Interactions.FastEventBuffer InstallEventSubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastEventBuffer InstallEventUnsubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } public enum FastEventBufferKind { Subscribe = 0, Unsubscribe = 1, } - public static class FastIndexerBufferFactory - { - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1) { } @@ -682,6 +667,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2) { } @@ -691,6 +677,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3) { } @@ -700,6 +687,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } @@ -709,6 +697,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, TValue value) { } @@ -718,6 +707,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, TValue value) { } @@ -727,6 +717,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, TValue value) { } @@ -736,6 +727,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4, TValue value) { } @@ -745,6 +737,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod0Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod0Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name) { } public void Clear() { } @@ -753,6 +746,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod1Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod1Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1) { } public void Clear() { } @@ -761,6 +755,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod2Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod2Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2) { } public void Clear() { } @@ -769,6 +764,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod3Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod3Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3) { } public void Clear() { } @@ -777,19 +773,12 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod4Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod4Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } public void Clear() { } public int ConsumeMatching(Mockolate.Parameters.IParameterMatch match1, Mockolate.Parameters.IParameterMatch match2, Mockolate.Parameters.IParameterMatch match3, Mockolate.Parameters.IParameterMatch match4) { } } - public static class FastMethodBufferFactory - { - public static Mockolate.Interactions.FastMethod0Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod1Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod2Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod3Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod4Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} interactions")] public class FastMockInteractions : Mockolate.Interactions.IMockInteractions, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.IEnumerable { @@ -802,29 +791,27 @@ namespace Mockolate.Interactions public event System.EventHandler? OnClearing; public void Clear() { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory, TState state) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } public System.Collections.Generic.IReadOnlyCollection GetUnverifiedInteractions() { } - public void InstallBuffer(int memberId, Mockolate.Interactions.IFastMemberBuffer buffer) { } public long NextSequence() { } public void RaiseAdded() { } } - public static class FastPropertyBufferFactory - { - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId, Mockolate.Interactions.PropertyGetterAccess access) { } - public static Mockolate.Interactions.FastPropertySetterBuffer InstallPropertySetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} property gets")] public sealed class FastPropertyGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertyGetterBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.PropertyGetterAccess access) { } public int Count { get; } public void Append() { } - public void Append(string name) { } public void Clear() { } public int ConsumeMatching() { } } [System.Diagnostics.DebuggerDisplay("{Count} property sets")] public sealed class FastPropertySetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertySetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T value) { } public void Clear() { } diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt index 6fbc0518..5e4e3a1a 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt @@ -202,7 +202,6 @@ namespace Mockolate public TResult GetProperty(Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetProperty(string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor) { } public TResult GetPropertyFast(int memberId, Mockolate.Interactions.PropertyGetterAccess access, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } - public TResult GetPropertyFast(int memberId, string propertyName, System.Func defaultValueGenerator, System.Func? baseValueAccessor = null) { } public System.Collections.Generic.IReadOnlyCollection GetUnusedSetups(Mockolate.Interactions.IMockInteractions interactions) { } public Mockolate.Verify.VerificationResult IndexerGot(T subject, int memberId, System.Func gotPredicate, System.Func parametersDescription) { } public Mockolate.Verify.VerificationResult IndexerGotTyped(T subject, int memberId, Mockolate.Parameters.IParameterMatch match1, System.Func parametersDescription) { } @@ -603,35 +602,21 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} event {_kind}s")] public sealed class FastEventBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastEventBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.FastEventBufferKind kind) { } public int Count { get; } public void Append(string name, object? target, System.Reflection.MethodInfo method) { } public void Clear() { } public int ConsumeMatching() { } } - public static class FastEventBufferFactory - { - public static Mockolate.Interactions.FastEventBuffer InstallEventSubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastEventBuffer InstallEventUnsubscribe(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } public enum FastEventBufferKind { Subscribe = 0, Unsubscribe = 1, } - public static class FastIndexerBufferFactory - { - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerGetterBuffer InstallIndexerGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastIndexerSetterBuffer InstallIndexerSetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1) { } @@ -641,6 +626,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2) { } @@ -650,6 +636,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3) { } @@ -659,6 +646,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer gets")] public sealed class FastIndexerGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerGetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerGetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } @@ -668,6 +656,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, TValue value) { } @@ -677,6 +666,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, TValue value) { } @@ -686,6 +676,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, TValue value) { } @@ -695,6 +686,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} indexer sets")] public sealed class FastIndexerSetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastIndexerSetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(Mockolate.Interactions.IndexerSetterAccess access) { } public void Append(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4, TValue value) { } @@ -704,6 +696,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod0Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod0Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name) { } public void Clear() { } @@ -712,6 +705,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod1Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod1Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1) { } public void Clear() { } @@ -720,6 +714,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod2Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod2Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2) { } public void Clear() { } @@ -728,6 +723,7 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod3Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod3Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3) { } public void Clear() { } @@ -736,19 +732,12 @@ namespace Mockolate.Interactions [System.Diagnostics.DebuggerDisplay("{Count} method calls")] public sealed class FastMethod4Buffer : Mockolate.Interactions.IFastMemberBuffer { + public FastMethod4Buffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) { } public void Clear() { } public int ConsumeMatching(Mockolate.Parameters.IParameterMatch match1, Mockolate.Parameters.IParameterMatch match2, Mockolate.Parameters.IParameterMatch match3, Mockolate.Parameters.IParameterMatch match4) { } } - public static class FastMethodBufferFactory - { - public static Mockolate.Interactions.FastMethod0Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod1Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod2Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod3Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastMethod4Buffer InstallMethod(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} interactions")] public class FastMockInteractions : Mockolate.Interactions.IMockInteractions, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.IEnumerable { @@ -761,29 +750,27 @@ namespace Mockolate.Interactions public event System.EventHandler? OnClearing; public void Clear() { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } + public TBuffer GetOrCreateBuffer(int memberId, System.Func factory, TState state) + where TBuffer : class, Mockolate.Interactions.IFastMemberBuffer { } public System.Collections.Generic.IReadOnlyCollection GetUnverifiedInteractions() { } - public void InstallBuffer(int memberId, Mockolate.Interactions.IFastMemberBuffer buffer) { } public long NextSequence() { } public void RaiseAdded() { } } - public static class FastPropertyBufferFactory - { - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - public static Mockolate.Interactions.FastPropertyGetterBuffer InstallPropertyGetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId, Mockolate.Interactions.PropertyGetterAccess access) { } - public static Mockolate.Interactions.FastPropertySetterBuffer InstallPropertySetter(this Mockolate.Interactions.FastMockInteractions interactions, int memberId) { } - } [System.Diagnostics.DebuggerDisplay("{Count} property gets")] public sealed class FastPropertyGetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertyGetterBuffer(Mockolate.Interactions.FastMockInteractions owner, Mockolate.Interactions.PropertyGetterAccess access) { } public int Count { get; } public void Append() { } - public void Append(string name) { } public void Clear() { } public int ConsumeMatching() { } } [System.Diagnostics.DebuggerDisplay("{Count} property sets")] public sealed class FastPropertySetterBuffer : Mockolate.Interactions.IFastMemberBuffer { + public FastPropertySetterBuffer(Mockolate.Interactions.FastMockInteractions owner) { } public int Count { get; } public void Append(string name, T value) { } public void Clear() { } diff --git a/Tests/Mockolate.Internal.Tests/Interactions/ChunkedSlotStorageTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/ChunkedSlotStorageTests.cs index 6caec1e8..c37e02dc 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/ChunkedSlotStorageTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/ChunkedSlotStorageTests.cs @@ -11,7 +11,8 @@ public async Task Clear_AfterMultipleChunks_ResetsCountAndAllowsRefill() { const int total = (ChunkedSlotStorage.ChunkSize * 2) + 5; FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); for (int i = 0; i < total; i++) { @@ -32,7 +33,8 @@ public async Task SlotForWrite_AcrossMultipleChunks_PreservesAllRecords() { const int total = ChunkedSlotStorage.ChunkSize * 3; FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); for (int i = 0; i < total; i++) { @@ -53,7 +55,8 @@ public async Task SlotForWrite_BeyondInitialChunksArrayLength_ExpandsArrayUnderL { const int total = (ChunkedSlotStorage.ChunkSize * 4) + 1; FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); for (int i = 0; i < total; i++) { diff --git a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferBoxingAndUnverifiedTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferBoxingAndUnverifiedTests.cs index 90a9b383..f82ea779 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferBoxingAndUnverifiedTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferBoxingAndUnverifiedTests.cs @@ -13,8 +13,8 @@ public async Task FastEventBuffer_AppendBoxed_KindMatters() { FastMockInteractions subscribeStore = new(1); FastMockInteractions unsubscribeStore = new(1); - FastEventBuffer subscribe = subscribeStore.InstallEventSubscribe(0); - FastEventBuffer unsubscribe = unsubscribeStore.InstallEventUnsubscribe(0); + FastEventBuffer subscribe = InstallEventSubscribe(subscribeStore, 0); + FastEventBuffer unsubscribe = InstallEventUnsubscribe(unsubscribeStore, 0); subscribe.Append("E", this, SampleMethod); unsubscribe.Append("E", this, SampleMethod); @@ -27,7 +27,7 @@ public async Task FastEventBuffer_AppendBoxed_KindMatters() public async Task FastEventBuffer_AppendBoxedUnverified_ShouldSkipMatchedSlots() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = InstallEventSubscribe(store, 0); buffer.Append("E", this, SampleMethod); buffer.Append("E", this, SampleMethod); buffer.Append("E", this, SampleMethod); @@ -53,7 +53,7 @@ public async Task FastEventBuffer_Subscribe_AppendBoxed_CachesAndReusesAlreadyBo // Pins the `r.Boxed ??= new EventSubscription(...)` cache in AppendBoxed. With the // `??=` mutated to `=`, every AppendBoxed call would allocate a fresh record. FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = InstallEventSubscribe(store, 0); buffer.Append("E", this, SampleMethod); List<(long Seq, IInteraction Interaction)> first = []; @@ -71,7 +71,7 @@ public async Task FastEventBuffer_Subscribe_AppendBoxedUnverified_CachesAndReuse { // Pins the `r.Boxed ??= new EventSubscription(...)` cache in AppendBoxedUnverified. FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = InstallEventSubscribe(store, 0); buffer.Append("E", this, SampleMethod); List<(long Seq, IInteraction Interaction)> first = []; @@ -88,7 +88,7 @@ public async Task FastEventBuffer_Subscribe_AppendBoxedUnverified_CachesAndReuse public async Task FastEventBuffer_SubscribeAppend_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = InstallEventSubscribe(store, 0); return () => buffer.Append("E", this, SampleMethod); }); @@ -96,7 +96,7 @@ public async Task FastEventBuffer_SubscribeAppend_ShouldRaiseInteractionAdded() public async Task FastEventBuffer_Unsubscribe_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = InstallEventUnsubscribe(store, 0); buffer.Append("E", this, SampleMethod); List<(long Seq, IInteraction Interaction)> first = []; @@ -113,7 +113,7 @@ public async Task FastEventBuffer_Unsubscribe_AppendBoxed_CachesAndReusesAlready public async Task FastEventBuffer_Unsubscribe_AppendBoxedUnverified_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = InstallEventUnsubscribe(store, 0); buffer.Append("E", this, SampleMethod); List<(long Seq, IInteraction Interaction)> first = []; @@ -134,7 +134,7 @@ public async Task FastEventBuffer_Unsubscribe_AppendBoxedUnverified_ShouldBoxAsE // flipped to `(true ? Subscription : Unsubscription)`, an unsubscribe buffer would // surface its records as EventSubscription. FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = InstallEventUnsubscribe(store, 0); buffer.Append("E", this, SampleMethod); List<(long Seq, IInteraction Interaction)> dest = []; @@ -148,7 +148,7 @@ public async Task FastEventBuffer_Unsubscribe_AppendBoxedUnverified_ShouldBoxAsE public async Task FastEventBuffer_UnsubscribeAppend_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = InstallEventUnsubscribe(store, 0); return () => buffer.Append("E", this, SampleMethod); }); @@ -156,7 +156,7 @@ public async Task FastEventBuffer_UnsubscribeAppend_ShouldRaiseInteractionAdded( public async Task FastIndexerGetterBuffer1_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); return () => buffer.Append(1); }); @@ -164,7 +164,7 @@ public async Task FastIndexerGetterBuffer1_Append_ShouldRaiseInteractionAdded() public async Task FastIndexerGetterBuffer1_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(7); @@ -182,7 +182,7 @@ public async Task FastIndexerGetterBuffer1_AppendBoxed_CachesAndReusesAlreadyBox public async Task FastIndexerGetterBuffer1_AppendBoxedUnverified_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(7); @@ -200,7 +200,7 @@ public async Task FastIndexerGetterBuffer1_AppendBoxedUnverified_CachesAndReuses public async Task FastIndexerGetterBuffer1_AppendWithAccess_ShouldPublishAndRaiseInteractionAdded() => await VerifyAppendWithAccessPublishesAndRaises(store => { - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); IndexerGetterAccess access = new(7); return (() => buffer.Append(access), () => buffer.Count); }); @@ -209,7 +209,7 @@ public async Task FastIndexerGetterBuffer1_AppendWithAccess_ShouldPublishAndRais public async Task FastIndexerGetterBuffer2_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); return () => buffer.Append(1, "a"); }); @@ -217,7 +217,7 @@ public async Task FastIndexerGetterBuffer2_Append_ShouldRaiseInteractionAdded() public async Task FastIndexerGetterBuffer2_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(7, "k"); @@ -235,7 +235,7 @@ public async Task FastIndexerGetterBuffer2_AppendBoxed_CachesAndReusesAlreadyBox public async Task FastIndexerGetterBuffer2_AppendBoxedUnverified_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(7, "k"); @@ -253,7 +253,7 @@ public async Task FastIndexerGetterBuffer2_AppendBoxedUnverified_CachesAndReuses public async Task FastIndexerGetterBuffer2_AppendWithAccess_ShouldPublishAndRaiseInteractionAdded() => await VerifyAppendWithAccessPublishesAndRaises(store => { - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); IndexerGetterAccess access = new(7, "k"); return (() => buffer.Append(access), () => buffer.Count); }); @@ -263,7 +263,7 @@ public async Task FastIndexerGetterBuffer3_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); return () => buffer.Append(1, "a", true); }); @@ -272,7 +272,7 @@ public async Task FastIndexerGetterBuffer3_AppendBoxed_CachesAndReusesAlreadyBox { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true); @@ -291,7 +291,7 @@ public async Task FastIndexerGetterBuffer3_AppendBoxedUnverified_CachesAndReuses { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true); @@ -310,7 +310,7 @@ public async Task FastIndexerGetterBuffer3_AppendWithAccess_ShouldPublishAndRais => await VerifyAppendWithAccessPublishesAndRaises(store => { FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); IndexerGetterAccess access = new(7, "k", true); return (() => buffer.Append(access), () => buffer.Count); }); @@ -320,7 +320,7 @@ public async Task FastIndexerGetterBuffer4_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); return () => buffer.Append(1, "a", true, 1.0); }); @@ -329,7 +329,7 @@ public async Task FastIndexerGetterBuffer4_AppendBoxed_CachesAndReusesAlreadyBox { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -348,7 +348,7 @@ public async Task FastIndexerGetterBuffer4_AppendBoxedUnverified_CachesAndReuses { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -367,7 +367,7 @@ public async Task FastIndexerGetterBuffer4_AppendWithAccess_ShouldPublishAndRais => await VerifyAppendWithAccessPublishesAndRaises(store => { FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); IndexerGetterAccess access = new(7, "k", true, 3.14); return (() => buffer.Append(access), () => buffer.Count); }); @@ -376,7 +376,7 @@ public async Task FastIndexerGetterBuffer4_AppendWithAccess_ShouldPublishAndRais public async Task FastIndexerSetterBuffer1_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = InstallIndexerSetter(store, 0); return () => buffer.Append(1, "a"); }); @@ -384,7 +384,7 @@ public async Task FastIndexerSetterBuffer1_Append_ShouldRaiseInteractionAdded() public async Task FastIndexerSetterBuffer1_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = InstallIndexerSetter(store, 0); buffer.Append(7, "k"); @@ -402,7 +402,7 @@ public async Task FastIndexerSetterBuffer1_AppendBoxed_CachesAndReusesAlreadyBox public async Task FastIndexerSetterBuffer1_AppendBoxedUnverified_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = InstallIndexerSetter(store, 0); buffer.Append(7, "k"); @@ -420,7 +420,7 @@ public async Task FastIndexerSetterBuffer1_AppendBoxedUnverified_CachesAndReuses public async Task FastIndexerSetterBuffer1_AppendWithAccess_ShouldPublishAndRaiseInteractionAdded() => await VerifyAppendWithAccessPublishesAndRaises(store => { - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = InstallIndexerSetter(store, 0); IndexerSetterAccess access = new(7, "k"); return (() => buffer.Append(access), () => buffer.Count); }); @@ -430,7 +430,7 @@ public async Task FastIndexerSetterBuffer2_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); return () => buffer.Append(1, "a", true); }); @@ -439,7 +439,7 @@ public async Task FastIndexerSetterBuffer2_AppendBoxed_CachesAndReusesAlreadyBox { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true); @@ -458,7 +458,7 @@ public async Task FastIndexerSetterBuffer2_AppendBoxedUnverified_CachesAndReuses { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true); @@ -477,7 +477,7 @@ public async Task FastIndexerSetterBuffer2_AppendWithAccess_ShouldPublishAndRais => await VerifyAppendWithAccessPublishesAndRaises(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); IndexerSetterAccess access = new(7, "k", true); return (() => buffer.Append(access), () => buffer.Count); }); @@ -487,7 +487,7 @@ public async Task FastIndexerSetterBuffer3_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); return () => buffer.Append(1, "a", true, 1.0); }); @@ -496,7 +496,7 @@ public async Task FastIndexerSetterBuffer3_AppendBoxed_CachesAndReusesAlreadyBox { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -515,7 +515,7 @@ public async Task FastIndexerSetterBuffer3_AppendBoxedUnverified_CachesAndReuses { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -534,7 +534,7 @@ public async Task FastIndexerSetterBuffer3_AppendWithAccess_ShouldPublishAndRais => await VerifyAppendWithAccessPublishesAndRaises(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); IndexerSetterAccess access = new(7, "k", true, 3.14); return (() => buffer.Append(access), () => buffer.Count); }); @@ -544,7 +544,7 @@ public async Task FastIndexerSetterBuffer4_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); return () => buffer.Append(1, "a", true, 1.0, 'x'); }); @@ -553,7 +553,7 @@ public async Task FastIndexerSetterBuffer4_AppendBoxed_CachesAndReusesAlreadyBox { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14, 'z'); @@ -572,7 +572,7 @@ public async Task FastIndexerSetterBuffer4_AppendBoxedUnverified_CachesAndReuses { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14, 'z'); @@ -591,7 +591,7 @@ public async Task FastIndexerSetterBuffer4_AppendWithAccess_ShouldPublishAndRais => await VerifyAppendWithAccessPublishesAndRaises(store => { FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); IndexerSetterAccess access = new(7, "k", true, 3.14, 'z'); return (() => buffer.Append(access), () => buffer.Count); }); @@ -601,7 +601,8 @@ public async Task FastMethod0Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecor { // Pins the `r.Boxed ??= new MethodInvocation(r.Name)` cache in Method0 AppendBoxed. FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); buffer.Append("M"); @@ -619,7 +620,8 @@ public async Task FastMethod0Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecor public async Task FastMethod1Buffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); return () => buffer.Append("M", 1); }); @@ -627,7 +629,8 @@ public async Task FastMethod1Buffer_Append_ShouldRaiseInteractionAdded() public async Task FastMethod1Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); buffer.Append("M", 1); @@ -645,7 +648,8 @@ public async Task FastMethod1Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecor public async Task FastMethod2Buffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); return () => buffer.Append("M", 1, "a"); }); @@ -653,7 +657,7 @@ public async Task FastMethod2Buffer_Append_ShouldRaiseInteractionAdded() public async Task FastMethod3Buffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = InstallMethod(store, 0); return () => buffer.Append("M", 1, "a", true); }); @@ -662,7 +666,7 @@ public async Task FastMethod3Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecor { // Pins the `r.Boxed ??= new MethodInvocation(...)` cache in Method3 AppendBoxed. FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = InstallMethod(store, 0); buffer.Append("M", 1, "a", true); @@ -681,7 +685,7 @@ public async Task FastMethod3Buffer_AppendBoxedUnverified_CachesAndReusesAlready { // Pins the `r.Boxed ??= new MethodInvocation(...)` cache in Method3 AppendBoxedUnverified. FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = InstallMethod(store, 0); buffer.Append("M", 1, "a", true); @@ -699,7 +703,7 @@ public async Task FastMethod3Buffer_AppendBoxedUnverified_CachesAndReusesAlready public async Task FastMethod3Buffer_AppendBoxedUnverified_ShouldSkipMatchedSlots() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = InstallMethod(store, 0); buffer.Append("M", 0, "a", true); buffer.Append("M", 1, "b", false); buffer.Append("M", 2, "c", true); @@ -722,7 +726,7 @@ public async Task FastMethod4Buffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { FastMethod4Buffer buffer = - store.InstallMethod(0); + InstallMethod(store, 0); return () => buffer.Append("M", 1, "a", true, 1.0); }); @@ -732,7 +736,7 @@ public async Task FastMethod4Buffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecor // Pins the `r.Boxed ??= new MethodInvocation(...)` cache in Method4 AppendBoxed. FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + InstallMethod(store, 0); buffer.Append("M", 1, "a", true, 1.0); @@ -752,7 +756,7 @@ public async Task FastMethod4Buffer_AppendBoxedUnverified_CachesAndReusesAlready // Pins the `r.Boxed ??= new MethodInvocation(...)` cache in Method4 AppendBoxedUnverified. FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + InstallMethod(store, 0); buffer.Append("M", 1, "a", true, 1.0); @@ -771,7 +775,7 @@ public async Task FastMethod4Buffer_AppendBoxedUnverified_ShouldSkipMatchedSlots { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + InstallMethod(store, 0); buffer.Append("M", 0, "a", true, 0.5); buffer.Append("M", 1, "b", false, 1.5); buffer.Append("M", 2, "c", true, 2.5); @@ -794,49 +798,17 @@ public async Task FastMethod4Buffer_AppendBoxedUnverified_ShouldSkipMatchedSlots public async Task FastPropertyGetterBuffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); - return () => buffer.Append("P"); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(store, 0); + return () => buffer.Append(); }); - [Fact] - public async Task FastPropertyGetterBuffer_Append_WithoutInstalledSingleton_ShouldIncludeFactoryGuidanceInMessage() - { - // Kills the `$"..."` -> `$""` string mutation on the InvalidOperationException message. - // The message points callers at the correct factory overload — without it, the failure - // is just an empty-string IOE, which is useless guidance. - FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); - - void Act() - { - buffer.Append(); - } - - await That(Act).Throws() - .WithMessage("*InstallPropertyGetter*").AsWildcard(); - } - - [Fact] - public async Task FastPropertyGetterBuffer_Append_WithoutInstalledSingleton_ShouldThrow() - { - FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); - - void Act() - { - buffer.Append(); - } - - await That(Act).Throws(); - } - [Fact] public async Task FastPropertyGetterBuffer_AppendBoxed_RepeatedCallsReturnSameSingleton() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(store, 0); - buffer.Append("P"); + buffer.Append(); List<(long Seq, IInteraction Interaction)> first = []; List<(long Seq, IInteraction Interaction)> second = []; @@ -858,10 +830,10 @@ public async Task FastPropertyGetterBuffer_AppendBoxed_SharesSingletonAcrossReco // shared identity (the Then walker is positional, the verified filter is // all-or-nothing per matched property). FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(store, 0); - buffer.Append("P"); - buffer.Append("P"); + buffer.Append(); + buffer.Append(); List<(long Seq, IInteraction Interaction)> dest = []; ((IFastMemberBuffer)buffer).AppendBoxed(dest); @@ -874,13 +846,13 @@ public async Task FastPropertyGetterBuffer_AppendBoxed_SharesSingletonAcrossReco public async Task FastPropertyGetterBuffer_AppendString_LazyInitsAccessOnce() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(store, 0); - buffer.Append("P"); + buffer.Append(); List<(long Seq, IInteraction Interaction)> firstSnapshot = []; ((IFastMemberBuffer)buffer).AppendBoxed(firstSnapshot); - buffer.Append("P"); + buffer.Append(); List<(long Seq, IInteraction Interaction)> secondSnapshot = []; ((IFastMemberBuffer)buffer).AppendBoxed(secondSnapshot); @@ -894,7 +866,7 @@ public async Task FastPropertyGetterBuffer_AppendString_LazyInitsAccessOnce() public async Task FastPropertySetterBuffer_Append_ShouldRaiseInteractionAdded() => await VerifyRaisesInteractionAdded(store => { - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = InstallPropertySetter(store, 0); return () => buffer.Append("P", 1); }); @@ -902,7 +874,7 @@ public async Task FastPropertySetterBuffer_Append_ShouldRaiseInteractionAdded() public async Task FastPropertySetterBuffer_AppendBoxed_CachesAndReusesAlreadyBoxedRecord() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = InstallPropertySetter(store, 0); buffer.Append("P", 5); @@ -922,7 +894,7 @@ public async Task FastPropertySetterBuffer_AppendBoxedUnverified_CachesAndReuses // Mirrors the AppendBoxed caching test for the Unverified path so the `r.Boxed ??= new // PropertySetterAccess(...)` mutation is killed there as well. FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = InstallPropertySetter(store, 0); buffer.Append("P", 5); @@ -941,7 +913,7 @@ public async Task FastPropertySetterBuffer_AppendBoxedUnverified_ShouldSkipMatch { // Covers the AppendBoxedUnverified branch on the setter buffer (NoCoverage cluster). FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = InstallPropertySetter(store, 0); buffer.Append("P", 1); buffer.Append("P", 2); buffer.Append("P", 3); @@ -963,7 +935,7 @@ public async Task FastPropertySetterBuffer_ConsumeMatching_ShouldMarkSlotsVerifi // to `false`, ConsumeMatching would still report matches but the slots would never be // marked verified — so a second ConsumeMatching call would re-count the same records. FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = InstallPropertySetter(store, 0); buffer.Append("P", 1); buffer.Append("P", 1); @@ -980,7 +952,7 @@ public async Task FastPropertySetterBuffer_ConsumeMatching_ShouldMarkSlotsVerifi public async Task IndexerGetterBuffer1_AppendBoxedUnverified_ShouldSkipMatchedSlots() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(0); buffer.Append(1); buffer.Append(2); @@ -999,7 +971,7 @@ public async Task IndexerGetterBuffer1_AppendBoxedUnverified_ShouldSkipMatchedSl public async Task IndexerGetterBuffer2_AppendBoxedUnverified_ShouldSkipMatchedSlots() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = InstallIndexerGetter(store, 0); buffer.Append(0, "a"); buffer.Append(1, "b"); buffer.Append(2, "c"); @@ -1021,7 +993,7 @@ public async Task IndexerGetterBuffer3_AppendBoxed_BoxesAsIndexerGetterAccess() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true); @@ -1037,7 +1009,7 @@ public async Task IndexerGetterBuffer3_AppendBoxedUnverified_ShouldSkipMatchedSl { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(0, "a", true); buffer.Append(1, "b", false); buffer.Append(2, "c", true); @@ -1060,7 +1032,7 @@ public async Task IndexerGetterBuffer4_AppendBoxed_BoxesAsIndexerGetterAccess() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -1077,7 +1049,7 @@ public async Task IndexerGetterBuffer4_AppendBoxedUnverified_ShouldSkipMatchedSl { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + InstallIndexerGetter(store, 0); buffer.Append(0, "a", true, 0.5); buffer.Append(1, "b", false, 1.5); buffer.Append(2, "c", true, 2.5); @@ -1100,7 +1072,7 @@ public async Task IndexerGetterBuffer4_AppendBoxedUnverified_ShouldSkipMatchedSl public async Task IndexerSetterBuffer1_AppendBoxedUnverified_ShouldSkipMatchedSlots() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = InstallIndexerSetter(store, 0); buffer.Append(0, "x"); buffer.Append(1, "y"); buffer.Append(2, "z"); @@ -1122,7 +1094,7 @@ public async Task IndexerSetterBuffer2_AppendBoxedUnverified_ShouldSkipMatchedSl { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(0, "x", true); buffer.Append(1, "y", false); buffer.Append(2, "z", true); @@ -1145,7 +1117,7 @@ public async Task IndexerSetterBuffer3_AppendBoxed_BoxesAsIndexerSetterAccess() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14); @@ -1162,7 +1134,7 @@ public async Task IndexerSetterBuffer3_AppendBoxedUnverified_ShouldSkipMatchedSl { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(0, "x", true, 0.5); buffer.Append(1, "y", false, 1.5); buffer.Append(2, "z", true, 2.5); @@ -1186,7 +1158,7 @@ public async Task IndexerSetterBuffer4_AppendBoxed_BoxesAsIndexerSetterAccess() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(7, "k", true, 3.14, 'z'); @@ -1204,7 +1176,7 @@ public async Task IndexerSetterBuffer4_AppendBoxedUnverified_ShouldSkipMatchedSl { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + InstallIndexerSetter(store, 0); buffer.Append(0, "x", true, 0.5, 'a'); buffer.Append(1, "y", false, 1.5, 'b'); buffer.Append(2, "z", true, 2.5, 'c'); @@ -1224,6 +1196,62 @@ public async Task IndexerSetterBuffer4_AppendBoxedUnverified_ShouldSkipMatchedSl await That(((IndexerSetterAccess)dest[1].Interaction).Parameter1).IsEqualTo(2); } + private static FastMethod3Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastMethod3Buffer(f)); + + private static FastMethod4Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastMethod4Buffer(f)); + + private static FastIndexerGetterBuffer InstallIndexerGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerGetterBuffer(f)); + + private static FastIndexerGetterBuffer InstallIndexerGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerGetterBuffer(f)); + + private static FastIndexerGetterBuffer InstallIndexerGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerGetterBuffer(f)); + + private static FastIndexerGetterBuffer InstallIndexerGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerGetterBuffer(f)); + + private static FastIndexerSetterBuffer InstallIndexerSetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerSetterBuffer(f)); + + private static FastIndexerSetterBuffer InstallIndexerSetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerSetterBuffer(f)); + + private static FastIndexerSetterBuffer InstallIndexerSetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerSetterBuffer(f)); + + private static FastIndexerSetterBuffer InstallIndexerSetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastIndexerSetterBuffer(f)); + + private static FastEventBuffer InstallEventSubscribe(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); + + private static FastEventBuffer InstallEventUnsubscribe(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); + + private static FastPropertyGetterBuffer InstallPropertyGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess(string.Empty))); + + private static FastPropertySetterBuffer InstallPropertySetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, + static f => new FastPropertySetterBuffer(f)); + private static async Task VerifyAppendWithAccessPublishesAndRaises( Func CountReader)> setupFactory) { diff --git a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConcurrencyTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConcurrencyTests.cs index e0cb512d..c97bf0a4 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConcurrencyTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConcurrencyTests.cs @@ -13,7 +13,8 @@ public async Task FastMethod1Buffer_ConcurrentAppend_ShouldRecordAllInteractions const int appendsPerWriter = 1000; FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); #if NET48 CancellationToken cancellationToken = TestContext.Current.CancellationToken; #else @@ -44,7 +45,8 @@ await That(buffer.ConsumeMatching((IParameterMatch)It.IsAny())) public async Task FastMethod1Buffer_InteractionAdded_ShouldFireWhenSubscribed() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); int invocations = 0; diff --git a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConsumeMatchingTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConsumeMatchingTests.cs index cb547930..f09ebb60 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConsumeMatchingTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/FastBufferConsumeMatchingTests.cs @@ -10,7 +10,8 @@ public class FastBufferConsumeMatchingTests public async Task FastEventBuffer_ConsumeMatching_ShouldReturnCount() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); await That(buffer.ConsumeMatching()).IsEqualTo(0); @@ -26,7 +27,8 @@ public async Task FastEventBuffer_ConsumeMatching_ShouldReturnCount() public async Task FastIndexerGetterBuffer1_ConsumeMatching_ShouldHonorMatcher() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1); buffer.Append(2); @@ -41,7 +43,8 @@ public async Task FastIndexerGetterBuffer1_ConsumeMatching_ShouldHonorMatcher() public async Task FastIndexerGetterBuffer2_ConsumeMatching_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a"); buffer.Append(1, "b"); @@ -59,7 +62,9 @@ await That(buffer.ConsumeMatching( public async Task FastIndexerGetterBuffer3_ConsumeMatching_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a", true); buffer.Append(2, "a", false); @@ -84,7 +89,8 @@ public async Task FastIndexerGetterBuffer4_ConsumeMatching_ShouldHonorAllMatcher { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a", true, 1.0); buffer.Append(1, "b", true, 2.0); @@ -111,7 +117,8 @@ await That(buffer.ConsumeMatching( public async Task FastIndexerSetterBuffer1_ConsumeMatching_ShouldHonorMatchers() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a"); buffer.Append(1, "b"); @@ -133,7 +140,8 @@ public async Task FastIndexerSetterBuffer2_ConsumeMatching_ShouldHonorAllMatcher { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true); buffer.Append(1, "b", false); @@ -158,7 +166,8 @@ public async Task FastIndexerSetterBuffer3_ConsumeMatching_ShouldHonorAllMatcher { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true, 1.0); buffer.Append(1, "b", true, 2.0); @@ -186,7 +195,8 @@ public async Task FastIndexerSetterBuffer4_ConsumeMatching_ShouldHonorAllMatcher { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true, 1.0, 'x'); buffer.Append(1, "b", true, 2.0, 'x'); @@ -216,7 +226,8 @@ await That(buffer.ConsumeMatching( public async Task FastMethod0Buffer_ConsumeMatching_ShouldReturnCount() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); await That(buffer.ConsumeMatching()).IsEqualTo(0); @@ -234,7 +245,8 @@ public async Task FastMethod1Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWit // buffer (n == 0) would still enter the loop at slot=0 and call VerifiedUnderLock(0), // which dereferences the not-yet-allocated VerifiedChunks[0] → NRE. FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); int consumed = buffer.ConsumeAll(); @@ -245,7 +257,8 @@ public async Task FastMethod1Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWit public async Task FastMethod1Buffer_ConsumeMatching_ShouldHonorMatcher() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); buffer.Append("Foo", 1); buffer.Append("Foo", 2); @@ -260,7 +273,8 @@ public async Task FastMethod1Buffer_ConsumeMatching_ShouldHonorMatcher() public async Task FastMethod2Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWithoutThrowing() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); int consumed = buffer.ConsumeAll(); @@ -271,7 +285,8 @@ public async Task FastMethod2Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWit public async Task FastMethod2Buffer_ConsumeMatching_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); buffer.Append("Foo", 1, "a"); buffer.Append("Foo", 1, "b"); @@ -295,7 +310,8 @@ await That(buffer.ConsumeMatching( public async Task FastMethod3Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWithoutThrowing() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); int consumed = buffer.ConsumeAll(); @@ -306,7 +322,8 @@ public async Task FastMethod3Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWit public async Task FastMethod3Buffer_ConsumeMatching_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); buffer.Append("Foo", 1, "a", true); buffer.Append("Foo", 2, "a", false); @@ -335,7 +352,8 @@ public async Task FastMethod4Buffer_ConsumeAll_OnEmptyBuffer_ShouldReturnZeroWit { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); int consumed = buffer.ConsumeAll(); @@ -347,7 +365,8 @@ public async Task FastMethod4Buffer_ConsumeMatching_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); buffer.Append("Foo", 1, "a", true, 1.0); buffer.Append("Foo", 1, "b", true, 2.0); @@ -384,12 +403,13 @@ await That(buffer.ConsumeMatching( public async Task FastPropertyGetterBuffer_ConsumeMatching_ShouldReturnCount() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess("Bar"))); await That(buffer.ConsumeMatching()).IsEqualTo(0); - buffer.Append("Bar"); - buffer.Append("Bar"); + buffer.Append(); + buffer.Append(); await That(buffer.ConsumeMatching()).IsEqualTo(2); } @@ -398,7 +418,8 @@ public async Task FastPropertyGetterBuffer_ConsumeMatching_ShouldReturnCount() public async Task FastPropertySetterBuffer_ConsumeMatching_ShouldHonorMatcher() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); buffer.Append("Bar", 1); buffer.Append("Bar", 2); diff --git a/Tests/Mockolate.Internal.Tests/Interactions/FastMockInteractionsTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/FastMockInteractionsTests.cs index e4448297..fb548bfc 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/FastMockInteractionsTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/FastMockInteractionsTests.cs @@ -13,7 +13,7 @@ public class FastMockInteractionsTests public async Task Append_ShouldRaiseInteractionAdded() { FastMockInteractions sut = new(1); - FastMethod0Buffer buffer = sut.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(sut, 0); int invocations = 0; sut.InteractionAdded += Handler; @@ -35,9 +35,10 @@ void Handler(object? sender, EventArgs e) public async Task Buffers_ShouldExposeInstalledBuffersByMemberId() { FastMockInteractions sut = new(3); - FastMethod0Buffer method = sut.InstallMethod(0); - FastPropertyGetterBuffer getter = sut.InstallPropertyGetter(1); - FastEventBuffer subscribe = sut.InstallEventSubscribe(2); + FastMethod0Buffer method = InstallMethod(sut, 0); + FastPropertyGetterBuffer getter = InstallPropertyGetter(sut, 1); + FastEventBuffer subscribe = sut.GetOrCreateBuffer(2, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); await That(sut.Buffers).HasCount(3); await That(sut.Buffers[0]).IsSameAs(method); @@ -109,7 +110,7 @@ public async Task Clear_FallbackPath_ShouldNotResurfaceOldRecordsAfterRefill() public async Task Clear_ShouldFireOnClearing() { FastMockInteractions sut = new(1); - sut.InstallMethod(0); + InstallMethod(sut, 0); int invocations = 0; sut.OnClearing += Handler; @@ -129,11 +130,11 @@ void Handler(object? sender, EventArgs e) public async Task Clear_ShouldResetAllBuffersAndCount() { FastMockInteractions sut = new(2); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); - FastPropertyGetterBuffer getterBuffer = sut.InstallPropertyGetter(1); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); + FastPropertyGetterBuffer getterBuffer = InstallPropertyGetter(sut, 1); methodBuffer.Append("a"); - getterBuffer.Append("b"); + getterBuffer.Append(); sut.Clear(); @@ -147,18 +148,18 @@ public async Task Clear_ShouldResetAllBuffersAndCount() public async Task Clear_ShouldResetPerBufferVerifiedTracking() { FastMockInteractions sut = new(2); - FastMethod1Buffer methodBuffer = sut.InstallMethod(0); - FastPropertyGetterBuffer getterBuffer = sut.InstallPropertyGetter(1); + FastMethod1Buffer methodBuffer = InstallMethod(sut, 0); + FastPropertyGetterBuffer getterBuffer = InstallPropertyGetter(sut, 1); methodBuffer.Append("M", 1); - getterBuffer.Append("Prop"); + getterBuffer.Append(); _ = methodBuffer.ConsumeMatching((IParameterMatch)It.Is(1)); _ = getterBuffer.ConsumeMatching(); sut.Clear(); methodBuffer.Append("M", 2); - getterBuffer.Append("Prop"); + getterBuffer.Append(); await That(sut.GetUnverifiedInteractions()).HasCount(2); } @@ -167,7 +168,7 @@ public async Task Clear_ShouldResetPerBufferVerifiedTracking() public async Task Clear_ShouldResetVerifiedBookkeeping() { FastMockInteractions sut = new(1); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("first"); List all = [..sut,]; ((IMockInteractions)sut).Verified(all); @@ -189,14 +190,14 @@ public async Task Clear_WithSharedSingletonInVerifiedSet_ShouldResurfaceItAsUnve // removed, the verified set keeps the singleton across Clear, and a fresh post-Clear // Append would surface as already-verified — masking the new interaction. FastMockInteractions sut = new(1); - FastPropertyGetterBuffer buffer = sut.InstallPropertyGetter(0); - buffer.Append("P"); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(sut, 0); + buffer.Append(); List all = [..sut,]; ((IMockInteractions)sut).Verified(all); sut.Clear(); - buffer.Append("P"); + buffer.Append(); IReadOnlyCollection unverified = sut.GetUnverifiedInteractions(); await That(unverified).HasCount(1); @@ -206,11 +207,11 @@ public async Task Clear_WithSharedSingletonInVerifiedSet_ShouldResurfaceItAsUnve public async Task Count_ShouldReflectAppendsAcrossBuffers() { FastMockInteractions sut = new(2); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); - FastPropertyGetterBuffer getterBuffer = sut.InstallPropertyGetter(1); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); + FastPropertyGetterBuffer getterBuffer = InstallPropertyGetter(sut, 1); methodBuffer.Append("a"); - getterBuffer.Append("b"); + getterBuffer.Append(); methodBuffer.Append("c"); await That(sut.Count).IsEqualTo(3); @@ -222,8 +223,9 @@ public async Task Count_ShouldReflectAppendsAcrossBuffers() public async Task GetEnumerator_ShouldReturnInteractionsInRegistrationOrder() { FastMockInteractions sut = new(2); - FastMethod1Buffer methodBuffer = sut.InstallMethod(0); - FastPropertySetterBuffer setterBuffer = sut.InstallPropertySetter(1); + FastMethod1Buffer methodBuffer = InstallMethod(sut, 0); + FastPropertySetterBuffer setterBuffer = sut.GetOrCreateBuffer>(1, + static f => new FastPropertySetterBuffer(f)); methodBuffer.Append("Method", 1); setterBuffer.Append("Property", "x"); @@ -347,8 +349,8 @@ public async Task GetUnverifiedInteractions_AcrossBuffersWithInterleavedAppends_ // sequence), the Sort step is what restores chronological order. Mutations that skip the // Sort (`< 1`, `<= 1`, `!(>1)`) leave the snapshot grouped by buffer, not by Seq. FastMockInteractions sut = new(2); - FastMethod1Buffer bufA = sut.InstallMethod(0); - FastMethod1Buffer bufB = sut.InstallMethod(1); + FastMethod1Buffer bufA = InstallMethod(sut, 0); + FastMethod1Buffer bufB = InstallMethod(sut, 1); bufA.Append("A", 0); bufB.Append("B", 1); @@ -368,11 +370,11 @@ public async Task GetUnverifiedInteractions_AcrossBuffersWithInterleavedAppends_ public async Task GetUnverifiedInteractions_AcrossMultipleBuffers_ShouldUnionFastAndSlowVerifications() { FastMockInteractions sut = new(2); - FastMethod1Buffer methodBuffer = sut.InstallMethod(0); - FastPropertyGetterBuffer getterBuffer = sut.InstallPropertyGetter(1); + FastMethod1Buffer methodBuffer = InstallMethod(sut, 0); + FastPropertyGetterBuffer getterBuffer = InstallPropertyGetter(sut, 1); methodBuffer.Append("M", 7); - getterBuffer.Append("Prop"); + getterBuffer.Append(); _ = methodBuffer.ConsumeMatching((IParameterMatch)It.Is(7)); _ = getterBuffer.ConsumeMatching(); @@ -384,7 +386,7 @@ public async Task GetUnverifiedInteractions_AcrossMultipleBuffers_ShouldUnionFas public async Task GetUnverifiedInteractions_AfterMatcherLessConsumeMatching_ShouldDropMarkedSlots() { FastMockInteractions sut = new(1); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("first"); methodBuffer.Append("second"); @@ -403,7 +405,7 @@ public async Task GetUnverifiedInteractions_AfterMatcherLessConsumeMatching_Shou public async Task GetUnverifiedInteractions_AfterTypedConsumeMatching_ShouldDropOnlyMatchedSlots() { FastMockInteractions sut = new(1); - FastMethod1Buffer methodBuffer = sut.InstallMethod(0); + FastMethod1Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("Dispense", 1); methodBuffer.Append("Dispense", 2); @@ -422,7 +424,7 @@ public async Task GetUnverifiedInteractions_AfterTypedConsumeMatching_ShouldDrop public async Task GetUnverifiedInteractions_FastPathPlusSlowPath_ShouldFilterByBoth() { FastMockInteractions sut = new(1); - FastMethod1Buffer methodBuffer = sut.InstallMethod(0); + FastMethod1Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("M", 1); methodBuffer.Append("M", 2); methodBuffer.Append("M", 3); @@ -441,7 +443,7 @@ public async Task GetUnverifiedInteractions_FastPathPlusSlowPath_ShouldFilterByB public async Task GetUnverifiedInteractions_ShouldRespectVerifiedSet() { FastMockInteractions sut = new(1); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("first"); methodBuffer.Append("second"); @@ -462,7 +464,7 @@ public async Task GetUnverifiedInteractions_WhenNothingRecorded_ShouldReturnArra // the block removed, the method falls through to `new IInteraction[unverified.Count]` // and returns a freshly-allocated zero-length array instead of the shared singleton. FastMockInteractions sut = new(1); - sut.InstallMethod(0); + InstallMethod(sut, 0); IReadOnlyCollection result = sut.GetUnverifiedInteractions(); @@ -473,7 +475,7 @@ public async Task GetUnverifiedInteractions_WhenNothingRecorded_ShouldReturnArra public async Task GetUnverifiedInteractions_WhenNothingVerified_ShouldReturnEverything() { FastMockInteractions sut = new(1); - FastMethod0Buffer methodBuffer = sut.InstallMethod(0); + FastMethod0Buffer methodBuffer = InstallMethod(sut, 0); methodBuffer.Append("first"); IReadOnlyCollection unverified = sut.GetUnverifiedInteractions(); @@ -609,7 +611,7 @@ public async Task SkipInteractionRecording_ShouldReflectConstructionValue() public async Task Verified_BeforeAnyAppend_OnSecondCallAddsToExistingSet() { FastMockInteractions sut = new(1); - FastMethod0Buffer buffer = sut.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(sut, 0); ((IMockInteractions)sut).Verified([]); @@ -627,7 +629,7 @@ public async Task Verified_OnSecondCallWithDifferentItems_PreservesPreviouslyVer // plain `_verified = []`, the second call would reset the verified set, so the first // call's entry would re-surface as "unverified". FastMockInteractions sut = new(1); - FastMethod0Buffer buffer = sut.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(sut, 0); buffer.Append("first"); buffer.Append("second"); List all = [..sut,]; @@ -642,7 +644,7 @@ public async Task Verified_OnSecondCallWithDifferentItems_PreservesPreviouslyVer public async Task Verified_WithMultipleInteractions_AddsAllToInternalSet() { FastMockInteractions sut = new(1); - FastMethod0Buffer buffer = sut.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(sut, 0); buffer.Append("first"); buffer.Append("second"); @@ -652,13 +654,23 @@ public async Task Verified_WithMultipleInteractions_AddsAllToInternalSet() await That(sut.GetUnverifiedInteractions()).IsEmpty(); } + private static FastMethod0Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, static f => new FastMethod0Buffer(f)); + + private static FastMethod1Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, static f => new FastMethod1Buffer(f)); + + private static FastPropertyGetterBuffer InstallPropertyGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess(string.Empty))); + public sealed class MethodBufferTests { [Fact] public async Task Method0_BoxesAsMethodInvocation() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(store, 0); buffer.Append("Foo"); @@ -670,7 +682,7 @@ public async Task Method0_BoxesAsMethodInvocation() public async Task Method1_BoxesAsMethodInvocationT1() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); buffer.Append("Foo", 42); @@ -683,7 +695,8 @@ public async Task Method1_BoxesAsMethodInvocationT1() public async Task Method2_BoxesAsMethodInvocationT1T2() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); buffer.Append("Foo", 42, "bar"); @@ -696,7 +709,8 @@ public async Task Method2_BoxesAsMethodInvocationT1T2() public async Task Method3_BoxesAsMethodInvocationT1T2T3() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); buffer.Append("Foo", 1, "two", true); @@ -711,7 +725,8 @@ public async Task Method4_BoxesAsMethodInvocationT1T2T3T4() { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); buffer.Append("Foo", 1, "two", true, 3.14); @@ -724,7 +739,7 @@ public async Task Method4_BoxesAsMethodInvocationT1T2T3T4() public async Task ResizesAndPreservesOrder() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); for (int i = 0; i < 100; i++) { @@ -746,9 +761,10 @@ public sealed class PropertyBufferTests public async Task Getter_BoxesAsPropertyGetterAccess() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer( + 0, static (f, a) => new FastPropertyGetterBuffer(f, a), new PropertyGetterAccess("Foo")); - buffer.Append("Foo"); + buffer.Append(); PropertyGetterAccess boxed = (PropertyGetterAccess)store.Single(); await That(boxed.Name).IsEqualTo("Foo"); @@ -758,7 +774,8 @@ public async Task Getter_BoxesAsPropertyGetterAccess() public async Task Setter_BoxesAsPropertySetterAccessT() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); buffer.Append("Foo", "value"); @@ -774,7 +791,8 @@ public sealed class IndexerBufferTests public async Task Getter1_BoxesAsIndexerGetterAccess() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append("k"); @@ -786,7 +804,8 @@ public async Task Getter1_BoxesAsIndexerGetterAccess() public async Task Getter2_BoxesAsIndexerGetterAccess() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append("k", 1); @@ -799,7 +818,8 @@ public async Task Getter2_BoxesAsIndexerGetterAccess() public async Task Setter1_BoxesAsIndexerSetterAccess() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append("k", true); @@ -813,7 +833,8 @@ public async Task Setter2_BoxesAsIndexerSetterAccess() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append("k", 7, true); @@ -828,7 +849,8 @@ public sealed class EventBufferTests public async Task Subscribe_BoxesAsEventSubscription() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MethodInfo method = typeof(EventBufferTests).GetMethod(nameof(Subscribe_BoxesAsEventSubscription))!; buffer.Append("E", this, method); @@ -843,7 +865,8 @@ public async Task Subscribe_BoxesAsEventSubscription() public async Task Unsubscribe_BoxesAsEventUnsubscription() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MethodInfo method = typeof(EventBufferTests).GetMethod(nameof(Unsubscribe_BoxesAsEventUnsubscription))!; buffer.Append("E", null, method); @@ -864,7 +887,7 @@ public async Task ConcurrentAppendsAcrossMembers_ShouldPreserveTotalCount() FastMethod1Buffer[] buffers = new FastMethod1Buffer[threads]; for (int t = 0; t < threads; t++) { - buffers[t] = store.InstallMethod(t); + buffers[t] = InstallMethod(store, t); } using ManualResetEventSlim start = new(false); diff --git a/Tests/Mockolate.Internal.Tests/Interactions/FastPropertyBufferTests.cs b/Tests/Mockolate.Internal.Tests/Interactions/FastPropertyBufferTests.cs index c4569366..71d810e5 100644 --- a/Tests/Mockolate.Internal.Tests/Interactions/FastPropertyBufferTests.cs +++ b/Tests/Mockolate.Internal.Tests/Interactions/FastPropertyBufferTests.cs @@ -70,9 +70,7 @@ public async Task SkipInteractionRecording_DoesNotAppendToBuffer() FastMockInteractions fast = (FastMockInteractions)((IMock)sut).MockRegistry.Interactions; int getterId = Mock.FastPropertyBufferTests_IFastPropertyService.MemberId_Counter_Get; - FastPropertyGetterBuffer? buffer = fast.Buffers[getterId] as FastPropertyGetterBuffer; - await That(buffer).IsNotNull(); - await That(buffer!.Count).IsEqualTo(0); + await That(fast.Buffers[getterId]).IsNull(); await That(fast.Count).IsEqualTo(0); } diff --git a/Tests/Mockolate.Internal.Tests/Registry/MockRegistrySetupSnapshotTests.cs b/Tests/Mockolate.Internal.Tests/Registry/MockRegistrySetupSnapshotTests.cs index 83158df7..1179dc97 100644 --- a/Tests/Mockolate.Internal.Tests/Registry/MockRegistrySetupSnapshotTests.cs +++ b/Tests/Mockolate.Internal.Tests/Registry/MockRegistrySetupSnapshotTests.cs @@ -153,7 +153,7 @@ public async Task PublishPropertyToMemberIdBucket_WithDefaultThenUserSetup_Retai registry.SetupProperty(1, new PropertySetup.Default("P1", 0)); registry.SetupProperty(1, userSetup); - int observed = registry.GetPropertyFast(1, "P1", _ => -1); + int observed = registry.GetPropertyFast(1, new PropertyGetterAccess("P1"), _ => -1); await That(observed).IsEqualTo(99); } @@ -181,7 +181,7 @@ public async Task PublishPropertyToMemberIdBucket_WithUserThenDefaultSetup_Retai registry.SetupProperty(1, userSetup); registry.SetupProperty(1, new PropertySetup.Default("P1", 0)); - int observed = registry.GetPropertyFast(1, "P1", _ => -1); + int observed = registry.GetPropertyFast(1, new PropertyGetterAccess("P1"), _ => -1); await That(observed).IsEqualTo(99); } @@ -250,9 +250,9 @@ public async Task SetupProperty_WithIncreasingMemberIds_GrowsTableLazily() registry.SetupProperty(7, setup7); registry.SetupProperty(3, setup3); - await That(registry.GetPropertyFast(0, "P0", _ => -1)).IsEqualTo(10); - await That(registry.GetPropertyFast(7, "P7", _ => -1)).IsEqualTo(70); - await That(registry.GetPropertyFast(3, "P3", _ => -1)).IsEqualTo(30); + await That(registry.GetPropertyFast(0, new PropertyGetterAccess("P0"), _ => -1)).IsEqualTo(10); + await That(registry.GetPropertyFast(7, new PropertyGetterAccess("P7"), _ => -1)).IsEqualTo(70); + await That(registry.GetPropertyFast(3, new PropertyGetterAccess("P3"), _ => -1)).IsEqualTo(30); } [Fact] @@ -279,7 +279,7 @@ public async Task SetupProperty_WithMemberId_PublishesToSnapshot() registry.SetupProperty(5, setup); - int observed = registry.GetPropertyFast(5, "P5", _ => -1); + int observed = registry.GetPropertyFast(5, new PropertyGetterAccess("P5"), _ => -1); await That(observed).IsEqualTo(50); } @@ -319,7 +319,7 @@ public async Task SetupProperty_WithMemberIdAndDefaultScenario_PublishesToSnapsh registry.SetupProperty(5, "", setup); - int observed = registry.GetPropertyFast(5, "P5", _ => -1); + int observed = registry.GetPropertyFast(5, new PropertyGetterAccess("P5"), _ => -1); await That(observed).IsEqualTo(50); } @@ -345,7 +345,7 @@ public async Task SetupProperty_WithMemberIdAndNamedScenario_DoesNotPublishToSna registry.SetupProperty(5, "s1", setup); - int observed = registry.GetPropertyFast(5, "P5", _ => -1); + int observed = registry.GetPropertyFast(5, new PropertyGetterAccess("P5"), _ => -1); await That(observed).IsEqualTo(-1); } @@ -387,7 +387,7 @@ public async Task SetupProperty_WithSameMemberIdTwice_RetainsLatestUserSetup() registry.SetupProperty(2, setupA); registry.SetupProperty(2, setupB); - int observed = registry.GetPropertyFast(2, "P2", _ => -1); + int observed = registry.GetPropertyFast(2, new PropertyGetterAccess("P2"), _ => -1); await That(observed).IsEqualTo(99); } } diff --git a/Tests/Mockolate.Internal.Tests/Registry/MockRegistryTests.cs b/Tests/Mockolate.Internal.Tests/Registry/MockRegistryTests.cs index eba1ec3c..83cd7665 100644 --- a/Tests/Mockolate.Internal.Tests/Registry/MockRegistryTests.cs +++ b/Tests/Mockolate.Internal.Tests/Registry/MockRegistryTests.cs @@ -557,7 +557,7 @@ public async Task WithActiveScenario_ShouldAlwaysTakeColdPath() registry.SetupProperty(2, "myScenario", scenarioSetup); registry.TransitionTo("myScenario"); - int result = registry.GetPropertyFast(2, "P", _ => 0); + int result = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), _ => 0); await That(result).IsEqualTo(99); } @@ -577,7 +577,7 @@ int Base() return 99; } - int result = registry.GetPropertyFast(2, "P", _ => 7, Base); + int result = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), _ => 7, Base); await That(baseInvocations).IsEqualTo(1); await That(result).IsEqualTo(99); @@ -594,7 +594,7 @@ public async Task WithNullSnapshotAtMemberIdSlot_ShouldFallBackToColdPathWithout unrelatedSetup.InitializeWith(99); registry.SetupProperty(5, unrelatedSetup); - int result = registry.GetPropertyFast(0, "P", _ => 7); + int result = registry.GetPropertyFast(0, new PropertyGetterAccess("P"), _ => 7); await That(result).IsEqualTo(7); } @@ -604,7 +604,7 @@ public async Task WithoutSnapshotSetup_ShouldFallBackToColdPath() { MockRegistry registry = new(MockBehavior.Default, new FastMockInteractions(0)); - int result = registry.GetPropertyFast(0, "P", _ => 7); + int result = registry.GetPropertyFast(0, new PropertyGetterAccess("P"), _ => 7); await That(result).IsEqualTo(7); } @@ -625,8 +625,8 @@ int Generator(MockBehavior _) return -1; } - int first = registry.GetPropertyFast(2, "P", Generator); - int second = registry.GetPropertyFast(2, "P", Generator); + int first = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), Generator); + int second = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), Generator); await That(first).IsEqualTo(42); await That(second).IsEqualTo(42); @@ -711,7 +711,7 @@ public async Task WithSnapshotSetup_ShouldInvokeSetterAndStoreValue() bool skipBase = registry.SetPropertyFast(2, 3, "P", 42); await That(skipBase).IsFalse(); - int after = registry.GetPropertyFast(2, "P", _ => -1); + int after = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), _ => -1); await That(after).IsEqualTo(42); } } @@ -912,7 +912,7 @@ public async Task GetPropertyFast_WhenSnapshotTableHasNullEntryAtMemberId_Should snapshotAtFive.InitializeWith(50); registry.SetupProperty(5, snapshotAtFive); - int result = registry.GetPropertyFast(2, "P", _ => 7); + int result = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), _ => 7); await That(result).IsEqualTo(7); } @@ -941,7 +941,7 @@ public async Task SetPropertyFast_WithActiveScenario_ShouldUseColdPathAndWriteTo registry.TransitionTo("myScenario"); registry.SetPropertyFast(2, 3, "P", 42); - int result = registry.GetPropertyFast(2, "P", _ => -1); + int result = registry.GetPropertyFast(2, new PropertyGetterAccess("P"), _ => -1); await That(result).IsEqualTo(42); } @@ -986,7 +986,8 @@ public async Task WithSharedAccessSingleton_AndMatchingFastBuffer_ShouldAppendTo { FastMockInteractions store = new(1); PropertyGetterAccess access = new("P"); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0, access); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer( + 0, static (f, a) => new FastPropertyGetterBuffer(f, a), access); MockRegistry registry = new(MockBehavior.Default, store); int result = registry.GetPropertyFast(0, access, _ => 7); @@ -1012,10 +1013,12 @@ public async Task WithSharedAccessSingleton_WithoutMatchingBuffer_ShouldRegister public async Task WithStringName_AndMatchingFastBuffer_ShouldAppendToBuffer() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + PropertyGetterAccess access = new("P"); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer( + 0, static (f, a) => new FastPropertyGetterBuffer(f, a), access); MockRegistry registry = new(MockBehavior.Default, store); - int result = registry.GetPropertyFast(0, "P", _ => 7); + int result = registry.GetPropertyFast(0, access, _ => 7); await That(buffer.Count).IsEqualTo(1); await That(result).IsEqualTo(7); @@ -1027,7 +1030,7 @@ public async Task WithStringName_AtBufferLengthBoundary_ShouldFallBackWithoutThr FastMockInteractions store = new(1); MockRegistry registry = new(MockBehavior.Default, store); - int result = registry.GetPropertyFast(1, "P", _ => 7); + int result = registry.GetPropertyFast(1, new PropertyGetterAccess("P"), _ => 7); await That(result).IsEqualTo(7); await That(registry.Interactions.Count).IsEqualTo(1); @@ -1041,7 +1044,7 @@ public async Task WithStringName_AtTableLengthBoundary_ShouldFallToColdPathWitho snapshot.InitializeWith(42); registry.SetupProperty(0, snapshot); - int result = registry.GetPropertyFast(1, "Q", _ => 7); + int result = registry.GetPropertyFast(1, new PropertyGetterAccess("Q"), _ => 7); await That(result).IsEqualTo(7); } @@ -1051,10 +1054,12 @@ public async Task WithStringName_WhenBehaviorSkipsInteractionRecording_ShouldNot { MockBehavior behavior = MockBehavior.Default.SkippingInteractionRecording(); FastMockInteractions store = new(1, behavior.SkipInteractionRecording); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + PropertyGetterAccess access = new("P"); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer( + 0, static (f, a) => new FastPropertyGetterBuffer(f, a), access); MockRegistry registry = new(behavior, store); - registry.GetPropertyFast(0, "P", _ => 7); + registry.GetPropertyFast(0, access, _ => 7); await That(buffer.Count).IsEqualTo(0); await That(registry.Interactions.Count).IsEqualTo(0); @@ -1066,7 +1071,7 @@ public async Task WithStringName_WithoutMatchingBuffer_ShouldFallBackToRegisterP FastMockInteractions store = new(0); MockRegistry registry = new(MockBehavior.Default, store); - registry.GetPropertyFast(0, "P", _ => 7); + registry.GetPropertyFast(0, new PropertyGetterAccess("P"), _ => 7); IInteraction recorded = registry.Interactions.Single(); await That(recorded).IsExactly() diff --git a/Tests/Mockolate.Internal.Tests/Verify/CountSourceTests.cs b/Tests/Mockolate.Internal.Tests/Verify/CountSourceTests.cs index 8aa8d720..66da8d28 100644 --- a/Tests/Mockolate.Internal.Tests/Verify/CountSourceTests.cs +++ b/Tests/Mockolate.Internal.Tests/Verify/CountSourceTests.cs @@ -11,7 +11,8 @@ public class CountSourceTests public async Task EventCountSource_Subscribe_Count_IsExercised() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MockRegistry registry = new(MockBehavior.Default, store); MethodInfo m = typeof(CountSourceTests).GetMethod( @@ -28,7 +29,8 @@ public async Task EventCountSource_Subscribe_Count_IsExercised() public async Task EventCountSource_Unsubscribe_Count_IsExercised() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MockRegistry registry = new(MockBehavior.Default, store); MethodInfo m = typeof(CountSourceTests).GetMethod( @@ -46,7 +48,8 @@ public async Task EventCountSource_Unsubscribe_Count_IsExercised() public async Task IndexerGetter1_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5); @@ -63,7 +66,8 @@ public async Task IndexerGetter1_FastPath_Count_IsExercised() public async Task IndexerGetter2_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a"); @@ -83,7 +87,8 @@ public async Task IndexerGetter3_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a", true); @@ -104,7 +109,8 @@ public async Task IndexerGetter4_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a", true, 1.5); @@ -125,7 +131,8 @@ public async Task IndexerGetter4_FastPath_Count_IsExercised() public async Task IndexerSetter1_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "v"); @@ -145,7 +152,8 @@ public async Task IndexerSetter2_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a", 1.5); @@ -166,7 +174,8 @@ public async Task IndexerSetter3_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a", true, 1.5); @@ -188,7 +197,8 @@ public async Task IndexerSetter4_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "a", true, 1.5, 100L); @@ -210,7 +220,8 @@ public async Task IndexerSetter4_FastPath_Count_IsExercised() public async Task Method0_FastPath_Count_AndCountAll_AreExercised() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo"); @@ -227,7 +238,8 @@ public async Task Method0_FastPath_Count_AndCountAll_AreExercised() public async Task Method1_FastPath_Count_AndCountAll_AreExercised() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1); @@ -245,7 +257,8 @@ public async Task Method1_FastPath_Count_AndCountAll_AreExercised() public async Task Method2_FastPath_Count_AndCountAll_AreExercised() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1, "a"); @@ -265,7 +278,8 @@ public async Task Method2_FastPath_Count_AndCountAll_AreExercised() public async Task Method3_FastPath_Count_AndCountAll_AreExercised() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1, "a", true); @@ -291,7 +305,8 @@ public async Task Method4_FastPath_Count_AndCountAll_AreExercised() { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1, "a", true, 1.5); @@ -317,11 +332,12 @@ public async Task Method4_FastPath_Count_AndCountAll_AreExercised() public async Task PropertyGetter_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess("P"))); MockRegistry registry = new(MockBehavior.Default, store); - buffer.Append("P"); - buffer.Append("P"); + buffer.Append(); + buffer.Append(); registry.VerifyPropertyTyped(new object(), 0, "P").Twice(); @@ -332,7 +348,8 @@ public async Task PropertyGetter_FastPath_Count_IsExercised() public async Task PropertySetter_FastPath_Count_IsExercised() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("P", 1); diff --git a/Tests/Mockolate.Internal.Tests/Verify/MethodCountSourcesTests.cs b/Tests/Mockolate.Internal.Tests/Verify/MethodCountSourcesTests.cs index 9431e01f..8f7d5b93 100644 --- a/Tests/Mockolate.Internal.Tests/Verify/MethodCountSourcesTests.cs +++ b/Tests/Mockolate.Internal.Tests/Verify/MethodCountSourcesTests.cs @@ -12,7 +12,8 @@ public class MethodCountSourcesTests public async Task EventCountSource_ShouldReturnSubscribeCount() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MethodInfo handler = typeof(MethodCountSourcesTests).GetMethod( nameof(EventCountSource_ShouldReturnSubscribeCount))!; buffer.Append("E", null, handler); @@ -27,7 +28,8 @@ public async Task EventCountSource_ShouldReturnSubscribeCount() public async Task IndexerGetter1CountSource_ShouldHonorKeyMatcher() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1); buffer.Append(2); buffer.Append(1); @@ -41,7 +43,8 @@ public async Task IndexerGetter1CountSource_ShouldHonorKeyMatcher() public async Task IndexerGetter2CountSource_ShouldHonorBothMatchers() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a"); buffer.Append(2, "a"); buffer.Append(1, "b"); @@ -58,7 +61,8 @@ public async Task IndexerGetter3CountSource_ShouldHonorAllThreeMatchers() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a", true); buffer.Append(1, "a", false); buffer.Append(2, "a", true); @@ -76,7 +80,8 @@ public async Task IndexerGetter4CountSource_ShouldHonorAllFourMatchers() { FastMockInteractions store = new(1); FastIndexerGetterBuffer buffer = - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1, "a", true, 0.5); buffer.Append(1, "a", true, 1.5); buffer.Append(2, "a", true, 0.5); @@ -94,7 +99,8 @@ public async Task IndexerGetter4CountSource_ShouldHonorAllFourMatchers() public async Task IndexerSetter1CountSource_ShouldHonorKeyAndValueMatchers() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a"); buffer.Append(1, "b"); buffer.Append(2, "a"); @@ -111,7 +117,8 @@ public async Task IndexerSetter2CountSource_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true); buffer.Append(1, "a", false); buffer.Append(2, "a", true); @@ -129,7 +136,8 @@ public async Task IndexerSetter3CountSource_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true, 0.5); buffer.Append(1, "a", true, 1.5); buffer.Append(2, "a", true, 0.5); @@ -148,7 +156,8 @@ public async Task IndexerSetter4CountSource_ShouldHonorAllMatchers() { FastMockInteractions store = new(1); FastIndexerSetterBuffer buffer = - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "a", true, 0.5, 'x'); buffer.Append(1, "a", true, 0.5, 'y'); buffer.Append(2, "a", true, 0.5, 'x'); @@ -163,11 +172,29 @@ public async Task IndexerSetter4CountSource_ShouldHonorAllMatchers() await That(source.Count()).IsEqualTo(1); } + [Fact] + public async Task Method0CountSource_CountAll_ShouldMarkSlotsVerified() + { + FastMockInteractions store = new(1); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); + buffer.Append("M"); + buffer.Append("M"); + + Method0CountSource source = new(buffer); + await That(source.CountAll()).IsEqualTo(2); + + List<(long Seq, IInteraction Interaction)> dest = []; + ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); + await That(dest).IsEmpty(); + } + [Fact] public async Task Method0CountSource_ShouldRouteCountAndCountAllThroughBuffer() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); buffer.Append("M"); buffer.Append("M"); @@ -177,11 +204,29 @@ public async Task Method0CountSource_ShouldRouteCountAndCountAllThroughBuffer() await That(source.Count()).IsEqualTo(2); } + [Fact] + public async Task Method1CountSource_CountAll_ShouldMarkSlotsVerified() + { + FastMockInteractions store = new(1); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); + buffer.Append("M", 1); + buffer.Append("M", 2); + + Method1CountSource source = new(buffer, (IParameterMatch)It.Is(1)); + await That(source.CountAll()).IsEqualTo(2); + + List<(long Seq, IInteraction Interaction)> dest = []; + ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); + await That(dest).IsEmpty(); + } + [Fact] public async Task Method1CountSource_ShouldHonorMatcher() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); buffer.Append("M", 1); buffer.Append("M", 2); buffer.Append("M", 1); @@ -197,85 +242,55 @@ public async Task Method1CountSource_ShouldHonorMatcher() } [Fact] - public async Task Method2CountSource_ShouldHonorBothMatchers() + public async Task Method2CountSource_CountAll_ShouldMarkSlotsVerified() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); buffer.Append("M", 1, "a"); - buffer.Append("M", 2, "a"); - buffer.Append("M", 1, "b"); + buffer.Append("M", 2, "b"); Method2CountSource source = new(buffer, (IParameterMatch)It.Is(1), (IParameterMatch)It.Is("a")); + await That(source.CountAll()).IsEqualTo(2); - await That(source.CountAll()).IsEqualTo(3); - await That(source.Count()).IsEqualTo(1); + List<(long Seq, IInteraction Interaction)> dest = []; + ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); + await That(dest).IsEmpty(); } [Fact] - public async Task Method3CountSource_ShouldHonorAllThreeMatchers() + public async Task Method2CountSource_ShouldHonorBothMatchers() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); - buffer.Append("M", 1, "a", true); - buffer.Append("M", 2, "a", false); - buffer.Append("M", 1, "b", true); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); + buffer.Append("M", 1, "a"); + buffer.Append("M", 2, "a"); + buffer.Append("M", 1, "b"); - Method3CountSource source = new(buffer, + Method2CountSource source = new(buffer, (IParameterMatch)It.Is(1), - (IParameterMatch)It.IsAny(), - (IParameterMatch)It.Is(true)); + (IParameterMatch)It.Is("a")); await That(source.CountAll()).IsEqualTo(3); - await That(source.Count()).IsEqualTo(2); + await That(source.Count()).IsEqualTo(1); } [Fact] - public async Task Method4CountSource_ShouldHonorAllFourMatchers() + public async Task Method3CountSource_CountAll_ShouldMarkSlotsVerified() { FastMockInteractions store = new(1); - FastMethod4Buffer buffer = - store.InstallMethod(0); - buffer.Append("M", 1, "a", true, 0.5); - buffer.Append("M", 2, "a", false, 1.5); - buffer.Append("M", 1, "a", true, 2.5); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); + buffer.Append("M", 1, "a", true); + buffer.Append("M", 2, "b", false); - Method4CountSource source = new(buffer, + Method3CountSource source = new(buffer, (IParameterMatch)It.Is(1), (IParameterMatch)It.Is("a"), - (IParameterMatch)It.Is(true), - (IParameterMatch)It.IsAny()); - - await That(source.CountAll()).IsEqualTo(3); - await That(source.Count()).IsEqualTo(2); - } - - [Fact] - public async Task Method0CountSource_CountAll_ShouldMarkSlotsVerified() - { - FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); - buffer.Append("M"); - buffer.Append("M"); - - Method0CountSource source = new(buffer); - await That(source.CountAll()).IsEqualTo(2); - - List<(long Seq, IInteraction Interaction)> dest = []; - ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); - await That(dest).IsEmpty(); - } - - [Fact] - public async Task Method1CountSource_CountAll_ShouldMarkSlotsVerified() - { - FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); - buffer.Append("M", 1); - buffer.Append("M", 2); - - Method1CountSource source = new(buffer, (IParameterMatch)It.Is(1)); + (IParameterMatch)It.Is(true)); await That(source.CountAll()).IsEqualTo(2); List<(long Seq, IInteraction Interaction)> dest = []; @@ -284,35 +299,39 @@ public async Task Method1CountSource_CountAll_ShouldMarkSlotsVerified() } [Fact] - public async Task Method2CountSource_CountAll_ShouldMarkSlotsVerified() + public async Task Method3CountSource_ShouldHonorAllThreeMatchers() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); - buffer.Append("M", 1, "a"); - buffer.Append("M", 2, "b"); + FastMethod3Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); + buffer.Append("M", 1, "a", true); + buffer.Append("M", 2, "a", false); + buffer.Append("M", 1, "b", true); - Method2CountSource source = new(buffer, + Method3CountSource source = new(buffer, (IParameterMatch)It.Is(1), - (IParameterMatch)It.Is("a")); - await That(source.CountAll()).IsEqualTo(2); + (IParameterMatch)It.IsAny(), + (IParameterMatch)It.Is(true)); - List<(long Seq, IInteraction Interaction)> dest = []; - ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); - await That(dest).IsEmpty(); + await That(source.CountAll()).IsEqualTo(3); + await That(source.Count()).IsEqualTo(2); } [Fact] - public async Task Method3CountSource_CountAll_ShouldMarkSlotsVerified() + public async Task Method4CountSource_CountAll_ShouldMarkSlotsVerified() { FastMockInteractions store = new(1); - FastMethod3Buffer buffer = store.InstallMethod(0); - buffer.Append("M", 1, "a", true); - buffer.Append("M", 2, "b", false); + FastMethod4Buffer buffer = + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); + buffer.Append("M", 1, "a", true, 0.5); + buffer.Append("M", 2, "b", false, 1.5); - Method3CountSource source = new(buffer, + Method4CountSource source = new(buffer, (IParameterMatch)It.Is(1), (IParameterMatch)It.Is("a"), - (IParameterMatch)It.Is(true)); + (IParameterMatch)It.Is(true), + (IParameterMatch)It.Is(0.5)); await That(source.CountAll()).IsEqualTo(2); List<(long Seq, IInteraction Interaction)> dest = []; @@ -321,34 +340,35 @@ public async Task Method3CountSource_CountAll_ShouldMarkSlotsVerified() } [Fact] - public async Task Method4CountSource_CountAll_ShouldMarkSlotsVerified() + public async Task Method4CountSource_ShouldHonorAllFourMatchers() { FastMockInteractions store = new(1); FastMethod4Buffer buffer = - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); buffer.Append("M", 1, "a", true, 0.5); - buffer.Append("M", 2, "b", false, 1.5); + buffer.Append("M", 2, "a", false, 1.5); + buffer.Append("M", 1, "a", true, 2.5); Method4CountSource source = new(buffer, (IParameterMatch)It.Is(1), (IParameterMatch)It.Is("a"), (IParameterMatch)It.Is(true), - (IParameterMatch)It.Is(0.5)); - await That(source.CountAll()).IsEqualTo(2); + (IParameterMatch)It.IsAny()); - List<(long Seq, IInteraction Interaction)> dest = []; - ((IFastMemberBuffer)buffer).AppendBoxedUnverified(dest); - await That(dest).IsEmpty(); + await That(source.CountAll()).IsEqualTo(3); + await That(source.Count()).IsEqualTo(2); } [Fact] public async Task PropertyGetterCountSource_ShouldReturnRecordedCount() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); - buffer.Append("P"); - buffer.Append("P"); - buffer.Append("P"); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess("P"))); + buffer.Append(); + buffer.Append(); + buffer.Append(); PropertyGetterCountSource source = new(buffer); @@ -359,7 +379,8 @@ public async Task PropertyGetterCountSource_ShouldReturnRecordedCount() public async Task PropertySetterCountSource_ShouldHonorValueMatcher() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); buffer.Append("P", 1); buffer.Append("P", 2); buffer.Append("P", 1); diff --git a/Tests/Mockolate.Internal.Tests/Verify/TypedVerifyFastPathTests.cs b/Tests/Mockolate.Internal.Tests/Verify/TypedVerifyFastPathTests.cs index fff032f6..b3db8ce0 100644 --- a/Tests/Mockolate.Internal.Tests/Verify/TypedVerifyFastPathTests.cs +++ b/Tests/Mockolate.Internal.Tests/Verify/TypedVerifyFastPathTests.cs @@ -12,7 +12,8 @@ public class TypedVerifyFastPathTests public async Task IndexerGot_WithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation() { FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5); buffer.Append(7); @@ -31,7 +32,7 @@ public async Task IndexerGot_WithMemberIdAndBuffer_CountsBufferEntriesAndProduce public async Task IndexerGot_WithMemberIdAndInstalledBuffer_OnlyWalksBuffer() { FastMockInteractions store = new(1); - store.InstallPropertyGetter(0); + InstallPropertyGetter(store, 0); MockRegistry registry = new(MockBehavior.Default, store); IMockInteractions interactions = store; @@ -64,7 +65,8 @@ public async Task IndexerGot_WithoutBuffer_ProducesParametersDescriptionInExpect public async Task IndexerGotTyped_WithBuffer_ProducesParametersDescriptionInExpectation() { FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult result = registry.IndexerGotTyped( @@ -79,7 +81,8 @@ public async Task IndexerGotTyped_WithBuffer_ProducesParametersDescriptionInExpe public async Task IndexerSet_WithMemberIdAndBuffer_CountsMatchingValuesAndProducesExpectation() { FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append(5, "v"); buffer.Append(7, "v"); @@ -101,7 +104,7 @@ public async Task IndexerSet_WithMemberIdAndBuffer_CountsMatchingValuesAndProduc public async Task IndexerSet_WithMemberIdAndInstalledBuffer_OnlyWalksBuffer() { FastMockInteractions store = new(1); - store.InstallPropertyGetter(0); + InstallPropertyGetter(store, 0); MockRegistry registry = new(MockBehavior.Default, store); IMockInteractions interactions = store; @@ -139,7 +142,8 @@ public async Task IndexerSet_WithoutBuffer_ProducesParametersDescriptionInExpect public async Task IndexerSetTyped_WithBuffer_ProducesParametersDescriptionInExpectation() { FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); IParameterMatch value = (IParameterMatch)It.Is("v"); @@ -157,7 +161,8 @@ public async Task IndexerSetTyped_WithBuffer_ProducesParametersDescriptionInExpe public async Task SubscribedTo_WithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MockRegistry registry = new(MockBehavior.Default, store); MethodInfo method = typeof(TypedVerifyFastPathTests).GetMethod( nameof(SubscribedTo_WithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation))!; @@ -192,7 +197,8 @@ public async Task SubscribedTo_WithMemberIdButNoBuffer_FallsBackAndFiltersByName public async Task SubscribedToTyped_WithBuffer_ProducesEventNameInExpectation() { FastMockInteractions store = new(1); - store.InstallEventSubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult result = registry.SubscribedToTyped(new object(), 0, "OnFoo"); @@ -215,7 +221,8 @@ public async Task SubscribedToTyped_WithMemberIdButNoBuffer_FallsBackToStringKey public async Task TryGetBuffer_WhenBufferReturned_TypedFastPathIgnoresOtherInteractions() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); IMockInteractions interactions = store; @@ -233,7 +240,8 @@ public async Task TryGetBuffer_WhenBufferReturned_TypedFastPathIgnoresOtherInter public async Task UnsubscribedFrom_WithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MockRegistry registry = new(MockBehavior.Default, store); MethodInfo method = typeof(TypedVerifyFastPathTests).GetMethod( nameof(UnsubscribedFrom_WithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation))!; @@ -268,7 +276,8 @@ public async Task UnsubscribedFrom_WithMemberIdButNoBuffer_FallsBackAndFiltersBy public async Task UnsubscribedFromTyped_WithBuffer_ProducesEventNameInExpectation() { FastMockInteractions store = new(1); - store.InstallEventUnsubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult result = registry.UnsubscribedFromTyped(new object(), 0, "OnFoo"); @@ -291,7 +300,7 @@ public async Task UnsubscribedFromTyped_WithMemberIdButNoBuffer_FallsBackToStrin public async Task UnsubscribedFromTyped_WithMemberIdButNonMatchingBufferKind_FallsBackToStringKeyedPath() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer(0, static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult result = registry.UnsubscribedFromTyped(new object(), 0, "OnFoo"); @@ -304,7 +313,8 @@ public async Task UnsubscribedFromTyped_WithMemberIdButNonMatchingBufferKind_Fal public async Task VerifyMethod0_TypedFastPath_ShouldCount() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); @@ -337,7 +347,8 @@ public async Task VerifyMethod0_WithMemberIdButNoMatchingBuffer_FallbackPredicat public async Task VerifyMethod1_TypedFastPath_FailsWithExpectedMessage() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); @@ -353,7 +364,8 @@ await That(() => registry.VerifyMethod(new object(), 0, "Foo", public async Task VerifyMethod1_TypedFastPath_ShouldHonorMatcher() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); @@ -373,7 +385,8 @@ public async Task VerifyMethod1_TypedFastPath_ShouldHonorMatcher() public async Task VerifyMethod2_TypedFastPath_AnyParameters_UsesCountAll() { FastMockInteractions store = new(1); - FastMethod2Buffer buffer = store.InstallMethod(0); + FastMethod2Buffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); @@ -444,10 +457,10 @@ public async Task VerifyMethod4_FallbackPath_RequiresAllParametersToMatch() public async Task VerifyProperty_GetterWithMemberIdAndBuffer_CountsBufferEntriesAndProducesExpectation() { FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); + FastPropertyGetterBuffer buffer = InstallPropertyGetter(store, 0); MockRegistry registry = new(MockBehavior.Default, store); - buffer.Append("P"); - buffer.Append("P"); + buffer.Append(); + buffer.Append(); VerificationResult result = registry.VerifyProperty(new object(), 0, "P"); @@ -459,7 +472,8 @@ public async Task VerifyProperty_GetterWithMemberIdAndBuffer_CountsBufferEntries public async Task VerifyProperty_SetterWithMemberIdAndBuffer_CountsMatchingValuesAndProducesExpectation() { FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("P", 1); buffer.Append("P", 2); @@ -543,7 +557,7 @@ public async Task VerifyPropertySetter_WithMemberIdButNoBuffer_FallsBackToString public async Task VerifyPropertyTyped_Getter_WithBuffer_ProducesPropertyNameInExpectation() { FastMockInteractions store = new(1); - store.InstallPropertyGetter(0); + InstallPropertyGetter(store, 0); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult result = registry.VerifyPropertyTyped(new object(), 0, "P"); @@ -555,7 +569,8 @@ public async Task VerifyPropertyTyped_Getter_WithBuffer_ProducesPropertyNameInEx public async Task VerifyPropertyTyped_Setter_WithBuffer_ProducesPropertyNameInExpectation() { FastMockInteractions store = new(1); - store.InstallPropertySetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); IParameterMatch value = (IParameterMatch)It.Is(42); @@ -564,4 +579,8 @@ public async Task VerifyPropertyTyped_Setter_WithBuffer_ProducesPropertyNameInEx await That(((IVerificationResult)result).Expectation).Contains("set property P"); await That(((IVerificationResult)result).Expectation).Contains(value.ToString()!); } + + private static FastPropertyGetterBuffer InstallPropertyGetter(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess(string.Empty))); } diff --git a/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs index c0f9343b..c184fa89 100644 --- a/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs +++ b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs @@ -11,6 +11,12 @@ namespace Mockolate.Internal.Tests.Verify; public class VerificationResultTests { + private static FastMethod0Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer(memberId, static f => new FastMethod0Buffer(f)); + + private static FastMethod1Buffer InstallMethod(FastMockInteractions store, int memberId) + => store.GetOrCreateBuffer>(memberId, static f => new FastMethod1Buffer(f)); + public sealed class AwaitableTests { [Fact] @@ -37,12 +43,12 @@ void Act() public async Task VerifyCount_WhenPredicateNeverSatisfies_ShouldTimeOut() { FastMockInteractions store = new(1); - store.InstallMethod(0); + InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); void Act() { - registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") + registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") .Within(50.Milliseconds()).AtLeast(2); } @@ -60,7 +66,7 @@ public async Task VerifyCount_WithUseCountAll_ShouldPickCountAllNotFilteredCount // (Count()) of the mutated conditional satisfies it synchronously, then short-circuits // before the async loop can re-evaluate via the unmutated CountAll(). FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1); @@ -86,7 +92,7 @@ void Act() public async Task WithCancellation_PreservesUseCountAllFlag() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1); @@ -112,7 +118,7 @@ void Act() public async Task Within_PreservesUseCountAllFlag() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1); @@ -167,8 +173,8 @@ public async Task Map_WhenBufferOnlyAndFastSourceNull_PreservesBuffer() // CollectMatching falls back to a global Where over _interactions, which would pick up // records from OTHER buffers that satisfy the (un-name-filtered) predicate. FastMockInteractions store = new(2); - FastMethod1Buffer bufA = store.InstallMethod(0); - FastMethod1Buffer bufB = store.InstallMethod(1); + FastMethod1Buffer bufA = InstallMethod(store, 0); + FastMethod1Buffer bufB = InstallMethod(store, 1); MockRegistry registry = new(MockBehavior.Default, store); bufA.Append("Foo", 1); @@ -196,14 +202,14 @@ public async Task Map_WhenBufferOnlyAndFastSourceNull_PreservesBuffer() public async Task Map_WithBuffer_PreservesFastPathSource() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo"); buffer.Append("Foo"); object original = new(); - VerificationResult.IgnoreParameters result = registry.VerifyMethod( + VerificationResult.IgnoreParameters result = registry.VerifyMethod( original, 0, "Foo", () => "Foo()"); string newSubject = "newMock"; @@ -245,7 +251,7 @@ public async Task WithBufferAndExactlyTwoRecords_PreservesSequenceOrder() // with the existing N=1 / N=3 / N=0 cases, this pins the boundary so flipping `> 1` to // `>= 1` is no longer a silent rewrite of the sort path. FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 10); @@ -274,7 +280,7 @@ public async Task WithBufferAndExactlyTwoRecords_PreservesSequenceOrder() public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 10); @@ -303,7 +309,7 @@ public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() public async Task WithBufferAndNoMatchingRecord_ReturnsEmpty() { FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); + FastMethod1Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo", 1); @@ -326,7 +332,7 @@ public async Task WithBufferAndNoMatchingRecord_ReturnsEmpty() public async Task WithBufferAndSingleRecord_ReturnsRecord() { FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); + FastMethod0Buffer buffer = InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); buffer.Append("Foo"); @@ -349,7 +355,7 @@ public async Task WithBufferAndSingleRecord_ReturnsRecord() public async Task WithEmptyBuffer_ReturnsEmpty() { FastMockInteractions store = new(1); - store.InstallMethod(0); + InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default, store); VerificationResult.IgnoreParameters result = registry.VerifyMethod( @@ -394,7 +400,7 @@ public async Task VerifyCount_WhenRecordingDisabled_AndAwaitableViaWithin_Should { // Same guard, Awaitable path (via Within). Distinct mutation site. FastMockInteractions store = new(1, true); - store.InstallMethod(0); + InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default with { SkipInteractionRecording = true, @@ -402,7 +408,7 @@ public async Task VerifyCount_WhenRecordingDisabled_AndAwaitableViaWithin_Should void Act() { - registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") + registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") .Within(50.Milliseconds()).Once(); } @@ -417,7 +423,7 @@ public async Task VerifyCount_WhenRecordingDisabled_ShouldThrowMockException() // IFastVerifyCountResult.VerifyCount path. Without the guard, Once() would silently // report a (probably false) count and never throw. FastMockInteractions store = new(1, true); - store.InstallMethod(0); + InstallMethod(store, 0); MockRegistry registry = new(MockBehavior.Default with { SkipInteractionRecording = true, @@ -425,7 +431,7 @@ public async Task VerifyCount_WhenRecordingDisabled_ShouldThrowMockException() void Act() { - registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()").Once(); + registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()").Once(); } await That(Act).Throws() diff --git a/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.MethodTests.cs b/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.MethodTests.cs index aa563af2..91ff560b 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.MethodTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.MethodTests.cs @@ -1424,9 +1424,9 @@ public interface IStaticOps await That(result.Sources).ContainsKey("Mock.IStaticOps.g.cs"); await That(result.Sources["Mock.IStaticOps.g.cs"]) .Contains("global::Mockolate.Interactions.FastMethod1Buffer").And - .Contains("MockRegistryProvider.Value.Interactions).Buffers[") + .Contains("MockRegistryProvider.Value.Interactions).GetOrCreateBuffer<") .Because( - "static methods record interactions via the typed FastMethodBuffer accessed through the AsyncLocal-backed registry") + "static methods record interactions via the typed FastMethodBuffer accessed through the AsyncLocal-backed registry; the buffer is now lazily materialized on first touch via GetOrCreateBuffer") .And .Contains("Append(\"global::MyCode.IStaticOps.DoIt\", value)") .Because("the static-method fast-buffer branch must include the call argument when arity > 0"); 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 d6f26d81..6665ca37 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 @@ -511,16 +511,10 @@ internal class ComprehensiveAbstractClass : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.PropertyAccess_V_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -545,10 +539,10 @@ internal class ComprehensiveAbstractClass : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_A - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_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.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_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)] 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 86d70a01..9a934d04 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 @@ -210,15 +210,10 @@ internal class ICombinationMockA : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ICombinationMockA.MemberId_Run); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockA.PropertyAccess_Value_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Set); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -236,7 +231,7 @@ internal class ICombinationMockA : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_Run - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ICombinationMockA.MemberId_Run]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ICombinationMockA.MemberId_Run, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] 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 71c02c1b..88ffb1e0 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 @@ -210,15 +210,10 @@ internal class ICombinationMockB : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ICombinationMockB.MemberId_Run); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockB.PropertyAccess_Value_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Set); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -236,7 +231,7 @@ internal class ICombinationMockB : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_Run - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ICombinationMockB.MemberId_Run]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.ICombinationMockB.MemberId_Run, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] 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 d6f26d81..6665ca37 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 @@ -511,16 +511,10 @@ internal class ComprehensiveAbstractClass : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_A); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_P); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Get, global::Mockolate.Mock.ComprehensiveAbstractClass.PropertyAccess_V_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_V_Set); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -545,10 +539,10 @@ internal class ComprehensiveAbstractClass : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_A - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_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.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.ComprehensiveAbstractClass.MemberId_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)] 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 62bb9a3d..7937aae1 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 @@ -263,48 +263,10 @@ internal class IComprehensiveInterface : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_StaticAbstractMethod); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers); - fast.InstallBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithDefaults, new global::Mockolate.Interactions.FastMethod7Buffer(fast)); - fast.InstallBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithCollidingNames, new global::Mockolate.Interactions.FastMethod5Buffer(fast)); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetMaybeNull); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTask); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTaskOf); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVT); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVTOf); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetTuple); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetNullable); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetSpan); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetROSpan); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRef); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRefReadonly); - fast.InstallBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Five, new global::Mockolate.Interactions.FastMethod5Buffer(fast)); - fast.InstallBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Seventeen, new global::Mockolate.Interactions.FastMethod17Buffer(fast)); - fast.InstallBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_SeventeenVoid, new global::Mockolate.Interactions.FastMethod17Buffer(fast)); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetSet_Get, global::Mockolate.Mock.IComprehensiveInterface.PropertyAccess_GetSet_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetSet_Set); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.PropertyAccess_GetOnly_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Set); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.PropertyAccess_SetOnly_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Set); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_NullableProp_Get, global::Mockolate.Mock.IComprehensiveInterface.PropertyAccess_NullableProp_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_NullableProp_Set); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_InitOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.PropertyAccess_InitOnly_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_InitOnly_Set); - global::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerGetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Get); - global::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerSetter(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Set); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventSubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_PlainEvent_Subscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventUnsubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_PlainEvent_Unsubscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventSubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_TypedEvent_Subscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventUnsubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_TypedEvent_Unsubscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventSubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_CustomEvent_Subscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventUnsubscribe(fast, global::Mockolate.Mock.IComprehensiveInterface.MemberId_CustomEvent_Unsubscribe); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -325,61 +287,61 @@ internal class IComprehensiveInterface : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastIndexerGetterBuffer MockolateBuffer_Indexer_int_Get - => field ?? (field = (global::Mockolate.Interactions.FastIndexerGetterBuffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Get]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Get, static fast => new global::Mockolate.Interactions.FastIndexerGetterBuffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastIndexerSetterBuffer MockolateBuffer_Indexer_int_Set - => field ?? (field = (global::Mockolate.Interactions.FastIndexerSetterBuffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Set]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Indexer_int_Set, static fast => new global::Mockolate.Interactions.FastIndexerSetterBuffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod4Buffer MockolateBuffer_WithModifiers - => field ?? (field = (global::Mockolate.Interactions.FastMethod4Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, static fast => new global::Mockolate.Interactions.FastMethod4Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod7Buffer MockolateBuffer_WithDefaults - => field ?? (field = (global::Mockolate.Interactions.FastMethod7Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithDefaults]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithDefaults, static fast => new global::Mockolate.Interactions.FastMethod7Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod5Buffer MockolateBuffer_WithCollidingNames - => field ?? (field = (global::Mockolate.Interactions.FastMethod5Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithCollidingNames]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithCollidingNames, static fast => new global::Mockolate.Interactions.FastMethod5Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer_GetMaybeNull - => field ?? (field = (global::Mockolate.Interactions.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetMaybeNull]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetMaybeNull, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_DoTask - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTask]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTask, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_DoTaskOf - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTaskOf]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoTaskOf, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_DoVT - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVT]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVT, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_DoVTOf - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVTOf]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_DoVTOf, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_GetTuple - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetTuple]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetTuple, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_GetNullable - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetNullable]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetNullable, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer_GetSpan - => field ?? (field = (global::Mockolate.Interactions.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetSpan]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetSpan, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer_GetROSpan - => field ?? (field = (global::Mockolate.Interactions.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetROSpan]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetROSpan, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_GetByRef - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRef]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRef, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer_GetByRefReadonly - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRefReadonly]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetByRefReadonly, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod5Buffer MockolateBuffer_Five - => field ?? (field = (global::Mockolate.Interactions.FastMethod5Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_Five]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Five, static fast => new global::Mockolate.Interactions.FastMethod5Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod17Buffer MockolateBuffer_Seventeen - => field ?? (field = (global::Mockolate.Interactions.FastMethod17Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_Seventeen]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_Seventeen, static fast => new global::Mockolate.Interactions.FastMethod17Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod17Buffer MockolateBuffer_SeventeenVoid - => field ?? (field = (global::Mockolate.Interactions.FastMethod17Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_SeventeenVoid]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IComprehensiveInterface.MemberId_SeventeenVoid, static fast => new global::Mockolate.Interactions.FastMethod17Buffer(fast))); /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] @@ -759,7 +721,7 @@ public static int StaticAbstractMethod() int wrappedResult = default!; if (MockRegistryProvider.Value.Behavior.SkipInteractionRecording == false) { - ((global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).Buffers[global::Mockolate.Mock.IComprehensiveInterface.MemberId_StaticAbstractMethod]!).Append("global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.StaticAbstractMethod"); + ((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IComprehensiveInterface.MemberId_StaticAbstractMethod, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)).Append("global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.StaticAbstractMethod"); } try { 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 6b299f02..e3384700 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 @@ -529,15 +529,10 @@ internal class HttpClient : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpClient.MemberId_Send); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpClient.MemberId_SendAsync); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpClient.MemberId_Dispose); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -562,13 +557,13 @@ internal class HttpClient : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod2Buffer MockolateBuffer_Send - => field ?? (field = (global::Mockolate.Interactions.FastMethod2Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpClient.MemberId_Send]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpClient.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.FastMethod2Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpClient.MemberId_SendAsync]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpClient.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.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpClient.MemberId_Dispose]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.HttpClient.MemberId_Dispose, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] 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 e1c8d49d..22c0dc0c 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 @@ -361,15 +361,10 @@ internal class HttpMessageHandler : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpMessageHandler.MemberId_Send); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpMessageHandler.MemberId_SendAsync); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.HttpMessageHandler.MemberId_Dispose); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -394,13 +389,13 @@ internal class HttpMessageHandler : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod2Buffer MockolateBuffer_Send - => field ?? (field = (global::Mockolate.Interactions.FastMethod2Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpMessageHandler.MemberId_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.FastMethod2Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpMessageHandler.MemberId_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.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.HttpMessageHandler.MemberId_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::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] 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 7ddf1dc1..5d66fe61 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 @@ -218,20 +218,10 @@ internal class IKeywordEdgeCases : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__return); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__if); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertyGetter(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Get, global::Mockolate.Mock.IKeywordEdgeCases.PropertyAccess__class_Get); - global::Mockolate.Interactions.FastPropertyBufferFactory.InstallPropertySetter(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Set); - global::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerGetter(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Get); - global::Mockolate.Interactions.FastIndexerBufferFactory.InstallIndexerSetter(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Set); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventSubscribe(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__event_Subscribe); - global::Mockolate.Interactions.FastEventBufferFactory.InstallEventUnsubscribe(fast, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__event_Unsubscribe); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -249,16 +239,16 @@ internal class IKeywordEdgeCases : [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastIndexerGetterBuffer MockolateBuffer_Indexer_int_string_Get - => field ?? (field = (global::Mockolate.Interactions.FastIndexerGetterBuffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Get]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Get, static fast => new global::Mockolate.Interactions.FastIndexerGetterBuffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastIndexerSetterBuffer MockolateBuffer_Indexer_int_string_Set - => field ?? (field = (global::Mockolate.Interactions.FastIndexerSetterBuffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Set]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IKeywordEdgeCases.MemberId_Indexer_int_string_Set, static fast => new global::Mockolate.Interactions.FastIndexerSetterBuffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod0Buffer MockolateBuffer__return - => field ?? (field = (global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IKeywordEdgeCases.MemberId__return]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IKeywordEdgeCases.MemberId__return, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast))); [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] private global::Mockolate.Interactions.FastMethod1Buffer MockolateBuffer__if - => field ?? (field = (global::Mockolate.Interactions.FastMethod1Buffer)((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).Buffers[global::Mockolate.Mock.IKeywordEdgeCases.MemberId__if]!); + => field ?? (field = ((global::Mockolate.Interactions.FastMockInteractions)this.MockRegistry.Interactions).GetOrCreateBuffer>(global::Mockolate.Mock.IKeywordEdgeCases.MemberId__if, static fast => new global::Mockolate.Interactions.FastMethod1Buffer(fast))); /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] 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 6ae671f2..a9a3e5a6 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 @@ -209,12 +209,10 @@ internal class IRefStructConsumer : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . 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 d0442cfa..e0a26c5e 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 @@ -217,14 +217,10 @@ internal class IStaticAbstractMembers : /// /// 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) - { - global::Mockolate.Interactions.FastMockInteractions fast = new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IStaticAbstractMembers.MemberId_AbstractStaticMethod); - global::Mockolate.Interactions.FastMethodBufferFactory.InstallMethod(fast, global::Mockolate.Mock.IStaticAbstractMembers.MemberId_VirtualStaticMethod); - return fast; - } + => new global::Mockolate.Interactions.FastMockInteractions(MemberCount, behavior.SkipInteractionRecording); /// /// Builds a MockRegistry backed by a typed-buffer-sized FastMockInteractions from . @@ -394,7 +390,7 @@ public static int AbstractStaticMethod() int wrappedResult = default!; if (MockRegistryProvider.Value.Behavior.SkipInteractionRecording == false) { - ((global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).Buffers[global::Mockolate.Mock.IStaticAbstractMembers.MemberId_AbstractStaticMethod]!).Append("global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.AbstractStaticMethod"); + ((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IStaticAbstractMembers.MemberId_AbstractStaticMethod, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)).Append("global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.AbstractStaticMethod"); } try { @@ -448,7 +444,7 @@ public static int VirtualStaticMethod() int wrappedResult = default!; if (MockRegistryProvider.Value.Behavior.SkipInteractionRecording == false) { - ((global::Mockolate.Interactions.FastMethod0Buffer)((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).Buffers[global::Mockolate.Mock.IStaticAbstractMembers.MemberId_VirtualStaticMethod]!).Append("global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.VirtualStaticMethod"); + ((global::Mockolate.Interactions.FastMockInteractions)MockRegistryProvider.Value.Interactions).GetOrCreateBuffer(global::Mockolate.Mock.IStaticAbstractMembers.MemberId_VirtualStaticMethod, static fast => new global::Mockolate.Interactions.FastMethod0Buffer(fast)).Append("global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.VirtualStaticMethod"); } try { diff --git a/Tests/Mockolate.Tests/Verify/MockRegistryVerifyTests.cs b/Tests/Mockolate.Tests/Verify/MockRegistryVerifyTests.cs index a345ecc7..bd899107 100644 --- a/Tests/Mockolate.Tests/Verify/MockRegistryVerifyTests.cs +++ b/Tests/Mockolate.Tests/Verify/MockRegistryVerifyTests.cs @@ -12,7 +12,8 @@ public sealed class FailureMessageTests public async Task IndexerGotTyped_FourKeys_FailureMessageIncludesGotIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -33,7 +34,8 @@ await That(Act).Throws() public async Task IndexerGotTyped_OneKey_FailureMessageIncludesGotIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -51,7 +53,8 @@ await That(Act).Throws() public async Task IndexerGotTyped_ThreeKeys_FailureMessageIncludesGotIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -71,7 +74,8 @@ await That(Act).Throws() public async Task IndexerGotTyped_TwoKeys_FailureMessageIncludesGotIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -90,7 +94,8 @@ await That(Act).Throws() public async Task IndexerSetTyped_FourKeys_FailureMessageIncludesSetIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -112,7 +117,8 @@ await That(Act).Throws() public async Task IndexerSetTyped_OneKey_FailureMessageIncludesSetIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -131,7 +137,8 @@ await That(Act).Throws() public async Task IndexerSetTyped_ThreeKeys_FailureMessageIncludesSetIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -152,7 +159,8 @@ await That(Act).Throws() public async Task IndexerSetTyped_TwoKeys_FailureMessageIncludesSetIndexerPrefix() { FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -172,7 +180,8 @@ await That(Act).Throws() public async Task SubscribedToTyped_FailureMessageIncludesSubscribedToEventPrefix() { FastMockInteractions store = new(1); - store.InstallEventSubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -188,7 +197,8 @@ await That(Act).Throws() public async Task UnsubscribedFromTyped_FailureMessageIncludesUnsubscribedFromEventPrefix() { FastMockInteractions store = new(1); - store.InstallEventUnsubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -204,7 +214,8 @@ await That(Act).Throws() public async Task VerifyMethodTyped_FourParameters_FailureMessageIncludesInvokedMethodPrefix() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod4Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -225,7 +236,8 @@ await That(Act).Throws() public async Task VerifyMethodTyped_OneParameter_FailureMessageIncludesInvokedMethodPrefix() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod1Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -243,7 +255,8 @@ await That(Act).Throws() public async Task VerifyMethodTyped_Parameterless_FailureMessageIncludesInvokedMethodPrefix() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -259,7 +272,8 @@ await That(Act).Throws() public async Task VerifyMethodTyped_ThreeParameters_FailureMessageIncludesInvokedMethodPrefix() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod3Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -279,7 +293,8 @@ await That(Act).Throws() public async Task VerifyMethodTyped_TwoParameters_FailureMessageIncludesInvokedMethodPrefix() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer>(0, + static f => new FastMethod2Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -298,7 +313,8 @@ await That(Act).Throws() public async Task VerifyPropertyTyped_Getter_FailureMessageIncludesGotPropertyPrefix() { FastMockInteractions store = new(1); - store.InstallPropertyGetter(0); + store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess(string.Empty))); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -314,7 +330,8 @@ await That(Act).Throws() public async Task VerifyPropertyTyped_Setter_FailureMessageIncludesSetPropertyPrefix() { FastMockInteractions store = new(1); - store.InstallPropertySetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -338,7 +355,8 @@ public async Task VerifyMethodTyped_WithMemberIdEqualToBufferLength_ShouldFallTo // IndexOutOfRangeException-crash on `buffers[memberId]`. Asserting the verify // resolves cleanly via the slow-path fallback documents the boundary. FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -353,7 +371,8 @@ void Act() public async Task VerifyMethodTyped_WithMemberIdFarOutOfRange_ShouldFallToSlowPath() { FastMockInteractions store = new(1); - store.InstallMethod(0); + store.GetOrCreateBuffer(0, + static f => new FastMethod0Buffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -488,7 +507,8 @@ public async Task Getter_FailureMessageIncludesGotPropertyPrefix() // Pins the expectation factory `() => $"got property {propertyName...}"` against the // string-removal mutation that would replace it with an empty interpolation. FastMockInteractions store = new(1); - store.InstallPropertyGetter(0); + store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess(string.Empty))); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -507,8 +527,9 @@ public async Task Getter_WithBufferAndRecord_PredicateMatchesEveryRecord() // Mutating it to `static _ => false` would skip every record and turn this Once() into a // failed verification. FastMockInteractions store = new(1); - FastPropertyGetterBuffer buffer = store.InstallPropertyGetter(0); - buffer.Append("X"); + FastPropertyGetterBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastPropertyGetterBuffer(f, new PropertyGetterAccess("X"))); + buffer.Append(); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -525,7 +546,8 @@ public async Task Setter_FailureMessageIncludesSetPropertyPrefix() // Pins the expectation factory `() => $"set property {propertyName...} to {value}"` // against the string-removal mutation. FastMockInteractions store = new(1); - store.InstallPropertySetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -545,7 +567,8 @@ public async Task Setter_WithBufferAndMatchingRecord_PredicateMatchesByValue() // Block-removal would turn the predicate into `return default;` (i.e. always false) and // drop every recorded setter, failing this Once(). FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); buffer.Append("X", 7); MockRegistry registry = new(MockBehavior.Default, store); @@ -564,7 +587,8 @@ public async Task Setter_WithNonMatchingValue_PredicateRejects() // Same Predicate body — but exercises the negative branch so the `value.Matches(...)` // term cannot be silently dropped. FastMockInteractions store = new(1); - FastPropertySetterBuffer buffer = store.InstallPropertySetter(0); + FastPropertySetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastPropertySetterBuffer(f)); buffer.Append("X", 99); MockRegistry registry = new(MockBehavior.Default, store); @@ -586,7 +610,8 @@ public async Task Got_FailureMessageIncludesGotIndexerPrefix() // Pins `() => $"got indexer {parametersDescription()}"` in the public memberId-keyed // IndexerGot expression body against the string-removal mutation. FastMockInteractions store = new(1); - store.InstallIndexerGetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -606,7 +631,8 @@ public async Task Set_FailureMessageIncludesSetIndexerPrefix() // Pins `() => $"set indexer {parametersDescription()} to {value}"` against the // string-removal mutation. FastMockInteractions store = new(1); - store.InstallIndexerSetter(0); + store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -627,7 +653,8 @@ public async Task Set_WithBufferAndMatchingRecord_PredicateMatchesByValue() // Pins the local Predicate body in the memberId-keyed IndexerSet overload — the // block-removal mutant would turn it into `return default;` and skip every record. FastMockInteractions store = new(1); - FastIndexerSetterBuffer buffer = store.InstallIndexerSetter(0); + FastIndexerSetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerSetterBuffer(f)); buffer.Append(1, "x"); MockRegistry registry = new(MockBehavior.Default, store); @@ -651,7 +678,8 @@ public async Task FailureMessageIncludesSubscribedToEventPrefix() { // Pins the expectation factory `() => $"subscribed to event {eventName...}"`. FastMockInteractions store = new(1); - store.InstallEventSubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -669,7 +697,8 @@ public async Task WithBufferAndRecord_PredicateMatchesEveryRecord() // Pins `static _ => true` in the memberId-keyed SubscribedTo. Mutating to `false` // would drop every record and fail Once(). FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventSubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Subscribe)); buffer.Append("Tick", null, typeof(object).GetMethod(nameof(ToString))!); MockRegistry registry = new(MockBehavior.Default, store); @@ -712,7 +741,8 @@ public sealed class UnsubscribedFromFastPathTests public async Task FailureMessageIncludesUnsubscribedFromEventPrefix() { FastMockInteractions store = new(1); - store.InstallEventUnsubscribe(0); + store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); MockRegistry registry = new(MockBehavior.Default, store); void Act() @@ -728,7 +758,8 @@ await That(Act).Throws() public async Task WithBufferAndRecord_PredicateMatchesEveryRecord() { FastMockInteractions store = new(1); - FastEventBuffer buffer = store.InstallEventUnsubscribe(0); + FastEventBuffer buffer = store.GetOrCreateBuffer(0, + static f => new FastEventBuffer(f, FastEventBufferKind.Unsubscribe)); buffer.Append("Tick", null, typeof(object).GetMethod(nameof(ToString))!); MockRegistry registry = new(MockBehavior.Default, store); diff --git a/Tests/Mockolate.Tests/Verify/VerificationResultMutationTests.cs b/Tests/Mockolate.Tests/Verify/VerificationResultMutationTests.cs index 4502daac..39824856 100644 --- a/Tests/Mockolate.Tests/Verify/VerificationResultMutationTests.cs +++ b/Tests/Mockolate.Tests/Verify/VerificationResultMutationTests.cs @@ -65,7 +65,8 @@ public async Task AwaitableVerifyCount_NoFastCountSource_AfterSuccess_MarksMatch // IndexerGot(memberId, ...) returns a VerificationResult with a buffer but no fast-count // source, so wrapping it with .Within(...) walks exactly that branch. FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1); MockRegistry registry = new(MockBehavior.Default, store); @@ -95,7 +96,7 @@ public async Task CollectMatching_WithMultipleRecordsOutOfSeqOrder_SortsBySeqBef (1L, rec1), (3L, rec3), ]); - store.InstallBuffer(0, buffer); + store.Buffers[0] = buffer; MockRegistry registry = new(MockBehavior.Default, store); VerificationResult.IgnoreParameters result = @@ -123,7 +124,8 @@ public async Task SyncVerifyCount_NoFastCountSource_AfterSuccess_MarksMatchingIn // Pins the `_interactions.Verified(matchingInteractions);` call inside the non-Awaitable // IFastVerifyCountResult.VerifyCount second branch (when `_fastCountSource is null`). FastMockInteractions store = new(1); - FastIndexerGetterBuffer buffer = store.InstallIndexerGetter(0); + FastIndexerGetterBuffer buffer = store.GetOrCreateBuffer>(0, + static f => new FastIndexerGetterBuffer(f)); buffer.Append(1); MockRegistry registry = new(MockBehavior.Default, store);