Skip to content

Commit

Permalink
Handling named, indexed VB.NET properties, re: #221
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveWilkes committed Mar 25, 2022
1 parent 02679ed commit 93f2b4f
Show file tree
Hide file tree
Showing 18 changed files with 136 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses.Vb\AgileMapper.UnitTests.MoreTestClasses.Vb.vbproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
<ProjectReference Include="..\AgileMapper\AgileMapper.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net35;netstandard1.0</TargetFrameworks>
<AssemblyName>AgileObjects.AgileMapper.UnitTests.MoreTestClasses.Vb</AssemblyName>
<RootNamespace>AgileObjects.AgileMapper.UnitTests.MoreTestClasses.Vb</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup>
<FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35'">$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>
</PropertyGroup>

</Project>
19 changes: 19 additions & 0 deletions AgileMapper.UnitTests.MoreTestClasses.Vb/PublicNamedIndex.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Public Class PublicNamedIndex(Of T)

Private _valueToReturn As T

Public WriteOnly Property ValueToReturn As T
Set
_valueToReturn = Value
End Set
End Property

Public ReadOnly Property Value(
Optional indexOne As Integer = 1,
Optional indexTwo As Integer = 2) As T
Get
Return _valueToReturn
End Get
End Property

End Class
4 changes: 0 additions & 4 deletions AgileMapper.UnitTests.MoreTestClasses/packages.config

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
<ProjectReference Include="..\AgileMapper\AgileMapper.csproj" AdditionalProperties="TargetFramework=netstandard1.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests\AgileMapper.UnitTests.csproj" />
</ItemGroup>

Expand Down
1 change: 0 additions & 1 deletion AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@

<ItemGroup>
<ProjectReference Include="..\AgileMapper.UnitTests.Common\AgileMapper.UnitTests.Common.csproj" />
<ProjectReference Include="..\AgileMapper.UnitTests.MoreTestClasses\AgileMapper.UnitTests.MoreTestClasses.csproj" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions AgileMapper.UnitTests/Configuration/WhenViewingMappingPlans.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using AgileMapper.Members;
using Common;
using Common.TestClasses;
using MoreTestClasses.Vb;
using TestClasses;
#if !NET35
using Xunit;
Expand Down Expand Up @@ -154,6 +155,16 @@ public void ShouldIncludeUnmappableReadOnlyArrayMemberDetails()
}
}

[Fact]
public void ShouldIncludeUnmappableIndexedPropertyDetails()
{
string plan = Mapper
.GetPlanFor<PublicField<PublicField<string>>>()
.ToANew<PublicNamedIndex<PublicField<string>>>();

plan.ShouldContain("requires index(es) - indexOne: int, indexTwo: int");
}

[Fact]
public void ShouldIncludeUnmappableReadOnlyReadOnlyCollectionMemberDetails()
{
Expand Down
33 changes: 33 additions & 0 deletions AgileMapper.UnitTests/WhenMappingToNewComplexTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using AgileMapper.Extensions;
using Common;
using MoreTestClasses.Vb;
using TestClasses;
#if !NET35
using Xunit;
Expand Down Expand Up @@ -133,6 +134,38 @@ public void ShouldConditionallyUseConstructorsWhereArgumentsAreNull()
addressResult.Address.Line1.ShouldBe("Line 1!");
}

// See https://github.com/agileobjects/AgileMapper/issues/221
[Fact]
public void ShouldIgnoreSourceIndexedProperties()
{
var source = new PublicNamedIndex<PublicField<string>>
{
ValueToReturn = new PublicField<string> { Value = "Test" }
};

var result = Mapper
.Map(source)
.ToANew<PublicField<PublicField<string>>>();

result.ShouldNotBeNull().Value.ShouldBeNull();
}

// See https://github.com/agileobjects/AgileMapper/issues/221
[Fact]
public void ShouldIgnoreTargetIndexedProperties()
{
var source = new PublicField<PublicField<string>>
{
Value = new PublicField<string> { Value = "Hello!" }
};

var result = Mapper
.Map(source)
.ToANew<PublicNamedIndex<PublicField<string>>>();

result.ShouldNotBeNull().get_Value().ShouldBeNull();
}

