diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs index 2cde682760..652fa2daef 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersMappingStateBuilder.cs @@ -30,7 +30,9 @@ public static MembersMappingState Build(MappingBuilderContext ctx) unmappedSourceMemberNames.ExceptWith(ignoredSourceMemberNames); targetMembers.RemoveRange(ignoredTargetMemberNames); - var targetMemberCaseMapping = targetMembers.Keys.ToDictionary(x => x, x => x, StringComparer.OrdinalIgnoreCase); + var targetMemberCaseMapping = targetMembers + .Keys.GroupBy(x => x, StringComparer.OrdinalIgnoreCase) + .ToDictionary(x => x.Key, x => x.First(), StringComparer.OrdinalIgnoreCase); var unmappedTargetMemberNames = targetMembers.Keys.ToHashSet(); return new MembersMappingState( unmappedSourceMemberNames, diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs index ced80bccd7..2949b8e7fa 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs @@ -435,6 +435,35 @@ public void UnmappedReadOnlyTargetPropertyShouldNotDiagnostic() ); } + [Fact] + public Task PropertiesWithCaseInsensitiveEqualNamesShouldWork() + { + var source = TestSourceBuilder.Mapping( + "A", + "B", + "class A { public int Value { get; set; } }", + "class B { public int value { get; set; } public int Value { get; set; } }" + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task PropertyConfigurationShouldPreferExactCasing() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """ + [MapProperty("Value", "value")] + [MapProperty("value", "Value")] + public partial B Map(A source); + """, + "class A { public int value { get; set; } public int Value { get; set; } }", + "class B { public int value { get; set; } public int Value { get; set; } }" + ); + + return TestHelper.VerifyGenerator(source); + } + [Fact] public void ShouldIgnoreStaticProperty() { diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs new file mode 100644 index 0000000000..34a4a20c20 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork#Mapper.g.verified.cs @@ -0,0 +1,13 @@ +//HintName: Mapper.g.cs +// +#nullable enable +public partial class Mapper +{ + [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "0.0.1.0")] + private partial global::B Map(global::A source) + { + var target = new global::B(); + target.Value = source.Value; + return target; + } +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt new file mode 100644 index 0000000000..6cc7952524 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertiesWithCaseInsensitiveEqualNamesShouldWork.verified.txt @@ -0,0 +1,14 @@ +{ + Diagnostics: [ + { + Id: RMG012, + Title: Source member was not found for target member, + Severity: Info, + WarningLevel: 1, + Location: : (11,4)-(11,36), + MessageFormat: The member {0} on the mapping target type {1} was not found on the mapping source type {2}, + Message: The member value on the mapping target type B was not found on the mapping source type A, + Category: Mapper + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs new file mode 100644 index 0000000000..e66ea73aac --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyTest.PropertyConfigurationShouldPreferExactCasing#Mapper.g.verified.cs @@ -0,0 +1,14 @@ +//HintName: Mapper.g.cs +// +#nullable enable +public partial class Mapper +{ + [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "0.0.1.0")] + public partial global::B Map(global::A source) + { + var target = new global::B(); + target.value = source.Value; + target.Value = source.value; + return target; + } +} \ No newline at end of file