Skip to content
25 changes: 25 additions & 0 deletions TUnit.Mocks.SourceGenerator.Tests/MockGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,29 @@ public virtual void DoWork() { }

return VerifyGeneratorOutput(source);
}

[Test]
public Task Static_Extension_Discovery_Without_Mock_Of()
{
// IFoo.Mock() should trigger generation even without Mock.Of<IFoo>()
var source = """
using TUnit.Mocks;

public interface INotifier
{
void Notify(string message);
string GetStatus();
}

public class TestUsage
{
void M()
{
var mock = INotifier.Mock();
}
}
""";

return VerifyGeneratorOutput(source);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
public sealed class IReadWriter_Mock : global::TUnit.Mocks.Mock<global::IReadWriter>, global::IReadWriter
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public IReadWriter_Mock(global::IReadWriter mockObject, global::TUnit.Mocks.MockEngine<global::IReadWriter> engine)
: base(mockObject, engine) { }

void global::IReadWriter.Flush()
{
Object.Flush();
}

string global::IReader.Read() => Object.Read();

void global::IWriter.Write(string data)
{
Object.Write(data);
}
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
internal static class IReadWriter_MockFactory
Expand All @@ -11,13 +39,13 @@ namespace TUnit.Mocks.Generated
global::TUnit.Mocks.MockRegistry.RegisterFactory<global::IReadWriter>(Create);
}

