diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index ffbe1d2f..2a1d760d 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -23,13 +23,13 @@ defaults:
jobs:
build:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 6.0.100
+ dotnet-version: 6.0.202
# Run unit tests
- name: Test
@@ -53,7 +53,16 @@ jobs:
}
dotnet pack --configuration Release --verbosity normal --output .
-
+
+ - name: Upload NuGet
+ uses: actions/upload-artifact@v3
+ with:
+ name: NuGet
+ if-no-files-found: error
+ path: |
+ **/*.nupkg
+ **/*.snupkg
+
# Update the docs
- name: Update Docs
if: github.event_name == 'push'
diff --git a/Directory.Build.props b/Directory.Build.props
index 9ddb2eac..82dc6821 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,10 +1,11 @@
-
+
10.0
enable
+ enable
true
true
-
+
\ No newline at end of file
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 00000000..6132714b
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/ControllerTests.cs b/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/ControllerTests.cs
new file mode 100644
index 00000000..09e40d04
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/ControllerTests.cs
@@ -0,0 +1,14 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Moq.AutoMock.Generator.Example.MSTest;
+
+[TestClass]
+[ConstructorTests(TargetType = typeof(Controller))]
+public partial class ControllerTests
+{
+ partial void ControllerConstructor_WithNullIService3_ThrowsArgumentNullExceptionSetup(AutoMocker mocker)
+ {
+ mocker.Use("");
+ }
+}
+
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/Moq.AutoMock.Generator.Example.MSTest.csproj b/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/Moq.AutoMock.Generator.Example.MSTest.csproj
new file mode 100644
index 00000000..ee601859
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.MSTest/Moq.AutoMock.Generator.Example.MSTest.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net6.0
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ Analyzer
+ false
+
+
+
+
+
+
+
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/ControllerTests.cs b/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/ControllerTests.cs
new file mode 100644
index 00000000..24f60171
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/ControllerTests.cs
@@ -0,0 +1,10 @@
+namespace Moq.AutoMock.Generator.Example.NUnit;
+
+[ConstructorTests(TargetType = typeof(Controller))]
+public partial class ControllerTests
+{
+ partial void AutoMockerTestSetup(Moq.AutoMock.AutoMocker mocker, string testName)
+ {
+ mocker.Use("");
+ }
+}
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/Moq.AutoMock.Generator.Example.NUnit.csproj b/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/Moq.AutoMock.Generator.Example.NUnit.csproj
new file mode 100644
index 00000000..7f080ee3
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.NUnit/Moq.AutoMock.Generator.Example.NUnit.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net6.0
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ Analyzer
+ false
+
+
+
+
+
+
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/ControllerTests.cs b/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/ControllerTests.cs
new file mode 100644
index 00000000..782549d8
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/ControllerTests.cs
@@ -0,0 +1,11 @@
+namespace Moq.AutoMock.Generator.Example.xUnit;
+
+[ConstructorTests(TargetType = typeof(Controller))]
+public partial class ControllerTests
+{
+ partial void AutoMockerTestSetup(Moq.AutoMock.AutoMocker mocker, string testName)
+ {
+ mocker.Use("");
+ }
+}
+
diff --git a/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/Moq.AutoMock.Generator.Example.xUnit.csproj b/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/Moq.AutoMock.Generator.Example.xUnit.csproj
new file mode 100644
index 00000000..b1dc24a8
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMock.Generator.Example.xUnit/Moq.AutoMock.Generator.Example.xUnit.csproj
@@ -0,0 +1,40 @@
+
+
+
+ net6.0
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+ Analyzer
+ false
+
+
+
+
+
+
+
+
+
diff --git a/GeneratorTests/Moq.AutoMocker.Generator.Example/Controller.cs b/GeneratorTests/Moq.AutoMocker.Generator.Example/Controller.cs
new file mode 100644
index 00000000..e9a2d129
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMocker.Generator.Example/Controller.cs
@@ -0,0 +1,23 @@
+namespace Moq.AutoMock.Generator.Example;
+
+public class Controller
+{
+ public Controller(IService service)
+ {
+ _ = service ?? throw new ArgumentNullException(nameof(service));
+ }
+
+ public Controller(IService service1, IService service2)
+ {
+ _ = service1 ?? throw new ArgumentNullException(nameof(service1));
+ _ = service2 ?? throw new ArgumentNullException(nameof(service2));
+ }
+
+ public Controller(IService service, string name)
+ {
+ _ = service ?? throw new ArgumentNullException(nameof(service));
+ Name = name ?? throw new ArgumentNullException(nameof(name));
+ }
+
+ public string Name { get; } = "";
+}
diff --git a/GeneratorTests/Moq.AutoMocker.Generator.Example/IService.cs b/GeneratorTests/Moq.AutoMocker.Generator.Example/IService.cs
new file mode 100644
index 00000000..8cb15948
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMocker.Generator.Example/IService.cs
@@ -0,0 +1,6 @@
+namespace Moq.AutoMock.Generator.Example;
+
+public interface IService
+{
+
+}
diff --git a/GeneratorTests/Moq.AutoMocker.Generator.Example/Moq.AutoMock.Generator.Example.csproj b/GeneratorTests/Moq.AutoMocker.Generator.Example/Moq.AutoMock.Generator.Example.csproj
new file mode 100644
index 00000000..268cbace
--- /dev/null
+++ b/GeneratorTests/Moq.AutoMocker.Generator.Example/Moq.AutoMock.Generator.Example.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net6.0
+ enable
+ enable
+ false
+
+
+
diff --git a/Moq.AutoMock.Tests/Moq.AutoMock.Tests.csproj b/Moq.AutoMock.Tests/Moq.AutoMock.Tests.csproj
index 8862e1c0..a2b541ba 100644
--- a/Moq.AutoMock.Tests/Moq.AutoMock.Tests.csproj
+++ b/Moq.AutoMock.Tests/Moq.AutoMock.Tests.csproj
@@ -24,8 +24,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/Moq.AutoMock.sln b/Moq.AutoMock.sln
index 2386be81..3216af2e 100644
--- a/Moq.AutoMock.sln
+++ b/Moq.AutoMock.sln
@@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
+ Directory.Build.targets = Directory.Build.targets
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
LICENSE.md = LICENSE.md
README.md = README.md
@@ -18,6 +19,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators", "Generators\Generators.csproj", "{98CADDA9-5D66-405A-8A59-90636A242869}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GeneratorTests", "GeneratorTests", "{1D10BDDE-2E03-42E4-AA7A-B12AF01E7FE8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMock.Generator.Example", "GeneratorTests\Moq.AutoMocker.Generator.Example\Moq.AutoMock.Generator.Example.csproj", "{F142399A-FAB8-4097-BC7B-0266200FA14D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMock.Generator.Example.MSTest", "GeneratorTests\Moq.AutoMock.Generator.Example.MSTest\Moq.AutoMock.Generator.Example.MSTest.csproj", "{BAFB5236-9C52-48D2-8CD5-E214652F38D3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMock.Generator.Example.NUnit", "GeneratorTests\Moq.AutoMock.Generator.Example.NUnit\Moq.AutoMock.Generator.Example.NUnit.csproj", "{0E545A4D-809E-47CA-AC16-5CB80CD231F6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMock.Generator.Example.xUnit", "GeneratorTests\Moq.AutoMock.Generator.Example.xUnit\Moq.AutoMock.Generator.Example.xUnit.csproj", "{586D1D6A-3EE2-4AB8-988A-CEB810EF7787}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMocker.TestGenerator", "Moq.AutoMocker.TestGenerator\Moq.AutoMocker.TestGenerator.csproj", "{710AF8FE-BB9E-4FE9-ABF7-0CE8BD212BB4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.AutoMocker.TestGenerator.Tests", "Moq.AutoMocker.TestGenerator.Tests\Moq.AutoMocker.TestGenerator.Tests.csproj", "{F3663663-0123-4DA3-9BDD-95C91AFA4596}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -36,10 +51,40 @@ Global
{98CADDA9-5D66-405A-8A59-90636A242869}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98CADDA9-5D66-405A-8A59-90636A242869}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98CADDA9-5D66-405A-8A59-90636A242869}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F142399A-FAB8-4097-BC7B-0266200FA14D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F142399A-FAB8-4097-BC7B-0266200FA14D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F142399A-FAB8-4097-BC7B-0266200FA14D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F142399A-FAB8-4097-BC7B-0266200FA14D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BAFB5236-9C52-48D2-8CD5-E214652F38D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BAFB5236-9C52-48D2-8CD5-E214652F38D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BAFB5236-9C52-48D2-8CD5-E214652F38D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BAFB5236-9C52-48D2-8CD5-E214652F38D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0E545A4D-809E-47CA-AC16-5CB80CD231F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0E545A4D-809E-47CA-AC16-5CB80CD231F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0E545A4D-809E-47CA-AC16-5CB80CD231F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0E545A4D-809E-47CA-AC16-5CB80CD231F6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {586D1D6A-3EE2-4AB8-988A-CEB810EF7787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {586D1D6A-3EE2-4AB8-988A-CEB810EF7787}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {586D1D6A-3EE2-4AB8-988A-CEB810EF7787}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {586D1D6A-3EE2-4AB8-988A-CEB810EF7787}.Release|Any CPU.Build.0 = Release|Any CPU
+ {710AF8FE-BB9E-4FE9-ABF7-0CE8BD212BB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {710AF8FE-BB9E-4FE9-ABF7-0CE8BD212BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {710AF8FE-BB9E-4FE9-ABF7-0CE8BD212BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {710AF8FE-BB9E-4FE9-ABF7-0CE8BD212BB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F3663663-0123-4DA3-9BDD-95C91AFA4596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F3663663-0123-4DA3-9BDD-95C91AFA4596}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F3663663-0123-4DA3-9BDD-95C91AFA4596}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F3663663-0123-4DA3-9BDD-95C91AFA4596}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F142399A-FAB8-4097-BC7B-0266200FA14D} = {1D10BDDE-2E03-42E4-AA7A-B12AF01E7FE8}
+ {BAFB5236-9C52-48D2-8CD5-E214652F38D3} = {1D10BDDE-2E03-42E4-AA7A-B12AF01E7FE8}
+ {0E545A4D-809E-47CA-AC16-5CB80CD231F6} = {1D10BDDE-2E03-42E4-AA7A-B12AF01E7FE8}
+ {586D1D6A-3EE2-4AB8-988A-CEB810EF7787} = {1D10BDDE-2E03-42E4-AA7A-B12AF01E7FE8}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1A499C6A-1AB1-4A04-A133-BBCF4759DACA}
EndGlobalSection
diff --git a/Moq.AutoMock/AutoMocker.Verify.cs b/Moq.AutoMock/AutoMocker.Verify.cs
index bc826643..767c7820 100644
--- a/Moq.AutoMock/AutoMocker.Verify.cs
+++ b/Moq.AutoMock/AutoMocker.Verify.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Linq.Expressions;
+using System.Linq.Expressions;
namespace Moq.AutoMock;
diff --git a/Moq.AutoMock/AutoMocker.cs b/Moq.AutoMock/AutoMocker.cs
index 9025e874..0b84012f 100644
--- a/Moq.AutoMock/AutoMocker.cs
+++ b/Moq.AutoMock/AutoMocker.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.ExceptionServices;
@@ -262,10 +259,10 @@ public T CreateSelfMock(bool enablePrivate) where T : class?
/// Sets the CallBase property on the created Mock.
/// An instance with virtual and abstract members mocked
public T CreateSelfMock(
- bool enablePrivate = false,
- MockBehavior? mockBehavior = null,
- DefaultValue? defaultValue = null,
- bool? callBase = null)
+ bool enablePrivate = false,
+ MockBehavior? mockBehavior = null,
+ DefaultValue? defaultValue = null,
+ bool? callBase = null)
where T : class?
{
return BuildSelfMock(enablePrivate, mockBehavior ?? MockBehavior, defaultValue ?? DefaultValue, callBase ?? CallBase).Object;
@@ -284,13 +281,13 @@ public T CreateSelfMock(
/// An instance with virtual and abstract members mocked
public TImplementation WithSelfMock(
bool enablePrivate = false,
- MockBehavior? mockBehavior = null,
+ MockBehavior? mockBehavior = null,
DefaultValue? defaultValue = null,
bool? callBase = null)
where TImplementation : class, TService
where TService : class
{
- Mock selfMock = BuildSelfMock(enablePrivate,
+ Mock selfMock = BuildSelfMock(enablePrivate,
mockBehavior ?? MockBehavior,
defaultValue ?? DefaultValue,
callBase ?? CallBase);
@@ -391,7 +388,7 @@ public object WithSelfMock(
}
- private Mock BuildSelfMock(bool enablePrivate, MockBehavior mockBehavior, DefaultValue defaultValue, bool callBase)
+ private Mock BuildSelfMock(bool enablePrivate, MockBehavior mockBehavior, DefaultValue defaultValue, bool callBase)
where T : class?
{
var context = new ObjectGraphContext(enablePrivate);
diff --git a/Moq.AutoMock/CastChecker.cs b/Moq.AutoMock/CastChecker.cs
index b16b67d5..23adf513 100644
--- a/Moq.AutoMock/CastChecker.cs
+++ b/Moq.AutoMock/CastChecker.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Linq.Expressions;
+using System.Linq.Expressions;
namespace Moq.AutoMock;
diff --git a/Moq.AutoMock/ConstructorSelector.cs b/Moq.AutoMock/ConstructorSelector.cs
index 02bce0a8..a05e798d 100644
--- a/Moq.AutoMock/ConstructorSelector.cs
+++ b/Moq.AutoMock/ConstructorSelector.cs
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Reflection;
using Moq.AutoMock.Extensions;
diff --git a/Moq.AutoMock/ConstructorTestsAttribute.cs b/Moq.AutoMock/ConstructorTestsAttribute.cs
new file mode 100644
index 00000000..bc4fa595
--- /dev/null
+++ b/Moq.AutoMock/ConstructorTestsAttribute.cs
@@ -0,0 +1,26 @@
+namespace Moq.AutoMock;
+
+///
+/// An attribute used by Moq.AutoMock.TestGenerator to generate unit tests for null constructor arguments.
+///
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+public class ConstructorTestsAttribute : Attribute
+{
+ ///
+ /// The type of service to generate tests for.
+ ///
+ public Type? TargetType { get; set; }
+ ///
+ /// Create a new instance of the ConstructorTestsAttribute
+ ///
+ public ConstructorTestsAttribute()
+ { }
+ ///
+ /// Create a new instance of the ConstructorTestsAttribute specifying the targetType
+ ///
+ ///
+ public ConstructorTestsAttribute(Type targetType)
+ {
+ TargetType = targetType;
+ }
+}
diff --git a/Moq.AutoMock/IAutoMockerDisposable.cs b/Moq.AutoMock/IAutoMockerDisposable.cs
index 4ac33115..a7bf203d 100644
--- a/Moq.AutoMock/IAutoMockerDisposable.cs
+++ b/Moq.AutoMock/IAutoMockerDisposable.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Linq;
-
-namespace Moq.AutoMock;
+namespace Moq.AutoMock;
///
/// An interface that is used to clean up AutoMocker instances.
diff --git a/Moq.AutoMock/MockArrayInstance.cs b/Moq.AutoMock/MockArrayInstance.cs
index f0f9010a..162fa0fe 100644
--- a/Moq.AutoMock/MockArrayInstance.cs
+++ b/Moq.AutoMock/MockArrayInstance.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Moq.AutoMock;
+namespace Moq.AutoMock;
internal sealed class MockArrayInstance : IInstance
{
diff --git a/Moq.AutoMock/MockExtensions.cs b/Moq.AutoMock/MockExtensions.cs
index f4351441..de3e920e 100644
--- a/Moq.AutoMock/MockExtensions.cs
+++ b/Moq.AutoMock/MockExtensions.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq;
-using System.Linq.Expressions;
+using System.Linq.Expressions;
using System.Reflection;
using Moq.Language.Flow;
diff --git a/Moq.AutoMock/Moq.AutoMock.csproj b/Moq.AutoMock/Moq.AutoMock.csproj
index 2303f320..e58fd50a 100644
--- a/Moq.AutoMock/Moq.AutoMock.csproj
+++ b/Moq.AutoMock/Moq.AutoMock.csproj
@@ -24,6 +24,7 @@
snupkg
true
+ $(NoWarn);AMG0002
@@ -36,6 +37,7 @@
Analyzer
false
+
@@ -45,6 +47,7 @@
+
diff --git a/Moq.AutoMock/ObjectGraphContext.cs b/Moq.AutoMock/ObjectGraphContext.cs
index de19fc41..d55b4eff 100644
--- a/Moq.AutoMock/ObjectGraphContext.cs
+++ b/Moq.AutoMock/ObjectGraphContext.cs
@@ -1,5 +1,3 @@
-using System;
-using System.Collections.Generic;
using System.Reflection;
namespace Moq.AutoMock;
diff --git a/Moq.AutoMock/Resolvers/ArrayResolver.cs b/Moq.AutoMock/Resolvers/ArrayResolver.cs
index 045af009..e0890ed5 100644
--- a/Moq.AutoMock/Resolvers/ArrayResolver.cs
+++ b/Moq.AutoMock/Resolvers/ArrayResolver.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace Moq.AutoMock.Resolvers;
+namespace Moq.AutoMock.Resolvers;
///
/// Provides a means to create arrays.
diff --git a/Moq.AutoMock/Resolvers/CacheResolver.cs b/Moq.AutoMock/Resolvers/CacheResolver.cs
index 1ed1f08b..f05ac5b6 100644
--- a/Moq.AutoMock/Resolvers/CacheResolver.cs
+++ b/Moq.AutoMock/Resolvers/CacheResolver.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-
-namespace Moq.AutoMock.Resolvers;
+namespace Moq.AutoMock.Resolvers;
///
/// Provides the cache used by AutoMocker.
diff --git a/Moq.AutoMock/Resolvers/EnumerableResolver.cs b/Moq.AutoMock/Resolvers/EnumerableResolver.cs
index 2c174766..e81d96ec 100644
--- a/Moq.AutoMock/Resolvers/EnumerableResolver.cs
+++ b/Moq.AutoMock/Resolvers/EnumerableResolver.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
+using System.Reflection;
namespace Moq.AutoMock.Resolvers;
diff --git a/Moq.AutoMock/Resolvers/FuncResolver.cs b/Moq.AutoMock/Resolvers/FuncResolver.cs
index 3751258e..5e285d6d 100644
--- a/Moq.AutoMock/Resolvers/FuncResolver.cs
+++ b/Moq.AutoMock/Resolvers/FuncResolver.cs
@@ -1,5 +1,4 @@
-using System;
-using Moq.AutoMock.Extensions;
+using Moq.AutoMock.Extensions;
namespace Moq.AutoMock.Resolvers;
diff --git a/Moq.AutoMock/Resolvers/LazyResolver.cs b/Moq.AutoMock/Resolvers/LazyResolver.cs
index f4bc8085..630f541c 100644
--- a/Moq.AutoMock/Resolvers/LazyResolver.cs
+++ b/Moq.AutoMock/Resolvers/LazyResolver.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq;
-using System.Reflection;
+using System.Reflection;
using Moq.AutoMock.Extensions;
namespace Moq.AutoMock.Resolvers;
diff --git a/Moq.AutoMock/Resolvers/MockResolutionContext.cs b/Moq.AutoMock/Resolvers/MockResolutionContext.cs
index 04171afc..3f002813 100644
--- a/Moq.AutoMock/Resolvers/MockResolutionContext.cs
+++ b/Moq.AutoMock/Resolvers/MockResolutionContext.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace Moq.AutoMock.Resolvers;
+namespace Moq.AutoMock.Resolvers;
///
/// The context used to resolve types from an AutoMocker instance.
diff --git a/Moq.AutoMocker.TestGenerator.Tests/CSharpSourceGeneratorVerifier.cs b/Moq.AutoMocker.TestGenerator.Tests/CSharpSourceGeneratorVerifier.cs
new file mode 100644
index 00000000..cd2f9b0f
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator.Tests/CSharpSourceGeneratorVerifier.cs
@@ -0,0 +1,50 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace Moq.AutoMocker.TestGenerator.Tests;
+
+public static class CSharpSourceGeneratorVerifier
+ where TSourceGenerator : ISourceGenerator, new()
+{
+ public class Test : CSharpSourceGeneratorTest
+ {
+ public bool ReferenceAutoMocker { get; set; } = true;
+
+ protected override Project ApplyCompilationOptions(Project project)
+ {
+ if (ReferenceAutoMocker)
+ {
+ string fullPath = Path.GetFullPath($"{AutoMock.AssemblyName}.dll");
+ project = project.AddMetadataReference(MetadataReference.CreateFromFile(fullPath));
+ }
+ return base.ApplyCompilationOptions(project);
+ }
+
+ protected override CompilationOptions CreateCompilationOptions()
+ {
+ var compilationOptions = base.CreateCompilationOptions();
+ return compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler()));
+ }
+
+ public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
+
+ private static ImmutableDictionary GetNullableWarningsFromCompiler()
+ {
+ string[] args = { "/warnaserror:nullable" };
+ var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
+ var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
+
+ return nullableWarnings;
+ }
+
+ protected override ParseOptions CreateParseOptions()
+ {
+ return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
+ }
+ }
+}
diff --git a/Moq.AutoMocker.TestGenerator.Tests/Moq.AutoMocker.TestGenerator.Tests.csproj b/Moq.AutoMocker.TestGenerator.Tests/Moq.AutoMocker.TestGenerator.Tests.csproj
new file mode 100644
index 00000000..7967cf31
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator.Tests/Moq.AutoMocker.TestGenerator.Tests.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net6.0
+
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Moq.AutoMocker.TestGenerator.Tests/UnitTests.cs b/Moq.AutoMocker.TestGenerator.Tests/UnitTests.cs
new file mode 100644
index 00000000..68d52fdc
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator.Tests/UnitTests.cs
@@ -0,0 +1,94 @@
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Text;
+using System.Threading.Tasks;
+
+using VerifyCS = Moq.AutoMocker.TestGenerator.Tests.CSharpSourceGeneratorVerifier;
+
+namespace Moq.AutoMocker.TestGenerator.Tests;
+
+[TestClass]
+public class TestGeneratorTests
+{
+ [TestMethod]
+ public async Task Generation_WithProjectThatDoesNotReferenceAutoMocker_ProducesDiagnosticWarning()
+ {
+ var expectedResult =
+ DiagnosticResult.CompilerWarning(Diagnostics.MustReferenceAutoMock.DiagnosticId);
+ await new VerifyCS.Test
+ {
+ ReferenceAutoMocker = false,
+ ExpectedDiagnostics =
+ {
+ expectedResult
+ }
+ }.RunAsync();
+ }
+
+ [TestMethod]
+ public async Task Generation_WithDecoratedNonPartialClass_ProducesDiagnosticError()
+ {
+ var code = @"
+using Moq.AutoMock;
+
+namespace TestNamespace;
+
+[ConstructorTests(TargetType = typeof(Controller))]
+public class ControllerTests
+{
+
+}
+
+public class Controller { }
+";
+ var expectedResult =
+ DiagnosticResult.CompilerError(Diagnostics.TestClassesMustBePartial.DiagnosticId)
+ .WithSpan(6, 1, 10, 2)
+ .WithArguments("TestNamespace.ControllerTests");
+ await new VerifyCS.Test
+ {
+ TestState =
+ {
+ Sources = { code },
+ },
+ ExpectedDiagnostics =
+ {
+ expectedResult
+ }
+ }.RunAsync();
+ }
+
+ [TestMethod]
+ public async Task Generation_WithNoTargetTypeSpecified_ProducesDiagnosticError()
+ {
+ var code = @"
+using Moq.AutoMock;
+
+namespace TestNamespace;
+
+[ConstructorTests]
+public class ControllerTests
+{
+
+}
+
+public class Controller { }
+";
+ var expectedResult =
+ DiagnosticResult.CompilerError(Diagnostics.MustSpecifyTargetType.DiagnosticId)
+ .WithSpan(6, 2, 6, 18)
+ .WithArguments("TestNamespace.ControllerTests");
+ await new VerifyCS.Test
+ {
+ TestState =
+ {
+ Sources = { code },
+ },
+ ExpectedDiagnostics =
+ {
+ expectedResult
+ }
+ }.RunAsync();
+ }
+}
diff --git a/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Shipped.md b/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Shipped.md
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Shipped.md
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Unshipped.md b/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Unshipped.md
new file mode 100644
index 00000000..f7f5d6ce
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/AnalyzerReleases.Unshipped.md
@@ -0,0 +1,7 @@
+### New Rules
+
+Rule ID | Category | Severity | Notes
+--------|----------|----------|-------
+AMG0001 | AutoMocker.TestGenerator | Error | TestClassesMustBePartial
+AMG0002 | AutoMocker.TestGenerator | Warning | MustReferenceAutoMock
+AMG0003 | AutoMocker.TestGenerator | Error | MustSpecifyTargetType
\ No newline at end of file
diff --git a/Moq.AutoMocker.TestGenerator/AutoMock.cs b/Moq.AutoMocker.TestGenerator/AutoMock.cs
new file mode 100644
index 00000000..c3170c81
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/AutoMock.cs
@@ -0,0 +1,14 @@
+namespace Moq.AutoMocker.TestGenerator;
+
+public static class AutoMock
+{
+ public const string ConstructorTestsAttribute = "ConstructorTestsAttribute";
+
+ public const string TargetTypePropertyName = "TargetType";
+
+
+ public const string AssemblyName = "Moq.AutoMock";
+
+ public const string NuGetPackageName = "Moq.AutoMock";
+
+}
diff --git a/Moq.AutoMocker.TestGenerator/Diagnostics.cs b/Moq.AutoMocker.TestGenerator/Diagnostics.cs
new file mode 100644
index 00000000..675bf1db
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/Diagnostics.cs
@@ -0,0 +1,55 @@
+using Microsoft.CodeAnalysis;
+
+namespace Moq.AutoMocker.TestGenerator;
+
+public static class Diagnostics
+{
+ private const string Category = "AutoMocker.TestGenerator";
+ public static class TestClassesMustBePartial
+ {
+ public const string DiagnosticId = "AMG0001";
+ private const string Title = "Test class must be partial";
+ private const string MessageFormat = $"Class {{0}} is decorated with {AutoMock.ConstructorTestsAttribute} attribute but is not declared as a partial class";
+ private const string Description = "To generate constructor tests, the test class must be declared as partial. The tests are then generated into the partial class.";
+
+ //NB: Do not make a property or use target-typed new expression
+ //https://github.com/dotnet/roslyn-analyzers/issues/5890?msclkid=db74545bc13811ecac296aa1a3a09b53
+ private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat,
+ Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
+
+ public static Diagnostic Create(Location? location, string className)
+ => Diagnostic.Create(Rule, location, className);
+ }
+
+ public static class MustReferenceAutoMock
+ {
+ public const string DiagnosticId = "AMG0002";
+ private const string Title = $"Test projects must reference {AutoMock.AssemblyName}";
+ private const string MessageFormat = $"To use Moq.AutoMocker.TestGenerator, your test project must also reference {AutoMock.AssemblyName}";
+ private const string Description = $"Add a reference to the {AutoMock.AssemblyName} assembly or reference the {AutoMock.NuGetPackageName} NuGet package by running \"Install-Package Moq.AutoMock\".";
+
+ //NB: Do not make a property or use target-typed new expression
+ //https://github.com/dotnet/roslyn-analyzers/issues/5890?msclkid=db74545bc13811ecac296aa1a3a09b53
+ private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat,
+ Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
+
+ public static Diagnostic Create()
+ => Diagnostic.Create(Rule, null);
+ }
+
+ public static class MustSpecifyTargetType
+ {
+ public const string DiagnosticId = "AMG0003";
+ private const string Title = $"{AutoMock.ConstructorTestsAttribute} must specify a {AutoMock.TargetTypePropertyName}";
+ private const string MessageFormat = $"Class {{0}} is decorated with {AutoMock.ConstructorTestsAttribute} attribute but it does not specify a {AutoMock.TargetTypePropertyName}. Set this property to the type you want to generate tests for: [Moq.AutoMock.ConstructorTests(TargetType = typeof(TypeToGenerateTestsFor))].";
+ private const string Description = $"Add the {AutoMock.TargetTypePropertyName} to the {AutoMock.ConstructorTestsAttribute} attribute.";
+
+ //NB: Do not make a property or use target-typed new expression
+ //https://github.com/dotnet/roslyn-analyzers/issues/5890?msclkid=db74545bc13811ecac296aa1a3a09b53
+ private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat,
+ Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
+
+ public static Diagnostic Create(Location? location, string className)
+ => Diagnostic.Create(Rule, location, className);
+ }
+}
diff --git a/Moq.AutoMocker.TestGenerator/GeneratorTargetClass.cs b/Moq.AutoMocker.TestGenerator/GeneratorTargetClass.cs
new file mode 100644
index 00000000..e73a09c1
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/GeneratorTargetClass.cs
@@ -0,0 +1,40 @@
+using Microsoft.CodeAnalysis;
+
+namespace Moq.AutoMocker.TestGenerator;
+
+public class GeneratorTargetClass
+{
+ public string? Namespace { get; set; }
+ public string? TestClassName { get; set; }
+
+ public SutClass? Sut { get; set; }
+}
+
+
+public class SutClass
+{
+ public string? Name { get; set; }
+ public string? FullName { get; set; }
+
+ public List NullConstructorParameterTests { get; } = new();
+}
+
+public class NullConstructorParameterTest
+{
+ public List? Parameters { get; set; }
+ public int NullParameterIndex { get; set; }
+ public string? NullTypeName { get; set; }
+ public string? NullParameterName => Parameters?[NullParameterIndex].Name;
+}
+
+public class Parameter
+{
+ public Parameter(IParameterSymbol symbol)
+ {
+ Symbol = symbol;
+ }
+ private IParameterSymbol Symbol { get; }
+
+ public string Name => Symbol.Name;
+ public string ParameterType => Symbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+}
diff --git a/Moq.AutoMocker.TestGenerator/Moq.AutoMocker.TestGenerator.csproj b/Moq.AutoMocker.TestGenerator/Moq.AutoMocker.TestGenerator.csproj
new file mode 100644
index 00000000..03ddeb65
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/Moq.AutoMocker.TestGenerator.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netstandard2.0
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs b/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs
new file mode 100644
index 00000000..0cad2bba
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs
@@ -0,0 +1,89 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Moq.AutoMocker.TestGenerator;
+
+public class SyntaxReceiver : ISyntaxContextReceiver
+{
+ public List TestClasses { get; } = new();
+
+ public List DiagnosticMessages { get; } = new();
+
+ private TypeSyntax? GetTargetType(AttributeSyntax attributeSyntax)
+ {
+ return attributeSyntax.ArgumentList?.Arguments.Count > 0 &&
+ attributeSyntax.ArgumentList.Arguments
+ .Select(x => x.Expression)
+ .OfType()
+ .FirstOrDefault() is { } typeExpression
+ ? typeExpression.Type
+ : null;
+ }
+
+ public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
+ {
+ if (context.Node is ClassDeclarationSyntax classDeclaration &&
+ context.SemanticModel.GetDeclaredSymbol(classDeclaration) is INamedTypeSymbol symbol &&
+ classDeclaration.AttributeLists.SelectMany(x => x.Attributes)
+ .Select(a =>
+ {
+ if (context.SemanticModel.GetTypeInfo(a).Type?.Name == AutoMock.ConstructorTestsAttribute)
+ {
+ if (GetTargetType(a) is { } targetType &&
+ context.SemanticModel.GetTypeInfo(targetType).Type is INamedTypeSymbol sutType)
+ {
+ return sutType;
+ }
+ Diagnostic diagnostic = Diagnostics.MustSpecifyTargetType.Create(a.GetLocation(),
+ symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
+ DiagnosticMessages.Add(diagnostic);
+ }
+ return null;
+ })
+ .FirstOrDefault(a => a is not null) is { } sutType
+ )
+ {
+ if (!classDeclaration.Modifiers.Any(x => x.IsKind(SyntaxKind.PartialKeyword)))
+ {
+ Diagnostic diagnostic = Diagnostics.TestClassesMustBePartial.Create(classDeclaration.GetLocation(),
+ symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
+ DiagnosticMessages.Add(diagnostic);
+ return;
+ }
+ string testClassName = symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
+ string namespaceDeclaration = symbol.ContainingNamespace.ToDisplayString();
+
+ SutClass sut = new()
+ {
+ Name = sutType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
+ FullName = sutType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
+ };
+
+ foreach (IMethodSymbol ctor in sutType.Constructors)
+ {
+ var parameters = ctor.Parameters.Select(x => new Parameter(x)).ToList();
+ int nullIndex = 0;
+ foreach (IParameterSymbol parameter in ctor.Parameters)
+ {
+ sut.NullConstructorParameterTests.Add(new NullConstructorParameterTest()
+ {
+ Parameters = parameters,
+ NullParameterIndex = nullIndex,
+ NullTypeName = parameter.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
+ });
+ nullIndex++;
+ }
+ }
+
+ GeneratorTargetClass targetClass = new()
+ {
+ Namespace = namespaceDeclaration,
+ TestClassName = testClassName,
+ Sut = sut
+ };
+
+ TestClasses.Add(targetClass);
+ }
+ }
+}
diff --git a/Moq.AutoMocker.TestGenerator/UnitTestSourceGenerator.cs b/Moq.AutoMocker.TestGenerator/UnitTestSourceGenerator.cs
new file mode 100644
index 00000000..a506e74d
--- /dev/null
+++ b/Moq.AutoMocker.TestGenerator/UnitTestSourceGenerator.cs
@@ -0,0 +1,164 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+
+namespace Moq.AutoMocker.TestGenerator;
+
+[Generator]
+public class UnitTestSourceGenerator : ISourceGenerator
+{
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.Compilation.Language is not LanguageNames.CSharp) return;
+
+ if (!context.Compilation.ReferencedAssemblyNames.Any(ai => ai.Name.Equals(AutoMock.AssemblyName, StringComparison.OrdinalIgnoreCase)))
+ {
+ context.ReportDiagnostic(Diagnostics.MustReferenceAutoMock.Create());
+ return;
+ }
+
+ SyntaxReceiver rx = (SyntaxReceiver)context.SyntaxContextReceiver!;
+
+ foreach (Diagnostic diagnostic in rx.DiagnosticMessages)
+ {
+ context.ReportDiagnostic(diagnostic);
+ }
+
+ var testingFramework = GetTestingFramework(context.Compilation.ReferencedAssemblyNames);
+
+ foreach (GeneratorTargetClass testClass in rx.TestClasses)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine($"namespace {testClass.Namespace}");
+ builder.AppendLine("{");
+
+ builder.AppendLine($" partial class {testClass.TestClassName}");
+ builder.AppendLine(" {");
+ builder.AppendLine($" partial void AutoMockerTestSetup(Moq.AutoMock.AutoMocker mocker, string testName);");
+ builder.AppendLine();
+
+ HashSet testNames = new();
+
+ foreach (var test in testClass.Sut?.NullConstructorParameterTests ?? Enumerable.Empty())
+ {
+ string testName;
+ int testNameIndex = 0;
+ for (testName = $"{testClass.Sut!.Name}Constructor_WithNull{test.NullTypeName}_ThrowsArgumentNullException";
+ !testNames.Add(testName);
+ testName = $"{testClass.Sut!.Name}Constructor_WithNull{test.NullTypeName}{++testNameIndex}_ThrowsArgumentNullException")
+ { }
+
+ builder.AppendLine($" partial void {testName}Setup(Moq.AutoMock.AutoMocker mocker);");
+ builder.AppendLine();
+
+ switch (testingFramework)
+ {
+ case TargetTestingFramework.MSTest:
+ builder.AppendLine(" [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]");
+ break;
+ case TargetTestingFramework.Xunit:
+ builder.AppendLine(" [global::Xunit.Fact]");
+ break;
+ case TargetTestingFramework.NUnit:
+ builder.AppendLine(" [global::NUnit.Framework.Test]");
+ break;
+ }
+
+
+ builder.AppendLine($" public void {testName}()");
+ builder.AppendLine(" {");
+ builder.AppendLine(" Moq.AutoMock.AutoMocker mocker = new Moq.AutoMock.AutoMocker();");
+ builder.AppendLine($" AutoMockerTestSetup(mocker, \"{testName}\");");
+ builder.AppendLine($" {testName}Setup(mocker);");
+
+ for (int i = 0; i < test.Parameters?.Count; i++)
+ {
+ if (i == test.NullParameterIndex) continue;
+ Parameter parameter = test.Parameters[i];
+ builder.AppendLine($" var {parameter.Name} = mocker.Get<{parameter.ParameterType}>();");
+ }
+
+ string constructorInvocation = $"_ = new {testClass.Sut.FullName}({string.Join(",", GetParameterNames(test))})";
+
+ switch (testingFramework)
+ {
+ case TargetTestingFramework.MSTest:
+ builder.AppendLine($" System.ArgumentNullException ex = global::Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsException(() => {constructorInvocation});");
+ builder.AppendLine($" global::Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual(\"{test.NullParameterName}\", ex.ParamName);");
+ break;
+ case TargetTestingFramework.Xunit:
+ builder.AppendLine($" System.ArgumentNullException ex = global::Xunit.Assert.Throws(() => {constructorInvocation});");
+ builder.AppendLine($" global::Xunit.Assert.Equal(\"{test.NullParameterName}\", ex.ParamName);");
+ break;
+ case TargetTestingFramework.NUnit:
+ builder.AppendLine($" System.ArgumentNullException ex = global::NUnit.Framework.Assert.Throws(() => {constructorInvocation});");
+ builder.AppendLine($" global::NUnit.Framework.Assert.AreEqual(\"{test.NullParameterName}\", ex.ParamName);");
+ break;
+ }
+
+ builder.AppendLine(" }");
+ builder.AppendLine();
+ }
+
+ builder.AppendLine(" }");
+ builder.AppendLine("}");
+
+ context.AddSource($"{testClass.TestClassName}.g.cs", builder.ToString());
+
+ }
+
+ static IEnumerable GetParameterNames(NullConstructorParameterTest test)
+ {
+ for (int i = 0; i < test.Parameters?.Count; i++)
+ {
+ if (i == test.NullParameterIndex)
+ {
+ yield return $"default({test.Parameters[i].ParameterType})";
+ }
+ else
+ {
+ yield return test.Parameters[i].Name;
+ }
+ }
+ }
+ }
+
+ public void Initialize(GeneratorInitializationContext context)
+ {
+#if DEBUG
+ if (!System.Diagnostics.Debugger.IsAttached)
+ {
+ //System.Diagnostics.Debugger.Launch();
+ }
+#endif
+ context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
+ }
+
+ private static TargetTestingFramework GetTestingFramework(IEnumerable assemblies)
+ {
+ foreach (AssemblyIdentity assembly in assemblies)
+ {
+ if (assembly.Name.StartsWith("Microsoft.VisualStudio.TestPlatform.TestFramework"))
+ {
+ return TargetTestingFramework.MSTest;
+ }
+ if (assembly.Name.StartsWith("nunit."))
+ {
+ return TargetTestingFramework.NUnit;
+ }
+ if (assembly.Name.StartsWith("xunit."))
+ {
+ return TargetTestingFramework.Xunit;
+ }
+ }
+ return TargetTestingFramework.Unknown;
+ }
+}
+
+public enum TargetTestingFramework
+{
+ Unknown,
+ MSTest,
+ Xunit,
+ NUnit
+}