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

Improvements to Ignore() processing and Fix MapToTarget behavior for RecordTypes #769

Open
wants to merge 19 commits into
base: development
Choose a base branch
from
Open
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
107 changes: 107 additions & 0 deletions src/Mapster.Tests/WhenIgnoreMapping.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Shouldly;
Expand Down Expand Up @@ -55,6 +57,109 @@ public void TestIgnoreMember()
poco2.Name.ShouldBeNull();
}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/707
/// </summary>
[TestMethod]
public void WhenClassIgnoreCtorParamGetDefaultValue()
{
var config = new TypeAdapterConfig()
{
RequireDestinationMemberSource = true,
};
config.Default
.NameMatchingStrategy(new NameMatchingStrategy
{
SourceMemberNameConverter = input => input.ToLowerInvariant(),
DestinationMemberNameConverter = input => input.ToLowerInvariant(),
})
;
config
.NewConfig<A707, B707>()
.MapToConstructor(GetConstructor<B707>())
.Ignore(e => e.Id);

var source = new A707 { Text = "test" };
var dest = new B707(123, "Hello");

var docKind = source.Adapt<B707>(config);
var mapTotarget = source.Adapt(dest,config);

docKind.Id.ShouldBe(0);
mapTotarget.Id.ShouldBe(123);
mapTotarget.Text.ShouldBe("test");
}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/723
/// </summary>
[TestMethod]
public void MappingToIntefaceWithIgnorePrivateSetProperty()
{
TypeAdapterConfig<InterfaceSource723, InterfaceDestination723>
.NewConfig()
.TwoWays()
.Ignore(dest => dest.Ignore);

InterfaceDestination723 dataDestination = new Data723() { Inter = "IterDataDestination", Ignore = "IgnoreDataDestination" };

Should.NotThrow(() =>
{
var isourse = dataDestination.Adapt<InterfaceSource723>();
var idestination = dataDestination.Adapt<InterfaceDestination723>();
});

}

#region TestClasses

public interface InterfaceDestination723
{
public string Inter { get; set; }
public string Ignore { get; }
}

public interface InterfaceSource723
{
public string Inter { get; set; }
}

private class Data723 : InterfaceSource723, InterfaceDestination723
{
public string Ignore { get; set; }

public string Inter { get; set; }
}

static ConstructorInfo? GetConstructor<TDestination>()
{
var parameterlessCtorInfo = typeof(TDestination).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, new Type[0]);

var ctors = typeof(TDestination).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var validCandidateCtors = ctors.Except(new[] { parameterlessCtorInfo }).ToArray();
var ctorToUse = validCandidateCtors.Length == 1
? validCandidateCtors.First()
: validCandidateCtors.OrderByDescending(c => c.GetParameters().Length).First();

return ctorToUse;
}
public class A707
{
public string? Text { get; set; }
}

public class B707
{
public int Id { get; private set; }
public string Text { get; private set; }

public B707(int id, string text)
{
Id = id;
Text = text;
}
}

public class Poco
{
public Guid Id { get; set; }
Expand All @@ -67,5 +172,7 @@ public class Dto
[JsonIgnore]
public string Name { get; set; }
}

#endregion TestClasses
}
}
6 changes: 4 additions & 2 deletions src/Mapster.Tests/WhenIgnoringConditionally.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ public void IgnoreIf_Apply_To_RecordType()
.Compile();

var poco = new SimplePoco { Id = 1, Name = "TestName" };

var srt = poco.BuildAdapter().CreateMapToTargetExpression<SimpleRecord>();
var dto = TypeAdapter.Adapt<SimplePoco, SimpleRecord>(poco);