#region Helper Classes

private class CtorTester
Expand Down
11 changes: 9 additions & 2 deletions AgileMapper.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30002.166
# Visual Studio Version 17
VisualStudioVersion = 17.1.32319.34
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{05AB6D17-6066-41D5-8E79-31C342DFC2DC}"
ProjectSection(SolutionItems) = preProject
Expand Down Expand Up @@ -55,6 +55,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.UnitTests.NetCo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.UnitTests.NetCore2", "AgileMapper.UnitTests.NetCore2\AgileMapper.UnitTests.NetCore2.csproj", "{72287439-1634-4164-ABAC-E4A462235C5D}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "AgileMapper.UnitTests.MoreTestClasses.Vb", "AgileMapper.UnitTests.MoreTestClasses.Vb\AgileMapper.UnitTests.MoreTestClasses.Vb.vbproj", "{4D694869-5B53-4145-BD7F-9187652FD847}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -137,6 +139,10 @@ Global
{72287439-1634-4164-ABAC-E4A462235C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72287439-1634-4164-ABAC-E4A462235C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72287439-1634-4164-ABAC-E4A462235C5D}.Release|Any CPU.Build.0 = Release|Any CPU
{4D694869-5B53-4145-BD7F-9187652FD847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D694869-5B53-4145-BD7F-9187652FD847}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D694869-5B53-4145-BD7F-9187652FD847}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D694869-5B53-4145-BD7F-9187652FD847}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -162,6 +168,7 @@ Global
{5085AA3F-A5B7-40E2-9309-7E0B81FBE113} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B}
{F9307FDB-0F73-40AB-B7AC-AE79CFA5521C} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B}
{72287439-1634-4164-ABAC-E4A462235C5D} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B}
{4D694869-5B53-4145-BD7F-9187652FD847} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C39E9BDB-0077-445C-8F09-801CAE1AF8AB}
Expand Down
22 changes: 19 additions & 3 deletions AgileMapper/Members/Member.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal class Member
public const string RootSourceMemberName = "Source";
public const string RootTargetMemberName = "Target";

private static readonly int _ctorParameterHashCode =
private static readonly int _ctorParameterHashCode =
MemberType.ConstructorParameter.GetHashCode();

private readonly IAccessFactory _accessFactory;
Expand All @@ -30,6 +30,7 @@ private Member(
Type type,
MemberInfo memberInfo,
IAccessFactory accessFactory = null,
bool isIndexed = false,
bool isReadable = true,
bool isWriteable = true,
bool isRoot = false)
Expand All @@ -39,6 +40,7 @@ private Member(
memberInfo.DeclaringType,
type,
accessFactory,
isIndexed,
isReadable,
isWriteable,
isRoot)
Expand All @@ -52,6 +54,7 @@ private Member(
Type declaringType,
Type type,
IAccessFactory accessFactory = null,
bool isIndexed = false,
bool isReadable = true,
bool isWriteable = true,
bool isRoot = false)
Expand All @@ -61,6 +64,7 @@ private Member(
DeclaringType = declaringType;
Type = type;
_accessFactory = accessFactory;
IsIndexed = isIndexed;
IsReadable = isReadable;
IsWriteable = isWriteable;
IsRoot = isRoot;
Expand Down Expand Up @@ -136,13 +140,21 @@ public static Member Field(FieldInfo fieldInfo)

public static Member Property(PropertyInfo propertyInfo)
{
var isReadable = propertyInfo.IsReadable();
var isWritable = propertyInfo.IsWritable();

var isIndexed =
isReadable && propertyInfo.GetGetter().GetParameters().Any() ||
isWritable && propertyInfo.GetSetter().GetParameters().Length > 1;

return new Member(
MemberType.Property,
propertyInfo.PropertyType,
propertyInfo,
new PropertyInfoWrapper(propertyInfo),
propertyInfo.IsReadable(),
propertyInfo.IsWritable());
isIndexed,
isReadable,
isWritable);
}

