Skip to content

Commit

Permalink
Adding generator for generating extension method when IOptions is ref…
Browse files Browse the repository at this point in the history
…erenced
  • Loading branch information
Keboo committed Jan 16, 2024
1 parent 658b808 commit f7ad0db
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<LangVersion>10.0</LangVersion>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<EnforceCodeStyleInBuild Condition=" '$(BuildingForLiveUnitTesting)' == '' ">true</EnforceCodeStyleInBuild>
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest" Version="1.1.1" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Moq.AutoMock.Generator.Example.MSUnit;
[TestClass]
public class ControllerWithOptionsTests
{
[TestMethod]
public void CreateInstance_WithOptions_EmbedsOptions()
{
AutoMocker mocker = new();

mocker.WithOptions<TestsOptions>(options => options.Number = 42);

ControllerWithOptions controller = mocker.CreateInstance<ControllerWithOptions>();

Assert.AreEqual(42, controller.Options.Value.Number);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.Options;
using NUnit.Framework;

namespace Moq.AutoMock.Generator.Example.NUnit;
public class ControllerWithOptionsTests
{
[Test]
public void CreateInstance_WithOptions_EmbedsOptions()
{
AutoMocker mocker = new();

mocker.WithOptions<TestsOptions>(options => options.Number = 42);

ControllerWithOptions controller = mocker.CreateInstance<ControllerWithOptions>();

Assert.That(42 == controller.Options.Value.Number);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.Options;
using Xunit;

namespace Moq.AutoMock.Generator.Example.xUnit;
public class ControllerWithOptionsTests
{
[Fact]
public void CreateInstance_WithOptions_EmbedsOptions()
{
AutoMocker mocker = new();

mocker.WithOptions<TestsOptions>(options => options.Number = 42);

ControllerWithOptions controller = mocker.CreateInstance<ControllerWithOptions>();

Assert.Equal(42, controller.Options.Value.Number);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.Extensions.Options;

namespace Moq.AutoMock.Generator.Example;
public class ControllerWithOptions
{
public IOptions<TestsOptions> Options { get; }

public ControllerWithOptions(IOptions<TestsOptions> options)
{
Options = options;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand All @@ -7,4 +7,8 @@
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Moq.AutoMock.Generator.Example;

public class TestsOptions
{
public int Number { get; set; }
}
66 changes: 66 additions & 0 deletions Moq.AutoMocker.Generators/OptionsExtensionSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Microsoft.CodeAnalysis;

namespace Moq.AutoMocker.Generators;

[Generator]
public class OptionsExtensionSourceGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
if (!ReferencesOptions(context.Compilation.ReferencedAssemblyNames))
{
return;
}

context.AddSource("AutoMocker.Options.cs", OptionsExtensionContent);
}

public void Initialize(GeneratorInitializationContext context)
{ }

private static bool ReferencesOptions(IEnumerable<AssemblyIdentity> assemblies)
{
foreach (AssemblyIdentity assembly in assemblies)
{
if (assembly.Name.StartsWith("Microsoft.Extensions.Options"))
{
return true;
}
}
return false;
}

private const string OptionsExtensionContent =
"""
namespace Moq.AutoMock
{
using Microsoft.Extensions.Options;

public static class AutoMockerOptionsExtensions
{
/// <summary>
/// This method sets up <see cref="AutoMocker"/> with various option related services for Microsoft's Option pattern, and allows their interception and manipulation in testing scenarios.
/// </summary>
/// <param name="mocker">The <see cref="AutoMocker"/> instance</param>
/// <param name="configure">A delegate that can be used to configure an option instance of type TClass.</param>
/// <typeparam name="TClass">The type of Options being configured.</typeparam>
/// <returns>The same <see cref="AutoMocker"/> instance passed as parameter, allowing chained calls.</returns>
public static AutoMocker WithOptions<TClass>(this AutoMocker mocker, Action<TClass>? configure = null)
where TClass : class, new()
{
if (mocker == null) throw new ArgumentNullException(nameof(mocker));

mocker.Use<IEnumerable<IConfigureOptions<TClass>>>(new[] { new ConfigureOptions<TClass>(configure) });
mocker.With<IOptionsMonitorCache<TClass>, OptionsCache<TClass>>();
mocker.With<IOptionsFactory<TClass>, OptionsFactory<TClass>>();
mocker.With<IOptionsMonitor<TClass>, OptionsMonitor<TClass>>();
mocker.With<IOptionsSnapshot<TClass>, OptionsManager<TClass>>();
TClass options = mocker.Get<IOptionsFactory<TClass>>().Create(string.Empty);
mocker.Use(Options.Create(options));
mocker.Use(options);
return mocker;
}
}
}
""";
}

0 comments on commit f7ad0db

Please sign in to comment.