private static global::TUnit.Mocks.Mock<global::IReadWriter> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
internal static global::TUnit.Mocks.Mock<global::IReadWriter> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
{
if (constructorArgs.Length > 0) throw new global::System.ArgumentException($"Interface mock 'global::IReadWriter' does not support constructor arguments, but {constructorArgs.Length} were provided.");
var engine = new global::TUnit.Mocks.MockEngine<global::IReadWriter>(behavior);
var impl = new IReadWriter_MockImpl(engine);
engine.Raisable = impl;
var mock = new global::TUnit.Mocks.Mock<global::IReadWriter>(impl, engine);
var mock = new IReadWriter_Mock(impl, engine);
return mock;
}
}
Expand Down Expand Up @@ -174,6 +202,27 @@ namespace TUnit.Mocks.Generated
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks
{
public static class IReadWriter_MockStaticExtension
{
extension(global::IReadWriter)
{
[global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public static global::TUnit.Mocks.Generated.IReadWriter_Mock Mock(global::TUnit.Mocks.MockBehavior behavior = global::TUnit.Mocks.MockBehavior.Loose)
{
return (global::TUnit.Mocks.Generated.IReadWriter_Mock)global::TUnit.Mocks.Generated.IReadWriter_MockFactory.Create(behavior, []);
}
}
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
public sealed class IAsyncService_Mock : global::TUnit.Mocks.Mock<global::IAsyncService>, global::IAsyncService
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public IAsyncService_Mock(global::IAsyncService mockObject, global::TUnit.Mocks.MockEngine<global::IAsyncService> engine)
: base(mockObject, engine) { }

global::System.Threading.Tasks.Task<string> global::IAsyncService.GetValueAsync(string key) => Object.GetValueAsync(key);

global::System.Threading.Tasks.Task global::IAsyncService.DoWorkAsync() => Object.DoWorkAsync();

global::System.Threading.Tasks.ValueTask<int> global::IAsyncService.ComputeAsync(int input) => Object.ComputeAsync(input);

global::System.Threading.Tasks.ValueTask global::IAsyncService.InitializeAsync(global::System.Threading.CancellationToken ct) => Object.InitializeAsync(ct);
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
internal static class IAsyncService_MockFactory
Expand All @@ -11,13 +35,13 @@ namespace TUnit.Mocks.Generated
global::TUnit.Mocks.MockRegistry.RegisterFactory<global::IAsyncService>(Create);
}

private static global::TUnit.Mocks.Mock<global::IAsyncService> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
internal static global::TUnit.Mocks.Mock<global::IAsyncService> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
{
if (constructorArgs.Length > 0) throw new global::System.ArgumentException($"Interface mock 'global::IAsyncService' does not support constructor arguments, but {constructorArgs.Length} were provided.");
var engine = new global::TUnit.Mocks.MockEngine<global::IAsyncService>(behavior);
var impl = new IAsyncService_MockImpl(engine);
engine.Raisable = impl;
var mock = new global::TUnit.Mocks.Mock<global::IAsyncService>(impl, engine);
var mock = new IAsyncService_Mock(impl, engine);
return mock;
}
}
Expand Down Expand Up @@ -491,6 +515,27 @@ namespace TUnit.Mocks.Generated
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks
{
public static class IAsyncService_MockStaticExtension
{
extension(global::IAsyncService)
{
[global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public static global::TUnit.Mocks.Generated.IAsyncService_Mock Mock(global::TUnit.Mocks.MockBehavior behavior = global::TUnit.Mocks.MockBehavior.Loose)
{
return (global::TUnit.Mocks.Generated.IAsyncService_Mock)global::TUnit.Mocks.Generated.IAsyncService_MockFactory.Create(behavior, []);
}
}
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
public sealed class INotifier_Mock : global::TUnit.Mocks.Mock<global::INotifier>, global::INotifier
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public INotifier_Mock(global::INotifier mockObject, global::TUnit.Mocks.MockEngine<global::INotifier> engine)
: base(mockObject, engine) { }

void global::INotifier.Notify(string message)
{
Object.Notify(message);
}

event global::System.EventHandler<string> global::INotifier.ItemAdded { add => Object.ItemAdded += value; remove => Object.ItemAdded -= value; }
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
Expand Down Expand Up @@ -42,13 +65,13 @@ namespace TUnit.Mocks.Generated
global::TUnit.Mocks.MockRegistry.RegisterFactory<global::INotifier>(Create);
}

private static global::TUnit.Mocks.Mock<global::INotifier> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
internal static global::TUnit.Mocks.Mock<global::INotifier> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
{
if (constructorArgs.Length > 0) throw new global::System.ArgumentException($"Interface mock 'global::INotifier' does not support constructor arguments, but {constructorArgs.Length} were provided.");
var engine = new global::TUnit.Mocks.MockEngine<global::INotifier>(behavior);
var impl = new INotifier_MockImpl(engine);
engine.Raisable = impl;
var mock = new global::TUnit.Mocks.Mock<global::INotifier>(impl, engine);
var mock = new INotifier_Mock(impl, engine);
return mock;
}
}
Expand Down Expand Up @@ -212,6 +235,27 @@ namespace TUnit.Mocks.Generated
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks
{
public static class INotifier_MockStaticExtension
{
extension(global::INotifier)
{
[global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public static global::TUnit.Mocks.Generated.INotifier_Mock Mock(global::TUnit.Mocks.MockBehavior behavior = global::TUnit.Mocks.MockBehavior.Loose)
{
return (global::TUnit.Mocks.Generated.INotifier_Mock)global::TUnit.Mocks.Generated.INotifier_MockFactory.Create(behavior, []);
}
}
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
public sealed class IRepository_Mock : global::TUnit.Mocks.Mock<global::IRepository>, global::IRepository
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public IRepository_Mock(global::IRepository mockObject, global::TUnit.Mocks.MockEngine<global::IRepository> engine)
: base(mockObject, engine) { }

T global::IRepository.GetById<T>(int id) where T : class => Object.GetById<T>(id);

void global::IRepository.Save<T>(T entity) where T : class, new()
{
Object.Save<T>(entity);
}

TResult global::IRepository.Transform<TInput, TResult>(TInput input) where TInput : notnull where TResult : struct => Object.Transform<TInput, TResult>(input);
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks.Generated
{
internal static class IRepository_MockFactory
Expand All @@ -11,13 +36,13 @@ namespace TUnit.Mocks.Generated
global::TUnit.Mocks.MockRegistry.RegisterFactory<global::IRepository>(Create);
}

private static global::TUnit.Mocks.Mock<global::IRepository> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
internal static global::TUnit.Mocks.Mock<global::IRepository> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
{
if (constructorArgs.Length > 0) throw new global::System.ArgumentException($"Interface mock 'global::IRepository' does not support constructor arguments, but {constructorArgs.Length} were provided.");
var engine = new global::TUnit.Mocks.MockEngine<global::IRepository>(behavior);
var impl = new IRepository_MockImpl(engine);
engine.Raisable = impl;
var mock = new global::TUnit.Mocks.Mock<global::IRepository>(impl, engine);
var mock = new IRepository_Mock(impl, engine);
return mock;
}
}
Expand Down Expand Up @@ -118,6 +143,27 @@ namespace TUnit.Mocks.Generated
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
#nullable enable

namespace TUnit.Mocks
{
public static class IRepository_MockStaticExtension
{
extension(global::IRepository)
{
[global::System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public static global::TUnit.Mocks.Generated.IRepository_Mock Mock(global::TUnit.Mocks.MockBehavior behavior = global::TUnit.Mocks.MockBehavior.Loose)
{
return (global::TUnit.Mocks.Generated.IRepository_Mock)global::TUnit.Mocks.Generated.IRepository_MockFactory.Create(behavior, []);
}
}
}
}


// ===== FILE SEPARATOR =====

// <auto-generated/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace TUnit.Mocks.Generated
global::TUnit.Mocks.MockRegistry.RegisterFactory<global::TUnit.Mocks.Generated.IMyService_Mockable>(Create);
}

private static global::TUnit.Mocks.Mock<global::TUnit.Mocks.Generated.IMyService_Mockable> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
internal static global::TUnit.Mocks.Mock<global::TUnit.Mocks.Generated.IMyService_Mockable> Create(global::TUnit.Mocks.MockBehavior behavior, object[] constructorArgs)
{
if (constructorArgs.Length > 0) throw new global::System.ArgumentException($"Interface mock 'global::TUnit.Mocks.Generated.IMyService_Mockable' does not support constructor arguments, but {constructorArgs.Length} were provided.");
var engine = new global::TUnit.Mocks.MockEngine<global::TUnit.Mocks.Generated.IMyService_Mockable>(behavior);
Expand Down
Loading
Loading