public static Member GetMethod(MethodInfo methodInfo)
Expand Down Expand Up @@ -203,6 +215,8 @@ public static Member DictionaryEntry(string sourceMemberName, DictionaryTargetMe

public bool IsSimple { get; }

public bool IsIndexed { get; set; }

public bool IsReadable { get; }

public bool IsWriteable { get; }
Expand Down Expand Up @@ -240,6 +254,7 @@ public Member WithType(Type runtimeType)
runtimeType,
MemberInfo,
_accessFactory,
IsIndexed,
IsReadable,
IsWriteable,
IsRoot);
Expand All @@ -250,6 +265,7 @@ public Member WithType(Type runtimeType)
Name,
DeclaringType,
runtimeType,
isIndexed: IsIndexed,
isReadable: IsReadable,
isWriteable: IsWriteable,
isRoot: IsRoot);
Expand Down
14 changes: 9 additions & 5 deletions AgileMapper/Members/MemberCache.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
namespace AgileObjects.AgileMapper.Members
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Caching;
using Extensions;
using Extensions.Internal;
using NetStandardPolyfills;
using ReadableExpressions.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static System.StringComparer;

internal class MemberCache
Expand Down Expand Up @@ -132,7 +132,11 @@ private static IEnumerable<Member> GetProperties(Type targetType, Func<PropertyI
private static bool AllExceptBclComplexTypes(PropertyInfo property)
=> AllExceptBclComplexTypes(property.PropertyType);

private static bool OnlyGettable(PropertyInfo property) => property.IsReadable();
private static bool OnlyGettable(PropertyInfo property)
{
var getter = property.GetGetter();
return getter != null && getter.GetParameters().None();
}

#endregion

Expand Down
21 changes: 17 additions & 4 deletions AgileMapper/Members/MemberExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static bool IsUnmappable(this QualifiedMember member, out string reason)

if (member.IsSimple || member.Type.IsValueType())
{
reason = "readonly " + ((member.IsComplex) ? "struct" : member.Type.GetFriendlyName());
reason = "readonly " + (member.IsComplex ? "struct" : member.Type.GetFriendlyName());
return true;
}

Expand All @@ -113,6 +113,19 @@ public static bool IsUnmappable(this QualifiedMember member, out string reason)
return true;
}

if (member.IsIndexed)
{
var property = (PropertyInfo)member.LeafMember.MemberInfo;

var indexes = string.Join(", ", property
.GetGetter()
.GetParameters()
.ProjectToArray(p => p.Name + ": " + p.ParameterType.GetFriendlyName()));

reason = "requires index(es) - " + indexes;
return true;
}

reason = null;
return false;
}
Expand Down Expand Up @@ -285,7 +298,7 @@ public static QualifiedMember ToSourceMemberOrNull(
this Expression memberAccess,
MapperContext mapperContext)
{
return memberAccess.ToSourceMember(mapperContext, nt => { });
return memberAccess.ToSourceMember(mapperContext, _ => { });
}

public static QualifiedMember ToSourceMemberOrNull(
Expand All @@ -294,7 +307,7 @@ public static QualifiedMember ToSourceMemberOrNull(
out string failureReason)
{
var hasUnsupportedNodeType = false;
var sourceMember = memberAccess.ToSourceMember(mapperContext, nt => hasUnsupportedNodeType = true);
var sourceMember = memberAccess.ToSourceMember(mapperContext, _ => hasUnsupportedNodeType = true);

if (hasUnsupportedNodeType)
{
Expand Down Expand Up @@ -347,7 +360,7 @@ public static QualifiedMember ToTargetMemberOrNull(
out string failureReason)
{
var hasUnsupportedNodeType = false;
var targetMember = memberAccess.ToTargetMember(mapperContext, nt => hasUnsupportedNodeType = true);
var targetMember = memberAccess.ToTargetMember(mapperContext, _ => hasUnsupportedNodeType = true);

if (hasUnsupportedNodeType)
{
Expand Down
2 changes: 2 additions & 0 deletions AgileMapper/Members/QualifiedMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ public static QualifiedMember Create(Member[] memberChain, MapperContext mapperC
public bool IsReadable => LeafMember.IsReadable;

public bool IsReadOnly { get; set; }

public bool IsIndexed => LeafMember.IsIndexed;

public bool IsRecursion { get; }

Expand Down
Loading

0 comments on commit 93f2b4f

Please sign in to comment.