Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removes the obsolete attribute from MapProperty.ctor(string[], string[]) #1535

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions docs/docs/breaking-changes/4-0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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`.
Expand All @@ -53,7 +45,7 @@ New diagnostics can also be reported for existing mappings
## Limited auto-flattening

Mapperly tries to flatten properties automatically.
For this Mapperly tries to access object members based on the pascal case member name notation of C#.
For this Mapperly tries to access object members based on the PascalCase member name notation of C#.
Starting with 4.0 Mapperly will only try up to 256 member path permutations.
Before all possible permutations were tried.
Auto-flattening can always be overwritten by applying the `MapPropertyAttribute`.
Expand Down
1 change: 0 additions & 1 deletion src/Riok.Mapperly.Abstractions/MapPropertyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public MapPropertyAttribute(string source, string[] target)
/// </summary>
/// <param name="source">The path of the source property. The use of `nameof()` is encouraged.</param>
/// <param name="target">The path of the target property. The use of `nameof()` is encouraged.</param>
[Obsolete("Use MapPropertyAttribute(string[], string) or MapPropertyAttribute(string, string[]) instead.")]
public MapPropertyAttribute(string[] source, string[] target)
{
Source = source;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Source { get; }
Expand Down
94 changes: 94 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNestedTest.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}