diff --git a/TUnit.Mocks.SourceGenerator.Tests/MockGeneratorTests.cs b/TUnit.Mocks.SourceGenerator.Tests/MockGeneratorTests.cs index bd059cadec..e74f80f115 100644 --- a/TUnit.Mocks.SourceGenerator.Tests/MockGeneratorTests.cs +++ b/TUnit.Mocks.SourceGenerator.Tests/MockGeneratorTests.cs @@ -415,4 +415,32 @@ void M() return VerifyGeneratorOutput(source); } + + [Test] + public Task Interface_With_Nullable_Reference_Type_Parameters() + { + var source = """ + using TUnit.Mocks; + using System.Threading.Tasks; + + public interface IFoo + { + void Bar(object? baz); + string? GetValue(string? key, int count); + void Process(string nonNull, string? nullable, object? obj); + Task GetAsync(string? key); + string? NullableProp { get; set; } + } + + public class TestUsage + { + void M() + { + var mock = Mock.Of(); + } + } + """; + + return VerifyGeneratorOutput(source); + } } diff --git a/TUnit.Mocks.SourceGenerator.Tests/Snapshots/Interface_With_Nullable_Reference_Type_Parameters.verified.txt b/TUnit.Mocks.SourceGenerator.Tests/Snapshots/Interface_With_Nullable_Reference_Type_Parameters.verified.txt new file mode 100644 index 0000000000..1b42ee5f1b --- /dev/null +++ b/TUnit.Mocks.SourceGenerator.Tests/Snapshots/Interface_With_Nullable_Reference_Type_Parameters.verified.txt @@ -0,0 +1,542 @@ +// +#nullable enable + +namespace TUnit.Mocks.Generated +{ + internal static class IFoo_MockFactory + { + [global::System.Runtime.CompilerServices.ModuleInitializer] + internal static void Register() + { + global::TUnit.Mocks.Mock.RegisterFactory(Create); + } + + private static global::TUnit.Mocks.Mock Create(global::TUnit.Mocks.MockBehavior behavior) + { + var engine = new global::TUnit.Mocks.MockEngine(behavior); + var impl = new IFoo_MockImpl(engine); + engine.Raisable = impl; + var mock = new global::TUnit.Mocks.Mock(impl, engine); + return mock; + } + } +} + + +// ===== FILE SEPARATOR ===== + +// +#nullable enable + +namespace TUnit.Mocks.Generated +{ + internal sealed class IFoo_MockImpl : global::IFoo, global::TUnit.Mocks.IRaisable + { + private readonly global::TUnit.Mocks.MockEngine _engine; + + internal IFoo_MockImpl(global::TUnit.Mocks.MockEngine engine) + { + _engine = engine; + } + + public void Bar(object? baz) + { + _engine.HandleCall(0, "Bar", new object?[] { baz }); + } + + public string? GetValue(string? key, int count) + { + return _engine.HandleCallWithReturn(1, "GetValue", new object?[] { key, count }, default); + } + + public void Process(string nonNull, string? nullable, object? obj) + { + _engine.HandleCall(2, "Process", new object?[] { nonNull, nullable, obj }); + } + + public global::System.Threading.Tasks.Task GetAsync(string? key) + { + try + { + var __result = _engine.HandleCallWithReturn(3, "GetAsync", new object?[] { key }, default); + return global::System.Threading.Tasks.Task.FromResult(__result); + } + catch (global::System.Exception __ex) + { + return global::System.Threading.Tasks.Task.FromException(__ex); + } + } + + public string? NullableProp + { + get => _engine.HandleCallWithReturn(4, "get_NullableProp", global::System.Array.Empty(), default); + set => _engine.HandleCall(5, "set_NullableProp", new object?[] { value }); + } + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public void RaiseEvent(string eventName, object? args) + { + throw new global::System.InvalidOperationException($"No event named '{eventName}' exists on this mock."); + } + } +} + + +// ===== FILE SEPARATOR ===== + +// +#nullable enable + +namespace TUnit.Mocks.Generated +{ + public static class IFoo_MockMemberExtensions + { + public static IFoo_Bar_M0_MockCall Bar(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg baz) + { + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { baz.Matcher }; + return new IFoo_Bar_M0_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 0, "Bar", matchers); + } + + public static IFoo_Bar_M0_MockCall Bar(this global::TUnit.Mocks.Mock mock, global::System.Func baz) + { + global::TUnit.Mocks.Arguments.Arg __fa_baz = baz; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_baz.Matcher }; + return new IFoo_Bar_M0_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 0, "Bar", matchers); + } + + public static IFoo_GetValue_M1_MockCall GetValue(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg key, global::TUnit.Mocks.Arguments.Arg count) + { + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { key.Matcher, count.Matcher }; + return new IFoo_GetValue_M1_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 1, "GetValue", matchers); + } + + public static IFoo_GetValue_M1_MockCall GetValue(this global::TUnit.Mocks.Mock mock, global::System.Func key, global::TUnit.Mocks.Arguments.Arg count) + { + global::TUnit.Mocks.Arguments.Arg __fa_key = key; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_key.Matcher, count.Matcher }; + return new IFoo_GetValue_M1_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 1, "GetValue", matchers); + } + + public static IFoo_GetValue_M1_MockCall GetValue(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg key, global::System.Func count) + { + global::TUnit.Mocks.Arguments.Arg __fa_count = count; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { key.Matcher, __fa_count.Matcher }; + return new IFoo_GetValue_M1_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 1, "GetValue", matchers); + } + + public static IFoo_GetValue_M1_MockCall GetValue(this global::TUnit.Mocks.Mock mock, global::System.Func key, global::System.Func count) + { + global::TUnit.Mocks.Arguments.Arg __fa_key = key; + global::TUnit.Mocks.Arguments.Arg __fa_count = count; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_key.Matcher, __fa_count.Matcher }; + return new IFoo_GetValue_M1_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 1, "GetValue", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg nonNull, global::TUnit.Mocks.Arguments.Arg nullable, global::TUnit.Mocks.Arguments.Arg obj) + { + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { nonNull.Matcher, nullable.Matcher, obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::System.Func nonNull, global::TUnit.Mocks.Arguments.Arg nullable, global::TUnit.Mocks.Arguments.Arg obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nonNull = nonNull; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_nonNull.Matcher, nullable.Matcher, obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg nonNull, global::System.Func nullable, global::TUnit.Mocks.Arguments.Arg obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nullable = nullable; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { nonNull.Matcher, __fa_nullable.Matcher, obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::System.Func nonNull, global::System.Func nullable, global::TUnit.Mocks.Arguments.Arg obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nonNull = nonNull; + global::TUnit.Mocks.Arguments.Arg __fa_nullable = nullable; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_nonNull.Matcher, __fa_nullable.Matcher, obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg nonNull, global::TUnit.Mocks.Arguments.Arg nullable, global::System.Func obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_obj = obj; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { nonNull.Matcher, nullable.Matcher, __fa_obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::System.Func nonNull, global::TUnit.Mocks.Arguments.Arg nullable, global::System.Func obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nonNull = nonNull; + global::TUnit.Mocks.Arguments.Arg __fa_obj = obj; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_nonNull.Matcher, nullable.Matcher, __fa_obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg nonNull, global::System.Func nullable, global::System.Func obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nullable = nullable; + global::TUnit.Mocks.Arguments.Arg __fa_obj = obj; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { nonNull.Matcher, __fa_nullable.Matcher, __fa_obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_Process_M2_MockCall Process(this global::TUnit.Mocks.Mock mock, global::System.Func nonNull, global::System.Func nullable, global::System.Func obj) + { + global::TUnit.Mocks.Arguments.Arg __fa_nonNull = nonNull; + global::TUnit.Mocks.Arguments.Arg __fa_nullable = nullable; + global::TUnit.Mocks.Arguments.Arg __fa_obj = obj; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_nonNull.Matcher, __fa_nullable.Matcher, __fa_obj.Matcher }; + return new IFoo_Process_M2_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 2, "Process", matchers); + } + + public static IFoo_GetAsync_M3_MockCall GetAsync(this global::TUnit.Mocks.Mock mock, global::TUnit.Mocks.Arguments.Arg key) + { + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { key.Matcher }; + return new IFoo_GetAsync_M3_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 3, "GetAsync", matchers); + } + + public static IFoo_GetAsync_M3_MockCall GetAsync(this global::TUnit.Mocks.Mock mock, global::System.Func key) + { + global::TUnit.Mocks.Arguments.Arg __fa_key = key; + var matchers = new global::TUnit.Mocks.Arguments.IArgumentMatcher[] { __fa_key.Matcher }; + return new IFoo_GetAsync_M3_MockCall(global::TUnit.Mocks.Mock.GetEngine(mock), 3, "GetAsync", matchers); + } + + extension(global::TUnit.Mocks.Mock mock) + { + public global::TUnit.Mocks.PropertyMockCall NullableProp + => new(global::TUnit.Mocks.Mock.GetEngine(mock), 4, 5, "NullableProp", true, true); + } + } + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public sealed class IFoo_Bar_M0_MockCall : global::TUnit.Mocks.Verification.ICallVerification + { + private readonly global::TUnit.Mocks.IMockEngineAccess _engine; + private readonly int _memberId; + private readonly string _memberName; + private readonly global::TUnit.Mocks.Arguments.IArgumentMatcher[] _matchers; + private readonly global::System.Lazy _lazyBuilder; + + internal IFoo_Bar_M0_MockCall(global::TUnit.Mocks.IMockEngineAccess engine, int memberId, string memberName, global::TUnit.Mocks.Arguments.IArgumentMatcher[] matchers) + { + _engine = engine; + _memberId = memberId; + _memberName = memberName; + _matchers = matchers; + _lazyBuilder = new global::System.Lazy(() => + { + var setup = new global::TUnit.Mocks.Setup.MethodSetup(_memberId, _matchers, _memberName); + _engine.AddSetup(setup); + return new global::TUnit.Mocks.Setup.VoidMethodSetupBuilder(setup); + } + ); + _ = _lazyBuilder.Value; + } + + private global::TUnit.Mocks.Setup.VoidMethodSetupBuilder EnsureSetup() => _lazyBuilder.Value; + + /// + public IFoo_Bar_M0_MockCall Throws() where TException : global::System.Exception, new() { EnsureSetup().Throws(); return this; } + /// + public IFoo_Bar_M0_MockCall Throws(global::System.Exception exception) { EnsureSetup().Throws(exception); return this; } + /// + public IFoo_Bar_M0_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_Bar_M0_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_Bar_M0_MockCall Throws(global::System.Func exceptionFactory) { EnsureSetup().Throws(exceptionFactory); return this; } + /// + public IFoo_Bar_M0_MockCall Raises(string eventName, object? args = null) { EnsureSetup().Raises(eventName, args); return this; } + /// + public IFoo_Bar_M0_MockCall SetsOutParameter(int paramIndex, object? value) { EnsureSetup().SetsOutParameter(paramIndex, value); return this; } + /// + public IFoo_Bar_M0_MockCall TransitionsTo(string stateName) { EnsureSetup().TransitionsTo(stateName); return this; } + /// + public IFoo_Bar_M0_MockCall Then() { EnsureSetup().Then(); return this; } + + /// Execute a typed callback using the actual method parameters. + public IFoo_Bar_M0_MockCall Callback(global::System.Action callback) + { + EnsureSetup().Callback(args => callback((object?)args[0]!)); + return this; + } + + /// Configure a typed computed exception using the actual method parameters. + public IFoo_Bar_M0_MockCall Throws(global::System.Func exceptionFactory) + { + EnsureSetup().Throws(args => exceptionFactory((object?)args[0]!)); + return this; + } + + // ICallVerification + /// + public void WasCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(); + /// + public void WasCalled(global::TUnit.Mocks.Times times) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times); + /// + public void WasCalled(global::TUnit.Mocks.Times times, string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times, message); + /// + public void WasCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(message); + /// + public void WasNeverCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(); + /// + public void WasNeverCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(message); + } + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public sealed class IFoo_GetValue_M1_MockCall : global::TUnit.Mocks.Verification.ICallVerification + { + private readonly global::TUnit.Mocks.IMockEngineAccess _engine; + private readonly int _memberId; + private readonly string _memberName; + private readonly global::TUnit.Mocks.Arguments.IArgumentMatcher[] _matchers; + private readonly global::System.Lazy> _lazyBuilder; + + internal IFoo_GetValue_M1_MockCall(global::TUnit.Mocks.IMockEngineAccess engine, int memberId, string memberName, global::TUnit.Mocks.Arguments.IArgumentMatcher[] matchers) + { + _engine = engine; + _memberId = memberId; + _memberName = memberName; + _matchers = matchers; + _lazyBuilder = new global::System.Lazy>(() => + { + var setup = new global::TUnit.Mocks.Setup.MethodSetup(_memberId, _matchers, _memberName); + _engine.AddSetup(setup); + return new global::TUnit.Mocks.Setup.MethodSetupBuilder(setup); + } + ); + } + + private global::TUnit.Mocks.Setup.MethodSetupBuilder EnsureSetup() => _lazyBuilder.Value; + + /// + public IFoo_GetValue_M1_MockCall Returns(string? value) { EnsureSetup().Returns(value); return this; } + /// + public IFoo_GetValue_M1_MockCall Returns(global::System.Func factory) { EnsureSetup().Returns(factory); return this; } + /// + public IFoo_GetValue_M1_MockCall ReturnsSequentially(params string?[] values) { EnsureSetup().ReturnsSequentially(values); return this; } + /// + public IFoo_GetValue_M1_MockCall Throws() where TException : global::System.Exception, new() { EnsureSetup().Throws(); return this; } + /// + public IFoo_GetValue_M1_MockCall Throws(global::System.Exception exception) { EnsureSetup().Throws(exception); return this; } + /// + public IFoo_GetValue_M1_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_GetValue_M1_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_GetValue_M1_MockCall Returns(global::System.Func factory) { EnsureSetup().Returns(factory); return this; } + /// + public IFoo_GetValue_M1_MockCall Throws(global::System.Func exceptionFactory) { EnsureSetup().Throws(exceptionFactory); return this; } + /// + public IFoo_GetValue_M1_MockCall Raises(string eventName, object? args = null) { EnsureSetup().Raises(eventName, args); return this; } + /// + public IFoo_GetValue_M1_MockCall SetsOutParameter(int paramIndex, object? value) { EnsureSetup().SetsOutParameter(paramIndex, value); return this; } + /// + public IFoo_GetValue_M1_MockCall TransitionsTo(string stateName) { EnsureSetup().TransitionsTo(stateName); return this; } + /// + public IFoo_GetValue_M1_MockCall Then() { EnsureSetup().Then(); return this; } + + /// Configure a typed computed return value using the actual method parameters. + public IFoo_GetValue_M1_MockCall Returns(global::System.Func factory) + { + EnsureSetup().Returns(args => factory((string?)args[0]!, (int)args[1]!)); + return this; + } + + /// Execute a typed callback using the actual method parameters. + public IFoo_GetValue_M1_MockCall Callback(global::System.Action callback) + { + EnsureSetup().Callback(args => callback((string?)args[0]!, (int)args[1]!)); + return this; + } + + /// Configure a typed computed exception using the actual method parameters. + public IFoo_GetValue_M1_MockCall Throws(global::System.Func exceptionFactory) + { + EnsureSetup().Throws(args => exceptionFactory((string?)args[0]!, (int)args[1]!)); + return this; + } + + // ICallVerification + /// + public void WasCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(); + /// + public void WasCalled(global::TUnit.Mocks.Times times) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times); + /// + public void WasCalled(global::TUnit.Mocks.Times times, string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times, message); + /// + public void WasCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(message); + /// + public void WasNeverCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(); + /// + public void WasNeverCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(message); + } + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public sealed class IFoo_Process_M2_MockCall : global::TUnit.Mocks.Verification.ICallVerification + { + private readonly global::TUnit.Mocks.IMockEngineAccess _engine; + private readonly int _memberId; + private readonly string _memberName; + private readonly global::TUnit.Mocks.Arguments.IArgumentMatcher[] _matchers; + private readonly global::System.Lazy _lazyBuilder; + + internal IFoo_Process_M2_MockCall(global::TUnit.Mocks.IMockEngineAccess engine, int memberId, string memberName, global::TUnit.Mocks.Arguments.IArgumentMatcher[] matchers) + { + _engine = engine; + _memberId = memberId; + _memberName = memberName; + _matchers = matchers; + _lazyBuilder = new global::System.Lazy(() => + { + var setup = new global::TUnit.Mocks.Setup.MethodSetup(_memberId, _matchers, _memberName); + _engine.AddSetup(setup); + return new global::TUnit.Mocks.Setup.VoidMethodSetupBuilder(setup); + } + ); + _ = _lazyBuilder.Value; + } + + private global::TUnit.Mocks.Setup.VoidMethodSetupBuilder EnsureSetup() => _lazyBuilder.Value; + + /// + public IFoo_Process_M2_MockCall Throws() where TException : global::System.Exception, new() { EnsureSetup().Throws(); return this; } + /// + public IFoo_Process_M2_MockCall Throws(global::System.Exception exception) { EnsureSetup().Throws(exception); return this; } + /// + public IFoo_Process_M2_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_Process_M2_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_Process_M2_MockCall Throws(global::System.Func exceptionFactory) { EnsureSetup().Throws(exceptionFactory); return this; } + /// + public IFoo_Process_M2_MockCall Raises(string eventName, object? args = null) { EnsureSetup().Raises(eventName, args); return this; } + /// + public IFoo_Process_M2_MockCall SetsOutParameter(int paramIndex, object? value) { EnsureSetup().SetsOutParameter(paramIndex, value); return this; } + /// + public IFoo_Process_M2_MockCall TransitionsTo(string stateName) { EnsureSetup().TransitionsTo(stateName); return this; } + /// + public IFoo_Process_M2_MockCall Then() { EnsureSetup().Then(); return this; } + + /// Execute a typed callback using the actual method parameters. + public IFoo_Process_M2_MockCall Callback(global::System.Action callback) + { + EnsureSetup().Callback(args => callback((string)args[0]!, (string?)args[1]!, (object?)args[2]!)); + return this; + } + + /// Configure a typed computed exception using the actual method parameters. + public IFoo_Process_M2_MockCall Throws(global::System.Func exceptionFactory) + { + EnsureSetup().Throws(args => exceptionFactory((string)args[0]!, (string?)args[1]!, (object?)args[2]!)); + return this; + } + + // ICallVerification + /// + public void WasCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(); + /// + public void WasCalled(global::TUnit.Mocks.Times times) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times); + /// + public void WasCalled(global::TUnit.Mocks.Times times, string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times, message); + /// + public void WasCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(message); + /// + public void WasNeverCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(); + /// + public void WasNeverCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(message); + } + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public sealed class IFoo_GetAsync_M3_MockCall : global::TUnit.Mocks.Verification.ICallVerification + { + private readonly global::TUnit.Mocks.IMockEngineAccess _engine; + private readonly int _memberId; + private readonly string _memberName; + private readonly global::TUnit.Mocks.Arguments.IArgumentMatcher[] _matchers; + private readonly global::System.Lazy> _lazyBuilder; + + internal IFoo_GetAsync_M3_MockCall(global::TUnit.Mocks.IMockEngineAccess engine, int memberId, string memberName, global::TUnit.Mocks.Arguments.IArgumentMatcher[] matchers) + { + _engine = engine; + _memberId = memberId; + _memberName = memberName; + _matchers = matchers; + _lazyBuilder = new global::System.Lazy>(() => + { + var setup = new global::TUnit.Mocks.Setup.MethodSetup(_memberId, _matchers, _memberName); + _engine.AddSetup(setup); + return new global::TUnit.Mocks.Setup.MethodSetupBuilder(setup); + } + ); + } + + private global::TUnit.Mocks.Setup.MethodSetupBuilder EnsureSetup() => _lazyBuilder.Value; + + /// + public IFoo_GetAsync_M3_MockCall Returns(string? value) { EnsureSetup().Returns(value); return this; } + /// + public IFoo_GetAsync_M3_MockCall Returns(global::System.Func factory) { EnsureSetup().Returns(factory); return this; } + /// + public IFoo_GetAsync_M3_MockCall ReturnsSequentially(params string?[] values) { EnsureSetup().ReturnsSequentially(values); return this; } + /// + public IFoo_GetAsync_M3_MockCall Throws() where TException : global::System.Exception, new() { EnsureSetup().Throws(); return this; } + /// + public IFoo_GetAsync_M3_MockCall Throws(global::System.Exception exception) { EnsureSetup().Throws(exception); return this; } + /// + public IFoo_GetAsync_M3_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_GetAsync_M3_MockCall Callback(global::System.Action callback) { EnsureSetup().Callback(callback); return this; } + /// + public IFoo_GetAsync_M3_MockCall Returns(global::System.Func factory) { EnsureSetup().Returns(factory); return this; } + /// + public IFoo_GetAsync_M3_MockCall Throws(global::System.Func exceptionFactory) { EnsureSetup().Throws(exceptionFactory); return this; } + /// + public IFoo_GetAsync_M3_MockCall Raises(string eventName, object? args = null) { EnsureSetup().Raises(eventName, args); return this; } + /// + public IFoo_GetAsync_M3_MockCall SetsOutParameter(int paramIndex, object? value) { EnsureSetup().SetsOutParameter(paramIndex, value); return this; } + /// + public IFoo_GetAsync_M3_MockCall TransitionsTo(string stateName) { EnsureSetup().TransitionsTo(stateName); return this; } + /// + public IFoo_GetAsync_M3_MockCall Then() { EnsureSetup().Then(); return this; } + + /// Configure a typed computed return value using the actual method parameters. + public IFoo_GetAsync_M3_MockCall Returns(global::System.Func factory) + { + EnsureSetup().Returns(args => factory((string?)args[0]!)); + return this; + } + + /// Execute a typed callback using the actual method parameters. + public IFoo_GetAsync_M3_MockCall Callback(global::System.Action callback) + { + EnsureSetup().Callback(args => callback((string?)args[0]!)); + return this; + } + + /// Configure a typed computed exception using the actual method parameters. + public IFoo_GetAsync_M3_MockCall Throws(global::System.Func exceptionFactory) + { + EnsureSetup().Throws(args => exceptionFactory((string?)args[0]!)); + return this; + } + + // ICallVerification + /// + public void WasCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(); + /// + public void WasCalled(global::TUnit.Mocks.Times times) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times); + /// + public void WasCalled(global::TUnit.Mocks.Times times, string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(times, message); + /// + public void WasCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasCalled(message); + /// + public void WasNeverCalled() => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(); + /// + public void WasNeverCalled(string? message) => _engine.CreateVerification(_memberId, _memberName, _matchers).WasNeverCalled(message); + } +} diff --git a/TUnit.Mocks.SourceGenerator/Discovery/MemberDiscovery.cs b/TUnit.Mocks.SourceGenerator/Discovery/MemberDiscovery.cs index 7dc063b15d..7a1c5536ee 100644 --- a/TUnit.Mocks.SourceGenerator/Discovery/MemberDiscovery.cs +++ b/TUnit.Mocks.SourceGenerator/Discovery/MemberDiscovery.cs @@ -307,7 +307,7 @@ private static MockMemberModel CreateMethodModel(IMethodSymbol method, ref int m { Name = method.Name, MemberId = memberIdCounter++, - ReturnType = returnType.GetFullyQualifiedName(), + ReturnType = returnType.GetFullyQualifiedNameWithNullability(), UnwrappedReturnType = unwrappedType, IsVoid = isVoid, IsAsync = isAsync, @@ -318,8 +318,8 @@ private static MockMemberModel CreateMethodModel(IMethodSymbol method, ref int m method.Parameters.Select(p => new MockParameterModel { Name = EscapeIdentifier(p.Name), - Type = p.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), - FullyQualifiedType = p.Type.GetFullyQualifiedName(), + Type = p.Type.GetMinimallyQualifiedNameWithNullability(), + FullyQualifiedType = p.Type.GetFullyQualifiedNameWithNullability(), Direction = p.GetParameterDirection(), HasDefaultValue = p.HasExplicitDefaultValue, DefaultValueExpression = p.HasExplicitDefaultValue ? FormatDefaultValue(p) : null, @@ -380,8 +380,8 @@ private static MockMemberModel CreatePropertyModel(IPropertySymbol property, ref { Name = property.Name, MemberId = getterId, - ReturnType = property.Type.GetFullyQualifiedName(), - UnwrappedReturnType = property.Type.GetFullyQualifiedName(), + ReturnType = property.Type.GetFullyQualifiedNameWithNullability(), + UnwrappedReturnType = property.Type.GetFullyQualifiedNameWithNullability(), IsVoid = false, IsAsync = false, IsProperty = true, @@ -418,8 +418,8 @@ public static EquatableArray DiscoverConstructors(INamedTy ctor.Parameters.Select(p => new MockParameterModel { Name = EscapeIdentifier(p.Name), - Type = p.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), - FullyQualifiedType = p.Type.GetFullyQualifiedName(), + Type = p.Type.GetMinimallyQualifiedNameWithNullability(), + FullyQualifiedType = p.Type.GetFullyQualifiedNameWithNullability(), Direction = p.GetParameterDirection(), HasDefaultValue = p.HasExplicitDefaultValue, DefaultValueExpression = p.HasExplicitDefaultValue ? FormatDefaultValue(p) : null, @@ -443,8 +443,8 @@ private static MockMemberModel CreateIndexerModel(IPropertySymbol indexer, ref i Name = "this", MemberId = getterId, SetterMemberId = setterId, - ReturnType = indexer.Type.GetFullyQualifiedName(), - UnwrappedReturnType = indexer.Type.GetFullyQualifiedName(), + ReturnType = indexer.Type.GetFullyQualifiedNameWithNullability(), + UnwrappedReturnType = indexer.Type.GetFullyQualifiedNameWithNullability(), IsVoid = false, IsAsync = false, IsProperty = true, @@ -455,8 +455,8 @@ private static MockMemberModel CreateIndexerModel(IPropertySymbol indexer, ref i indexer.Parameters.Select(p => new MockParameterModel { Name = EscapeIdentifier(p.Name), - Type = p.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), - FullyQualifiedType = p.Type.GetFullyQualifiedName(), + Type = p.Type.GetMinimallyQualifiedNameWithNullability(), + FullyQualifiedType = p.Type.GetFullyQualifiedNameWithNullability(), Direction = ParameterDirection.In }).ToImmutableArray() ), @@ -513,8 +513,8 @@ private static MockEventModel CreateEventModel(IEventSymbol evt, string? explici raiseParams.Select(p => new MockParameterModel { Name = EscapeIdentifier(p.Name), - FullyQualifiedType = p.Type.GetFullyQualifiedName(), - Type = p.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), + FullyQualifiedType = p.Type.GetFullyQualifiedNameWithNullability(), + Type = p.Type.GetMinimallyQualifiedNameWithNullability(), Direction = ParameterDirection.In }).ToImmutableArray()); diff --git a/TUnit.Mocks.SourceGenerator/Extensions/MethodSymbolExtensions.cs b/TUnit.Mocks.SourceGenerator/Extensions/MethodSymbolExtensions.cs index ae71c1953f..7114cd0a62 100644 --- a/TUnit.Mocks.SourceGenerator/Extensions/MethodSymbolExtensions.cs +++ b/TUnit.Mocks.SourceGenerator/Extensions/MethodSymbolExtensions.cs @@ -54,7 +54,7 @@ public static string GetParameterList(this IMethodSymbol method) RefKind.In => "in ", _ => "" }; - return $"{direction}{p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {p.Name}"; + return $"{direction}{p.Type.GetFullyQualifiedNameWithNullability()} {p.Name}"; })); } diff --git a/TUnit.Mocks.SourceGenerator/Extensions/TypeSymbolExtensions.cs b/TUnit.Mocks.SourceGenerator/Extensions/TypeSymbolExtensions.cs index 8643508e76..3bcd83fdd8 100644 --- a/TUnit.Mocks.SourceGenerator/Extensions/TypeSymbolExtensions.cs +++ b/TUnit.Mocks.SourceGenerator/Extensions/TypeSymbolExtensions.cs @@ -6,11 +6,30 @@ namespace TUnit.Mocks.SourceGenerator.Extensions; internal static class TypeSymbolExtensions { + private static readonly SymbolDisplayFormat FullyQualifiedWithNullability = + SymbolDisplayFormat.FullyQualifiedFormat.AddMiscellaneousOptions( + SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + private static readonly SymbolDisplayFormat MinimallyQualifiedWithNullability = + SymbolDisplayFormat.MinimallyQualifiedFormat.AddMiscellaneousOptions( + SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + /// + /// Returns the fully qualified name without nullable annotations. + /// For code generation that must preserve nullable reference type annotations, + /// use instead. + /// public static string GetFullyQualifiedName(this ITypeSymbol type) { return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } + public static string GetFullyQualifiedNameWithNullability(this ITypeSymbol type) + => type.ToDisplayString(FullyQualifiedWithNullability); + + public static string GetMinimallyQualifiedNameWithNullability(this ITypeSymbol type) + => type.ToDisplayString(MinimallyQualifiedWithNullability); + public static string GetFullyQualifiedNameWithoutGlobal(this ITypeSymbol type) { var fqn = type.GetFullyQualifiedName(); @@ -197,9 +216,9 @@ public static (string UnwrappedType, bool IsVoidAsync) GetUnwrappedReturnType(th var name = named.ConstructedFrom.Name; if ((name == "Task" || name == "ValueTask") && named.TypeArguments.Length == 1) { - return (named.TypeArguments[0].GetFullyQualifiedName(), false); + return (named.TypeArguments[0].GetFullyQualifiedNameWithNullability(), false); } } - return (type.GetFullyQualifiedName(), false); + return (type.GetFullyQualifiedNameWithNullability(), false); } }