2020-12-19 10:55:47 +03:00
|
|
|
using System.Linq;
|
2020-12-19 12:05:49 +03:00
|
|
|
using System.Text;
|
2020-12-19 10:55:47 +03:00
|
|
|
using Shouldly;
|
|
|
|
using Xunit;
|
|
|
|
using Xunit.Abstractions;
|
|
|
|
|
|
|
|
namespace MapToTests
|
|
|
|
{
|
|
|
|
public class Tests
|
|
|
|
{
|
|
|
|
private readonly ITestOutputHelper _output;
|
|
|
|
private const string ExpectedAttribute = @"
|
|
|
|
using System;
|
|
|
|
|
|
|
|
namespace MapTo
|
|
|
|
{
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
|
|
|
public sealed class MapFromAttribute : Attribute
|
|
|
|
{
|
|
|
|
public MapFromAttribute(Type sourceType)
|
|
|
|
{
|
|
|
|
SourceType = sourceType;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Type SourceType { get; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
public Tests(ITestOutputHelper output)
|
|
|
|
{
|
|
|
|
_output = output;
|
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void VerifyMapToAttribute()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
const string source = "";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.ShouldContain(c => c.ToString() == ExpectedAttribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_NoMapToAttributeFound_Should_GenerateOnlyTheAttribute()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
const string source = "";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.ShouldContain(s => s.ToString() == ExpectedAttribute);
|
|
|
|
compilation.SyntaxTrees.Select(s => s.ToString()).Where(s => s != string.Empty && s != ExpectedAttribute).ShouldBeEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_MapToAttributeFound_Should_GenerateTheClass()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
const string source = @"
|
|
|
|
namespace Test
|
|
|
|
{
|
|
|
|
[MapFrom(typeof(Baz)]
|
|
|
|
public partial class Foo
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public class Baz
|
|
|
|
{
|
|
|
|
public int Prop1 { get; set; }
|
|
|
|
public int Prop2 { get; }
|
|
|
|
public int Prop3 { get; set; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
const string expectedResult = @"
|
|
|
|
// <auto-generated />
|
2020-12-19 11:08:19 +03:00
|
|
|
using System;
|
2020-12-19 10:55:47 +03:00
|
|
|
|
|
|
|
namespace Test
|
|
|
|
{
|
|
|
|
public partial class Foo
|
|
|
|
{
|
|
|
|
public Foo(Baz baz)
|
|
|
|
{
|
2020-12-19 11:08:19 +03:00
|
|
|
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
2020-12-19 10:55:47 +03:00
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.Count().ShouldBe(3);
|
2020-12-19 11:08:19 +03:00
|
|
|
compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
|
2020-12-19 10:55:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_MapToAttributeWithNamespaceFound_Should_GenerateTheClass()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
const string source = @"
|
|
|
|
namespace Test
|
|
|
|
{
|
|
|
|
[MapTo.MapFrom(typeof(Baz)]
|
|
|
|
public partial class Foo
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public class Baz
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
const string expectedResult = @"
|
|
|
|
// <auto-generated />
|
2020-12-19 11:08:19 +03:00
|
|
|
using System;
|
2020-12-19 10:55:47 +03:00
|
|
|
|
|
|
|
namespace Test
|
|
|
|
{
|
|
|
|
public partial class Foo
|
|
|
|
{
|
|
|
|
public Foo(Baz baz)
|
|
|
|
{
|
2020-12-19 11:08:19 +03:00
|
|
|
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
2020-12-19 10:55:47 +03:00
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.Count().ShouldBe(3);
|
2020-12-19 11:08:19 +03:00
|
|
|
compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
|
2020-12-19 10:55:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_SourceTypeHasMatchingProperties_Should_CreateConstructorAndAssignSrcToDest()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
var source = GetSourceText();
|
|
|
|
|
|
|
|
const string expectedResult = @"
|
|
|
|
public partial class Foo
|
|
|
|
{
|
|
|
|
public Foo(Baz baz)
|
|
|
|
{
|
2020-12-19 11:08:19 +03:00
|
|
|
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
2020-12-19 10:55:47 +03:00
|
|
|
Prop1 = baz.Prop1;
|
|
|
|
Prop2 = baz.Prop2;
|
|
|
|
Prop3 = baz.Prop3;
|
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.Count().ShouldBe(3);
|
|
|
|
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim());
|
|
|
|
}
|
2020-12-19 11:08:19 +03:00
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_SourceTypeHasMatchingProperties_Should_CreateFromStaticMethod()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
var source = GetSourceText();
|
|
|
|
|
|
|
|
const string expectedResult = @"
|
|
|
|
public static Foo From(Baz baz)
|
|
|
|
{
|
|
|
|
return baz == null ? null : new Foo(baz);
|
|
|
|
}
|
|
|
|
";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.Count().ShouldBe(3);
|
|
|
|
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim());
|
|
|
|
}
|
2020-12-19 12:05:49 +03:00
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void When_SourceTypeHasDifferentNamespace_Should_AddToUsings()
|
|
|
|
{
|
|
|
|
// Arrange
|
|
|
|
var source = GetSourceText(sourceClassNamespace: "Bazaar");
|
|
|
|
|
|
|
|
const string expectedResult = @"
|
|
|
|
// <auto-generated />
|
|
|
|
using System;
|
|
|
|
using Bazaar;
|
|
|
|
";
|
|
|
|
|
|
|
|
// Act
|
|
|
|
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
diagnostics.ShouldBeSuccessful();
|
|
|
|
compilation.SyntaxTrees.Count().ShouldBe(3);
|
|
|
|
compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
|
|
|
|
}
|
2020-12-19 10:55:47 +03:00
|
|
|
|
2020-12-19 12:05:49 +03:00
|
|
|
private static string GetSourceText(bool includeAttributeNamespace = false, string sourceClassNamespace = "Test")
|
2020-12-19 10:55:47 +03:00
|
|
|
{
|
2020-12-19 12:05:49 +03:00
|
|
|
var builder = new StringBuilder();
|
|
|
|
builder.AppendLine($@"
|
2020-12-19 10:55:47 +03:00
|
|
|
namespace Test
|
|
|
|
{{
|
2020-12-19 12:05:49 +03:00
|
|
|
{(sourceClassNamespace != "Test" && !includeAttributeNamespace ? $"using {sourceClassNamespace};": string.Empty)}
|
|
|
|
|
2020-12-19 10:55:47 +03:00
|
|
|
{(includeAttributeNamespace ? "[MapTo.MapFrom(typeof(Baz))]" : "[MapFrom(typeof(Baz))]")}
|
|
|
|
public partial class Foo
|
|
|
|
{{
|
|
|
|
public int Prop1 {{ get; set; }}
|
|
|
|
public int Prop2 {{ get; }}
|
|
|
|
public int Prop3 {{ get; }}
|
|
|
|
}}
|
2020-12-19 12:05:49 +03:00
|
|
|
}}
|
|
|
|
");
|
2020-12-19 10:55:47 +03:00
|
|
|
|
2020-12-19 12:05:49 +03:00
|
|
|
builder.AppendLine($@"
|
|
|
|
namespace {sourceClassNamespace}
|
|
|
|
{{
|
2020-12-19 10:55:47 +03:00
|
|
|
public class Baz
|
|
|
|
{{
|
|
|
|
public int Prop1 {{ get; set; }}
|
|
|
|
public int Prop2 {{ get; }}
|
|
|
|
public int Prop3 {{ get; set; }}
|
|
|
|
}}
|
|
|
|
}}
|
2020-12-19 12:05:49 +03:00
|
|
|
");
|
|
|
|
|
|
|
|
return builder.ToString();
|
2020-12-19 10:55:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|