From 8ed331ed9534b38c8efd3b44d6a20a541f5e16b4 Mon Sep 17 00:00:00 2001 From: Mohammadreza Taikandi Date: Sat, 30 Jan 2021 09:09:58 +0000 Subject: [PATCH] Use SourceBuilder instead of StringBuilder. --- test/MapTo.Tests/Common.cs | 68 +++-- .../IgnorePropertyAttributeTests.cs | 6 +- test/MapTo.Tests/MapPropertyTests.cs | 7 +- test/MapTo.Tests/MapToTests.cs | 9 +- test/MapTo.Tests/MapTypeConverterTests.cs | 262 +++++++++--------- 5 files changed, 167 insertions(+), 185 deletions(-) diff --git a/test/MapTo.Tests/Common.cs b/test/MapTo.Tests/Common.cs index 7b3c8bc..42a25c6 100644 --- a/test/MapTo.Tests/Common.cs +++ b/test/MapTo.Tests/Common.cs @@ -27,75 +27,69 @@ namespace MapTo.Tests const string ns = "Test"; options ??= new SourceGeneratorOptions(); var hasDifferentSourceNamespace = options.SourceClassNamespace != ns; - var builder = new StringBuilder(); + var builder = new SourceBuilder(); - builder.AppendLine("//"); - builder.AppendLine("// Test source code."); - builder.AppendLine("//"); - builder.AppendLine(); + builder.WriteLine("//"); + builder.WriteLine("// Test source code."); + builder.WriteLine("//"); + builder.WriteLine(); if (options.UseMapToNamespace) { - builder.AppendFormat("using {0};", Constants.RootNamespace).AppendLine(); + builder.WriteLine($"using {Constants.RootNamespace};"); } builder - .AppendFormat("using {0};", options.SourceClassNamespace) - .AppendLine() - .AppendLine(); + .WriteLine($"using {options.SourceClassNamespace};") + .WriteLine() + .WriteLine(); builder - .AppendFormat("namespace {0}", ns) - .AppendOpeningBracket(); + .WriteLine($"namespace {ns}") + .WriteOpeningBracket(); if (hasDifferentSourceNamespace && options.UseMapToNamespace) { builder - .PadLeft(Indent1) - .AppendFormat("using {0};", options.SourceClassNamespace) - .AppendLine() - .AppendLine(); + .WriteLine($"using {options.SourceClassNamespace};") + .WriteLine() + .WriteLine(); } builder - .PadLeft(Indent1) - .AppendLine(options.UseMapToNamespace ? "[MapFrom(typeof(Baz))]" : "[MapTo.MapFrom(typeof(Baz))]") - .PadLeft(Indent1).Append("public partial class Foo") - .AppendOpeningBracket(Indent1); + .WriteLine(options.UseMapToNamespace ? "[MapFrom(typeof(Baz))]" : "[MapTo.MapFrom(typeof(Baz))]") + .WriteLine("public partial class Foo") + .WriteOpeningBracket(); for (var i = 1; i <= options.ClassPropertiesCount; i++) { - builder - .PadLeft(Indent2) - .AppendLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}"); + builder.WriteLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}"); } options.PropertyBuilder?.Invoke(builder); builder - .AppendClosingBracket(Indent1, false) - .AppendClosingBracket() - .AppendLine() - .AppendLine(); + .WriteClosingBracket() + .WriteClosingBracket() + .WriteLine() + .WriteLine(); builder - .AppendFormat("namespace {0}", options.SourceClassNamespace) - .AppendOpeningBracket() - .PadLeft(Indent1).Append("public class Baz") - .AppendOpeningBracket(Indent1); + .WriteLine($"namespace {options.SourceClassNamespace}") + .WriteOpeningBracket() + .WriteLine("public class Baz") + .WriteOpeningBracket(); for (var i = 1; i <= options.SourceClassPropertiesCount; i++) { - builder - .PadLeft(Indent2) - .AppendLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}"); + builder.WriteLine(i % 2 == 0 ? $"public int Prop{i} {{ get; set; }}" : $"public int Prop{i} {{ get; }}"); } options.SourcePropertyBuilder?.Invoke(builder); builder - .AppendClosingBracket(Indent1, false) - .AppendClosingBracket(); + .WriteClosingBracket() + .WriteClosingBracket(); return builder.ToString(); } @@ -125,7 +119,7 @@ namespace MapTo.Tests string SourceClassNamespace = "Test.Models", int ClassPropertiesCount = 3, int SourceClassPropertiesCount = 3, - Action PropertyBuilder = null, - Action SourcePropertyBuilder = null); + Action PropertyBuilder = null, + Action SourcePropertyBuilder = null); } } \ No newline at end of file diff --git a/test/MapTo.Tests/IgnorePropertyAttributeTests.cs b/test/MapTo.Tests/IgnorePropertyAttributeTests.cs index 0434803..cf83a18 100644 --- a/test/MapTo.Tests/IgnorePropertyAttributeTests.cs +++ b/test/MapTo.Tests/IgnorePropertyAttributeTests.cs @@ -44,10 +44,10 @@ namespace MapTo PropertyBuilder: builder => { builder - .PadLeft(Indent2).AppendLine("[IgnoreProperty]") - .PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }"); + .WriteLine("[IgnoreProperty]") + .WriteLine("public int Prop4 { get; set; }"); }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }"))); + SourcePropertyBuilder: builder => builder.WriteLine("public int Prop4 { get; set; }"))); var expectedResult = @" partial class Foo diff --git a/test/MapTo.Tests/MapPropertyTests.cs b/test/MapTo.Tests/MapPropertyTests.cs index daaeb6a..015181f 100644 --- a/test/MapTo.Tests/MapPropertyTests.cs +++ b/test/MapTo.Tests/MapPropertyTests.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using MapTo.Extensions; using MapTo.Sources; using MapTo.Tests.Extensions; using MapTo.Tests.Infrastructure; @@ -53,10 +52,10 @@ namespace MapTo PropertyBuilder: builder => { builder - .PadLeft(Indent2).AppendLine("[MapProperty(SourcePropertyName = nameof(Baz.Prop3))]") - .PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }"); + .WriteLine("[MapProperty(SourcePropertyName = nameof(Baz.Prop3))]") + .WriteLine("public int Prop4 { get; set; }"); }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }"))); + SourcePropertyBuilder: builder => builder.WriteLine("public int Prop4 { get; set; }"))); var expectedResult = @" partial class Foo diff --git a/test/MapTo.Tests/MapToTests.cs b/test/MapTo.Tests/MapToTests.cs index 4346368..29d5094 100644 --- a/test/MapTo.Tests/MapToTests.cs +++ b/test/MapTo.Tests/MapToTests.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using MapTo.Extensions; using MapTo.Sources; using MapTo.Tests.Extensions; using MapTo.Tests.Infrastructure; @@ -50,12 +49,8 @@ namespace MapTo // 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; }"))); + PropertyBuilder: builder => { builder.WriteLine("public string Prop4 { get; set; }"); }, + SourcePropertyBuilder: builder => builder.WriteLine("public int Prop4 { get; set; }"))); // Act var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); diff --git a/test/MapTo.Tests/MapTypeConverterTests.cs b/test/MapTo.Tests/MapTypeConverterTests.cs index f79e952..53312e6 100644 --- a/test/MapTo.Tests/MapTypeConverterTests.cs +++ b/test/MapTo.Tests/MapTypeConverterTests.cs @@ -1,69 +1,16 @@ using System.Linq; -using MapTo.Extensions; using MapTo.Sources; using MapTo.Tests.Extensions; using MapTo.Tests.Infrastructure; using Microsoft.CodeAnalysis; using Shouldly; using Xunit; -using static MapTo.Extensions.GeneratorExecutionContextExtensions; using static MapTo.Tests.Common; namespace MapTo.Tests { public class MapTypeConverterTests { - [Fact] - public void VerifyTypeConverterInterface() - { - // Arrange - const string source = ""; - var expectedInterface = $@" -{Constants.GeneratedFilesHeader} - -namespace MapTo -{{ - public interface ITypeConverter - {{ - TDestination Convert(TSource source, object[] converterParameters); - }} -}} -".Trim(); - - // Act - var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); - - // Assert - diagnostics.ShouldBeSuccessful(); - compilation.SyntaxTrees.ShouldContainSource(ITypeConverterSource.InterfaceName, expectedInterface); - } - - [Fact] - public void VerifyTypeConverterInterfaceWithNullableOptionOn() - { - // Arrange - const string source = ""; - var expectedInterface = $@" -{Constants.GeneratedFilesHeader} -#nullable enable - -namespace MapTo -{{ - public interface ITypeConverter - {{ - TDestination Convert(TSource source, object[]? converterParameters); - }} -}} -".Trim(); - - // Act - var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions, nullableContextOptions: NullableContextOptions.Enable); - - // Assert - diagnostics.ShouldBeSuccessful(); - compilation.SyntaxTrees.ShouldContainSource(ITypeConverterSource.InterfaceName, expectedInterface); - } - [Fact] public void VerifyMapTypeConverterAttribute() { @@ -99,7 +46,7 @@ namespace MapTo diagnostics.ShouldBeSuccessful(); compilation.SyntaxTrees.ShouldContainSource(MapTypeConverterAttributeSource.AttributeName, expectedInterface); } - + [Fact] public void VerifyMapTypeConverterAttributeWithNullableOptionOn() { @@ -138,7 +85,58 @@ namespace MapTo } [Fact] - public void When_FoundMatchingPropertyNameWithDifferentImplicitlyConvertibleType_Should_GenerateTheProperty() + public void VerifyTypeConverterInterface() + { + // Arrange + const string source = ""; + var expectedInterface = $@" +{Constants.GeneratedFilesHeader} + +namespace MapTo +{{ + public interface ITypeConverter + {{ + TDestination Convert(TSource source, object[] converterParameters); + }} +}} +".Trim(); + + // Act + var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); + + // Assert + diagnostics.ShouldBeSuccessful(); + compilation.SyntaxTrees.ShouldContainSource(ITypeConverterSource.InterfaceName, expectedInterface); + } + + [Fact] + public void VerifyTypeConverterInterfaceWithNullableOptionOn() + { + // Arrange + const string source = ""; + var expectedInterface = $@" +{Constants.GeneratedFilesHeader} +#nullable enable + +namespace MapTo +{{ + public interface ITypeConverter + {{ + TDestination Convert(TSource source, object[]? converterParameters); + }} +}} +".Trim(); + + // Act + var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions, nullableContextOptions: NullableContextOptions.Enable); + + // Assert + diagnostics.ShouldBeSuccessful(); + compilation.SyntaxTrees.ShouldContainSource(ITypeConverterSource.InterfaceName, expectedInterface); + } + + [Fact] + public void When_FoundMatchingPropertyNameWithConverterType_ShouldUseTheConverterAndItsParametersToAssignProperties() { // Arrange var source = GetSourceText(new SourceGeneratorOptions( @@ -146,9 +144,77 @@ namespace MapTo PropertyBuilder: builder => { builder - .PadLeft(Indent2).AppendLine("public long Prop4 { get; set; }"); + .WriteLine("[MapTypeConverter(typeof(Prop4Converter), new object[]{\"G\", 'C', 10})]") + .WriteLine("public string Prop4 { get; set; }"); }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public int Prop4 { get; set; }"))); + SourcePropertyBuilder: builder => builder.WriteLine("public long Prop4 { get; set; }"))); + + source += @" +namespace Test +{ + using MapTo; + + public class Prop4Converter: ITypeConverter + { + public string Convert(long source, object[] converterParameters) => source.ToString(converterParameters[0] as string); + } +} +"; + + const string expectedSyntax = "Prop4 = new Test.Prop4Converter().Convert(baz.Prop4, new object[] { \"G\", 'C', 10 });"; + + // Act + var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); + + // Assert + diagnostics.ShouldBeSuccessful(); + compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedSyntax); + } + + [Fact] + public void When_FoundMatchingPropertyNameWithConverterType_ShouldUseTheConverterToAssignProperties() + { + // Arrange + var source = GetSourceText(new SourceGeneratorOptions( + true, + PropertyBuilder: builder => + { + builder + .WriteLine("[MapTypeConverter(typeof(Prop4Converter))]") + .WriteLine("public long Prop4 { get; set; }"); + }, + SourcePropertyBuilder: builder => builder.WriteLine("public string Prop4 { get; set; }"))); + + source += @" +namespace Test +{ + using MapTo; + + public class Prop4Converter: ITypeConverter + { + public long Convert(string source, object[] converterParameters) => long.Parse(source); + } +} +"; + + const string expectedSyntax = "Prop4 = new Test.Prop4Converter().Convert(baz.Prop4, null);"; + + // Act + var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); + + // Assert + diagnostics.ShouldBeSuccessful(); + compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedSyntax); + } + + [Fact] + public void When_FoundMatchingPropertyNameWithDifferentImplicitlyConvertibleType_Should_GenerateTheProperty() + { + // Arrange + var source = GetSourceText(new SourceGeneratorOptions( + true, + PropertyBuilder: builder => { builder.WriteLine("public long Prop4 { get; set; }"); }, + SourcePropertyBuilder: builder => builder.WriteLine("public int Prop4 { get; set; }"))); var expectedResult = @" partial class Foo @@ -181,12 +247,12 @@ namespace MapTo PropertyBuilder: builder => { builder - .PadLeft(Indent2).AppendLine("[IgnoreProperty]") - .PadLeft(Indent2).AppendLine("public long IgnoreMe { get; set; }") - .PadLeft(Indent2).AppendLine("[MapTypeConverter(typeof(Prop4Converter))]") - .PadLeft(Indent2).AppendLine("public long Prop4 { get; set; }"); + .WriteLine("[IgnoreProperty]") + .WriteLine("public long IgnoreMe { get; set; }") + .WriteLine("[MapTypeConverter(typeof(Prop4Converter))]") + .WriteLine("public long Prop4 { get; set; }"); }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public string Prop4 { get; set; }"))); + SourcePropertyBuilder: builder => builder.WriteLine("public string Prop4 { get; set; }"))); source += @" namespace Test @@ -207,77 +273,5 @@ namespace Test var expectedError = DiagnosticProvider.InvalidTypeConverterGenericTypesError(GetSourcePropertySymbol("Prop4", compilation), GetSourcePropertySymbol("Prop4", compilation, "Baz")); diagnostics.ShouldBeUnsuccessful(expectedError); } - - [Fact] - public void When_FoundMatchingPropertyNameWithConverterType_ShouldUseTheConverterToAssignProperties() - { - // Arrange - var source = GetSourceText(new SourceGeneratorOptions( - true, - PropertyBuilder: builder => - { - builder - .PadLeft(Indent2).AppendLine("[MapTypeConverter(typeof(Prop4Converter))]") - .PadLeft(Indent2).AppendLine("public long Prop4 { get; set; }"); - }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public string Prop4 { get; set; }"))); - - source += @" -namespace Test -{ - using MapTo; - - public class Prop4Converter: ITypeConverter - { - public long Convert(string source, object[] converterParameters) => long.Parse(source); - } -} -"; - - const string expectedSyntax = "Prop4 = new Test.Prop4Converter().Convert(baz.Prop4, null);"; - - // Act - var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); - - // Assert - diagnostics.ShouldBeSuccessful(); - compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedSyntax); - } - - [Fact] - public void When_FoundMatchingPropertyNameWithConverterType_ShouldUseTheConverterAndItsParametersToAssignProperties() - { - // Arrange - var source = GetSourceText(new SourceGeneratorOptions( - true, - PropertyBuilder: builder => - { - builder - .PadLeft(Indent2).AppendLine("[MapTypeConverter(typeof(Prop4Converter), new object[]{\"G\", 'C', 10})]") - .PadLeft(Indent2).AppendLine("public string Prop4 { get; set; }"); - }, - SourcePropertyBuilder: builder => builder.PadLeft(Indent2).AppendLine("public long Prop4 { get; set; }"))); - - source += @" -namespace Test -{ - using MapTo; - - public class Prop4Converter: ITypeConverter - { - public string Convert(long source, object[] converterParameters) => source.ToString(converterParameters[0] as string); - } -} -"; - - const string expectedSyntax = "Prop4 = new Test.Prop4Converter().Convert(baz.Prop4, new object[] { \"G\", 'C', 10 });"; - - // Act - var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions); - - // Assert - diagnostics.ShouldBeSuccessful(); - compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedSyntax); - } } } \ No newline at end of file