Use SourceBuilder instead of StringBuilder.
This commit is contained in:
parent
34df045693
commit
8ed331ed95
|
@ -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<StringBuilder> PropertyBuilder = null,
|
||||
Action<StringBuilder> SourcePropertyBuilder = null);
|
||||
Action<SourceBuilder> PropertyBuilder = null,
|
||||
Action<SourceBuilder> SourcePropertyBuilder = null);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<in TSource, out TDestination>
|
||||
{{
|
||||
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<in TSource, out TDestination>
|
||||
{{
|
||||
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<in TSource, out TDestination>
|
||||
{{
|
||||
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<in TSource, out TDestination>
|
||||
{{
|
||||
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<long, string>
|
||||
{
|
||||
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<string, long>
|
||||
{
|
||||
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<string, long>
|
||||
{
|
||||
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<long, string>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue