diff --git a/Benchmarks/Mockolate.Benchmarks/CompleteEventBenchmarks.cs b/Benchmarks/Mockolate.Benchmarks/CompleteEventBenchmarks.cs index 786f6283..66818be1 100644 --- a/Benchmarks/Mockolate.Benchmarks/CompleteEventBenchmarks.cs +++ b/Benchmarks/Mockolate.Benchmarks/CompleteEventBenchmarks.cs @@ -89,7 +89,7 @@ public void Event_NSubstitute() EventHandler handler = (_, _) => { }; mock.SomeEvent += handler; - mock.SomeEvent += Raise.EventWith(null, EventArgs.Empty); + mock.SomeEvent += Raise.EventWith(null!, EventArgs.Empty); mock.Received(1).SomeEvent += Arg.Any(); } diff --git a/Docs/pages/08-analyzers.md b/Docs/pages/08-analyzers.md index b8c75bb6..64c39a78 100644 --- a/Docs/pages/08-analyzers.md +++ b/Docs/pages/08-analyzers.md @@ -66,7 +66,10 @@ implementing it, so the rule still fires. The same applies per accessor. For a property whose accessors differ in accessibility, such as `public abstract string Flavour { get; internal set; }`, an override further down discharges only the inaccessible half. The mock then overrides the accessor it can see and leaves the other one to the -referenced assembly's implementation, so writes through the mock are not intercepted or recorded. +referenced assembly's implementation. Because writes never reach the mock, `Setup` and `Verify` expose +only the getter for such a property, so a write that could never be recorded is not offered for +configuration or verification. See +[properties with only one accessor](setup/properties#properties-with-only-one-accessor) for details. ## Mockolate0003 diff --git a/Docs/pages/setup/01-properties.md b/Docs/pages/setup/01-properties.md index fffa47b7..632a03e5 100644 --- a/Docs/pages/setup/01-properties.md +++ b/Docs/pages/setup/01-properties.md @@ -72,6 +72,57 @@ sut.Mock.Setup.TotalDispensed.OnGet .Do(() => Console.WriteLine("Execute on all odd read interactions")); ``` +## Properties with only one accessor + +The setup and verify surfaces only offer the accessors the mock actually intercepts. +`Register()` and `SkippingBaseClass(…)` stay available on both, but the accessor-specific members do +not: a get-only property has no `OnSet`, and a set-only property has neither `OnGet` nor the +`Returns`/`Throws` read-sequence nor `InitializeWith`, since there is no getter to read the value +back. + +```csharp +public interface IChocolateInventory +{ + int RemainingBars { get; } // no setter + string LastCountedBy { set; } // no getter +} + +IChocolateInventory sut = IChocolateInventory.CreateMock(); + +sut.Mock.Setup.RemainingBars.Returns(3); +sut.Mock.Setup.RemainingBars.Register(); +sut.Mock.Setup.RemainingBars.OnSet… // does not compile +sut.Mock.Setup.RemainingBars.Returns(3).OnSet… // does not compile + +sut.Mock.Setup.LastCountedBy.OnSet.Do(value => { }); +sut.Mock.Setup.LastCountedBy.Register(); +sut.Mock.Setup.LastCountedBy.Returns("Ada")… // does not compile +sut.Mock.Setup.LastCountedBy.InitializeWith("Ada")… // does not compile +sut.Mock.Setup.LastCountedBy.OnSet.Do(value => { }).OnGet… // does not compile +``` + +The verify facade likewise offers the intercepted accessor only: + +```csharp +_ = sut.RemainingBars; +sut.LastCountedBy = "Ada"; + +await That(sut.Mock.Verify.RemainingBars.Got()).Once(); +await That(sut.Mock.Verify.LastCountedBy.Set("Ada")).Once(); + +sut.Mock.Verify.RemainingBars.Set(3)… // does not compile +sut.Mock.Verify.LastCountedBy.Got()… // does not compile +``` + +This also applies when the property declares an accessor the mock cannot see, such as +`{ get; internal set; }` on a type from an assembly that does not grant `InternalsVisibleTo`. Writes +never reach the mock in that case, so configuring or verifying one could only ever report zero +interactions. See [Mockolate0002](../analyzers#mockolate0002) for when such a type is mockable at all. + +Both facades are fully restricted: the fluent builders returned by `Returns`, `Throws`, `Do` and +`TransitionTo` stay on the narrowed surface, so no amount of chaining reaches the accessor the mock +does not intercept. + **Notes:** - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific property (only for class mocks). diff --git a/Source/Mockolate.SourceGenerators/Entities/PropertyAccessors.cs b/Source/Mockolate.SourceGenerators/Entities/PropertyAccessors.cs new file mode 100644 index 00000000..65eaaf08 --- /dev/null +++ b/Source/Mockolate.SourceGenerators/Entities/PropertyAccessors.cs @@ -0,0 +1,8 @@ +namespace Mockolate.SourceGenerators.Entities; + +internal enum PropertyAccessors +{ + Both, + GetOnly, + SetOnly, +} diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs index 9be05474..af310f73 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs @@ -3142,6 +3142,54 @@ private static bool ParametersBlockAllValuesPromotion(EquatableArray + /// Which accessors of the mock actually intercepts, and therefore + /// which setup/verify facade the generated surface exposes. The setup type, the verify type and the + /// verify constructor arguments all derive from this one classification so they cannot disagree. + /// + /// + /// The classification follows the accessors the mock emits a body for, which is exactly what + /// / being non-null means: the property + /// declares the accessor, and it is not an internal/private protected one hidden from + /// the mock's assembly. Other accessibilities are not considered here, so a + /// { get; private set; } property still classifies as . + /// The arm therefore also absorbs degenerate shapes that + /// cannot produce compiling output regardless of the facade chosen. + /// + private static PropertyAccessors GetInterceptedAccessors(Property property) + => (property.Getter, property.Setter) switch + { + (not null, null) => PropertyAccessors.GetOnly, + (null, not null) => PropertyAccessors.SetOnly, + _ => PropertyAccessors.Both, + }; + + /// + /// The setup facade emitted for , narrowed to the accessors classified + /// by . + /// + private static string GetPropertySetupType(Property property) + => GetInterceptedAccessors(property) switch + { + PropertyAccessors.GetOnly => $"global::Mockolate.Setup.IPropertyGetterOnlySetup<{property.Type.Fullname}>", + PropertyAccessors.SetOnly => $"global::Mockolate.Setup.IPropertySetterOnlySetup<{property.Type.Fullname}>", + _ => $"global::Mockolate.Setup.PropertySetup<{property.Type.Fullname}>", + }; + + /// + /// The verify facade emitted for , narrowed to the accessors classified + /// by . + /// + private static string GetPropertyVerifyType(Property property, string verifyName) + => GetInterceptedAccessors(property) switch + { + PropertyAccessors.GetOnly => + $"global::Mockolate.Verify.VerificationPropertyGetterResult<{verifyName}>", + PropertyAccessors.SetOnly => + $"global::Mockolate.Verify.VerificationPropertySetterResult<{verifyName}, {property.Type.Fullname}>", + _ => $"global::Mockolate.Verify.VerificationPropertyResult<{verifyName}, {property.Type.Fullname}>", + }; + private static void DefineSetupInterface(StringBuilder sb, Class @class, MemberType memberType, bool hasOverloadResolutionPriority) { @@ -3154,7 +3202,7 @@ private static void DefineSetupInterface(StringBuilder sb, Class @class, MemberT { sb.AppendXmlSummary( $"Setup for the {property.Type.Fullname.EscapeForXmlDoc()} property ."); - sb.Append("\t\tglobal::Mockolate.Setup.PropertySetup<").Append(property.Type.Fullname).Append("> ") + sb.Append("\t\t").Append(GetPropertySetupType(property)).Append(' ') .Append(property.Name).Append(" { get; }").AppendLine(); sb.AppendLine(); } @@ -3591,8 +3639,8 @@ private static void ImplementSetupInterface(StringBuilder sb, Class @class, stri sb.Append( "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]") .AppendLine(); - sb.Append("\t\tglobal::Mockolate.Setup.PropertySetup<").Append(property.Type.Fullname) - .Append("> global::Mockolate.Mock.").Append(setupName).Append('.').Append(property.Name).AppendLine(); + sb.Append("\t\t").Append(GetPropertySetupType(property)) + .Append(" global::Mockolate.Mock.").Append(setupName).Append('.').Append(property.Name).AppendLine(); sb.Append("\t\t{").AppendLine(); sb.Append("\t\t\tget").AppendLine(); sb.Append("\t\t\t{").AppendLine(); @@ -5013,8 +5061,8 @@ private static void DefineVerifyInterface(StringBuilder sb, Class @class, string { sb.AppendXmlSummary( $"Verify interactions with the {property.Type.Fullname.EscapeForXmlDoc()} property ."); - sb.Append("\t\tglobal::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName).Append(", ") - .Append(property.Type.Fullname).Append("> ").Append(property.Name).Append(" { get; }").AppendLine(); + sb.Append("\t\t").Append(GetPropertyVerifyType(property, verifyName)).Append(' ') + .Append(property.Name).Append(" { get; }").AppendLine(); sb.AppendLine(); } @@ -5287,15 +5335,21 @@ private static void ImplementVerifyInterface(StringBuilder sb, Class @class, str sb.Append( "\t\t[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]") .AppendLine(); - sb.Append("\t\tglobal::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName).Append(", ") - .Append(property.Type.Fullname).Append("> ").Append(verifyName).Append('.').Append(property.Name) + string verifyType = GetPropertyVerifyType(property, verifyName); + // The narrow views take only the member id of the accessor they expose. + string verifyMemberIds = GetInterceptedAccessors(property) switch + { + PropertyAccessors.GetOnly => propertyGetMemberId, + PropertyAccessors.SetOnly => propertySetMemberId, + _ => $"{propertyGetMemberId}, {propertySetMemberId}", + }; + sb.Append("\t\t").Append(verifyType).Append(' ').Append(verifyName).Append('.').Append(property.Name) .AppendLine(); sb.Append("\t\t{").AppendLine(); sb.Append("\t\t\tget").AppendLine(); sb.Append("\t\t\t{").AppendLine(); - sb.Append("\t\t\t\treturn new global::Mockolate.Verify.VerificationPropertyResult<").Append(verifyName) - .Append(", ").Append(property.Type.Fullname).Append(">(this, this.").Append(mockRegistryName) - .Append(", ").Append(propertyGetMemberId).Append(", ").Append(propertySetMemberId).Append(", ") + sb.Append("\t\t\t\treturn new ").Append(verifyType).Append("(this, this.").Append(mockRegistryName) + .Append(", ").Append(verifyMemberIds).Append(", ") .Append(property.GetUniqueNameString()).Append(");").AppendLine(); sb.Append("\t\t\t}").AppendLine(); sb.Append("\t\t}").AppendLine(); diff --git a/Source/Mockolate/Setup/Interfaces.PropertySetup.cs b/Source/Mockolate/Setup/Interfaces.PropertySetup.cs index 6f997f8c..3316c1f2 100644 --- a/Source/Mockolate/Setup/Interfaces.PropertySetup.cs +++ b/Source/Mockolate/Setup/Interfaces.PropertySetup.cs @@ -274,6 +274,76 @@ IPropertySetupReturnBuilder Throws() IPropertySetupReturnBuilder Throws(Func callback); } +/// +/// Setup for a mocked property of type that the mock only reads. +/// +/// +/// Used instead of when the mock has no setter to intercept, either +/// because the property is declared without one or because its setter is not accessible from the +/// mock's assembly. Writes then never reach the mock, so is not +/// offered. +/// +public interface IPropertyGetterOnlySetup +{ + /// + IPropertyGetterOnlyGetterSetup OnGet { get; } + + /// + IPropertyGetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + + /// + IPropertyGetterOnlySetup Register(); + + /// + /// + /// Seeds the value that reads return. Unlike a read-write property there is no setter to update the + /// slot afterwards, so it stays at unless a Returns entry applies. + /// + IPropertyGetterOnlySetup InitializeWith(T value); + + /// + IPropertyGetterOnlySetupReturnBuilder Returns(T returnValue); + + /// + IPropertyGetterOnlySetupReturnBuilder Returns(Func callback); + + /// + IPropertyGetterOnlySetupReturnBuilder Returns(Func callback); + + /// + IPropertyGetterOnlySetupReturnBuilder Throws() + where TException : Exception, new(); + + /// + IPropertyGetterOnlySetupReturnBuilder Throws(Exception exception); + + /// + IPropertyGetterOnlySetupReturnBuilder Throws(Func callback); + + /// + IPropertyGetterOnlySetupReturnBuilder Throws(Func callback); +} + +/// +/// Setup for a mocked property of type that the mock only writes. +/// +/// +/// The write-only counterpart of : the mock has no getter to +/// intercept, so and the Returns/Throws +/// read-sequence are not offered. +/// +public interface IPropertySetterOnlySetup +{ + /// + IPropertySetterOnlySetterSetup OnSet { get; } + + /// + IPropertySetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + + /// + IPropertySetterOnlySetup Register(); +} + /// /// Interface for setting up a property getter with fluent syntax. /// @@ -429,3 +499,130 @@ public interface IPropertySetupReturnWhenBuilder : IPropertySetup /// The outer setup for chaining additional returns/throws. IPropertySetup Only(int times); } + +/// +/// Setup for attaching side-effects to the getter of a property the mock only reads. +/// +/// +/// The counterpart of for : +/// the returned builders stay on the getter-only surface, so chaining can never reach +/// . +/// +public interface IPropertyGetterOnlyGetterSetup +{ + /// + IPropertyGetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertyGetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertyGetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertyGetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); +} + +/// +/// Interface for setting up the getter of a get-only property with fluent syntax. +/// +public interface IPropertyGetterOnlySetupParallelCallbackBuilder : IPropertyGetterOnlySetupCallbackWhenBuilder +{ + /// + IPropertyGetterOnlySetupCallbackWhenBuilder When(Func predicate); +} + +/// +/// Interface for setting up the getter of a get-only property with fluent syntax. +/// +public interface IPropertyGetterOnlySetupCallbackBuilder : IPropertyGetterOnlySetupParallelCallbackBuilder +{ + /// + IPropertyGetterOnlySetupParallelCallbackBuilder InParallel(); +} + +/// +/// Interface for setting up the getter of a get-only property with fluent syntax. +/// +public interface IPropertyGetterOnlySetupCallbackWhenBuilder : IPropertyGetterOnlySetup +{ + /// + IPropertyGetterOnlySetupCallbackWhenBuilder For(int times); + + /// + IPropertyGetterOnlySetup Only(int times); +} + +/// +/// Setup for attaching side-effects to the setter of a property the mock only writes. +/// +/// +/// The counterpart of for : +/// the returned builders stay on the setter-only surface, so chaining can never reach +/// or the Returns/Throws read-sequence. +/// +public interface IPropertySetterOnlySetterSetup +{ + /// + IPropertySetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertySetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertySetterOnlySetupCallbackBuilder Do(Action callback); + + /// + IPropertySetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); +} + +/// +/// Interface for setting up the setter of a set-only property with fluent syntax. +/// +public interface IPropertySetterOnlySetupParallelCallbackBuilder : IPropertySetterOnlySetupCallbackWhenBuilder +{ + /// + IPropertySetterOnlySetupCallbackWhenBuilder When(Func predicate); +} + +/// +/// Interface for setting up the setter of a set-only property with fluent syntax. +/// +public interface IPropertySetterOnlySetupCallbackBuilder : IPropertySetterOnlySetupParallelCallbackBuilder +{ + /// + IPropertySetterOnlySetupParallelCallbackBuilder InParallel(); +} + +/// +/// Interface for setting up the setter of a set-only property with fluent syntax. +/// +public interface IPropertySetterOnlySetupCallbackWhenBuilder : IPropertySetterOnlySetup +{ + /// + IPropertySetterOnlySetupCallbackWhenBuilder For(int times); + + /// + IPropertySetterOnlySetup Only(int times); +} + +/// +/// Interface for setting up a return/throw builder for a get-only property with fluent syntax. +/// +public interface IPropertyGetterOnlySetupReturnBuilder : IPropertyGetterOnlySetupReturnWhenBuilder +{ + /// + IPropertyGetterOnlySetupReturnWhenBuilder When(Func predicate); +} + +/// +/// Interface for setting up a when builder for returns/throws for a get-only property with fluent syntax. +/// +public interface IPropertyGetterOnlySetupReturnWhenBuilder : IPropertyGetterOnlySetup +{ + /// + IPropertyGetterOnlySetupReturnWhenBuilder For(int times); + + /// + IPropertyGetterOnlySetup Only(int times); +} diff --git a/Source/Mockolate/Setup/PropertySetup.cs b/Source/Mockolate/Setup/PropertySetup.cs index 6962fae3..84bedfeb 100644 --- a/Source/Mockolate/Setup/PropertySetup.cs +++ b/Source/Mockolate/Setup/PropertySetup.cs @@ -189,7 +189,11 @@ internal override TResult InvokeGetterFast(MockBehavior behavior, public class PropertySetup : PropertySetup, IPropertyGetterSetupCallbackBuilder, IPropertySetterSetupCallbackBuilder, IPropertySetupReturnBuilder, - IPropertyGetterSetup, IPropertySetterSetup + IPropertyGetterSetup, IPropertySetterSetup, + IPropertyGetterOnlySetup, IPropertySetterOnlySetup, + IPropertyGetterOnlyGetterSetup, IPropertySetterOnlySetterSetup, + IPropertyGetterOnlySetupCallbackBuilder, IPropertySetterOnlySetupCallbackBuilder, + IPropertyGetterOnlySetupReturnBuilder { private readonly MockRegistry _mockRegistry; private readonly string _name; @@ -668,4 +672,235 @@ T Delegate(int _, T p) } #endregion IPropertySetup + + #region Accessor-restricted views + + /// + IPropertyGetterOnlySetup IPropertyGetterOnlySetup.SkippingBaseClass(bool skipBaseClass) + { + SkippingBaseClass(skipBaseClass); + return this; + } + + /// + IPropertyGetterOnlySetup IPropertyGetterOnlySetup.Register() + { + Register(); + return this; + } + + /// + IPropertyGetterOnlySetup IPropertyGetterOnlySetup.InitializeWith(T value) + { + InitializeWith(value); + return this; + } + + /// + IPropertyGetterOnlyGetterSetup IPropertyGetterOnlySetup.OnGet + => this; + + /// + IPropertyGetterOnlySetupCallbackBuilder IPropertyGetterOnlyGetterSetup.Do(Action callback) + { + ((IPropertyGetterSetup)this).Do(callback); + return this; + } + + /// + IPropertyGetterOnlySetupCallbackBuilder IPropertyGetterOnlyGetterSetup.Do(Action callback) + { + ((IPropertyGetterSetup)this).Do(callback); + return this; + } + + /// + IPropertyGetterOnlySetupCallbackBuilder IPropertyGetterOnlyGetterSetup.Do(Action callback) + { + ((IPropertyGetterSetup)this).Do(callback); + return this; + } + + /// + IPropertyGetterOnlySetupParallelCallbackBuilder IPropertyGetterOnlyGetterSetup.TransitionTo(string scenario) + { + ((IPropertyGetterSetup)this).TransitionTo(scenario); + return this; + } + + /// + IPropertyGetterOnlySetupParallelCallbackBuilder IPropertyGetterOnlySetupCallbackBuilder.InParallel() + { + ((IPropertyGetterSetupCallbackBuilder)this).InParallel(); + return this; + } + + /// + IPropertyGetterOnlySetupCallbackWhenBuilder IPropertyGetterOnlySetupParallelCallbackBuilder.When( + Func predicate) + { + ((IPropertyGetterSetupParallelCallbackBuilder)this).When(predicate); + return this; + } + + /// + IPropertyGetterOnlySetupCallbackWhenBuilder IPropertyGetterOnlySetupCallbackWhenBuilder.For(int times) + { + ((IPropertyGetterSetupCallbackWhenBuilder)this).For(times); + return this; + } + + /// + IPropertyGetterOnlySetup IPropertyGetterOnlySetupCallbackWhenBuilder.Only(int times) + { + ((IPropertyGetterSetupCallbackWhenBuilder)this).Only(times); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Returns(T returnValue) + { + Returns(returnValue); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Returns(Func callback) + { + Returns(callback); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Returns(Func callback) + { + Returns(callback); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Throws() + { + Throws(); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Throws(Exception exception) + { + Throws(exception); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Throws(Func callback) + { + Throws(callback); + return this; + } + + /// + IPropertyGetterOnlySetupReturnBuilder IPropertyGetterOnlySetup.Throws(Func callback) + { + Throws(callback); + return this; + } + + /// + IPropertyGetterOnlySetupReturnWhenBuilder IPropertyGetterOnlySetupReturnBuilder.When(Func predicate) + { + ((IPropertySetupReturnBuilder)this).When(predicate); + return this; + } + + /// + IPropertyGetterOnlySetupReturnWhenBuilder IPropertyGetterOnlySetupReturnWhenBuilder.For(int times) + { + ((IPropertySetupReturnWhenBuilder)this).For(times); + return this; + } + + /// + IPropertyGetterOnlySetup IPropertyGetterOnlySetupReturnWhenBuilder.Only(int times) + { + ((IPropertySetupReturnWhenBuilder)this).Only(times); + return this; + } + + /// + IPropertySetterOnlySetup IPropertySetterOnlySetup.SkippingBaseClass(bool skipBaseClass) + { + SkippingBaseClass(skipBaseClass); + return this; + } + + /// + IPropertySetterOnlySetup IPropertySetterOnlySetup.Register() + { + Register(); + return this; + } + + /// + IPropertySetterOnlySetterSetup IPropertySetterOnlySetup.OnSet + => this; + + /// + IPropertySetterOnlySetupCallbackBuilder IPropertySetterOnlySetterSetup.Do(Action callback) + { + ((IPropertySetterSetup)this).Do(callback); + return this; + } + + /// + IPropertySetterOnlySetupCallbackBuilder IPropertySetterOnlySetterSetup.Do(Action callback) + { + ((IPropertySetterSetup)this).Do(callback); + return this; + } + + /// + IPropertySetterOnlySetupCallbackBuilder IPropertySetterOnlySetterSetup.Do(Action callback) + { + ((IPropertySetterSetup)this).Do(callback); + return this; + } + + /// + IPropertySetterOnlySetupParallelCallbackBuilder IPropertySetterOnlySetterSetup.TransitionTo(string scenario) + { + ((IPropertySetterSetup)this).TransitionTo(scenario); + return this; + } + + /// + IPropertySetterOnlySetupParallelCallbackBuilder IPropertySetterOnlySetupCallbackBuilder.InParallel() + { + ((IPropertySetterSetupCallbackBuilder)this).InParallel(); + return this; + } + + /// + IPropertySetterOnlySetupCallbackWhenBuilder IPropertySetterOnlySetupParallelCallbackBuilder.When( + Func predicate) + { + ((IPropertySetterSetupParallelCallbackBuilder)this).When(predicate); + return this; + } + + /// + IPropertySetterOnlySetupCallbackWhenBuilder IPropertySetterOnlySetupCallbackWhenBuilder.For(int times) + { + ((IPropertySetterSetupCallbackWhenBuilder)this).For(times); + return this; + } + + /// + IPropertySetterOnlySetup IPropertySetterOnlySetupCallbackWhenBuilder.Only(int times) + { + ((IPropertySetterSetupCallbackWhenBuilder)this).Only(times); + return this; + } + + #endregion Accessor-restricted views } diff --git a/Source/Mockolate/SetupExtensions.cs b/Source/Mockolate/SetupExtensions.cs index b6f842af..ca5430c3 100644 --- a/Source/Mockolate/SetupExtensions.cs +++ b/Source/Mockolate/SetupExtensions.cs @@ -69,6 +69,65 @@ public IPropertySetup OnlyOnce() => setup.Only(1); } + /// + /// Extensions for setups of get-only properties. + /// + extension(IPropertyGetterOnlySetupReturnWhenBuilder setup) + { + /// + /// Terminates the return/throw sequence by repeating the preceding entry forever instead of cycling + /// back to the first entry once the end is reached. + /// + /// + /// Equivalent to .For(int.MaxValue). Applies only to the preceding Returns(...)/Throws(...) + /// entry; earlier entries in the sequence still run once each in order. + /// + public void Forever() + => setup.For(int.MaxValue); + + /// + /// Deactivates the preceding Returns(...)/Throws(...) entry after a single invocation, + /// so subsequent invocations fall through to the next sequence entry (or to the mock's default behaviour). + /// + /// + /// Equivalent to .Only(1). + /// + public IPropertyGetterOnlySetup OnlyOnce() + => setup.Only(1); + } + + /// + /// Extensions for getter callback setups of get-only properties. + /// + extension(IPropertyGetterOnlySetupCallbackWhenBuilder setup) + { + /// + /// Deactivates the preceding Do(...) callback after a single invocation, so subsequent invocations + /// fall through to the next callback in the sequence (or are skipped). + /// + /// + /// Equivalent to .Only(1). + /// + public IPropertyGetterOnlySetup OnlyOnce() + => setup.Only(1); + } + + /// + /// Extensions for setter callback setups of set-only properties. + /// + extension(IPropertySetterOnlySetupCallbackWhenBuilder setup) + { + /// + /// Deactivates the preceding Do(...) callback after a single invocation, so subsequent invocations + /// fall through to the next callback in the sequence (or are skipped). + /// + /// + /// Equivalent to .Only(1). + /// + public IPropertySetterOnlySetup OnlyOnce() + => setup.Only(1); + } + /// /// Extensions for event subscription callback setups. /// diff --git a/Source/Mockolate/Verify/VerificationPropertyResult.cs b/Source/Mockolate/Verify/VerificationPropertyResult.cs index fff7d0f4..bdffb6bd 100644 --- a/Source/Mockolate/Verify/VerificationPropertyResult.cs +++ b/Source/Mockolate/Verify/VerificationPropertyResult.cs @@ -65,3 +65,86 @@ public VerificationResult Set(TParameter value, => _mockRegistry.VerifyPropertyTyped(_subject, _setMemberId, _propertyName, It.Is(value, doNotPopulateThisValue).AsParameterMatch()); } + +/// +/// Verifications on a property that the mock only reads. +/// +/// +/// Used instead of when the mock has no +/// setter to intercept, either because the property is declared without one or because its setter is +/// not accessible from the mock's assembly. Writes then never reach the mock, so offering +/// Set(...) here would always report zero interactions. The property type is not a type +/// parameter because only Set(...) needs it. +/// +#if !DEBUG +[System.Diagnostics.DebuggerNonUserCode] +#endif +public class VerificationPropertyGetterResult +{ + private readonly int _getMemberId; + private readonly MockRegistry _mockRegistry; + private readonly string _propertyName; + private readonly TSubject _subject; + + /// + /// The verification facade the result is bound to. + /// The mock registry holding the recorded interactions. + /// Member id of the property getter, or -1 when unknown. + /// The simple property name. + public VerificationPropertyGetterResult(TSubject subject, MockRegistry mockRegistry, int getMemberId, + string propertyName) + { + _subject = subject; + _mockRegistry = mockRegistry; + _getMemberId = getMemberId; + _propertyName = propertyName; + } + + /// + public VerificationResult Got() + => _mockRegistry.VerifyPropertyTyped(_subject, _getMemberId, _propertyName); +} + +/// +/// Verifications on a property of type that the mock only writes. +/// +/// +/// The write-only counterpart of : the mock +/// has no getter to intercept, so Got() is not offered. +/// +#if !DEBUG +[System.Diagnostics.DebuggerNonUserCode] +#endif +public class VerificationPropertySetterResult +{ + private readonly MockRegistry _mockRegistry; + private readonly string _propertyName; + private readonly int _setMemberId; + private readonly TSubject _subject; + + /// + /// The verification facade the result is bound to. + /// The mock registry holding the recorded interactions. + /// Member id of the property setter, or -1 when unknown. + /// The simple property name. + public VerificationPropertySetterResult(TSubject subject, MockRegistry mockRegistry, int setMemberId, + string propertyName) + { + _subject = subject; + _mockRegistry = mockRegistry; + _setMemberId = setMemberId; + _propertyName = propertyName; + } + + /// + public VerificationResult Set(IParameter value) + => _mockRegistry.VerifyPropertyTyped(_subject, _setMemberId, _propertyName, value.AsParameterMatch()); + + /// + [OverloadResolutionPriority(1)] + public VerificationResult Set(TParameter value, + [CallerArgumentExpression(nameof(value))] + string doNotPopulateThisValue = "") + => _mockRegistry.VerifyPropertyTyped(_subject, _setMemberId, _propertyName, + It.Is(value, doNotPopulateThisValue).AsParameterMatch()); +} diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt index f82bbcb1..06425391 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt @@ -382,6 +382,19 @@ namespace Mockolate { public Mockolate.Setup.IPropertySetup OnlyOnce() { } } + extension(Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder? setup) + { + public void Forever() { } + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertySetterOnlySetup OnlyOnce() { } + } extension(Mockolate.Setup.IEventSubscriptionSetupCallbackWhenBuilder? setup) { public void Forever() { } @@ -1472,6 +1485,50 @@ namespace Mockolate.Setup string Name { get; } } public interface IMockSetup : Mockolate.IInteractiveMock { } + public interface IPropertyGetterOnlyGetterSetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertyGetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertyGetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnBuilder : Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlyGetterSetup OnGet { get; } + Mockolate.Setup.IPropertyGetterOnlySetup InitializeWith(T value); + Mockolate.Setup.IPropertyGetterOnlySetup Register(); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(T returnValue); + Mockolate.Setup.IPropertyGetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Exception exception); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws() + where TException : System.Exception, new (); + } public interface IPropertyGetterSetupCallbackBuilder : Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder InParallel(); @@ -1492,6 +1549,32 @@ namespace Mockolate.Setup Mockolate.Setup.IPropertyGetterSetupCallbackBuilder Do(System.Action callback); Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder TransitionTo(string scenario); } + public interface IPropertySetterOnlySetterSetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertySetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertySetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertySetterOnlySetup Only(int times); + } + public interface IPropertySetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetterSetup OnSet { get; } + Mockolate.Setup.IPropertySetterOnlySetup Register(); + Mockolate.Setup.IPropertySetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + } public interface IPropertySetterSetupCallbackBuilder : Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder InParallel(); @@ -2308,7 +2391,7 @@ namespace Mockolate.Setup protected abstract void InvokeSetter(TValue value, Mockolate.MockBehavior behavior); protected abstract bool Matches(Mockolate.Interactions.PropertyAccess propertyAccess); } - public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup + public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterOnlyGetterSetup, Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterOnlySetterSetup, Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup { public PropertySetup(Mockolate.MockRegistry mockRegistry, string name) { } public override string Name { get; } @@ -2889,6 +2972,11 @@ namespace Mockolate.Verify public override Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public override Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertyGetterResult + { + public VerificationPropertyGetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int getMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Got() { } + } public class VerificationPropertyResult { public VerificationPropertyResult(TSubject subject, Mockolate.MockRegistry mockRegistry, string propertyName) { } @@ -2897,6 +2985,12 @@ namespace Mockolate.Verify public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertySetterResult + { + public VerificationPropertySetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int setMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } + public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } + } public static class VerificationResultExtensions { extension(Mockolate.Verify.VerificationResult? verificationResult) diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt index dac64b74..9db3d608 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt @@ -365,6 +365,19 @@ namespace Mockolate { public Mockolate.Setup.IPropertySetup OnlyOnce() { } } + extension(Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder? setup) + { + public void Forever() { } + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertySetterOnlySetup OnlyOnce() { } + } extension(Mockolate.Setup.IEventSubscriptionSetupCallbackWhenBuilder? setup) { public void Forever() { } @@ -1430,6 +1443,50 @@ namespace Mockolate.Setup string Name { get; } } public interface IMockSetup : Mockolate.IInteractiveMock { } + public interface IPropertyGetterOnlyGetterSetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertyGetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertyGetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnBuilder : Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlyGetterSetup OnGet { get; } + Mockolate.Setup.IPropertyGetterOnlySetup InitializeWith(T value); + Mockolate.Setup.IPropertyGetterOnlySetup Register(); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(T returnValue); + Mockolate.Setup.IPropertyGetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Exception exception); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws() + where TException : System.Exception, new (); + } public interface IPropertyGetterSetupCallbackBuilder : Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder InParallel(); @@ -1450,6 +1507,32 @@ namespace Mockolate.Setup Mockolate.Setup.IPropertyGetterSetupCallbackBuilder Do(System.Action callback); Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder TransitionTo(string scenario); } + public interface IPropertySetterOnlySetterSetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertySetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertySetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertySetterOnlySetup Only(int times); + } + public interface IPropertySetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetterSetup OnSet { get; } + Mockolate.Setup.IPropertySetterOnlySetup Register(); + Mockolate.Setup.IPropertySetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + } public interface IPropertySetterSetupCallbackBuilder : Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder InParallel(); @@ -2070,7 +2153,7 @@ namespace Mockolate.Setup protected abstract void InvokeSetter(TValue value, Mockolate.MockBehavior behavior); protected abstract bool Matches(Mockolate.Interactions.PropertyAccess propertyAccess); } - public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup + public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterOnlyGetterSetup, Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterOnlySetterSetup, Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup { public PropertySetup(Mockolate.MockRegistry mockRegistry, string name) { } public override string Name { get; } @@ -2443,6 +2526,11 @@ namespace Mockolate.Verify public override Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public override Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertyGetterResult + { + public VerificationPropertyGetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int getMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Got() { } + } public class VerificationPropertyResult { public VerificationPropertyResult(TSubject subject, Mockolate.MockRegistry mockRegistry, string propertyName) { } @@ -2451,6 +2539,12 @@ namespace Mockolate.Verify public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertySetterResult + { + public VerificationPropertySetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int setMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } + public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } + } public static class VerificationResultExtensions { extension(Mockolate.Verify.VerificationResult? verificationResult) diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt index 945ebdd9..47d186ea 100644 --- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt +++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt @@ -312,6 +312,19 @@ namespace Mockolate { public Mockolate.Setup.IPropertySetup OnlyOnce() { } } + extension(Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder? setup) + { + public void Forever() { } + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertyGetterOnlySetup OnlyOnce() { } + } + extension(Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder? setup) + { + public Mockolate.Setup.IPropertySetterOnlySetup OnlyOnce() { } + } extension(Mockolate.Setup.IEventSubscriptionSetupCallbackWhenBuilder? setup) { public void Forever() { } @@ -1373,6 +1386,50 @@ namespace Mockolate.Setup string Name { get; } } public interface IMockSetup : Mockolate.IInteractiveMock { } + public interface IPropertyGetterOnlyGetterSetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertyGetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertyGetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnBuilder : Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder When(System.Func predicate); + } + public interface IPropertyGetterOnlySetupReturnWhenBuilder : Mockolate.Setup.IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder For(int times); + Mockolate.Setup.IPropertyGetterOnlySetup Only(int times); + } + public interface IPropertyGetterOnlySetup + { + Mockolate.Setup.IPropertyGetterOnlyGetterSetup OnGet { get; } + Mockolate.Setup.IPropertyGetterOnlySetup InitializeWith(T value); + Mockolate.Setup.IPropertyGetterOnlySetup Register(); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Returns(T returnValue); + Mockolate.Setup.IPropertyGetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Exception exception); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws(System.Func callback); + Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder Throws() + where TException : System.Exception, new (); + } public interface IPropertyGetterSetupCallbackBuilder : Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder InParallel(); @@ -1393,6 +1450,32 @@ namespace Mockolate.Setup Mockolate.Setup.IPropertyGetterSetupCallbackBuilder Do(System.Action callback); Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder TransitionTo(string scenario); } + public interface IPropertySetterOnlySetterSetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder Do(System.Action callback); + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder TransitionTo(string scenario); + } + public interface IPropertySetterOnlySetupCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder InParallel(); + } + public interface IPropertySetterOnlySetupCallbackWhenBuilder : Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder For(int times); + Mockolate.Setup.IPropertySetterOnlySetup Only(int times); + } + public interface IPropertySetterOnlySetupParallelCallbackBuilder : Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder When(System.Func predicate); + } + public interface IPropertySetterOnlySetup + { + Mockolate.Setup.IPropertySetterOnlySetterSetup OnSet { get; } + Mockolate.Setup.IPropertySetterOnlySetup Register(); + Mockolate.Setup.IPropertySetterOnlySetup SkippingBaseClass(bool skipBaseClass = true); + } public interface IPropertySetterSetupCallbackBuilder : Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetup { Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder InParallel(); @@ -2013,7 +2096,7 @@ namespace Mockolate.Setup protected abstract void InvokeSetter(TValue value, Mockolate.MockBehavior behavior); protected abstract bool Matches(Mockolate.Interactions.PropertyAccess propertyAccess); } - public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup + public class PropertySetup : Mockolate.Setup.PropertySetup, Mockolate.Setup.IPropertyGetterOnlyGetterSetup, Mockolate.Setup.IPropertyGetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnBuilder, Mockolate.Setup.IPropertyGetterOnlySetupReturnWhenBuilder, Mockolate.Setup.IPropertyGetterOnlySetup, Mockolate.Setup.IPropertyGetterSetupCallbackBuilder, Mockolate.Setup.IPropertyGetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertyGetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertyGetterSetup, Mockolate.Setup.IPropertySetterOnlySetterSetup, Mockolate.Setup.IPropertySetterOnlySetupCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterOnlySetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterOnlySetup, Mockolate.Setup.IPropertySetterSetupCallbackBuilder, Mockolate.Setup.IPropertySetterSetupCallbackWhenBuilder, Mockolate.Setup.IPropertySetterSetupParallelCallbackBuilder, Mockolate.Setup.IPropertySetterSetup, Mockolate.Setup.IPropertySetupReturnBuilder, Mockolate.Setup.IPropertySetupReturnWhenBuilder, Mockolate.Setup.IPropertySetup { public PropertySetup(Mockolate.MockRegistry mockRegistry, string name) { } public override string Name { get; } @@ -2372,6 +2455,11 @@ namespace Mockolate.Verify public override Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public override Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertyGetterResult + { + public VerificationPropertyGetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int getMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Got() { } + } public class VerificationPropertyResult { public VerificationPropertyResult(TSubject subject, Mockolate.MockRegistry mockRegistry, string propertyName) { } @@ -2380,6 +2468,12 @@ namespace Mockolate.Verify public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } } + public class VerificationPropertySetterResult + { + public VerificationPropertySetterResult(TSubject subject, Mockolate.MockRegistry mockRegistry, int setMemberId, string propertyName) { } + public Mockolate.Verify.VerificationResult Set(Mockolate.Parameters.IParameter value) { } + public Mockolate.Verify.VerificationResult Set(TParameter value, [System.Runtime.CompilerServices.CallerArgumentExpression("value")] string doNotPopulateThisValue = "") { } + } public static class VerificationResultExtensions { extension(Mockolate.Verify.VerificationResult? verificationResult) diff --git a/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.PropertiesTests.cs b/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.PropertiesTests.cs index c51f297a..b4a66576 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.PropertiesTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.PropertiesTests.cs @@ -6,6 +6,48 @@ public sealed partial class ClassTests { public sealed class PropertiesTests { + [Theory] + [InlineData("string Name { get; }", "Setup.IPropertyGetterOnlySetup", + "Verify.VerificationPropertyGetterResult", + "Setup.PropertySetup", "Verify.VerificationPropertyResult")] + [InlineData("string Name { set; }", "Setup.IPropertySetterOnlySetup", + "Verify.VerificationPropertySetterResult", + "Setup.PropertySetup", "Verify.VerificationPropertyResult")] + [InlineData("string Name { get; set; }", "Setup.PropertySetup", + "Verify.VerificationPropertyResult", + "Setup.IPropertyGetterOnlySetup", "Verify.VerificationPropertyGetterResult")] + public async Task PropertySurface_ShouldOnlyExposeTheAccessorsTheMockIntercepts( + string property, string expectedSetupType, string expectedVerifyType, + string unexpectedSetupType, string unexpectedVerifyType) + { + GeneratorResult result = Generator + .Run($$""" + using Mockolate; + + namespace MyCode; + public class Program + { + public static void Main(string[] args) + { + _ = IMyService.CreateMock(); + } + } + + public interface IMyService + { + {{property}} + } + """); + + await That(result.Diagnostics).IsEmpty(); + await That(result.Sources["Mock.IMyService.g.cs"]) + .Contains($"global::Mockolate.{expectedSetupType} Name {{ get; }}").And + .Contains($"global::Mockolate.{expectedVerifyType} Name {{ get; }}").And + .DoesNotContain($"global::Mockolate.{unexpectedSetupType} Name {{ get; }}").And + .DoesNotContain($"global::Mockolate.{unexpectedVerifyType} Name {{ get; }}") + .Because("a widened facade would silently re-expose an accessor the mock never intercepts"); + } + [Fact] public async Task InitOnlyProperty_ShouldEmitInitAccessorAndCompile() { diff --git a/Tests/Mockolate.SourceGenerators.Tests/MockTests.CrossAssemblyTests.cs b/Tests/Mockolate.SourceGenerators.Tests/MockTests.CrossAssemblyTests.cs index 7c71111d..8a0f0be7 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/MockTests.CrossAssemblyTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/MockTests.CrossAssemblyTests.cs @@ -299,6 +299,9 @@ public abstract class MyExternalType : MyBaseType await That(result.Diagnostics).IsEmpty(); await That(result.Sources["Mock.MyExternalType.g.cs"]) + .Contains("global::Mockolate.Setup.IPropertyGetterOnlySetup Mixed { get; }").And + .Contains("global::Mockolate.Verify.VerificationPropertyGetterResult Mixed { get; }") + .Because("the mock does not intercept the inaccessible setter, so neither surface may offer it").And .Contains("public override string Mixed").And .Contains(".GetProperty").And .DoesNotContain(inaccessibleAccessor) @@ -329,6 +332,10 @@ public abstract class MyExternalType : MyBaseType await That(result.Diagnostics).IsEmpty(); await That(result.Sources["Mock.MyExternalType.g.cs"]) + .Contains("global::Mockolate.Setup.IPropertySetterOnlySetup Mixed { get; }").And + .Contains( + "global::Mockolate.Verify.VerificationPropertySetterResult Mixed { get; }") + .Because("the mock does not intercept the inaccessible getter, so neither surface may offer it").And .Contains("public override string Mixed").And .Contains(".SetProperty").And .DoesNotContain(inaccessibleAccessor) diff --git a/Tests/Mockolate.SourceGenerators.Tests/MockTests.cs b/Tests/Mockolate.SourceGenerators.Tests/MockTests.cs index 25babde0..4087f049 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/MockTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/MockTests.cs @@ -67,11 +67,11 @@ public static void Main(string[] args) await That(result.Sources).ContainsKey("Mock.OuterClass.g.cs"); await That(result.Sources["Mock.OuterClass.g.cs"]) - .Contains("global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForOuterClass.OuterValue").And - .Contains("global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForOuterClass.BaseClassValue").And - .DoesNotContain("global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForOuterClass.DirectValue").And - .DoesNotContain("global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForOuterClass.ParentValue").And - .DoesNotContain("global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForOuterClass.NestedValue").And + .Contains("global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForOuterClass.OuterValue").And + .Contains("global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForOuterClass.BaseClassValue").And + .DoesNotContain("IMockSetupForOuterClass.DirectValue").And + .DoesNotContain("IMockSetupForOuterClass.ParentValue").And + .DoesNotContain("IMockSetupForOuterClass.NestedValue").And .Contains("global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForOuterClass.OuterMethod()").And .Contains("global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForOuterClass.BaseClassMethod()").And .DoesNotContain("global::Mockolate.Setup.IReturnMethodSetup global::Mockolate.Mock.IMockSetupForOuterClass.DirectMethod()").And @@ -82,11 +82,11 @@ await That(result.Sources["Mock.OuterClass.g.cs"]) .DoesNotContain("void IMockRaiseOnOuterClass.DirectEvent(object? sender, global::System.EventArgs e)").And .DoesNotContain("void IMockRaiseOnOuterClass.ParentEvent(object? sender, global::System.EventArgs e)").And .DoesNotContain("void IMockRaiseOnOuterClass.NestedEvent(object? sender, global::System.EventArgs e)").And - .Contains("global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForOuterClass.OuterValue").And - .Contains("global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForOuterClass.BaseClassValue").And - .DoesNotContain("global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForOuterClass.DirectValue").And - .DoesNotContain("global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForOuterClass.ParentValue").And - .DoesNotContain("global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForOuterClass.NestedValue").And + .Contains("global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForOuterClass.OuterValue").And + .Contains("global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForOuterClass.BaseClassValue").And + .DoesNotContain("IMockVerifyForOuterClass.DirectValue").And + .DoesNotContain("IMockVerifyForOuterClass.ParentValue").And + .DoesNotContain("IMockVerifyForOuterClass.NestedValue").And .Contains("global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForOuterClass.OuterMethod()").And .Contains("global::Mockolate.Verify.VerificationResult.IgnoreParameters IMockVerifyForOuterClass.BaseClassMethod()").And .DoesNotContain("IMockVerifyForOuterClass.DirectMethod()").And diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs index 1d96ce08..64329f76 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA.g.cs @@ -415,7 +415,7 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value { get { @@ -463,11 +463,11 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockA.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockA.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, -1, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs index 4dc71c33..eba1dd31 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Snapshot/Expected/BaseClass_WithMultipleAdditionalInterfaces_CanBeCreated/Mock.ComprehensiveAbstractClass__ICombinationMockA__ICombinationMockB.g.cs @@ -523,7 +523,7 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value { get { @@ -547,7 +547,7 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value { get { @@ -595,11 +595,11 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockA.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockA.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, -1, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); } } @@ -612,11 +612,11 @@ protected override int P() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockB.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockB.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, -1, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, -1, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); } } 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 0022e9bf..c3358747 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 @@ -179,7 +179,7 @@ public void Run() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value { get { @@ -203,11 +203,11 @@ public void Run() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockA.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockA.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Set, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Get, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); } } @@ -226,11 +226,11 @@ private sealed class VerifyMonitorICombinationMockA(global::Mockolate.MockRegist /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockA.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockA.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Set, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockA.MemberId_Value_Get, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockA.Value"); } } @@ -260,7 +260,7 @@ public MockInScenarioForICombinationMockA(global::Mockolate.MockRegistry mockReg /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockA.Value { get { @@ -404,7 +404,7 @@ internal interface IMockSetupForICombinationMockA : global::Mockolate.Setup.IMoc /// /// Setup for the int property Value. /// - global::Mockolate.Setup.PropertySetup Value { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup Value { get; } /// /// Setup for the method Run(). @@ -422,7 +422,7 @@ internal interface IMockVerifyForICombinationMockA : global::Mockolate.Verify.IM /// /// Verify interactions with the int property Value. /// - global::Mockolate.Verify.VerificationPropertyResult Value { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult Value { get; } /// /// Verify invocations for the method Run(). 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 935f23c5..0dc5a39b 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 @@ -179,7 +179,7 @@ public void Run() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value { get { @@ -203,11 +203,11 @@ public void Run() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockB.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockB.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Set, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Get, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); } } @@ -226,11 +226,11 @@ private sealed class VerifyMonitorICombinationMockB(global::Mockolate.MockRegist /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForICombinationMockB.Value + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForICombinationMockB.Value { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Get, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Set, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.ICombinationMockB.MemberId_Value_Get, "global::Mockolate.Tests.GeneratorCoverage.ICombinationMockB.Value"); } } @@ -260,7 +260,7 @@ public MockInScenarioForICombinationMockB(global::Mockolate.MockRegistry mockReg /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForICombinationMockB.Value { get { @@ -404,7 +404,7 @@ internal interface IMockSetupForICombinationMockB : global::Mockolate.Setup.IMoc /// /// Setup for the int property Value. /// - global::Mockolate.Setup.PropertySetup Value { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup Value { get; } /// /// Setup for the method Run(). @@ -422,7 +422,7 @@ internal interface IMockVerifyForICombinationMockB : global::Mockolate.Verify.IM /// /// Verify interactions with the int property Value. /// - global::Mockolate.Verify.VerificationPropertyResult Value { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult Value { get; } /// /// Verify invocations for the method Run(). 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 c073699c..4dec103f 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 @@ -2204,7 +2204,7 @@ public void SeventeenVoid(int a1, int a2, int a3, int a4, int a5, int a6, int a7 /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.GetOnly + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.GetOnly { get { @@ -2216,7 +2216,7 @@ public void SeventeenVoid(int a1, int a2, int a3, int a4, int a5, int a6, int a7 /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.SetOnly + global::Mockolate.Setup.IPropertySetterOnlySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.SetOnly { get { @@ -2804,7 +2804,7 @@ public void SeventeenVoid(int a1, int a2, int a3, int a4, int a5, int a6, int a7 /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockStaticSetupForIComprehensiveInterface.StaticAbstractValue + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockStaticSetupForIComprehensiveInterface.StaticAbstractValue { get { @@ -2886,21 +2886,21 @@ void IMockRaiseOnIComprehensiveInterface.CustomEvent(global::Mockolate.Parameter /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIComprehensiveInterface.GetOnly + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForIComprehensiveInterface.GetOnly { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.GetOnly"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Get, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.GetOnly"); } } /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIComprehensiveInterface.SetOnly + global::Mockolate.Verify.VerificationPropertySetterResult IMockVerifyForIComprehensiveInterface.SetOnly { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.SetOnly"); + return new global::Mockolate.Verify.VerificationPropertySetterResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.SetOnly"); } } @@ -3383,11 +3383,11 @@ void IMockRaiseOnIComprehensiveInterface.CustomEvent(global::Mockolate.Parameter /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockStaticVerifyForIComprehensiveInterface.StaticAbstractValue + global::Mockolate.Verify.VerificationPropertyGetterResult IMockStaticVerifyForIComprehensiveInterface.StaticAbstractValue { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, -1, -1, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.StaticAbstractValue"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, -1, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.StaticAbstractValue"); } } @@ -3416,21 +3416,21 @@ private sealed class VerifyMonitorIComprehensiveInterface(global::Mockolate.Mock /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIComprehensiveInterface.GetOnly + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForIComprehensiveInterface.GetOnly { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.GetOnly"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_GetOnly_Get, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.GetOnly"); } } /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIComprehensiveInterface.SetOnly + global::Mockolate.Verify.VerificationPropertySetterResult IMockVerifyForIComprehensiveInterface.SetOnly { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Get, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.SetOnly"); + return new global::Mockolate.Verify.VerificationPropertySetterResult(this, this.MockRegistry, global::Mockolate.Mock.IComprehensiveInterface.MemberId_SetOnly_Set, "global::Mockolate.Tests.GeneratorCoverage.IComprehensiveInterface.SetOnly"); } } @@ -3942,7 +3942,7 @@ public MockInScenarioForIComprehensiveInterface(global::Mockolate.MockRegistry m /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.GetOnly + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.GetOnly { get { @@ -3954,7 +3954,7 @@ public MockInScenarioForIComprehensiveInterface(global::Mockolate.MockRegistry m /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.SetOnly + global::Mockolate.Setup.IPropertySetterOnlySetup global::Mockolate.Mock.IMockSetupForIComprehensiveInterface.SetOnly { get { @@ -4691,12 +4691,12 @@ internal interface IMockSetupForIComprehensiveInterface /// /// Setup for the int property GetOnly. /// - global::Mockolate.Setup.PropertySetup GetOnly { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup GetOnly { get; } /// /// Setup for the int property SetOnly. /// - global::Mockolate.Setup.PropertySetup SetOnly { get; } + global::Mockolate.Setup.IPropertySetterOnlySetup SetOnly { get; } /// /// Setup for the string? property NullableProp. @@ -5250,7 +5250,7 @@ internal interface IMockStaticSetupForIComprehensiveInterface /// /// Setup for the int property StaticAbstractValue. /// - global::Mockolate.Setup.PropertySetup StaticAbstractValue { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup StaticAbstractValue { get; } /// /// Setup for the method StaticAbstractMethod(). @@ -5310,12 +5310,12 @@ internal interface IMockVerifyForIComprehensiveInterface /// /// Verify interactions with the int property GetOnly. /// - global::Mockolate.Verify.VerificationPropertyResult GetOnly { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult GetOnly { get; } /// /// Verify interactions with the int property SetOnly. /// - global::Mockolate.Verify.VerificationPropertyResult SetOnly { get; } + global::Mockolate.Verify.VerificationPropertySetterResult SetOnly { get; } /// /// Verify interactions with the string? property NullableProp. @@ -5860,7 +5860,7 @@ internal interface IMockStaticVerifyForIComprehensiveInterface /// /// Verify interactions with the int property StaticAbstractValue. /// - global::Mockolate.Verify.VerificationPropertyResult StaticAbstractValue { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult StaticAbstractValue { get; } /// /// Verify invocations for the method StaticAbstractMethod(). 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 2d6faf64..7c537db5 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 @@ -415,7 +415,7 @@ public int @void<@class>(int @ref) /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIKeywordEdgeCases.@class + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForIKeywordEdgeCases.@class { get { @@ -567,11 +567,11 @@ void IMockRaiseOnIKeywordEdgeCases.@event(global::Mockolate.Parameters.IDefaultE /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIKeywordEdgeCases.@class + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForIKeywordEdgeCases.@class { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Get, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Set, "global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases.@class"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Get, "global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases.@class"); } } @@ -687,11 +687,11 @@ private sealed class VerifyMonitorIKeywordEdgeCases(global::Mockolate.MockRegist /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockVerifyForIKeywordEdgeCases.@class + global::Mockolate.Verify.VerificationPropertyGetterResult IMockVerifyForIKeywordEdgeCases.@class { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Get, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Set, "global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases.@class"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, global::Mockolate.Mock.IKeywordEdgeCases.MemberId__class_Get, "global::Mockolate.Tests.GeneratorCoverage.IKeywordEdgeCases.@class"); } } @@ -818,7 +818,7 @@ public MockInScenarioForIKeywordEdgeCases(global::Mockolate.MockRegistry mockReg /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockSetupForIKeywordEdgeCases.@class + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockSetupForIKeywordEdgeCases.@class { get { @@ -1081,7 +1081,7 @@ internal interface IMockSetupForIKeywordEdgeCases : global::Mockolate.Setup.IMoc /// /// Setup for the int property @class. /// - global::Mockolate.Setup.PropertySetup @class { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup @class { get; } /// /// Setup for the event @event. @@ -1211,7 +1211,7 @@ internal interface IMockVerifyForIKeywordEdgeCases : global::Mockolate.Verify.IM /// /// Verify interactions with the int property @class. /// - global::Mockolate.Verify.VerificationPropertyResult @class { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult @class { get; } /// /// Verify interactions with the string indexer this[int, string]. 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 c442eac0..2f1452a5 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 @@ -304,7 +304,7 @@ public static int VirtualStaticMethod() /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Setup.PropertySetup global::Mockolate.Mock.IMockStaticSetupForIStaticAbstractMembers.VirtualStaticProperty + global::Mockolate.Setup.IPropertyGetterOnlySetup global::Mockolate.Mock.IMockStaticSetupForIStaticAbstractMembers.VirtualStaticProperty { get { @@ -379,11 +379,11 @@ void IMockStaticRaiseOnIStaticAbstractMembers.AbstractStaticEvent(global::Mockol /// [global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)] - global::Mockolate.Verify.VerificationPropertyResult IMockStaticVerifyForIStaticAbstractMembers.VirtualStaticProperty + global::Mockolate.Verify.VerificationPropertyGetterResult IMockStaticVerifyForIStaticAbstractMembers.VirtualStaticProperty { get { - return new global::Mockolate.Verify.VerificationPropertyResult(this, this.MockRegistry, -1, -1, "global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.VirtualStaticProperty"); + return new global::Mockolate.Verify.VerificationPropertyGetterResult(this, this.MockRegistry, -1, "global::Mockolate.Tests.GeneratorCoverage.IStaticAbstractMembers.VirtualStaticProperty"); } } @@ -598,7 +598,7 @@ internal interface IMockStaticSetupForIStaticAbstractMembers /// /// Setup for the int property VirtualStaticProperty. /// - global::Mockolate.Setup.PropertySetup VirtualStaticProperty { get; } + global::Mockolate.Setup.IPropertyGetterOnlySetup VirtualStaticProperty { get; } /// /// Setup for the event AbstractStaticEvent. @@ -656,7 +656,7 @@ internal interface IMockStaticVerifyForIStaticAbstractMembers /// /// Verify interactions with the int property VirtualStaticProperty. /// - global::Mockolate.Verify.VerificationPropertyResult VirtualStaticProperty { get; } + global::Mockolate.Verify.VerificationPropertyGetterResult VirtualStaticProperty { get; } /// /// Verify invocations for the method AbstractStaticMethod(). diff --git a/Tests/Mockolate.Tests/MockProperties/SetupPropertyTests.AccessorRestrictedTests.cs b/Tests/Mockolate.Tests/MockProperties/SetupPropertyTests.AccessorRestrictedTests.cs new file mode 100644 index 00000000..03faec94 --- /dev/null +++ b/Tests/Mockolate.Tests/MockProperties/SetupPropertyTests.AccessorRestrictedTests.cs @@ -0,0 +1,354 @@ +using System.Collections.Generic; +using Mockolate.Setup; + +namespace Mockolate.Tests.MockProperties; + +public sealed partial class SetupPropertyTests +{ + public sealed class AccessorRestrictedTests + { + [Fact] + public async Task SetOnlyProperty_OnSet_ShouldFireAndRecordTheWrite() + { + IAccessorService sut = IAccessorService.CreateMock(); + List written = new(); + sut.Mock.Setup.WriteOnly.OnSet.Do(value => written.Add(value)); + + sut.WriteOnly = "Ada"; + + await That(written).IsEqualTo(["Ada",]); + await That(sut.Mock.Verify.WriteOnly.Set("Ada")).Once() + .Because("the setter facade must be keyed on the setter member id, not the getter's"); + } + + [Fact] + public async Task SetOnlyProperty_VerifyOtherValue_ShouldNotMatch() + { + IAccessorService sut = IAccessorService.CreateMock(); + + sut.WriteOnly = "Ada"; + + await That(sut.Mock.Verify.WriteOnly.Set("Grace")).Never(); + } + + [Fact] + public async Task SetOnlyProperty_VerifyWithParameterMatcher_ShouldMatch() + { + IAccessorService sut = IAccessorService.CreateMock(); + + sut.WriteOnly = "Ada"; + + await That(sut.Mock.Verify.WriteOnly.Set(It.IsAny())).Once(); + } + + [Fact] + public async Task SetOnlyProperty_Register_ShouldAllowWriteWithoutSetup() + { + IAccessorService sut = IAccessorService.CreateMock(MockBehavior.Default.ThrowingWhenNotSetup()); + sut.Mock.Setup.WriteOnly.Register(); + + void Act() => sut.WriteOnly = "Ada"; + + await That(Act).DoesNotThrow(); + } + + [Fact] + public async Task GetOnlyProperty_Register_ShouldAllowReadWithoutSetup() + { + IAccessorService sut = IAccessorService.CreateMock(MockBehavior.Default.ThrowingWhenNotSetup()); + sut.Mock.Setup.ReadOnly.Register(); + + int result = sut.ReadOnly; + + await That(result).IsEqualTo(0); + await That(sut.Mock.Verify.ReadOnly.Got()).Once(); + } + + [Theory] + [InlineData(false, 1)] + [InlineData(true, 0)] + public async Task SetOnlyClassProperty_ShouldSkipCallingBaseWhenRequested(bool skipBaseClass, + int expectedCallCount) + { + AccessorService sut = AccessorService.CreateMock(); + sut.Mock.Setup.WriteOnly.SkippingBaseClass(skipBaseClass); + + sut.WriteOnly = 1; + + await That(sut.WriteOnlySetterCallCount).IsEqualTo(expectedCallCount); + } + + [Fact] + public async Task GetOnlyProperty_ChainedReturns_ShouldStayOnGetterOnlySurface() + { + IAccessorService sut = IAccessorService.CreateMock(); + IPropertyGetterOnlySetup chained = sut.Mock.Setup.ReadOnly + .Returns(1).OnlyOnce(); + chained.Returns(() => 2); + + await That(sut.ReadOnly).IsEqualTo(1); + await That(sut.ReadOnly).IsEqualTo(2); + } + + [Fact] + public async Task GetOnlyProperty_ReturnsForever_ShouldUseTheLastValueForever() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .Returns(2) + .Returns(4).Forever(); + + int[] result = new int[4]; + for (int i = 0; i < 4; i++) + { + result[i] = sut.ReadOnly; + } + + await That(result).IsEqualTo([2, 4, 4, 4,]); + } + + [Fact] + public async Task GetOnlyProperty_ReturnsWhen_ShouldOnlyUseValueWhenPredicateIsTrue() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .Returns(() => 4).When(i => i > 0); + + int result1 = sut.ReadOnly; + int result2 = sut.ReadOnly; + + await That(result1).IsEqualTo(0); + await That(result2).IsEqualTo(4); + } + + [Fact] + public async Task GetOnlyProperty_ReturnsCallbackWithValue_ShouldReturnExpectedValue() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .InitializeWith(3) + .Returns(x => 4 * x); + + int result = sut.ReadOnly; + + await That(result).IsEqualTo(12); + } + + [Fact] + public async Task GetOnlyProperty_Throws_ShouldIterateThroughAllRegisteredExceptions() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .Throws() + .Throws(new Exception("foo")) + .Throws(() => new Exception("bar")) + .Throws(v => new Exception($"baz-{v}")); + + void Act() => _ = sut.ReadOnly; + + await That(Act).Throws(); + Exception? result2 = Record.Exception(Act); + Exception? result3 = Record.Exception(Act); + Exception? result4 = Record.Exception(Act); + await That(result2).HasMessage("foo"); + await That(result3).HasMessage("bar"); + await That(result4).HasMessage("baz-0"); + } + + [Fact] + public async Task GetOnlyProperty_OnGetChain_ShouldStayOnGetterOnlySurface() + { + int callCount1 = 0; + int callCount2 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + IPropertyGetterOnlySetup chained = sut.Mock.Setup.ReadOnly + .OnGet.Do(() => { callCount1++; }) + .OnGet.Do(v => { callCount2 += 1 + v; }).OnlyOnce(); + chained.Register(); + + _ = sut.ReadOnly; + _ = sut.ReadOnly; + _ = sut.ReadOnly; + _ = sut.ReadOnly; + + await That(callCount1).IsEqualTo(3); + await That(callCount2).IsEqualTo(1); + } + + [Fact] + public async Task GetOnlyProperty_OnGetWhen_ShouldOnlyInvokeCallbackWhenPredicateIsTrue() + { + int callCount = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .OnGet.Do(() => { callCount++; }).When(i => i > 0); + + _ = sut.ReadOnly; + _ = sut.ReadOnly; + _ = sut.ReadOnly; + + await That(callCount).IsEqualTo(2); + } + + [Fact] + public async Task GetOnlyProperty_OnGetInParallel_ShouldInvokeParallelCallbacksAlways() + { + int callCount1 = 0; + int callCount2 = 0; + int callCount3 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .OnGet.Do(() => { callCount1++; }) + .OnGet.Do(v => { callCount2++; }).InParallel() + .OnGet.Do((i, v) => { callCount3++; }); + + _ = sut.ReadOnly; + _ = sut.ReadOnly; + _ = sut.ReadOnly; + _ = sut.ReadOnly; + + await That(callCount1).IsEqualTo(2); + await That(callCount2).IsEqualTo(4); + await That(callCount3).IsEqualTo(2); + } + + [Fact] + public async Task GetOnlyProperty_OnGetFor_ShouldRepeatCallbackTheGivenNumberOfTimes() + { + int callCount1 = 0; + int callCount2 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.ReadOnly + .OnGet.Do(() => { callCount1++; }).For(2) + .OnGet.Do(() => { callCount2++; }); + + for (int i = 0; i < 6; i++) + { + _ = sut.ReadOnly; + } + + await That(callCount1).IsEqualTo(4); + await That(callCount2).IsEqualTo(2); + } + + [Fact] + public async Task GetOnlyProperty_OnGetTransitionTo_ShouldSwitchScenario() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.InScenario("a").Setup.ReadOnly + .OnGet.Do(() => { }) + .OnGet.TransitionTo("b"); + sut.Mock.TransitionTo("a"); + + _ = sut.ReadOnly; + + await That(((IMock)sut).MockRegistry.Scenario).IsEqualTo("b"); + } + + [Fact] + public async Task SetOnlyProperty_OnSetChain_ShouldStayOnSetterOnlySurface() + { + int callCount1 = 0; + int callCount2 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + IPropertySetterOnlySetup chained = sut.Mock.Setup.WriteOnly + .OnSet.Do(() => { callCount1++; }) + .OnSet.Do(v => { callCount2++; }).OnlyOnce(); + chained.Register(); + + sut.WriteOnly = "a"; + sut.WriteOnly = "b"; + sut.WriteOnly = "c"; + sut.WriteOnly = "d"; + + await That(callCount1).IsEqualTo(3); + await That(callCount2).IsEqualTo(1); + } + + [Fact] + public async Task SetOnlyProperty_OnSetWhen_ShouldOnlyInvokeCallbackWhenPredicateIsTrue() + { + int callCount = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.WriteOnly + .OnSet.Do(() => { callCount++; }).When(i => i > 0); + + sut.WriteOnly = "a"; + sut.WriteOnly = "b"; + sut.WriteOnly = "c"; + + await That(callCount).IsEqualTo(2); + } + + [Fact] + public async Task SetOnlyProperty_OnSetInParallel_ShouldInvokeParallelCallbacksAlways() + { + int callCount1 = 0; + int callCount2 = 0; + int callCount3 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.WriteOnly + .OnSet.Do(() => { callCount1++; }) + .OnSet.Do((i, v) => { callCount2++; }).InParallel() + .OnSet.Do(() => { callCount3++; }); + + sut.WriteOnly = "a"; + sut.WriteOnly = "b"; + sut.WriteOnly = "c"; + sut.WriteOnly = "d"; + + await That(callCount1).IsEqualTo(2); + await That(callCount2).IsEqualTo(4); + await That(callCount3).IsEqualTo(2); + } + + [Fact] + public async Task SetOnlyProperty_OnSetFor_ShouldRepeatCallbackTheGivenNumberOfTimes() + { + int callCount1 = 0; + int callCount2 = 0; + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.Setup.WriteOnly + .OnSet.Do(() => { callCount1++; }).For(2) + .OnSet.Do(() => { callCount2++; }); + + for (int i = 0; i < 6; i++) + { + sut.WriteOnly = "a"; + } + + await That(callCount1).IsEqualTo(4); + await That(callCount2).IsEqualTo(2); + } + + [Fact] + public async Task SetOnlyProperty_OnSetTransitionTo_ShouldSwitchScenario() + { + IAccessorService sut = IAccessorService.CreateMock(); + sut.Mock.InScenario("a").Setup.WriteOnly + .OnSet.Do(() => { }) + .OnSet.TransitionTo("b"); + sut.Mock.TransitionTo("a"); + + sut.WriteOnly = "x"; + + await That(((IMock)sut).MockRegistry.Scenario).IsEqualTo("b"); + } + + public interface IAccessorService + { + int ReadOnly { get; } + string WriteOnly { set; } + } + + public class AccessorService + { + public int WriteOnlySetterCallCount { get; private set; } + + public virtual int WriteOnly + { + set => WriteOnlySetterCallCount += value; + } + } + } +}