diff --git a/Source/Mockolate.SourceGenerators/Entities/Type.cs b/Source/Mockolate.SourceGenerators/Entities/Type.cs index 30dadf87..e32f5a7d 100644 --- a/Source/Mockolate.SourceGenerators/Entities/Type.cs +++ b/Source/Mockolate.SourceGenerators/Entities/Type.cs @@ -31,6 +31,11 @@ internal Type(ITypeSymbol typeSymbol) .ToArray()); } + if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol) + { + ElementType = From(arrayTypeSymbol.ElementType); + } + SpecialGenericType = typeSymbol.GetSpecialType(); SpecialType = typeSymbol.SpecialType; CanBeNullable = typeSymbol.NullableAnnotation == NullableAnnotation.Annotated || @@ -53,6 +58,11 @@ typeSymbol is INamedTypeSymbol public SpecialGenericType SpecialGenericType { get; } public EquatableArray? TupleTypes { get; } public EquatableArray? GenericTypeParameters { get; } + + /// + /// The element type when this type is an array (e.g. bool for bool[]); otherwise . + /// + public Type? ElementType { get; } public string? Namespace { get; } internal static Type Void { get; } = new("void"); diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs index 1ea8c81b..9230cda4 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs @@ -3235,6 +3235,12 @@ bool MethodPredicate(Method method) { AppendMethodSetupDefinition(sb, @class, method, false, hasOverloadResolutionPriority: hasOverloadResolutionPriority); + if (TryGetPerElementParamsParameter(method)) + { + AppendMethodSetupDefinition(sb, @class, method, false, + hasOverloadResolutionPriority: hasOverloadResolutionPriority, perElementParams: true); + } + if (method.Parameters.Count <= MaxExplicitParameters) { foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters)) @@ -3312,9 +3318,49 @@ private static void AppendOverloadDifferentiatorRemark(StringBuilder sb, sb.AppendXmlRemarks(text); } + /// + /// Detects whether ends in a params T[] parameter that can carry a + /// per-element matcher overload. The element type must flow through the regular IParameter<T> + /// pipeline; ref-struct element types are intentionally not supported, as they cannot satisfy + /// IParameter<T>. + /// + private static bool TryGetPerElementParamsParameter(Method method) + { + if (method.Parameters.Count == 0) + { + return false; + } + + MethodParameter last = method.Parameters.AsArray()[method.Parameters.Count - 1]; + if (!last.IsParams || last.Type.ElementType is null || last.NeedsRefStructPipeline()) + { + return false; + } + + return true; + } + + /// + /// True when marks the trailing params T[] parameter as a + /// literal value. Such overloads render the parameter as params T[] and match it element-wise + /// by value (via It.SequenceEquals) rather than by whole-array reference equality. + /// + private static bool HasParamsValueParameter(Method method, bool[]? valueFlags) + { + if (valueFlags is null || method.Parameters.Count == 0) + { + return false; + } + + int last = method.Parameters.Count - 1; + MethodParameter parameter = method.Parameters.AsArray()[last]; + return valueFlags[last] && parameter.IsParams && parameter.Type.ElementType is not null && + !parameter.NeedsRefStructPipeline(); + } + private static void AppendMethodSetupDefinition(StringBuilder sb, Class @class, Method method, bool useParameters, string? methodNameOverride = null, bool[]? valueFlags = null, - bool hasOverloadResolutionPriority = false) + bool hasOverloadResolutionPriority = false, bool perElementParams = false) { // Methods using a generic type parameter that declares `allows ref struct` cannot expose // a setup surface: IReturnMethodSetup / IVoidMethodSetup do not carry the same @@ -3478,8 +3524,19 @@ private static void AppendMethodSetupDefinition(StringBuilder sb, Class @class, } bool isValueParam = valueFlags?[i] == true; - if (isValueParam) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) + { + sb.Append("params global::Mockolate.Parameters.IParameter<") + .Append(parameter.Type.ElementType.Fullname).Append(">[] ").Append(parameter.Name); + } + else if (isValueParam) { + if (parameter.IsParams && parameter.Type.ElementType is not null) + { + sb.Append("params "); + } + sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name); } else @@ -3645,6 +3702,12 @@ bool MethodPredicate(Method method) { AppendMethodSetupImplementation(sb, method, mockRegistryName, setupName, false, memberIds, memberIdPrefix, scopeExpression: scopeExpression); + if (TryGetPerElementParamsParameter(method)) + { + AppendMethodSetupImplementation(sb, method, mockRegistryName, setupName, false, + memberIds, memberIdPrefix, scopeExpression: scopeExpression, perElementParams: true); + } + if (method.Parameters.Count <= MaxExplicitParameters) { foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters)) @@ -3674,7 +3737,7 @@ private static void AppendMethodSetupImplementation(StringBuilder sb, Method met string setupName, bool useParameters, MemberIdTable memberIds, string memberIdPrefix, string? methodNameOverride = null, bool[]? valueFlags = null, - string? scopeExpression = null) + string? scopeExpression = null, bool perElementParams = false) { // Setup-side carve-out: methods using a generic type parameter that declares // `allows ref struct` have no setup interface declaration (see @@ -3773,8 +3836,19 @@ private static void AppendMethodSetupImplementation(StringBuilder sb, Method met } bool isValueParam = valueFlags?[i] == true; - if (isValueParam) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) { + sb.Append("params global::Mockolate.Parameters.IParameter<") + .Append(parameter.Type.ElementType.Fullname).Append(">[] ").Append(parameter.Name); + } + else if (isValueParam) + { + if (parameter.IsParams && parameter.Type.ElementType is not null) + { + sb.Append("params "); + } + sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name); } else @@ -3863,8 +3937,11 @@ private static void AppendMethodSetupImplementation(StringBuilder sb, Method met // skip the per-parameter IParameterMatch allocations that WithParameterCollection // would otherwise force via It.IsValue(...). Gated to 1..4 parameters because that is // the arity range covered by the WithLiteralValues nested types. + // A params value parameter matches element-wise by value (It.SequenceEquals), which the + // reference-equality WithLiteralValues fast path cannot express — force the collection path. bool useLiteralValues = valueFlags is { Length: > 0 and <= MaxExplicitParameters, } && valueFlags.All(x => x) && + !HasParamsValueParameter(method, valueFlags) && !method.Parameters.Any(p => p.RefKind == RefKind.Out || p.RefKind == RefKind.Ref || p.RefKind == RefKind.RefReadOnlyParameter); @@ -3887,9 +3964,27 @@ private static void AppendMethodSetupImplementation(StringBuilder sb, Method met foreach (MethodParameter parameter in method.Parameters) { sb.Append(", "); - if (valueFlags?[j] == true) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) { - AppendNamedValueParameter(sb, parameter); + sb.Append("new global::Mockolate.Parameters.ParamsArrayParameterMatch<") + .Append(parameter.Type.ElementType.Fullname).Append(">(").Append(parameter.Name) + .Append(")"); + } + else if (valueFlags?[j] == true) + { + if (parameter.IsParams && parameter.Type.ElementType is not null) + { + // params value parameter: match element-wise by value via It.SequenceEquals. + sb.Append("CovariantParameterAdapter<").Append(parameter.Type.Fullname) + .Append(">.Wrap(global::Mockolate.It.SequenceEquals<") + .Append(parameter.Type.ElementType.Fullname).Append(">(").Append(parameter.Name) + .Append("))"); + } + else + { + AppendNamedValueParameter(sb, parameter); + } } else { @@ -4987,6 +5082,12 @@ bool MethodPredicate(Method method) { AppendMethodVerifyDefinition(sb, method, verifyName, false, hasOverloadResolutionPriority: hasOverloadResolutionPriority); + if (TryGetPerElementParamsParameter(method)) + { + AppendMethodVerifyDefinition(sb, method, verifyName, false, + hasOverloadResolutionPriority: hasOverloadResolutionPriority, perElementParams: true); + } + if (method.Parameters.Count <= MaxExplicitParameters) { foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters)) @@ -5029,7 +5130,7 @@ bool MethodPredicate(Method method) private static void AppendMethodVerifyDefinition(StringBuilder sb, Method method, string verifyName, bool useParameters, string? methodNameOverride = null, bool[]? valueFlags = null, - bool hasOverloadResolutionPriority = false) + bool hasOverloadResolutionPriority = false, bool perElementParams = false) { // For methods with ref-struct parameters, skip Verify emission entirely. The // VerificationResult pipeline takes IParameter? matchers that then feed into @@ -5115,8 +5216,19 @@ private static void AppendMethodVerifyDefinition(StringBuilder sb, Method method } bool isValueParam = valueFlags?[i] == true; - if (isValueParam) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) + { + sb.Append("params global::Mockolate.Parameters.IParameter<") + .Append(parameter.Type.ElementType.Fullname).Append(">[] ").Append(parameter.Name); + } + else if (isValueParam) { + if (parameter.IsParams && parameter.Type.ElementType is not null) + { + sb.Append("params "); + } + sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name); } else @@ -5255,6 +5367,12 @@ bool MethodPredicate(Method method) { AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false, memberIds, memberIdPrefix, useFastBuffers); + if (TryGetPerElementParamsParameter(method)) + { + AppendMethodVerifyImplementation(sb, method, mockRegistryName, verifyName, false, + memberIds, memberIdPrefix, useFastBuffers, perElementParams: true); + } + if (method.Parameters.Count <= MaxExplicitParameters) { foreach (bool[] valueFlags in GenerateValueFlagCombinations(method.Parameters)) @@ -5317,7 +5435,7 @@ bool MethodPredicate(Method method) private static void AppendMethodVerifyImplementation(StringBuilder sb, Method method, string mockRegistryName, string verifyName, bool useParameters, MemberIdTable memberIds, string memberIdPrefix, bool useFastBuffers, - string? methodNameOverride = null, bool[]? valueFlags = null) + string? methodNameOverride = null, bool[]? valueFlags = null, bool perElementParams = false) #pragma warning restore S107 { // Mirror the AppendMethodVerifyDefinition short-circuit for ref-struct signatures. @@ -5355,8 +5473,19 @@ private static void AppendMethodVerifyImplementation(StringBuilder sb, Method me } bool isValueParam = valueFlags?[i] == true; - if (isValueParam) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) + { + sb.Append("params global::Mockolate.Parameters.IParameter<") + .Append(parameter.Type.ElementType.Fullname).Append(">[] ").Append(parameter.Name); + } + else if (isValueParam) { + if (parameter.IsParams && parameter.Type.ElementType is not null) + { + sb.Append("params "); + } + sb.Append(parameter.ToNullableType()).Append(' ').Append(parameter.Name); } else @@ -5395,8 +5524,13 @@ private static void AppendMethodVerifyImplementation(StringBuilder sb, Method me bool canUseLiteralVerify = baseEligible && valueFlags is { Length: > 0 and <= 4, } && - valueFlags.All(x => x); - bool canUseTypedVerify = useFastForMethod + valueFlags.All(x => x) && + !HasParamsValueParameter(method, valueFlags); + // The per-element params overload passes a `params IParameter[]` argument, which neither the + // literal nor the typed fast path can render (both assume a whole-array IParameter). Route it + // through the slow predicate path, where the composite matcher is built explicitly. + bool canUseTypedVerify = !perElementParams + && useFastForMethod && !useParameters && method.Parameters.Count <= 4 && (method.GenericParameters is null || method.GenericParameters.Value.Count == 0) @@ -5491,10 +5625,19 @@ private static void AppendMethodVerifyImplementation(StringBuilder sb, Method me sb.AppendLine().Append("\t\t\t\t"); bool isValueParam = valueFlags?[i] == true; - if (isValueParam) + if (perElementParams && parameter.IsParams && + parameter.Type.ElementType is not null) + { + sb.Append("(new global::Mockolate.Parameters.ParamsArrayParameterMatch<") + .Append(parameter.Type.ElementType.Fullname).Append(">(").Append(parameter.Name) + .Append(").Matches(__i.Parameter").Append(i + 1).Append("))"); + } + else if (isValueParam) { sb.Append( - $"(global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals({parameter.Name}, __i.Parameter{i + 1}))"); + parameter.IsParams && parameter.Type.ElementType is not null + ? $"(CovariantParameterAdapter<{parameter.Type.Fullname}>.Wrap(global::Mockolate.It.SequenceEquals<{parameter.Type.ElementType.Fullname}>({parameter.Name})).Matches(__i.Parameter{i + 1}))" + : $"(global::System.Collections.Generic.EqualityComparer<{parameter.ToTypeOrWrapper()}>.Default.Equals({parameter.Name}, __i.Parameter{i + 1}))"); } else if (parameter.RefKind == RefKind.Out || parameter.RefKind == RefKind.Ref || parameter.RefKind == RefKind.RefReadOnlyParameter) diff --git a/Source/Mockolate/It.Contains.cs b/Source/Mockolate/It.Contains.cs index 4856160f..6742647b 100644 --- a/Source/Mockolate/It.Contains.cs +++ b/Source/Mockolate/It.Contains.cs @@ -75,6 +75,11 @@ IContainsParameter IContainsParameter.Using(IEqualityComparer comparer, /// protected override bool MatchesCollection(IEnumerable value) { + if (value is null) + { + return false; + } + IEqualityComparer comparer = _comparer ?? EqualityComparer.Default; return value.Contains(item, comparer); } diff --git a/Source/Mockolate/It.SequenceEquals.cs b/Source/Mockolate/It.SequenceEquals.cs index 00479ce1..852947d1 100644 --- a/Source/Mockolate/It.SequenceEquals.cs +++ b/Source/Mockolate/It.SequenceEquals.cs @@ -72,6 +72,11 @@ ISequenceEqualsParameter ISequenceEqualsParameter.Using(IEqualityComparer< /// protected override bool MatchesCollection(IEnumerable value) { + if (value is null) + { + return false; + } + IEqualityComparer comparer = _comparer ?? EqualityComparer.Default; return value.SequenceEqual(expected, comparer); } diff --git a/Source/Mockolate/Parameters/ParamsArrayParameterMatch.cs b/Source/Mockolate/Parameters/ParamsArrayParameterMatch.cs new file mode 100644 index 00000000..40dc6c6b --- /dev/null +++ b/Source/Mockolate/Parameters/ParamsArrayParameterMatch.cs @@ -0,0 +1,66 @@ +using System.Linq; + +namespace Mockolate.Parameters; + +/// +/// Matches a params array argument element-by-element against a set of per-element matchers. +/// The recorded array matches when its length equals the number of matchers and each element +/// satisfies the matcher at the same position. +/// +/// +/// Generated Setup/Verify overloads for params T[] methods wrap the per-element +/// matchers into a single instance of this type, which then flows through the regular whole-array +/// pipeline (where T is array). +/// +/// The element type of the params array. +#if !DEBUG +[System.Diagnostics.DebuggerNonUserCode] +#endif +public sealed class ParamsArrayParameterMatch : IParameterMatch +{ + private readonly IParameter[] _matchers; + + /// + /// Initializes a new from the per-element + /// . + /// + public ParamsArrayParameterMatch(params IParameter[] matchers) + => _matchers = matchers; + + /// + public bool Matches(TElement[] value) + { + if (value is null || value.Length != _matchers.Length) + { + return false; + } + + for (int i = 0; i < _matchers.Length; i++) + { + if (_matchers[i] is null || !_matchers[i].Matches(value[i])) + { + return false; + } + } + + return true; + } + + /// + public void InvokeCallbacks(TElement[] value) + { + if (value is null || value.Length != _matchers.Length) + { + return; + } + + for (int i = 0; i < _matchers.Length; i++) + { + _matchers[i]?.InvokeCallbacks(value[i]); + } + } + + /// + public override string ToString() + => $"[{string.Join(", ", _matchers.Select(m => m?.ToString() ?? "null"))}]"; +} diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt index 9cd87d61..e6e1a560 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt @@ -1042,6 +1042,13 @@ namespace Mockolate.Parameters public interface IVerifyReadOnlySpanParameter : Mockolate.Parameters.IParameter, Mockolate.Parameters.IParameterWithCallback>, Mockolate.Parameters.IParameter>, Mockolate.Parameters.IReadOnlySpanParameter { } public interface IVerifyRefParameter { } public interface IVerifySpanParameter : Mockolate.Parameters.IParameter, Mockolate.Parameters.IParameterWithCallback>, Mockolate.Parameters.IParameter>, Mockolate.Parameters.ISpanParameter { } + public sealed class ParamsArrayParameterMatch : Mockolate.Parameters.IParameterMatch + { + public ParamsArrayParameterMatch(params Mockolate.Parameters.IParameter[] matchers) { } + public void InvokeCallbacks(TElement[] value) { } + public bool Matches(TElement[] value) { } + public override string ToString() { } + } } namespace Mockolate.Setup { diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt index b4481c54..8cc498c1 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt @@ -1000,6 +1000,13 @@ namespace Mockolate.Parameters public interface IVerifyReadOnlySpanParameter : Mockolate.Parameters.IParameter, Mockolate.Parameters.IParameterWithCallback>, Mockolate.Parameters.IParameter>, Mockolate.Parameters.IReadOnlySpanParameter { } public interface IVerifyRefParameter { } public interface IVerifySpanParameter : Mockolate.Parameters.IParameter, Mockolate.Parameters.IParameterWithCallback>, Mockolate.Parameters.IParameter>, Mockolate.Parameters.ISpanParameter { } + public sealed class ParamsArrayParameterMatch : Mockolate.Parameters.IParameterMatch + { + public ParamsArrayParameterMatch(params Mockolate.Parameters.IParameter[] matchers) { } + public void InvokeCallbacks(TElement[] value) { } + public bool Matches(TElement[] value) { } + public override string ToString() { } + } } namespace Mockolate.Setup { diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt index 04ae5b53..b17771d3 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt @@ -943,6 +943,13 @@ namespace Mockolate.Parameters } public interface IVerifyOutParameter { } public interface IVerifyRefParameter { } + public sealed class ParamsArrayParameterMatch : Mockolate.Parameters.IParameterMatch + { + public ParamsArrayParameterMatch(params Mockolate.Parameters.IParameter[] matchers) { } + public void InvokeCallbacks(TElement[] value) { } + public bool Matches(TElement[] value) { } + public override string ToString() { } + } } namespace Mockolate.Setup { 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 fe14a1e4..0bc6de8c 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 @@ -2350,6 +2350,14 @@ public void SeventeenVoid(int a1, int a2, int a3, int a4, int a5, int a6, int a7 return methodSetup; } + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), new global::Mockolate.Parameters.ParamsArrayParameterMatch(tail)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, methodSetup); + return methodSetup; + } + /// global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, global::Mockolate.Parameters.IParameter? tail) { @@ -2359,17 +2367,17 @@ public void SeventeenVoid(int a1, int a2, int a3, int a4, int a5, int a6, int a7 } /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail) + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail) { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(tail)); + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail))); this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, methodSetup); return methodSetup; } /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, int[] tail) + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, params int[] tail) { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(c), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(tail)); + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(c), CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail))); this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, methodSetup); return methodSetup; } @@ -2982,6 +2990,13 @@ void IMockRaiseOnIComprehensiveInterface.CustomEvent(global::Mockolate.Parameter (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && (tail is not null ? CovariantParameterAdapter.Wrap(tail).Matches(__i.Parameter4) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter4, default(int[]))), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => + (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && + (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && + (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && + (new global::Mockolate.Parameters.ParamsArrayParameterMatch(tail).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + /// global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, global::Mockolate.Parameters.IParameter? tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && @@ -2989,19 +3004,19 @@ void IMockRaiseOnIComprehensiveInterface.CustomEvent(global::Mockolate.Parameter (global::System.Collections.Generic.EqualityComparer.Default.Equals(c, __i.Parameter3)) && (tail is not null ? CovariantParameterAdapter.Wrap(tail).Matches(__i.Parameter4) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter4, default(int[]))), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// - global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail) + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(tail, __i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + (CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail)).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// - global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, int[] tail) + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, params int[] tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && (global::System.Collections.Generic.EqualityComparer.Default.Equals(c, __i.Parameter3)) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(tail, __i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + (CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail)).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithDefaults(global::Mockolate.Parameters.IParameters parameters) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithDefaults, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithDefaults", __i => parameters switch @@ -3505,6 +3520,13 @@ private sealed class VerifyMonitorIComprehensiveInterface(global::Mockolate.Mock (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && (tail is not null ? CovariantParameterAdapter.Wrap(tail).Matches(__i.Parameter4) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter4, default(int[]))), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail) + => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => + (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && + (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && + (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && + (new global::Mockolate.Parameters.ParamsArrayParameterMatch(tail).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + /// global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, global::Mockolate.Parameters.IParameter? tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && @@ -3512,19 +3534,19 @@ private sealed class VerifyMonitorIComprehensiveInterface(global::Mockolate.Mock (global::System.Collections.Generic.EqualityComparer.Default.Equals(c, __i.Parameter3)) && (tail is not null ? CovariantParameterAdapter.Wrap(tail).Matches(__i.Parameter4) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter4, default(int[]))), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// - global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail) + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && (c is not null ? CovariantParameterAdapter.Wrap(c).Matches(__i.Parameter3) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter3, default(long))) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(tail, __i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + (CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail)).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// - global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, int[] tail) + global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, params int[] tail) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", __i => (a is global::Mockolate.Parameters.IParameterMatch aMatch ? aMatch.Matches(__i.Parameter1) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter1, default(int))) && (b is global::Mockolate.Parameters.IParameterMatch bMatch ? bMatch.Matches(__i.Parameter2) : global::System.Collections.Generic.EqualityComparer.Default.Equals(__i.Parameter2, default(string))) && (global::System.Collections.Generic.EqualityComparer.Default.Equals(c, __i.Parameter3)) && - (global::System.Collections.Generic.EqualityComparer.Default.Equals(tail, __i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); + (CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail)).Matches(__i.Parameter4)), () => $"WithModifiers({a}, {b}, {c}, {tail})"); /// global::Mockolate.Verify.VerificationResult IMockVerifyForIComprehensiveInterface.WithDefaults(global::Mockolate.Parameters.IParameters parameters) => this.MockRegistry.VerifyMethod>(this, global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithDefaults, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithDefaults", __i => parameters switch @@ -4066,6 +4088,14 @@ public MockInScenarioForIComprehensiveInterface(global::Mockolate.MockRegistry m return methodSetup; } + /// + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail) + { + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), new global::Mockolate.Parameters.ParamsArrayParameterMatch(tail)); + this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, _scenarioName, methodSetup); + return methodSetup; + } + /// global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, global::Mockolate.Parameters.IParameter? tail) { @@ -4075,17 +4105,17 @@ public MockInScenarioForIComprehensiveInterface(global::Mockolate.MockRegistry m } /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail) + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail) { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(tail)); + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)(c ?? global::Mockolate.It.IsNull("null")), CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail))); this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, _scenarioName, methodSetup); return methodSetup; } /// - global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, int[] tail) + global::Mockolate.Setup.IVoidMethodSetupWithCallback global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, params int[] tail) { - var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(c), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(tail)); + var methodSetup = new global::Mockolate.Setup.VoidMethodSetup.WithParameterCollection(MockRegistry, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.WithModifiers", (global::Mockolate.Parameters.IParameterMatch)(a), (global::Mockolate.Parameters.IParameterMatch)(b), (global::Mockolate.Parameters.IParameterMatch)global::Mockolate.It.IsValue(c), CovariantParameterAdapter.Wrap(global::Mockolate.It.SequenceEquals(tail))); this.MockRegistry.SetupMethod(global::Mockolate.Mock.IComprehensiveInterface.MemberId_WithModifiers, _scenarioName, methodSetup); return methodSetup; } @@ -4747,6 +4777,15 @@ internal interface IMockSetupForIComprehensiveInterface [global::System.Runtime.CompilerServices.OverloadResolutionPriority(4)] global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, global::Mockolate.Parameters.IParameter? tail); + /// + /// Setup for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(4)] + global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail); + /// /// Setup for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . /// @@ -4763,7 +4802,7 @@ internal interface IMockSetupForIComprehensiveInterface /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for , , . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(3)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail); + global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail); /// /// Setup for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . @@ -4772,7 +4811,7 @@ internal interface IMockSetupForIComprehensiveInterface /// This overload accepts a direct value for , (equivalent to It.Is<T>(value)) and an It matcher for , . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, int[] tail); + global::Mockolate.Setup.IVoidMethodSetupWithCallback WithModifiers(global::Mockolate.Parameters.IRefParameter a, global::Mockolate.Parameters.IOutParameter b, long c, params int[] tail); /// /// Setup for the method WithDefaults(int, MyEnum, decimal, float, char, string?, MyStruct) with the given . @@ -5342,6 +5381,15 @@ internal interface IMockVerifyForIComprehensiveInterface [global::System.Runtime.CompilerServices.OverloadResolutionPriority(4)] global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, global::Mockolate.Parameters.IParameter? tail); + /// + /// Verify invocations for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . + /// + /// + /// This overload takes It argument matchers (e.g. It.IsAny<T>(), It.Is<T>(value)) for every parameter. + /// + [global::System.Runtime.CompilerServices.OverloadResolutionPriority(4)] + global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params global::Mockolate.Parameters.IParameter[] tail); + /// /// Verify invocations for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . /// @@ -5358,7 +5406,7 @@ internal interface IMockVerifyForIComprehensiveInterface /// This overload accepts a direct value for (equivalent to It.Is<T>(value)) and an It matcher for , , . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(3)] - global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, int[] tail); + global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, global::Mockolate.Parameters.IParameter? c, params int[] tail); /// /// Verify invocations for the method WithModifiers(ref int, out string, in long, int[]) with the given , , , . @@ -5367,7 +5415,7 @@ internal interface IMockVerifyForIComprehensiveInterface /// This overload accepts a direct value for , (equivalent to It.Is<T>(value)) and an It matcher for , . /// [global::System.Runtime.CompilerServices.OverloadResolutionPriority(2)] - global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, int[] tail); + global::Mockolate.Verify.VerificationResult WithModifiers(global::Mockolate.Parameters.IVerifyRefParameter a, global::Mockolate.Parameters.IVerifyOutParameter b, long c, params int[] tail); /// /// Verify invocations for the method WithDefaults(int, MyEnum, decimal, float, char, string?, MyStruct) with the given . diff --git a/Tests/Mockolate.Tests/ItTests.ContainsTests.cs b/Tests/Mockolate.Tests/ItTests.ContainsTests.cs index 99ab0319..2fbb9071 100644 --- a/Tests/Mockolate.Tests/ItTests.ContainsTests.cs +++ b/Tests/Mockolate.Tests/ItTests.ContainsTests.cs @@ -157,6 +157,16 @@ public async Task ShouldNotMatchWhenValueIsNull() await That(result).IsFalse(); } + [Fact] + public async Task TypedArrayMatch_WithNullValue_ShouldNotMatch() + { + IParameter sut = It.Contains(5); + + bool result = ((IParameterMatch)sut).Matches(null!); + + await That(result).IsFalse(); + } + [Fact] public async Task ShouldSupportVerify() { diff --git a/Tests/Mockolate.Tests/ItTests.SequenceEqualsTests.cs b/Tests/Mockolate.Tests/ItTests.SequenceEqualsTests.cs index dd93a30f..63df8bb1 100644 --- a/Tests/Mockolate.Tests/ItTests.SequenceEqualsTests.cs +++ b/Tests/Mockolate.Tests/ItTests.SequenceEqualsTests.cs @@ -193,6 +193,16 @@ public async Task WithComparer_ShouldUseComparer() await That(result).IsTrue(); } + [Fact] + public async Task TypedArrayMatch_WithNullValue_ShouldNotMatch() + { + IParameter sut = It.SequenceEquals(1, 2, 3); + + bool result = ((IParameterMatch)sut).Matches(null!); + + await That(result).IsFalse(); + } + public sealed class DoTests { [Fact] diff --git a/Tests/Mockolate.Tests/MockMethods/SetupMethodTests.cs b/Tests/Mockolate.Tests/MockMethods/SetupMethodTests.cs index 3da21d93..8d05dc92 100644 --- a/Tests/Mockolate.Tests/MockMethods/SetupMethodTests.cs +++ b/Tests/Mockolate.Tests/MockMethods/SetupMethodTests.cs @@ -484,7 +484,7 @@ public async Task WithOptionalParameters_ShouldUseOptionalValueWhenNotSet() } [Fact] - public async Task WithParamsParameters_ExplicitArrayArgument_ShouldUseReferenceEquality() + public async Task WithParamsParameters_ExplicitArrayArgument_ShouldUseValueEquality() { IMyService sut = IMyService.CreateMock(); bool[] flags = [true, false,]; @@ -492,9 +492,39 @@ public async Task WithParamsParameters_ExplicitArrayArgument_ShouldUseReferenceE bool result1 = sut.MyMethodWithParams(1, flags); bool result2 = sut.MyMethodWithParams(1, true, false); + bool result3 = sut.MyMethodWithParams(1, false, true); + + await That(result1).IsTrue(); + await That(result2).IsTrue(); + await That(result3).IsFalse(); + } + + [Fact] + public async Task WithParamsParameters_PerElementValues_ShouldMatchElementByElement() + { + IMyService sut = IMyService.CreateMock(); + sut.Mock.Setup.MyMethodWithParams(It.IsAny(), true, false).Returns(true); + + bool result1 = sut.MyMethodWithParams(5, true, false); + bool result2 = sut.MyMethodWithParams(5, true, true); + bool result3 = sut.MyMethodWithParams(5, true); + bool result4 = sut.MyMethodWithParams(5, true, false, true); await That(result1).IsTrue(); await That(result2).IsFalse(); + await That(result3).IsFalse(); + await That(result4).IsFalse(); + } + + [Fact] + public async Task WithParamsParameters_PerElementValues_ShouldSupportVerify() + { + IMyService sut = IMyService.CreateMock(); + + _ = sut.MyMethodWithParams(5, true, false); + + await That(sut.Mock.Verify.MyMethodWithParams(It.IsAny(), true, false)).Once(); + await That(sut.Mock.Verify.MyMethodWithParams(It.IsAny(), true, true)).Never(); } [Fact] @@ -514,6 +544,40 @@ public async Task WithParamsParameters_ShouldSupportParams() await That(result4).IsTrue(); } + [Fact] + public async Task WithParamsParameters_PerElementMatchers_ShouldMatchElementByElement() + { + IMyService sut = IMyService.CreateMock(); + sut.Mock.Setup.MyMethodWithParams(It.IsAny(), It.IsAny(), It.IsFalse()).Returns(true); + + bool result1 = sut.MyMethodWithParams(5); + bool result2 = sut.MyMethodWithParams(5, true); + bool result3 = sut.MyMethodWithParams(5, true, false); + bool result4 = sut.MyMethodWithParams(5, true, true); + bool result5 = sut.MyMethodWithParams(5, true, false, true); + + await That(result1).IsFalse(); + await That(result2).IsFalse(); + await That(result3).IsTrue(); + await That(result4).IsFalse(); + await That(result5).IsFalse(); + } + + [Fact] + public async Task WithParamsParameters_PerElementMatchers_ShouldSupportVerify() + { + IMyService sut = IMyService.CreateMock(); + + _ = sut.MyMethodWithParams(5); + _ = sut.MyMethodWithParams(5, true); + _ = sut.MyMethodWithParams(5, true, false); + _ = sut.MyMethodWithParams(5, true, true); + _ = sut.MyMethodWithParams(5, true, false, true); + + await That(sut.Mock.Verify.MyMethodWithParams( + It.IsAny(), It.IsAny(), It.IsFalse())).Once(); + } + [Fact] public async Task WithRefReadonlyParameter_ShouldUseSetup() { diff --git a/Tests/Mockolate.Tests/Parameters/ParamsArrayParameterMatchTests.cs b/Tests/Mockolate.Tests/Parameters/ParamsArrayParameterMatchTests.cs new file mode 100644 index 00000000..214240c3 --- /dev/null +++ b/Tests/Mockolate.Tests/Parameters/ParamsArrayParameterMatchTests.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using Mockolate.Parameters; + +namespace Mockolate.Tests.Parameters; + +public sealed class ParamsArrayParameterMatchTests +{ + [Fact] + public async Task Matches_WhenLengthMatchesAndAllElementsSatisfy_ShouldReturnTrue() + { + StubParameter first = new(true, "first"); + StubParameter second = new(true, "second"); + ParamsArrayParameterMatch sut = new(first, second); + + bool result = sut.Matches([1, 2,]); + + await That(result).IsTrue(); + await That(first.MatchedValues).IsEqualTo([1,]); + await That(second.MatchedValues).IsEqualTo([2,]); + } + + [Fact] + public async Task Matches_WhenAnElementFails_ShouldReturnFalse() + { + ParamsArrayParameterMatch sut = new(new StubParameter(true, "first"), new StubParameter(false, "second")); + + bool result = sut.Matches([1, 2,]); + + await That(result).IsFalse(); + } + + [Fact] + public async Task Matches_WhenLengthDiffers_ShouldReturnFalseWithoutInvokingMatchers() + { + StubParameter only = new(true, "only"); + ParamsArrayParameterMatch sut = new(only); + + bool result = sut.Matches([1, 2,]); + + await That(result).IsFalse(); + await That(only.MatchedValues).IsEmpty(); + } + + [Fact] + public async Task Matches_WhenValueIsNull_ShouldReturnFalse() + { + ParamsArrayParameterMatch sut = new(new StubParameter(true, "only")); + + bool result = sut.Matches(null!); + + await That(result).IsFalse(); + } + + [Fact] + public async Task Matches_WhenMatcherElementIsNull_ShouldReturnFalseWithoutThrowing() + { + ParamsArrayParameterMatch sut = new(new StubParameter(true, "first"), null!); + + bool result = sut.Matches([1, 2,]); + + await That(result).IsFalse(); + } + + [Fact] + public async Task InvokeCallbacks_WhenLengthMatches_ShouldInvokeEachMatcher() + { + StubParameter first = new(true, "first"); + StubParameter second = new(true, "second"); + ParamsArrayParameterMatch sut = new(first, second); + + sut.InvokeCallbacks([1, 2,]); + + await That(first.InvokedValues).IsEqualTo([1,]); + await That(second.InvokedValues).IsEqualTo([2,]); + } + + [Fact] + public async Task InvokeCallbacks_WhenLengthDiffers_ShouldNotInvokeMatchers() + { + StubParameter only = new(true, "only"); + ParamsArrayParameterMatch sut = new(only); + + sut.InvokeCallbacks([1, 2,]); + + await That(only.InvokedValues).IsEmpty(); + } + + [Fact] + public async Task InvokeCallbacks_WhenValueIsNull_ShouldNotInvokeMatchers() + { + StubParameter only = new(true, "only"); + ParamsArrayParameterMatch sut = new(only); + + sut.InvokeCallbacks(null!); + + await That(only.InvokedValues).IsEmpty(); + } + + [Fact] + public async Task InvokeCallbacks_WhenMatcherElementIsNull_ShouldSkipItWithoutThrowing() + { + StubParameter first = new(true, "first"); + ParamsArrayParameterMatch sut = new(first, null!); + + sut.InvokeCallbacks([1, 2,]); + + await That(first.InvokedValues).IsEqualTo([1,]); + } + + [Fact] + public async Task ToString_ShouldRenderMatchersInOrder() + { + ParamsArrayParameterMatch sut = new(new StubParameter(true, "first"), new StubParameter(true, "second")); + + await That(sut.ToString()).IsEqualTo("[first, second]"); + } + + [Fact] + public async Task ToString_WithNullMatcher_ShouldRenderNullToken() + { + ParamsArrayParameterMatch sut = new(new StubParameter(true, "first"), null!); + + await That(sut.ToString()).IsEqualTo("[first, null]"); + } + + private sealed class StubParameter(bool matches, string label) : IParameter + { + public List MatchedValues { get; } = []; + public List InvokedValues { get; } = []; + + public bool Matches(object? value) + { + MatchedValues.Add((int)value!); + return matches; + } + + public void InvokeCallbacks(object? value) => InvokedValues.Add((int)value!); + + public override string ToString() => label; + } +}