|
| 1 | + |
| 2 | +using System; |
| 3 | +using System.Linq.Expressions; |
| 4 | +using Xunit; |
| 5 | + |
| 6 | +namespace AutoMapper.Extensions.ExpressionMapping.UnitTests |
| 7 | +{ |
| 8 | + public class ExpressionMappingEnumToNumericOrString : AutoMapperSpecBase |
| 9 | + { |
| 10 | + public enum SimpleEnumByte : byte |
| 11 | + { |
| 12 | + Value1 = 1, |
| 13 | + Value2 = 2, |
| 14 | + Value3 = 3 |
| 15 | + } |
| 16 | + public enum SimpleEnumSByte : sbyte |
| 17 | + { |
| 18 | + Value1 = 1, |
| 19 | + Value2 = 2, |
| 20 | + Value3 = 3 |
| 21 | + } |
| 22 | + public enum SimpleEnumShort : short |
| 23 | + { |
| 24 | + Value1 = 1, |
| 25 | + Value2 = 2, |
| 26 | + Value3 = 3 |
| 27 | + } |
| 28 | + public enum SimpleEnumUShort : ushort |
| 29 | + { |
| 30 | + Value1 = 1, |
| 31 | + Value2 = 2, |
| 32 | + Value3 = 3 |
| 33 | + } |
| 34 | + public enum SimpleEnumInt : int |
| 35 | + { |
| 36 | + Value1 = 1, |
| 37 | + Value2 = 2, |
| 38 | + Value3 = 3 |
| 39 | + } |
| 40 | + public enum SimpleEnumUInt : uint |
| 41 | + { |
| 42 | + Value1 = 1, |
| 43 | + Value2 = 2, |
| 44 | + Value3 = 3 |
| 45 | + } |
| 46 | + public enum SimpleEnumLong : long |
| 47 | + { |
| 48 | + Value1 = 1, |
| 49 | + Value2 = 2, |
| 50 | + Value3 = long.MaxValue |
| 51 | + } |
| 52 | + public enum SimpleEnumULong : ulong |
| 53 | + { |
| 54 | + Value1 = 1, |
| 55 | + Value2 = 2, |
| 56 | + Value3 = long.MaxValue |
| 57 | + } |
| 58 | + private class EntityDto<TEnum> |
| 59 | + where TEnum : Enum |
| 60 | + { |
| 61 | + internal TEnum Value { get; set; } |
| 62 | + } |
| 63 | + private class Entity<T> |
| 64 | + { |
| 65 | + internal T Value { get; set; } |
| 66 | + } |
| 67 | + |
| 68 | + protected override MapperConfiguration Configuration |
| 69 | + { |
| 70 | + get |
| 71 | + { |
| 72 | + return new MapperConfiguration(config => |
| 73 | + { |
| 74 | + config.AddExpressionMapping(); |
| 75 | + config.CreateMap<Entity<byte>, EntityDto<SimpleEnumByte>>() |
| 76 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 77 | + .ReverseMap(); |
| 78 | + |
| 79 | + config.CreateMap<Entity<sbyte>, EntityDto<SimpleEnumSByte>>() |
| 80 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 81 | + .ReverseMap(); |
| 82 | + config.CreateMap<Entity<short>, EntityDto<SimpleEnumShort>>() |
| 83 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 84 | + .ReverseMap(); |
| 85 | + config.CreateMap<Entity<ushort>, EntityDto<SimpleEnumUShort>>() |
| 86 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 87 | + .ReverseMap(); |
| 88 | + config.CreateMap<Entity<int>, EntityDto<SimpleEnumInt>>() |
| 89 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 90 | + .ReverseMap(); |
| 91 | + config.CreateMap<Entity<uint>, EntityDto<SimpleEnumUInt>>() |
| 92 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 93 | + .ReverseMap(); |
| 94 | + config.CreateMap<Entity<long>, EntityDto<SimpleEnumLong>>() |
| 95 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 96 | + .ReverseMap(); |
| 97 | + config.CreateMap<Entity<ulong>, EntityDto<SimpleEnumULong>>() |
| 98 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 99 | + .ReverseMap(); |
| 100 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumByte>>() |
| 101 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 102 | + .ReverseMap(); |
| 103 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumSByte>>() |
| 104 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 105 | + .ReverseMap(); |
| 106 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumShort>>() |
| 107 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 108 | + .ReverseMap(); |
| 109 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumUShort>>() |
| 110 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 111 | + .ReverseMap(); |
| 112 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumInt>>() |
| 113 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 114 | + .ReverseMap(); |
| 115 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumUInt>>() |
| 116 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 117 | + .ReverseMap(); |
| 118 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumLong>>() |
| 119 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 120 | + .ReverseMap(); |
| 121 | + config.CreateMap<Entity<string>, EntityDto<SimpleEnumULong>>() |
| 122 | + .ForMember(dest => dest.Value, config => config.MapFrom(src => src.Value)) |
| 123 | + .ReverseMap(); |
| 124 | + |
| 125 | + config.CreateMap<SimpleEnumByte, string>().ConvertUsing(e => e.ToString()); |
| 126 | + config.CreateMap<SimpleEnumSByte, string>().ConvertUsing(e => e.ToString()); |
| 127 | + config.CreateMap<SimpleEnumShort, string>().ConvertUsing(e => e.ToString()); |
| 128 | + config.CreateMap<SimpleEnumUShort, string>().ConvertUsing(e => e.ToString()); |
| 129 | + config.CreateMap<SimpleEnumInt, string>().ConvertUsing(e => e.ToString()); |
| 130 | + config.CreateMap<SimpleEnumUInt, string>().ConvertUsing(e => e.ToString()); |
| 131 | + config.CreateMap<SimpleEnumLong, string>().ConvertUsing(e => e.ToString()); |
| 132 | + config.CreateMap<SimpleEnumULong, string>().ConvertUsing(e => e.ToString()); |
| 133 | + |
| 134 | + config.CreateMap<ComplexEntity, ComplexEntityDto>() |
| 135 | +.ForMember(dest => dest.intToEnum, config => config.MapFrom(src => src.intToEnum)) |
| 136 | +.ForMember(dest => dest.enumToEnum, config => config.MapFrom(src => src.enumToEnum)) |
| 137 | +.ForMember(dest => dest.enumToInt, config => config.MapFrom(src => src.enumToInt)) |
| 138 | +.ForMember(dest => dest.intToInt, config => config.MapFrom(src => src.intToInt)) |
| 139 | +.ReverseMap(); |
| 140 | + }); |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + [Theory] |
| 145 | + [InlineData(SimpleEnumByte.Value2, (byte)2)] |
| 146 | + [InlineData(SimpleEnumSByte.Value2, (sbyte)2)] |
| 147 | + [InlineData(SimpleEnumShort.Value2, (short)2)] |
| 148 | + [InlineData(SimpleEnumUShort.Value2, (ushort)2)] |
| 149 | + [InlineData(SimpleEnumInt.Value2, 2)] |
| 150 | + [InlineData(SimpleEnumUInt.Value2, 2U)] |
| 151 | + [InlineData(SimpleEnumLong.Value2, 2L)] |
| 152 | + [InlineData(SimpleEnumULong.Value2, 2UL)] |
| 153 | + [InlineData(SimpleEnumSByte.Value2, (sbyte)1)] |
| 154 | + [InlineData(SimpleEnumByte.Value2, (byte)1)] |
| 155 | + [InlineData(SimpleEnumShort.Value2, (short)1)] |
| 156 | + [InlineData(SimpleEnumUShort.Value2, (ushort)1)] |
| 157 | + [InlineData(SimpleEnumInt.Value2, 1)] |
| 158 | + [InlineData(SimpleEnumUInt.Value2, 1U)] |
| 159 | + [InlineData(SimpleEnumLong.Value2, 1L)] |
| 160 | + [InlineData(SimpleEnumULong.Value2, 1UL)] |
| 161 | + [InlineData(SimpleEnumSByte.Value3, (sbyte)3)] |
| 162 | + [InlineData(SimpleEnumByte.Value3, (byte)1)] |
| 163 | + [InlineData(SimpleEnumShort.Value3, (short)1)] |
| 164 | + [InlineData(SimpleEnumUShort.Value3, (ushort)1)] |
| 165 | + [InlineData(SimpleEnumInt.Value3, 1)] |
| 166 | + [InlineData(SimpleEnumUInt.Value3, 1U)] |
| 167 | + [InlineData(SimpleEnumLong.Value3, 1L)] |
| 168 | + [InlineData(SimpleEnumULong.Value3, 1UL)] |
| 169 | + [InlineData(SimpleEnumSByte.Value3, (sbyte)3)] |
| 170 | + [InlineData(SimpleEnumByte.Value3, (byte)3)] |
| 171 | + [InlineData(SimpleEnumShort.Value3, (short)3)] |
| 172 | + [InlineData(SimpleEnumUShort.Value3, (ushort)3)] |
| 173 | + [InlineData(SimpleEnumInt.Value3, 3)] |
| 174 | + [InlineData(SimpleEnumUInt.Value3, 3U)] |
| 175 | + [InlineData(SimpleEnumLong.Value3, 3L)] |
| 176 | + [InlineData(SimpleEnumULong.Value3, 3UL)] |
| 177 | + [InlineData(SimpleEnumLong.Value3, long.MaxValue)] |
| 178 | + [InlineData(SimpleEnumULong.Value3, (ulong)long.MaxValue)] |
| 179 | + public void BinaryExpressionEquals<TEnum, TNumeric>(TEnum enumConstant, TNumeric numericConstant) |
| 180 | + where TEnum : Enum |
| 181 | + { |
| 182 | + var correctResult = ((TNumeric)(object)enumConstant).Equals(numericConstant); |
| 183 | + Expression<Func<Entity<TNumeric>, bool>> mappedExpression; |
| 184 | + { |
| 185 | + var param = Expression.Parameter(typeof(EntityDto<TEnum>), "x"); |
| 186 | + var property = Expression.Property(param, nameof(EntityDto<TEnum>.Value)); |
| 187 | + var constantExp = Expression.Constant(enumConstant, typeof(TEnum)); |
| 188 | + var binaryExpression = Expression.Equal(property, constantExp); |
| 189 | + var lambdaExpression = Expression.Lambda(binaryExpression, param); |
| 190 | + mappedExpression = Mapper.Map<Expression<Func<Entity<TNumeric>, bool>>>(lambdaExpression); |
| 191 | + } |
| 192 | + |
| 193 | + var mappedExpressionDelegate = mappedExpression.Compile(); |
| 194 | + |
| 195 | + var entity = new Entity<TNumeric> { Value = numericConstant }; |
| 196 | + var result = mappedExpressionDelegate(entity); |
| 197 | + |
| 198 | + Assert.Equal(result, correctResult); |
| 199 | + } |
| 200 | + |
| 201 | + private class ComplexEntity |
| 202 | + { |
| 203 | + public int intToEnum { get; set; } |
| 204 | + public SimpleEnumInt enumToInt { get; set; } |
| 205 | + public SimpleEnumInt enumToEnum { get; set; } |
| 206 | + public int intToInt { get; set; } |
| 207 | + } |
| 208 | + |
| 209 | + private class ComplexEntityDto |
| 210 | + { |
| 211 | + public SimpleEnumInt intToEnum { get; set; } |
| 212 | + public int enumToInt { get; set; } |
| 213 | + |
| 214 | + public SimpleEnumInt enumToEnum { get; set; } |
| 215 | + public int intToInt { get; set; } |
| 216 | + } |
| 217 | + |
| 218 | + [Fact] |
| 219 | + public void BinaryExpressionPartialTranslation() |
| 220 | + { |
| 221 | + Expression<Func<ComplexEntityDto, bool>> mappedExpression; |
| 222 | + { |
| 223 | + var param = Expression.Parameter(typeof(ComplexEntity), "x"); |
| 224 | + var property1 = Expression.Property(param, nameof(ComplexEntity.intToEnum)); |
| 225 | + var property2 = Expression.Property(param, nameof(ComplexEntity.intToInt)); |
| 226 | + var property5 = Expression.Property(param, nameof(ComplexEntity.enumToEnum)); |
| 227 | + var property6 = Expression.Property(param, nameof(ComplexEntity.enumToInt)); |
| 228 | + |
| 229 | + var constant1 = Expression.Constant(2, typeof(int)); |
| 230 | + var constant2 = Expression.Constant(1, typeof(int)); |
| 231 | + var constant5 = Expression.Constant(SimpleEnumInt.Value3, typeof(SimpleEnumInt)); |
| 232 | + var constant6 = Expression.Constant(SimpleEnumInt.Value2, typeof(SimpleEnumInt)); |
| 233 | + |
| 234 | + Expression[] equals = new Expression[]{ |
| 235 | + Expression.Equal(property1, constant1), |
| 236 | + Expression.Equal(property2, constant2), |
| 237 | + Expression.Equal(property5, constant5), |
| 238 | + Expression.Equal(property6, constant6), |
| 239 | + }; |
| 240 | + |
| 241 | + Expression andExpression = equals[0]; |
| 242 | + for (int i = 1; i < equals.Length; i++) |
| 243 | + { |
| 244 | + andExpression = Expression.And(andExpression, equals[i]); |
| 245 | + } |
| 246 | + var lambdaExpression = Expression.Lambda(andExpression, param); |
| 247 | + mappedExpression = Mapper.Map<Expression<Func<ComplexEntityDto, bool>>>(lambdaExpression); |
| 248 | + } |
| 249 | + |
| 250 | + Expression<Func<ComplexEntityDto, bool>> translatedExpression = |
| 251 | + translatedExpression = x => |
| 252 | + x.intToEnum == SimpleEnumInt.Value2 |
| 253 | + && x.intToInt == (int)SimpleEnumInt.Value1 |
| 254 | + && x.enumToEnum == SimpleEnumInt.Value3 |
| 255 | + && x.enumToInt == (int)SimpleEnumInt.Value2 |
| 256 | + ; |
| 257 | + |
| 258 | + var mappedExpressionDelegate = mappedExpression.Compile(); |
| 259 | + var translatedExpressionDelegate = translatedExpression.Compile(); |
| 260 | + |
| 261 | + var entity = new ComplexEntityDto { intToEnum = SimpleEnumInt.Value2, intToInt = 1, enumToEnum = SimpleEnumInt.Value3, enumToInt = 2 }; |
| 262 | + var mappedResult = mappedExpressionDelegate(entity); |
| 263 | + var translatedResult = translatedExpressionDelegate(entity); |
| 264 | + |
| 265 | + Assert.True(translatedResult); |
| 266 | + Assert.Equal(mappedResult, translatedResult); |
| 267 | + } |
| 268 | + } |
| 269 | +} |
0 commit comments