Skip to content

Commit

Permalink
Add test covering explicit case of nullable value type setting
Browse files Browse the repository at this point in the history
  • Loading branch information
namtab00 committed Feb 8, 2024
1 parent ab188c6 commit 736bb69
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
9 changes: 7 additions & 2 deletions framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,21 @@ public static void TrySetProperty<TObject, TValue>(
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;
Expand Down
87 changes: 74 additions & 13 deletions framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,88 @@ public void TrySetProperty_Test()
}

[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<out TKey>
{
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<TKey> : IHasKey<TKey>
{
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<TKey> : GenericBase<TKey>, 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<long>
{
public long OwnProp1 { get; set; }
public string OwnProp2 { get; set; }
}

class MyClass
Expand Down

0 comments on commit 736bb69

Please sign in to comment.