dto.Id.ShouldBe(1);
Expand All @@ -190,8 +192,8 @@ public class SimpleDto
[AdaptWith(AdaptDirectives.DestinationAsRecord)]
public class SimpleRecord
{
public int Id { get; }
public string Name { get; }
public int Id { get; private set; }
public string Name { get; private set; }

public SimpleRecord(int id, string name)
{
Expand Down
121 changes: 111 additions & 10 deletions src/Mapster.Tests/WhenMappingRecordRegression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@ public class WhenMappingRecordRegression
[TestMethod]
public void AdaptRecordToRecord()
{
TypeAdapterConfig<TestRecordY, TestRecordY>
.NewConfig()
.Ignore(dest => dest.Y);

var _source = new TestRecord() { X = 700 };
var _destination = new TestRecord() { X = 500 };
var _destination = new TestRecordY() { X = 500 , Y = 200 };

var _destination2 = new TestRecordY() { X = 300, Y = 400 };
var _result = _source.Adapt(_destination);

var result2 = _destination.Adapt(_destination2);

_result.X.ShouldBe(700);
_result.Y.ShouldBe(200);
object.ReferenceEquals(_result, _destination).ShouldBeFalse();
}

Expand Down Expand Up @@ -353,7 +362,65 @@ public void MappingInterfaceToInterface()

}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/456
/// </summary>
[TestMethod]
public void WhenRecordReceivedIgnoreCtorParamProcessing()
{
TypeAdapterConfig<UserDto456,UserRecord456>.NewConfig()
.Ignore(dest => dest.Name);

TypeAdapterConfig<DtoInside, UserInside>.NewConfig()
.Ignore(dest => dest.User);

var userDto = new UserDto456("Amichai");
var user = new UserRecord456("John");
var DtoInsider = new DtoInside(userDto);
var UserInsider = new UserInside(user, new UserRecord456("Skot"));

var map = userDto.Adapt<UserRecord456>();
var maptoTarget = userDto.Adapt(user);

var MapToTargetInsider = DtoInsider.Adapt(UserInsider);

map.Name.ShouldBeNullOrEmpty(); // Ignore is work set default value
maptoTarget.Name.ShouldBe("John"); // Ignore is work ignored member save value from Destination
MapToTargetInsider.User.Name.ShouldBe("John"); // Ignore is work member save value from Destination
MapToTargetInsider.SecondName.Name.ShouldBe("Skot"); // Unmached member save value from Destination

}

[TestMethod]
public void WhenRecordTypeWorksWithUseDestinationValueAndIgnoreNullValues()
{

TypeAdapterConfig<SourceFromTestUseDestValue, TestRecordUseDestValue>
.NewConfig()
.IgnoreNullValues(true);

var _source = new SourceFromTestUseDestValue() { X = 300, Y = 200, Name = new StudentNameRecord() { Name = "John" } };
var result = _source.Adapt<TestRecordUseDestValue>();

var _sourceFromMapToTarget = new SourceFromTestUseDestValue() { A = 100, X = null, Y = null, Name = null };

var txt1 = _sourceFromMapToTarget.BuildAdapter().CreateMapExpression<TestRecordUseDestValue>();

var txt = _sourceFromMapToTarget.BuildAdapter().CreateMapToTargetExpression<TestRecordUseDestValue>();

var _resultMapToTarget = _sourceFromMapToTarget.Adapt(result);

result.A.ShouldBe(0); // default Value - not match
result.S.ShouldBe("Inside Data"); // is not AutoProperty not mod by source
result.Y.ShouldBe(200); // Y is AutoProperty value transmitted from source
result.Name.Name.ShouldBe("John"); // transmitted from source standart method

_resultMapToTarget.A.ShouldBe(100);
_resultMapToTarget.X.ShouldBe(300); // Ignore NullValues work
_resultMapToTarget.Y.ShouldBe(200); // Ignore NullValues work
_resultMapToTarget.Name.Name.ShouldBe("John"); // Ignore NullValues work

}

#region NowNotWorking

Expand Down Expand Up @@ -381,6 +448,49 @@ public void CollectionUpdate()


#region TestClasses
public class SourceFromTestUseDestValue
{
public int? A { get; set; }
public int? X { get; set; }
public int? Y { get; set; }
public StudentNameRecord Name { get; set; }
}


public record TestRecordUseDestValue()
{
private string _s = "Inside Data";

public int A { get; set; }
public int X { get; set; }

[UseDestinationValue]
public int Y { get; }

[UseDestinationValue]
public string S { get => _s; }

[UseDestinationValue]
public StudentNameRecord Name { get; } = new StudentNameRecord() { Name = "Marta" };
}

public record StudentNameRecord
{
public string Name { get; set; }
}

public record TestRecordY()
{
public int X { get; set; }
public int Y { get; set; }
}

public record UserInside(UserRecord456 User, UserRecord456 SecondName);
public record DtoInside(UserDto456 User);

public record UserRecord456(string Name);

public record UserDto456(string Name);

public interface IActivityDataExtentions : IActivityData
{
Expand Down Expand Up @@ -674,14 +784,5 @@ sealed record TestSealedRecord()

sealed record TestSealedRecordPositional(int X);










#endregion TestClasses
}
Loading
Loading