Use same access modifier as the declaring class.
This commit is contained in:
parent
c7d6d3ff27
commit
f7ff6e4793
|
@ -9,7 +9,7 @@ namespace MapTo.Extensions
|
|||
|
||||
internal static T GetBuildGlobalOption<T>(this GeneratorExecutionContext context, string propertyName, T defaultValue = default!) where T: notnull
|
||||
{
|
||||
if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue($"build_property.{PropertyNameSuffix}{propertyName}", out var optionValue))
|
||||
if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(GetBuildPropertyName(propertyName), out var optionValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
@ -31,5 +31,7 @@ namespace MapTo.Extensions
|
|||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetBuildPropertyName(string propertyName) => $"build_property.{PropertyNameSuffix}{propertyName}";
|
||||
}
|
||||
}
|
|
@ -30,87 +30,27 @@ namespace MapTo
|
|||
AddGeneratedMappingsClasses(context, receiver.CandidateClasses, options);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddAttribute(GeneratorExecutionContext context, (string source, string hintName) attribute)
|
||||
=> context.AddSource(attribute.hintName, attribute.source);
|
||||
|
||||
private static void AddGeneratedMappingsClasses(GeneratorExecutionContext context, IEnumerable<ClassDeclarationSyntax> candidateClasses, SourceGenerationOptions options)
|
||||
{
|
||||
foreach (var classSyntax in candidateClasses)
|
||||
{
|
||||
var model = CreateModel(context, classSyntax, options);
|
||||
var classSemanticModel = context.Compilation.GetSemanticModel(classSyntax.SyntaxTree);
|
||||
var (model, diagnostics) = MapModel.CreateModel(classSemanticModel, classSyntax, options);
|
||||
|
||||
diagnostics.ForEach(context.ReportDiagnostic);
|
||||
|
||||
if (model is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var (source, hintName) = SourceBuilder.GenerateSource(model);
|
||||
|
||||
context.AddSource(hintName, source);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddAttribute(GeneratorExecutionContext context, (string source, string hintName) attribute)
|
||||
=> context.AddSource(attribute.hintName, attribute.source);
|
||||
|
||||
private static INamedTypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classSyntax, SemanticModel model)
|
||||
{
|
||||
var sourceTypeExpressionSyntax = classSyntax
|
||||
.GetAttribute(SourceBuilder.MapFromAttributeName)
|
||||
?.DescendantNodes()
|
||||
.OfType<TypeOfExpressionSyntax>()
|
||||
.SingleOrDefault();
|
||||
|
||||
return sourceTypeExpressionSyntax is not null ? model.GetTypeInfo(sourceTypeExpressionSyntax.Type).Type as INamedTypeSymbol : null;
|
||||
}
|
||||
|
||||
private static MapModel? CreateModel(GeneratorExecutionContext context, ClassDeclarationSyntax classSyntax, SourceGenerationOptions sourceGenerationOptions)
|
||||
{
|
||||
var root = classSyntax.GetCompilationUnit();
|
||||
var classSemanticModel = context.Compilation.GetSemanticModel(classSyntax.SyntaxTree);
|
||||
|
||||
if (!(classSemanticModel.GetDeclaredSymbol(classSyntax) is INamedTypeSymbol classSymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostics.SymbolNotFoundError(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
|
||||
return null;
|
||||
}
|
||||
|
||||
var sourceTypeSymbol = GetSourceTypeSymbol(classSyntax, classSemanticModel);
|
||||
if (sourceTypeSymbol is null)
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostics.MapFromAttributeNotFoundError(classSyntax.GetLocation()));
|
||||
return null;
|
||||
}
|
||||
|
||||
var className = classSyntax.GetClassName();
|
||||
var sourceClassName = sourceTypeSymbol.Name;
|
||||
|
||||
var mappedProperties = GetMappedProperties(classSymbol, sourceTypeSymbol);
|
||||
if (!mappedProperties.Any())
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostics.NoMatchingPropertyFoundError(classSyntax.GetLocation(), className, sourceClassName));
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MapModel(
|
||||
sourceGenerationOptions,
|
||||
root.GetNamespace(),
|
||||
classSyntax.Modifiers,
|
||||
className,
|
||||
sourceTypeSymbol.ContainingNamespace.ToString(),
|
||||
sourceClassName,
|
||||
sourceTypeSymbol.ToString(),
|
||||
mappedProperties);
|
||||
}
|
||||
|
||||
private static ImmutableArray<string> GetMappedProperties(ITypeSymbol classSymbol, ITypeSymbol sourceTypeSymbol)
|
||||
{
|
||||
return sourceTypeSymbol
|
||||
.GetAllMembersOfType<IPropertySymbol>()
|
||||
.Select(p => (p.Name, p.Type.ToString()))
|
||||
.Intersect(classSymbol
|
||||
.GetAllMembersOfType<IPropertySymbol>()
|
||||
.Where(p => p.GetAttributes().All(a => a.AttributeClass?.Name != SourceBuilder.IgnorePropertyAttributeName))
|
||||
.Select(p => (p.Name, p.Type.ToString())))
|
||||
.Select(p => p.Name)
|
||||
.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using MapTo.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace MapTo.Models
|
||||
{
|
||||
|
@ -12,5 +16,74 @@ namespace MapTo.Models
|
|||
string SourceClassName,
|
||||
string SourceClassFullName,
|
||||
ImmutableArray<string> MappedProperties
|
||||
);
|
||||
)
|
||||
{
|
||||
internal static (MapModel? model, IEnumerable<Diagnostic> diagnostics) CreateModel(
|
||||
SemanticModel classSemanticModel,
|
||||
ClassDeclarationSyntax classSyntax,
|
||||
SourceGenerationOptions sourceGenerationOptions)
|
||||
{
|
||||
var diagnostics = new List<Diagnostic>();
|
||||
var root = classSyntax.GetCompilationUnit();
|
||||
|
||||
if (!(classSemanticModel.GetDeclaredSymbol(classSyntax) is INamedTypeSymbol classSymbol))
|
||||
{
|
||||
diagnostics.Add(Diagnostics.SymbolNotFoundError(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
|
||||
return (default, diagnostics);
|
||||
}
|
||||
|
||||
var sourceTypeSymbol = GetSourceTypeSymbol(classSyntax, classSemanticModel);
|
||||
if (sourceTypeSymbol is null)
|
||||
{
|
||||
diagnostics.Add(Diagnostics.MapFromAttributeNotFoundError(classSyntax.GetLocation()));
|
||||
return (default, diagnostics);
|
||||
}
|
||||
|
||||
var className = classSyntax.GetClassName();
|
||||
var sourceClassName = sourceTypeSymbol.Name;
|
||||
|
||||
var mappedProperties = GetMappedProperties(classSymbol, sourceTypeSymbol);
|
||||
if (!mappedProperties.Any())
|
||||
{
|
||||
diagnostics.Add(Diagnostics.NoMatchingPropertyFoundError(classSyntax.GetLocation(), className, sourceClassName));
|
||||
return (default, diagnostics);
|
||||
}
|
||||
|
||||
var model = new MapModel(
|
||||
sourceGenerationOptions,
|
||||
root.GetNamespace(),
|
||||
classSyntax.Modifiers,
|
||||
className,
|
||||
sourceTypeSymbol.ContainingNamespace.ToString(),
|
||||
sourceClassName,
|
||||
sourceTypeSymbol.ToString(),
|
||||
mappedProperties);
|
||||
|
||||
return (model, diagnostics);
|
||||
}
|
||||
|
||||
private static INamedTypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classSyntax, SemanticModel model)
|
||||
{
|
||||
var sourceTypeExpressionSyntax = classSyntax
|
||||
.GetAttribute(SourceBuilder.MapFromAttributeName)
|
||||
?.DescendantNodes()
|
||||
.OfType<TypeOfExpressionSyntax>()
|
||||
.SingleOrDefault();
|
||||
|
||||
return sourceTypeExpressionSyntax is not null ? model.GetTypeInfo(sourceTypeExpressionSyntax.Type).Type as INamedTypeSymbol : null;
|
||||
}
|
||||
|
||||
private static ImmutableArray<string> GetMappedProperties(ITypeSymbol classSymbol, ITypeSymbol sourceTypeSymbol)
|
||||
{
|
||||
return sourceTypeSymbol
|
||||
.GetAllMembersOfType<IPropertySymbol>()
|
||||
.Select(p => (p.Name, p.Type.ToString()))
|
||||
.Intersect(classSymbol
|
||||
.GetAllMembersOfType<IPropertySymbol>()
|
||||
.Where(p => p.GetAttributes().All(a => a.AttributeClass?.Name != SourceBuilder.IgnorePropertyAttributeName))
|
||||
.Select(p => (p.Name, p.Type.ToString())))
|
||||
.Select(p => p.Name)
|
||||
.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Models;
|
||||
|
||||
|
@ -111,7 +110,7 @@ namespace MapTo
|
|||
|
||||
// Class declaration
|
||||
.PadLeft(Indent1)
|
||||
.AppendFormat("{0} class {1}", model.ClassModifiers.ToFullString().Trim(), model.ClassName)
|
||||
.AppendFormat("partial class {0}", model.ClassName)
|
||||
.AppendOpeningBracket(Indent1)
|
||||
|
||||
// Class body
|
||||
|
@ -126,7 +125,7 @@ namespace MapTo
|
|||
.AppendLine()
|
||||
.AppendLine()
|
||||
.PadLeft(Indent1)
|
||||
.AppendFormat("{0} static partial class {1}To{2}Extensions", model.ClassModifiers.FirstOrDefault().ToFullString().Trim(), model.SourceClassName, model.ClassName)
|
||||
.AppendFormat("{0} static partial class {1}To{2}Extensions", model.Options.GeneratedMethodsAccessModifier.ToLowercaseString(), model.SourceClassName, model.ClassName)
|
||||
.AppendOpeningBracket(Indent1)
|
||||
|
||||
// Extension class body
|
||||
|
|
|
@ -8,6 +8,7 @@ using MapTo.Tests.Infrastructure;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using static MapTo.Extensions.GeneratorExecutionContextExtensions;
|
||||
|
||||
namespace MapTo.Tests
|
||||
{
|
||||
|
@ -19,9 +20,9 @@ namespace MapTo.Tests
|
|||
|
||||
private static readonly Dictionary<string, string> DefaultAnalyzerOptions = new()
|
||||
{
|
||||
["build_property.MapTo_GenerateXmlDocument"] = "false"
|
||||
[GetBuildPropertyName(nameof(SourceGenerationOptions.GenerateXmlDocument))] = "false"
|
||||
};
|
||||
|
||||
|
||||
private static readonly string ExpectedAttribute = $@"{SourceBuilder.GeneratedFilesHeader}
|
||||
using System;
|
||||
|
||||
|
@ -40,20 +41,20 @@ namespace MapTo
|
|||
}}";
|
||||
|
||||
private record SourceGeneratorOptions(
|
||||
bool UseMapToNamespace = false,
|
||||
string SourceClassNamespace = "Test.Models",
|
||||
int ClassPropertiesCount = 3,
|
||||
bool UseMapToNamespace = false,
|
||||
string SourceClassNamespace = "Test.Models",
|
||||
int ClassPropertiesCount = 3,
|
||||
int SourceClassPropertiesCount = 3,
|
||||
Action<StringBuilder> PropertyBuilder = null,
|
||||
Action<StringBuilder> SourcePropertyBuilder = null);
|
||||
|
||||
|
||||
private static string GetSourceText(SourceGeneratorOptions options = null)
|
||||
{
|
||||
const string ns = "Test";
|
||||
options ??= new SourceGeneratorOptions();
|
||||
var hasDifferentSourceNamespace = options.SourceClassNamespace != ns;
|
||||
var builder = new StringBuilder();
|
||||
|
||||
|
||||
if (options.UseMapToNamespace)
|
||||
{
|
||||
builder.AppendFormat("using {0};", SourceBuilder.NamespaceName).AppendLine();
|
||||
|
@ -76,7 +77,7 @@ namespace MapTo
|
|||
.AppendLine()
|
||||
.AppendLine();
|
||||
}
|
||||
|
||||
|
||||
builder
|
||||
.PadLeft(Indent1)
|
||||
.AppendLine(options.UseMapToNamespace ? "[MapTo.MapFrom(typeof(Baz))]" : "[MapFrom(typeof(Baz))]")
|
||||
|
@ -89,15 +90,15 @@ namespace MapTo
|
|||
.PadLeft(Indent2)
|
||||
.AppendLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}");
|
||||
}
|
||||
|
||||
|
||||
options.PropertyBuilder?.Invoke(builder);
|
||||
|
||||
builder
|
||||
.AppendClosingBracket(Indent1, padNewLine: false)
|
||||
.AppendClosingBracket(Indent1, false)
|
||||
.AppendClosingBracket()
|
||||
.AppendLine()
|
||||
.AppendLine();
|
||||
|
||||
|
||||
builder
|
||||
.AppendFormat("namespace {0}", options.SourceClassNamespace)
|
||||
.AppendOpeningBracket()
|
||||
|
@ -110,16 +111,40 @@ namespace MapTo
|
|||
.PadLeft(Indent2)
|
||||
.AppendLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}");
|
||||
}
|
||||
|
||||
|
||||
options.SourcePropertyBuilder?.Invoke(builder);
|
||||
|
||||
|
||||
builder
|
||||
.AppendClosingBracket(Indent1, padNewLine: false)
|
||||
.AppendClosingBracket(Indent1, false)
|
||||
.AppendClosingBracket();
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyIgnorePropertyAttribute()
|
||||
{
|
||||
// Arrange
|
||||
const string source = "";
|
||||
var expectedAttribute = $@"
|
||||
{SourceBuilder.GeneratedFilesHeader}
|
||||
using System;
|
||||
|
||||
namespace MapTo
|
||||
{{
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class IgnorePropertyAttribute : Attribute {{ }}
|
||||
}}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.ShouldContain(c => c.ToString() == expectedAttribute);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyMapToAttribute()
|
||||
{
|
||||
|
@ -134,6 +159,112 @@ namespace MapTo
|
|||
compilation.SyntaxTrees.ShouldContain(c => c.ToString() == ExpectedAttribute);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_FoundMatchingPropertyNameWithDifferentType_Should_Ignore()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText(new SourceGeneratorOptions(
|
||||
true,
|
||||
PropertyBuilder: builder =>
|
||||
{
|
||||
builder
|
||||
.PadLeft(Indent2).AppendLine("public string Prop4 { get; set; }");
|
||||
},
|
||||
SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }")));
|
||||
|
||||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
Prop1 = baz.Prop1;
|
||||
Prop2 = baz.Prop2;
|
||||
Prop3 = baz.Prop3;
|
||||
}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_IgnorePropertyAttributeIsSpecified_Should_NotGenerateMappingsForThatProperty()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText(new SourceGeneratorOptions(
|
||||
true,
|
||||
PropertyBuilder: builder =>
|
||||
{
|
||||
builder
|
||||
.PadLeft(Indent2).AppendLine("[IgnoreProperty]")
|
||||
.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }");
|
||||
},
|
||||
SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }")));
|
||||
|
||||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
Prop1 = baz.Prop1;
|
||||
Prop2 = baz.Prop2;
|
||||
Prop3 = baz.Prop3;
|
||||
}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_MappingsModifierOptionIsSetToInternal_Should_GenerateThoseMethodsWithInternalAccessModifier()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText();
|
||||
var configOptions = new Dictionary<string, string>
|
||||
{
|
||||
[GetBuildPropertyName(nameof(SourceGenerationOptions.GeneratedMethodsAccessModifier))] = "Internal",
|
||||
[GetBuildPropertyName(nameof(SourceGenerationOptions.GenerateXmlDocument))] = "false"
|
||||
};
|
||||
|
||||
var expectedExtension = @"
|
||||
internal static partial class BazToFooExtensions
|
||||
{
|
||||
internal static Foo ToFoo(this Test.Models.Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}
|
||||
}".Trim();
|
||||
|
||||
var expectedFactory = @"
|
||||
internal static Foo From(Test.Models.Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: configOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
|
||||
var syntaxTree = compilation.SyntaxTrees.Last().ToString();
|
||||
syntaxTree.ShouldContain(expectedFactory);
|
||||
syntaxTree.ShouldContain(expectedExtension);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_MapToAttributeFound_Should_GenerateTheClass()
|
||||
{
|
||||
|
@ -162,7 +293,7 @@ using System;
|
|||
|
||||
namespace Test
|
||||
{
|
||||
public partial class Foo
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Baz baz)
|
||||
{
|
||||
|
@ -179,7 +310,7 @@ namespace Test
|
|||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void When_MapToAttributeFoundWithoutMatchingProperties_Should_ReportError()
|
||||
{
|
||||
|
@ -225,7 +356,7 @@ using System;
|
|||
|
||||
namespace Test
|
||||
{
|
||||
public partial class Foo
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Baz baz)
|
||||
{
|
||||
|
@ -289,7 +420,7 @@ namespace Test
|
|||
var source = GetSourceText();
|
||||
|
||||
const string expectedResult = @"
|
||||
public partial class Foo
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
{
|
||||
|
@ -353,131 +484,5 @@ namespace Test
|
|||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyIgnorePropertyAttribute()
|
||||
{
|
||||
// Arrange
|
||||
const string source = "";
|
||||
var expectedAttribute = $@"
|
||||
{SourceBuilder.GeneratedFilesHeader}
|
||||
using System;
|
||||
|
||||
namespace MapTo
|
||||
{{
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class IgnorePropertyAttribute : Attribute {{ }}
|
||||
}}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.ShouldContain(c => c.ToString() == expectedAttribute);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_IgnorePropertyAttributeIsSpecified_Should_NotGenerateMappingsForThatProperty()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText(new SourceGeneratorOptions(
|
||||
UseMapToNamespace: true,
|
||||
PropertyBuilder: builder =>
|
||||
{
|
||||
builder
|
||||
.PadLeft(Indent2).AppendLine("[IgnoreProperty]")
|
||||
.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }");
|
||||
},
|
||||
SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }")));
|
||||
|
||||
var expectedResult = @"
|
||||
public partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
Prop1 = baz.Prop1;
|
||||
Prop2 = baz.Prop2;
|
||||
Prop3 = baz.Prop3;
|
||||
}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_FoundMatchingPropertyNameWithDifferentType_Should_Ignore()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText(new SourceGeneratorOptions(
|
||||
UseMapToNamespace: true,
|
||||
PropertyBuilder: builder =>
|
||||
{
|
||||
builder
|
||||
.PadLeft(Indent2).AppendLine("public string Prop4 { get; set; }");
|
||||
},
|
||||
SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }")));
|
||||
|
||||
var expectedResult = @"
|
||||
public partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
Prop1 = baz.Prop1;
|
||||
Prop2 = baz.Prop2;
|
||||
Prop3 = baz.Prop3;
|
||||
}
|
||||
".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_MappingsModifierOptionIsSetToInternal_Should_GenerateThoseMethodsWithInternalAccessModifier()
|
||||
{
|
||||
// Arrange
|
||||
var source = GetSourceText();
|
||||
var configOptions = new Dictionary<string, string>
|
||||
{
|
||||
[$"build_property.MapTo_{nameof(SourceGenerationOptions.GeneratedMethodsAccessModifier)}"] = "Internal"
|
||||
};
|
||||
|
||||
var expectedExtension = @"
|
||||
internal static Foo ToFoo(this Test.Models.Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}".Trim();
|
||||
|
||||
var expectedFactory = @"
|
||||
internal static Foo From(Test.Models.Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}".Trim();
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: configOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
|
||||
var syntaxTree = compilation.SyntaxTrees.Last().ToString();
|
||||
syntaxTree.ShouldContain(expectedFactory);
|
||||
syntaxTree.ShouldContain(expectedExtension);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue