From 736bb69a812910a562226b12c42a5830dceeda42 Mon Sep 17 00:00:00 2001 From: namtab00 Date: Thu, 8 Feb 2024 14:55:56 +0000 Subject: [PATCH] Add test covering explicit case of nullable value type setting --- .../Volo.Abp.Core/Volo/Abp/ObjectHelper.cs | 9 +- .../Volo/Abp/ObjectHelper_Tests.cs | 87 ++++++++++++++++--- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs index c4bdc67a2a..9d9398b847 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs @@ -57,16 +57,21 @@ public static class ObjectHelper return null; } - var propertyInfo = obj?.GetType() .GetProperties() - .FirstOrDefault(x => x.Name == memberExpression.Member.Name && x.GetSetMethod(true) != null); + .FirstOrDefault(x => x.Name == memberExpression.Member.Name); if (propertyInfo == null) { return null; } + var propPrivateSetMethod = propertyInfo.GetSetMethod(true); + if (propPrivateSetMethod == null) + { + return null; + } + if (ignoreAttributeTypes != null && ignoreAttributeTypes.Any(ignoreAttribute => propertyInfo.IsDefined(ignoreAttribute, true))) { return null; diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs index f23d54cf29..0c47fa829c 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs @@ -40,27 +40,88 @@ public class ObjectHelper_Tests } [Fact] - public void TrySetPropertyWithValueType_SetsCorrectly() + public void TrySetProperty_WithNullableNewValueType_SetsCorrectly() { // Arrange - var testClass = new MyClass(); - const long newValue = 10; + var sut = new AbstractParentImpl(); + long? newValue = 10; + // Act & Assert - ObjectHelper.TrySetProperty(testClass, x => x.Number, () => newValue); - testClass.Number.ShouldBe(newValue); + var sutAsIFirst = (IFirst)sut; + + ObjectHelper.TrySetProperty(sutAsIFirst, x => x.ValueProp1FromIFirst, () => newValue); + sutAsIFirst.ValueProp1FromIFirst.ShouldBe(newValue.Value); + + ObjectHelper.TrySetProperty(sutAsIFirst, x => x.ValueProp2FromIFirst, () => newValue); + sutAsIFirst.ValueProp2FromIFirst.ShouldBe(newValue.Value); + + ObjectHelper.TrySetProperty(sutAsIFirst, x => x.ValueProp3FromIFirst, () => newValue); + sutAsIFirst.ValueProp3FromIFirst.ShouldNotBe(newValue.Value); // private set on implementation not accessible + + ObjectHelper.TrySetProperty(sutAsIFirst, x => x.ValueProp4FromIFirst, () => newValue); + sutAsIFirst.ValueProp4FromIFirst.ShouldNotBe(newValue.Value); // readonly + + ObjectHelper.TrySetProperty(sutAsIFirst, x => x.ValueProp5FromIFirst, () => newValue, + ignoreAttributeTypes: typeof(IgnoreDataMemberAttribute)); + sutAsIFirst.ValueProp5FromIFirst.ShouldNotBe(newValue.Value); // ignore by attribute + + var sutAsISecond = (ISecond)sut; + ObjectHelper.TrySetProperty(sutAsISecond, x => x.ValueProp1FromISecond, () => newValue); + sutAsISecond.ValueProp1FromISecond.ShouldNotBe(newValue.Value); // readonly + } + + internal interface IFirst + { + public long ValueProp1FromIFirst { get; } + + public long ValueProp2FromIFirst { get; } + + public long ValueProp3FromIFirst { get; } + + public long ValueProp4FromIFirst { get; } + + public long ValueProp5FromIFirst { get; } + } + + internal interface ISecond + { + public long ValueProp1FromISecond { get; } + } - ObjectHelper.TrySetProperty(testClass, x => x.Number2, () => newValue); - testClass.Number2.ShouldBe(newValue); + internal interface IHasKey + { + TKey Id { get; } + } - ObjectHelper.TrySetProperty(testClass, x => x.Number3, () => newValue); - testClass.Number3.ShouldBe(newValue); + internal interface IHaveMixedProps : IFirst, ISecond + { + } - ObjectHelper.TrySetProperty(testClass, x => x.Number4, () => newValue); - testClass.Number4.ShouldBe(0); // readonly + abstract internal class GenericBase : IHasKey + { + public virtual TKey Id { get; protected set; } + } - ObjectHelper.TrySetProperty(testClass, x => x.Number5, () => newValue, ignoreAttributeTypes: typeof(IgnoreDataMemberAttribute)); - testClass.Number5.ShouldNotBe(newValue); // ignore by attribute + abstract internal class AbstractParent : GenericBase, IHaveMixedProps + { + public long ValueProp1FromIFirst { get; set; } + + public long ValueProp2FromIFirst { get; protected set; } + + public long ValueProp3FromIFirst { get; private set; } + + public long ValueProp4FromIFirst { get; } + + [IgnoreDataMember] public long ValueProp5FromIFirst { get; } + + public long ValueProp1FromISecond { get; } + } + + internal class AbstractParentImpl : AbstractParent + { + public long OwnProp1 { get; set; } + public string OwnProp2 { get; set; } } class MyClass