143 lines
5.9 KiB
C#
143 lines
5.9 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Xunit;
|
|
|
|
namespace AutoMapProperty.Tests;
|
|
|
|
public class NullabilityTests
|
|
{
|
|
[Theory]
|
|
[InlineData("string", "Nullable", true)]
|
|
[InlineData("string?", "NonNullable", false)]
|
|
[InlineData("string?", "Preserve", true)]
|
|
[InlineData("string", "Preserve", false)]
|
|
[InlineData("int", "Nullable", true)]
|
|
[InlineData("int?", "Nullable", true)]
|
|
[InlineData("int?", "NonNullable", false)]
|
|
[InlineData("int", "NonNullable", false)]
|
|
[InlineData("int?", "Preserve", true)]
|
|
[InlineData("DateTime", "Nullable", true)]
|
|
[InlineData("DateTime?", "NonNullable", false)]
|
|
[InlineData("string[]", "Nullable", true)]
|
|
[InlineData("string[]?", "NonNullable", false)]
|
|
[InlineData("ICollection<string?>", "Nullable", true)]
|
|
public void OverridesTopLevelNullability(string type, string mode, bool nullable)
|
|
{
|
|
var compilation = new GeneratorTestCompilation($$"""
|
|
namespace Fixtures
|
|
{
|
|
public class Entity
|
|
{
|
|
[AutoMapProperty("Response", Nullability = AutoMapNullability.{{mode}})]
|
|
public {{type}} Value { get; set; }
|
|
}
|
|
}
|
|
""");
|
|
compilation.AssertCompiles();
|
|
var generatedType = compilation.Property("Fixtures.EntityResponse", "Value").Type;
|
|
Assert.Equal(nullable, generatedType.NullableAnnotation == NullableAnnotation.Annotated ||
|
|
generatedType is INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T });
|
|
if (generatedType is INamedTypeSymbol { Name: "ICollection" } collection)
|
|
Assert.Equal(NullableAnnotation.Annotated, collection.TypeArguments[0].NullableAnnotation);
|
|
}
|
|
|
|
[Fact]
|
|
public void OverridesAreIndependentForEachDtoAndAppliedAfterTypeReplacement()
|
|
{
|
|
var compilation = new GeneratorTestCompilation("""
|
|
namespace Fixtures
|
|
{
|
|
public class Entity
|
|
{
|
|
[AutoMapProperty("Request", typeof(long), Nullability = AutoMapNullability.Nullable)]
|
|
[AutoMapProperty("Response", typeof(long?), Nullability = AutoMapNullability.NonNullable)]
|
|
[AutoMapProperty("Copy")]
|
|
public int Value { get; set; }
|
|
}
|
|
}
|
|
""");
|
|
compilation.AssertCompiles();
|
|
var request = Assert.IsAssignableFrom<INamedTypeSymbol>(compilation.Property("Fixtures.EntityRequest", "Value").Type);
|
|
Assert.Equal(SpecialType.System_Nullable_T, request.OriginalDefinition.SpecialType);
|
|
Assert.Equal(SpecialType.System_Int64, request.TypeArguments[0].SpecialType);
|
|
Assert.Equal(SpecialType.System_Int64, compilation.Property("Fixtures.EntityResponse", "Value").Type.SpecialType);
|
|
Assert.Equal(SpecialType.System_Int32, compilation.Property("Fixtures.EntityCopy", "Value").Type.SpecialType);
|
|
}
|
|
|
|
[Fact]
|
|
public void NullableValuesMapInBothDirectionsAndThroughProjectors()
|
|
{
|
|
var compilation = new GeneratorTestCompilation("""
|
|
namespace Fixtures
|
|
{
|
|
public class Entity
|
|
{
|
|
[AutoMapProperty("Request", Nullability = AutoMapNullability.Nullable)]
|
|
public int Value { get; set; }
|
|
}
|
|
public static class Check
|
|
{
|
|
public static bool Run()
|
|
{
|
|
var entity = new Entity { Value = 42 };
|
|
var dto = new EntityRequest().ApplyFrom(null, entity);
|
|
var projected = dto.GetProjectorFrom(null).Compile()(entity);
|
|
dto.Value = 17;
|
|
dto.ApplyTo(null, entity);
|
|
dto.Value = null;
|
|
try { dto.ApplyTo(null, entity); }
|
|
catch (InvalidOperationException) { return entity.Value == 17 && projected.Value == 42; }
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
""");
|
|
Assert.Equal(true, compilation.Evaluate());
|
|
}
|
|
|
|
[Fact]
|
|
public void ValueTypeNullabilityOverridesKeepValidInitializers()
|
|
{
|
|
var compilation = new GeneratorTestCompilation("""
|
|
namespace Fixtures
|
|
{
|
|
public class Entity
|
|
{
|
|
[AutoMapProperty("Request", Nullability = AutoMapNullability.Nullable)]
|
|
public DateTime Date { get; set; } = new DateTime(2026, 1, 2);
|
|
[AutoMapProperty("Request", Nullability = AutoMapNullability.NonNullable)]
|
|
public int? Count { get; set; } = null;
|
|
[AutoMapProperty("Request", Nullability = AutoMapNullability.NonNullable)]
|
|
public int? Total { get; set; } = default(int?);
|
|
}
|
|
public static class Check
|
|
{
|
|
public static bool Run()
|
|
{
|
|
var dto = new EntityRequest();
|
|
return dto.Date == new DateTime(2026, 1, 2) && dto.Count == 0 && dto.Total == 0;
|
|
}
|
|
}
|
|
}
|
|
""");
|
|
Assert.Equal(true, compilation.Evaluate());
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidNullabilityReportsPropertyDiagnostic()
|
|
{
|
|
var compilation = new GeneratorTestCompilation("""
|
|
namespace Fixtures
|
|
{
|
|
public class Entity
|
|
{
|
|
[AutoMapProperty("Response", Nullability = (AutoMapNullability)99)]
|
|
public string Value { get; set; }
|
|
}
|
|
}
|
|
""");
|
|
var diagnostic = Assert.Single(compilation.RunResult.Diagnostics);
|
|
Assert.Equal("NEJ23", diagnostic.Id);
|
|
Assert.True(diagnostic.Location.IsInSource);
|
|
}
|
|
}
|