From 5be1a9ee66f06991c335cf9a2d87dbe2841b996f Mon Sep 17 00:00:00 2001 From: Yuriy Anisimov Date: Thu, 5 Nov 2015 20:40:37 -0800 Subject: [PATCH] Adding unit tests for projections --- ExpressMapper NET40/MappingServiceBase.cs | 2 +- .../NullCheckNestedMemberVisitor.cs | 25 ++- ExpressMapper NET40/SourceTypeMapper.cs | 8 + .../ExpressMapper.Tests.Projections.csproj | 1 + .../Tests/NestedAssociationNullChecktest.cs | 191 ++++++++++++++++++ .../ViewModel/ProductViewModel.cs | 3 +- 6 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 ExpressMapper.Tests.Projections/Tests/NestedAssociationNullChecktest.cs diff --git a/ExpressMapper NET40/MappingServiceBase.cs b/ExpressMapper NET40/MappingServiceBase.cs index 27f21ef..a0b77f2 100644 --- a/ExpressMapper NET40/MappingServiceBase.cs +++ b/ExpressMapper NET40/MappingServiceBase.cs @@ -112,7 +112,7 @@ protected virtual bool ComplexMapCondition(Type src, Type dst) public Expression GetMemberMappingExpression(Expression left, Expression right) { - var nullCheckNestedMemberVisitor = new NullCheckNestedMemberVisitor(); + var nullCheckNestedMemberVisitor = new NullCheckNestedMemberVisitor(false); nullCheckNestedMemberVisitor.Visit(right); var destNullableType = Nullable.GetUnderlyingType(left.Type); diff --git a/ExpressMapper NET40/NullCheckNestedMemberVisitor.cs b/ExpressMapper NET40/NullCheckNestedMemberVisitor.cs index 4cb4fda..c00fbad 100644 --- a/ExpressMapper NET40/NullCheckNestedMemberVisitor.cs +++ b/ExpressMapper NET40/NullCheckNestedMemberVisitor.cs @@ -4,9 +4,27 @@ namespace ExpressMapper { + /// + /// NullCheckNestedMemberVisitor + /// public class NullCheckNestedMemberVisitor : ExpressionVisitor { + private readonly bool _isNull; + + /// + /// NullCheckNestedMemberVisitor constructor + /// + /// + public NullCheckNestedMemberVisitor(bool isNull) + { + _isNull = isNull; + } + private readonly List _uniquefList = new List(); + + /// + /// CheckNullExpression + /// public Expression CheckNullExpression { get; set; } protected override Expression VisitMember(MemberExpression node) @@ -18,14 +36,17 @@ protected override Expression VisitMember(MemberExpression node) if (!_uniquefList.Contains(memberExpression.ToString())) { _uniquefList.Add(memberExpression.ToString()); + var expression = _isNull + ? Expression.Constant(null, memberExpression.Type) + : (Expression)Expression.Default(memberExpression.Type); if (CheckNullExpression == null) { - CheckNullExpression = Expression.Equal(memberExpression, Expression.Default(memberExpression.Type)); + CheckNullExpression = Expression.Equal(memberExpression, expression); } else { CheckNullExpression = - Expression.OrElse(Expression.Equal(memberExpression, Expression.Default(memberExpression.Type)), + Expression.OrElse(Expression.Equal(memberExpression, expression), CheckNullExpression); } } diff --git a/ExpressMapper NET40/SourceTypeMapper.cs b/ExpressMapper NET40/SourceTypeMapper.cs index 766926b..8158886 100644 --- a/ExpressMapper NET40/SourceTypeMapper.cs +++ b/ExpressMapper NET40/SourceTypeMapper.cs @@ -166,6 +166,14 @@ where p.ParameterType.GetGenericArguments().Count() == 2 Expression.Condition( Expression.Equal(sourceExp, Expression.Constant(null, sourceExp.Type)), Expression.Constant(null, destProp.PropertyType), clearanceExp); + + //var nullCheckNestedMemberVisitor = new NullCheckNestedMemberVisitor(true); + //nullCheckNestedMemberVisitor.Visit(sourceExp); + + //expression = nullCheckNestedMemberVisitor.CheckNullExpression != null + // ? Expression.Condition(nullCheckNestedMemberVisitor.CheckNullExpression, + // Expression.Constant(null, destProp.PropertyType), expression) + // : expression; } else { diff --git a/ExpressMapper.Tests.Projections/ExpressMapper.Tests.Projections.csproj b/ExpressMapper.Tests.Projections/ExpressMapper.Tests.Projections.csproj index 79b76e8..046329f 100644 --- a/ExpressMapper.Tests.Projections/ExpressMapper.Tests.Projections.csproj +++ b/ExpressMapper.Tests.Projections/ExpressMapper.Tests.Projections.csproj @@ -83,6 +83,7 @@ + diff --git a/ExpressMapper.Tests.Projections/Tests/NestedAssociationNullChecktest.cs b/ExpressMapper.Tests.Projections/Tests/NestedAssociationNullChecktest.cs new file mode 100644 index 0000000..13c9a5f --- /dev/null +++ b/ExpressMapper.Tests.Projections/Tests/NestedAssociationNullChecktest.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ExpressMapper.Extensions; +using ExpressMapper.Tests.Projections.Entities; +using ExpressMapper.Tests.Projections.ViewModel; +using NUnit.Framework; + +namespace ExpressMapper.Tests.Projections.Tests +{ + public class NestedAssociationNullChecktest : BaseTest + { + private List _result; + private List _planResult; + + #region Initialize data + + private void InitializeData() + { + var sizeId = Guid.NewGuid(); + var sizeName = "Medium"; + var sizeCode = "M"; + + var size = new Size + { + Id = sizeId, + Name = sizeName, + Code = sizeCode + }; + + var sizeVm = new SizeViewModel + { + Id = sizeId, + Name = sizeName, + Code = sizeCode + }; + + var productVarId = Guid.NewGuid(); + var productVarName = "Orange"; + var productVarColor = "Orange"; + var productVariant = new ProductVariant + { + Id = productVarId, + Name = productVarName, + Color = productVarColor, + Size = size, + SizeId = size.Id + }; + + var productVariantVm = new ProductVariantViewModel + { + Id = productVarId, + Name = productVarName, + Color = productVarColor, + Size = sizeVm + }; + + var productId = Guid.NewGuid(); + var prodName = "Blue Jeans"; + var prodDimensions = "23x56x21"; + var product = new Product + { + Id = productId, + Name = prodName, + Dimensions = prodDimensions, + Variant = productVariant, + VariantId = productVariant.Id + }; + + var productViewModel = new ProductViewModel + { + Id = productId, + Name = prodName + " : " + sizeVm.Code, + Dimensions = prodDimensions, + Variant = productVariantVm, + SizeName = sizeName + }; + + + var prodVarId1 = Guid.NewGuid(); + var prodVarName1 = "Yellow"; + var prodVarColor1 = "Yellow"; + var productVariant1 = new ProductVariant + { + Id = prodVarId1, + Name = prodVarName1, + Color = prodVarColor1 + }; + + var productVariantVm1 = new ProductVariantViewModel + { + Id = prodVarId1, + Name = prodVarName1, + Color = prodVarColor1 + }; + + var prodId1 = Guid.NewGuid(); + var prodName1 = "Blue Jeans"; + var prodDimensions1 = "53x51x99"; + var product1 = new Product + { + Id = prodId1, + Name = prodName1, + Dimensions = prodDimensions1, + Variant = productVariant1, + VariantId = productVariant1.Id + }; + + var productVm1 = new ProductViewModel + { + Id = prodId1, + Name = prodName1 + " : ", + Dimensions = prodDimensions1, + Variant = productVariantVm1, + SizeName = null + }; + + var prodId2 = Guid.NewGuid(); + var prodName2 = "Precious"; + var prodDimensions2 = "13x36x61"; + var product2 = new Product + { + Id = prodId2, + Name = prodName2, + Dimensions = prodDimensions2 + }; + + var prodVm2 = new ProductViewModel + { + Id = prodId2, + Name = prodName2 + " : ", + Dimensions = prodDimensions2, + SizeName = null + }; + + Context.Set().Add(size); + Context.Set().Add(productVariant); + Context.Set().Add(product); + + Context.Set().Add(productVariant1); + Context.Set().Add(product1); + + Context.Set().Add(product2); + + Context.SaveChanges(); + + _planResult = new List + { + productViewModel, productVm1, prodVm2 + }; + } + + #endregion + + #region Register mappings + + private static void RegisterMappings() + { + Mapper.Register() + .Member(t => t.Name, t => t.Name + " : " + t.Variant.Size.Code) + .Member(t => t.SizeName, t => t.Variant.Size.Name); + Mapper.Register(); + Mapper.Register(); + } + + #endregion + + protected override void Setup() + { + InitializeData(); + RegisterMappings(); + } + + protected override void Execute() + { + _result = Context.Set().Project().ToList(); + } + + [Test] + public void Test() + { + _result = _result.OrderBy(p => p.Id).ToList(); + _planResult = _planResult.OrderBy(p => p.Id).ToList(); + Assert.AreEqual(_result.Count(), 3); + for (var i = 0; i < _result.Count; i++) + { + Assert.AreEqual(_result[i], _planResult[i]); + } + } + } +} diff --git a/ExpressMapper.Tests.Projections/ViewModel/ProductViewModel.cs b/ExpressMapper.Tests.Projections/ViewModel/ProductViewModel.cs index 8b6da44..e31d2cf 100644 --- a/ExpressMapper.Tests.Projections/ViewModel/ProductViewModel.cs +++ b/ExpressMapper.Tests.Projections/ViewModel/ProductViewModel.cs @@ -7,11 +7,12 @@ public class ProductViewModel : IEquatable public Guid Id { get; set; } public string Name { get; set; } public string Dimensions { get; set; } + public string SizeName { get; set; } public ProductVariantViewModel Variant { get; set; } public bool Equals(ProductViewModel other) { - return Id == other.Id && Name == other.Name && Dimensions == other.Dimensions && ((Variant == null && other.Variant == null) || Variant.Equals(other.Variant)); + return Id == other.Id && Name == other.Name && SizeName == other.SizeName && Dimensions == other.Dimensions && ((Variant == null && other.Variant == null) || Variant.Equals(other.Variant)); } } }