diff --git a/.editorconfig b/.editorconfig index 0ec2192c..8bc95a8d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -170,7 +170,11 @@ csharp_space_between_square_brackets = false # Wrapping preferences csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = true -csharp_style_namespace_declarations=file_scoped:warning +csharp_style_namespace_declarations= file_scoped:warning +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion #### Naming styles #### [*.{cs,vb}] @@ -362,4 +366,7 @@ dotnet_naming_style.s_camelcase.required_prefix = s_ dotnet_naming_style.s_camelcase.required_suffix = dotnet_naming_style.s_camelcase.word_separator = dotnet_naming_style.s_camelcase.capitalization = camel_case +tab_width = 4 +indent_size = 4 +end_of_line = crlf diff --git a/Moq.AutoMocker.Generators.Tests/UnitTests.cs b/Moq.AutoMocker.Generators.Tests/GeneratorsTests.cs similarity index 74% rename from Moq.AutoMocker.Generators.Tests/UnitTests.cs rename to Moq.AutoMocker.Generators.Tests/GeneratorsTests.cs index cb03d824..cc6e156f 100644 --- a/Moq.AutoMocker.Generators.Tests/UnitTests.cs +++ b/Moq.AutoMocker.Generators.Tests/GeneratorsTests.cs @@ -89,42 +89,44 @@ public class Controller { } [Description("Issue 142")] public async Task Generation_WithGenericParameter_RemovesInvalidCharactersFromTestsName() { - var code = @" -using Moq.AutoMock; + var code = """ + using Moq.AutoMock; -namespace TestNamespace; + namespace TestNamespace; -[ConstructorTests(typeof(Controller))] -public partial class ControllerTests -{ + [ConstructorTests(typeof(Controller))] + public partial class ControllerTests + { -} + } -public class Controller -{ - public Controller(ILogger logger) { } -} + public class Controller + { + public Controller(ILogger logger) { } + } -public interface ILogger { } -"; - string expected = @"namespace TestNamespace -{ - partial class ControllerTests - { - partial void AutoMockerTestSetup(Moq.AutoMock.AutoMocker mocker, string testName); + public interface ILogger { } + """; + string expected = """ + namespace TestNamespace + { + partial class ControllerTests + { + partial void AutoMockerTestSetup(Moq.AutoMock.AutoMocker mocker, string testName); - partial void ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullExceptionSetup(Moq.AutoMock.AutoMocker mocker); + partial void ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullExceptionSetup(Moq.AutoMock.AutoMocker mocker); - public void ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullException() - { - Moq.AutoMock.AutoMocker mocker = new Moq.AutoMock.AutoMocker(); - AutoMockerTestSetup(mocker, ""ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullException""); - ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullExceptionSetup(mocker); - } + public void ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullException() + { + Moq.AutoMock.AutoMocker mocker = new Moq.AutoMock.AutoMocker(); + AutoMockerTestSetup(mocker, "ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullException"); + ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullExceptionSetup(mocker); + } - } -} -"; + } + } + + """; await new VerifyCS.Test { diff --git a/Moq.AutoMocker.TestGenerator.Tests/TestGeneratorTests.cs b/Moq.AutoMocker.Generators.Tests/TestGeneratorTests.cs similarity index 98% rename from Moq.AutoMocker.TestGenerator.Tests/TestGeneratorTests.cs rename to Moq.AutoMocker.Generators.Tests/TestGeneratorTests.cs index fe30f37d..0ab79be4 100644 --- a/Moq.AutoMocker.TestGenerator.Tests/TestGeneratorTests.cs +++ b/Moq.AutoMocker.Generators.Tests/TestGeneratorTests.cs @@ -2,10 +2,9 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; +using VerifyCS = Moq.AutoMocker.Generators.Tests.CSharpSourceGeneratorVerifier; -using VerifyCS = Moq.AutoMocker.TestGenerator.Tests.CSharpSourceGeneratorVerifier; - -namespace Moq.AutoMocker.TestGenerator.Tests; +namespace Moq.AutoMocker.Generators.Tests; [TestClass] public class TestGeneratorTests @@ -136,7 +135,7 @@ public void ControllerConstructor_WithNullILoggerController_ThrowsArgumentNullEx GetSourceFile(expected, "ControllerTests.g.cs") } } - + }.RunAsync(); } diff --git a/Moq.AutoMocker.Generators/SyntaxReceiver.cs b/Moq.AutoMocker.Generators/SyntaxReceiver.cs index abae63f0..67b4da9d 100644 --- a/Moq.AutoMocker.Generators/SyntaxReceiver.cs +++ b/Moq.AutoMocker.Generators/SyntaxReceiver.cs @@ -2,6 +2,8 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Moq.AutoMocker.Generators.AutoMock; + namespace Moq.AutoMocker.Generators; public class SyntaxReceiver : ISyntaxContextReceiver @@ -21,29 +23,35 @@ public class SyntaxReceiver : ISyntaxContextReceiver : null; } + private bool GetSkipNullableParameters(AttributeSyntax attributeSyntax) + { + return attributeSyntax.ArgumentList?.Arguments.Count > 0 && + attributeSyntax.ArgumentList!.Arguments + .Select(x => x.Expression) + .OfType() + .FirstOrDefault() is { Name.Identifier.ValueText: IgnoreNullableParametersEnumValue }; + } + + 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 - ) + .Select(a => context.SemanticModel.GetTypeInfo(a).Type?.Name == ConstructorTestsAttribute ? a : null) + .FirstOrDefault(a => a is not null) is { } attribute) { + if (!(GetTargetType(attribute) is { } targetType) || + context.SemanticModel.GetTypeInfo(targetType).Type is not INamedTypeSymbol sutType) + { + Diagnostic diagnostic = Diagnostics.MustSpecifyTargetType.Create(attribute.GetLocation(), + symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + DiagnosticMessages.Add(diagnostic); + return; + } + + bool skipNullableParameters = GetSkipNullableParameters(attribute); + if (!classDeclaration.Modifiers.Any(x => x.IsKind(SyntaxKind.PartialKeyword))) { Diagnostic diagnostic = Diagnostics.TestClassesMustBePartial.Create(classDeclaration.GetLocation(), @@ -66,7 +74,6 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) int nullIndex = 0; foreach (IParameterSymbol parameter in ctor.Parameters) { - if (parameter.Type.IsValueType) continue; sut.NullConstructorParameterTests.Add(new NullConstructorParameterTest() { Parameters = parameters, @@ -81,7 +88,8 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { Namespace = namespaceDeclaration, TestClassName = testClassName, - Sut = sut + Sut = sut, + SkipNullableParameters = skipNullableParameters }; TestClasses.Add(targetClass); diff --git a/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs b/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs deleted file mode 100644 index 9776b1f4..00000000 --- a/Moq.AutoMocker.TestGenerator/SyntaxReceiver.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using static Moq.AutoMocker.TestGenerator.AutoMock; - -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; - } - - private bool GetSkipNullableParameters(AttributeSyntax attributeSyntax) - { - return attributeSyntax.ArgumentList?.Arguments.Count > 0 && - attributeSyntax.ArgumentList!.Arguments - .Select(x => x.Expression) - .OfType() - .FirstOrDefault() is { Name.Identifier.ValueText: IgnoreNullableParametersEnumValue }; - } - - 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 => context.SemanticModel.GetTypeInfo(a).Type?.Name == ConstructorTestsAttribute ? a : null) - .FirstOrDefault(a => a is not null) is { } attribute) - { - if (!(GetTargetType(attribute) is { } targetType) || - context.SemanticModel.GetTypeInfo(targetType).Type is not INamedTypeSymbol sutType) - { - Diagnostic diagnostic = Diagnostics.MustSpecifyTargetType.Create(attribute.GetLocation(), - symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); - DiagnosticMessages.Add(diagnostic); - return; - } - - bool skipNullableParameters = GetSkipNullableParameters(attribute); - - 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, - SkipNullableParameters = skipNullableParameters - }; - - TestClasses.Add(targetClass); - } - } -}