From 042ca8d36c313d29260a91d04d341cc8ce17cc87 Mon Sep 17 00:00:00 2001 From: latonz Date: Mon, 14 Oct 2024 19:12:59 +0200 Subject: [PATCH] remove obsolete attribute of MapProperty.ctor(string[], string[]) --- docs/docs/breaking-changes/4-0.md | 8 -- .../MapPropertyAttribute.cs | 1 - ...ApiTest.PublicApiHasNotChanged.verified.cs | 2 - .../Mapping/ObjectPropertyNestedTest.cs | 94 +++++++++++++++++++ 4 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNestedTest.cs diff --git a/docs/docs/breaking-changes/4-0.md b/docs/docs/breaking-changes/4-0.md index f9ea9f6342..1087608ca2 100644 --- a/docs/docs/breaking-changes/4-0.md +++ b/docs/docs/breaking-changes/4-0.md @@ -11,7 +11,6 @@ description: How to upgrade to Mapperly v4.0 and a list of all its breaking chan ## Migration guide from v3.6.0 -- `MapPropertyAttribute.ctor(string[], string[])` is marked as obsolete, replace either with `MapPropertyAttribute.ctor(string[], string)` or `MapPropertyAttribute.ctor(string, string[])`. - Strict mappings are enabled by default, either use `MapperAttribute.RequiredMappingStrategy`/`MapperRequiredMappingAttribute` or revert to non-strict mappings (see [strict mappings by default](#strict-mappings-by-default)). - If the `ExplicitCast` conversion is disabled, disable the new `EnumUnderlyingType` conversion too. - Members of foreach mappings are now mapped, which may result in additional members being mapped or new diagnostics being reported. @@ -20,13 +19,6 @@ description: How to upgrade to Mapperly v4.0 and a list of all its breaking chan - Well-known .NET immutable types are not copied, even if `UseDeepCloning` is enabled. - For long property names, auto-flattening may not work anymore and may need to be configured manually by applying the `MapPropertyAttribute`. -## MapPropertyAttribute constructors - -Since Mapperly does not support source nested member to target nested member mappings, -the constructor `MapPropertyAttribute.ctor(string[], string[])` is marked as obsolete -and will be removed in a future release. -Use `MapPropertyAttribute.ctor(string[], string)` or `MapPropertyAttribute.ctor(string, string[])` instead. - ## Strict mappings by default Starting with v4.0 Mapperly enables strict mappings by default with a severity of `Warning`. diff --git a/src/Riok.Mapperly.Abstractions/MapPropertyAttribute.cs b/src/Riok.Mapperly.Abstractions/MapPropertyAttribute.cs index ebd8197b3a..d607cc699c 100644 --- a/src/Riok.Mapperly.Abstractions/MapPropertyAttribute.cs +++ b/src/Riok.Mapperly.Abstractions/MapPropertyAttribute.cs @@ -50,7 +50,6 @@ public MapPropertyAttribute(string source, string[] target) /// /// The path of the source property. The use of `nameof()` is encouraged. /// The path of the target property. The use of `nameof()` is encouraged. - [Obsolete("Use MapPropertyAttribute(string[], string) or MapPropertyAttribute(string, string[]) instead.")] public MapPropertyAttribute(string[] source, string[] target) { Source = source; diff --git a/test/Riok.Mapperly.Abstractions.Tests/_snapshots/PublicApiTest.PublicApiHasNotChanged.verified.cs b/test/Riok.Mapperly.Abstractions.Tests/_snapshots/PublicApiTest.PublicApiHasNotChanged.verified.cs index e7d3bb8949..06227bb16e 100644 --- a/test/Riok.Mapperly.Abstractions.Tests/_snapshots/PublicApiTest.PublicApiHasNotChanged.verified.cs +++ b/test/Riok.Mapperly.Abstractions.Tests/_snapshots/PublicApiTest.PublicApiHasNotChanged.verified.cs @@ -82,8 +82,6 @@ public sealed class MapPropertyAttribute : System.Attribute public MapPropertyAttribute(string source, string target) { } public MapPropertyAttribute(string[] source, string target) { } public MapPropertyAttribute(string source, string[] target) { } - [System.Obsolete("Use MapPropertyAttribute(string[], string) or MapPropertyAttribute(string, string" + - "[]) instead.")] public MapPropertyAttribute(string[] source, string[] target) { } public string? FormatProvider { get; set; } public System.Collections.Generic.IReadOnlyCollection Source { get; } diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNestedTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNestedTest.cs new file mode 100644 index 0000000000..825f324e4f --- /dev/null +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNestedTest.cs @@ -0,0 +1,94 @@ +using Riok.Mapperly.Diagnostics; + +namespace Riok.Mapperly.Tests.Mapping; + +public class ObjectPropertyNestedTest +{ + [Fact] + public void ManualNestedToNestedProperty() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """ + [MapProperty(new [] {"Value", "IntValue"}, new [] {"Value", "StringValue"})] + public partial B Map(A source); + """, + "class A { public C Value { get; set; } }", + "class B { public D Value { get; set; } }", + "class C { public int IntValue { get; set; } }", + "class D { public string StringValue { get; set; } }" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveSingleMethodBody( + """ + var target = new global::B(); + target.Value.StringValue = source.Value.IntValue.ToString(); + return target; + """ + ); + } + + [Fact] + public void ManualNullableNestedToNullableNestedProperty() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """ + [MapProperty(new [] {"Value", "IntValue"}, new [] {"Value", "StringValue"})] + public partial B Map(A source); + """, + "class A { public C? Value { get; set; } }", + "class B { public D? Value { get; set; } }", + "class C { public int IntValue { get; set; } }", + "class D { public string StringValue { get; set; } }" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveSingleMethodBody( + """ + var target = new global::B(); + if (source.Value != null) + { + target.Value ??= new global::D(); + target.Value.StringValue = source.Value.IntValue.ToString(); + } + return target; + """ + ); + } + + [Fact] + public void ManualNestedToInitOnlyNestedPropertyShouldDiagnostic() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """ + [MapProperty(new [] {"Value", "IntValue"}, new [] {"Value", "StringValue"})] + public partial B Map(A source); + """, + "class A { public C Value { get; set; } }", + "class B { public D Value { get; set; } }", + "class C { public int IntValue { get; init; } }", + "class D { public string StringValue { get; init; } }" + ); + + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) + .Should() + .HaveDiagnostic( + DiagnosticDescriptors.SourceMemberNotMapped, + "The member Value on the mapping source type A is not mapped to any member on the mapping target type B" + ) + .HaveDiagnostic( + DiagnosticDescriptors.SourceMemberNotFound, + "The member Value on the mapping target type B was not found on the mapping source type A" + ) + .HaveDiagnostic( + DiagnosticDescriptors.CannotMapToInitOnlyMemberPath, + "Cannot map from A.Value.IntValue to init only member path B.Value.StringValue" + ) + .HaveAssertedAllDiagnostics(); + } +}