Skip to content

Commit df6c49e

Browse files
committed
Add unit tests for property attribute forwarding
1 parent 5ffee2c commit df6c49e

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed

tests/CommunityToolkit.Mvvm.Roslyn401.UnitTests/CommunityToolkit.Mvvm.Roslyn401.UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
1010
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
1111
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
12+
<PackageReference Include="System.Text.Json" Version="6.0.6" />
1213
</ItemGroup>
1314

1415
<ItemGroup>

tests/CommunityToolkit.Mvvm.Roslyn430.UnitTests/CommunityToolkit.Mvvm.Roslyn430.UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
1010
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
1111
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
12+
<PackageReference Include="System.Text.Json" Version="6.0.6" />
1213
</ItemGroup>
1314

1415
<ItemGroup>

tests/CommunityToolkit.Mvvm.UnitTests/Test_ObservablePropertyAttribute.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
using System.Linq;
1010
using System.Reflection;
1111
using System.Runtime.CompilerServices;
12+
using System.Text.Json.Serialization;
1213
using System.Threading.Tasks;
14+
using System.Xml.Serialization;
1315
using CommunityToolkit.Mvvm.ComponentModel;
1416
using CommunityToolkit.Mvvm.ExternalAssembly;
1517
using CommunityToolkit.Mvvm.Input;
@@ -871,6 +873,79 @@ public void Test_ObservableProperty_WithCommandReferencingGeneratedPropertyFromO
871873
Assert.IsTrue(model.HasSaved);
872874
}
873875

876+
// See https://github.com/CommunityToolkit/dotnet/issues/413
877+
[TestMethod]
878+
public void Test_ObservableProperty_WithExplicitAttributeForProperty()
879+
{
880+
PropertyInfo nameProperty = typeof(MyViewModelWithExplicitPropertyAttributes).GetProperty(nameof(MyViewModelWithExplicitPropertyAttributes.Name))!;
881+
882+
Assert.IsNotNull(nameProperty.GetCustomAttribute<RequiredAttribute>());
883+
Assert.IsNotNull(nameProperty.GetCustomAttribute<MinLengthAttribute>());
884+
Assert.AreEqual(nameProperty.GetCustomAttribute<MinLengthAttribute>()!.Length, 1);
885+
Assert.IsNotNull(nameProperty.GetCustomAttribute<MaxLengthAttribute>());
886+
Assert.AreEqual(nameProperty.GetCustomAttribute<MaxLengthAttribute>()!.Length, 100);
887+
888+
PropertyInfo lastNameProperty = typeof(MyViewModelWithExplicitPropertyAttributes).GetProperty(nameof(MyViewModelWithExplicitPropertyAttributes.LastName))!;
889+
890+
Assert.IsNotNull(lastNameProperty.GetCustomAttribute<JsonPropertyNameAttribute>());
891+
Assert.AreEqual(lastNameProperty.GetCustomAttribute<JsonPropertyNameAttribute>()!.Name, "lastName");
892+
Assert.IsNotNull(lastNameProperty.GetCustomAttribute<XmlIgnoreAttribute>());
893+
894+
PropertyInfo justOneSimpleAttributeProperty = typeof(MyViewModelWithExplicitPropertyAttributes).GetProperty(nameof(MyViewModelWithExplicitPropertyAttributes.JustOneSimpleAttribute))!;
895+
896+
Assert.IsNotNull(justOneSimpleAttributeProperty.GetCustomAttribute<TestAttribute>());
897+
898+
PropertyInfo someComplexValidationAttributeProperty = typeof(MyViewModelWithExplicitPropertyAttributes).GetProperty(nameof(MyViewModelWithExplicitPropertyAttributes.SomeComplexValidationAttribute))!;
899+
900+
TestValidationAttribute testAttribute = someComplexValidationAttributeProperty.GetCustomAttribute<TestValidationAttribute>()!;
901+
902+
Assert.IsNotNull(testAttribute);
903+
Assert.IsNull(testAttribute.O);
904+
Assert.AreEqual(testAttribute.T, typeof(MyViewModelWithExplicitPropertyAttributes));
905+
Assert.AreEqual(testAttribute.Flag, true);
906+
Assert.AreEqual(testAttribute.D, 6.28);
907+
CollectionAssert.AreEqual(testAttribute.Names, new[] { "Bob", "Ross" });
908+
909+
object[]? nestedArray = (object[]?)testAttribute.NestedArray;
910+
911+
Assert.IsNotNull(nestedArray);
912+
Assert.AreEqual(nestedArray!.Length, 3);
913+
Assert.AreEqual(nestedArray[0], 1);
914+
Assert.AreEqual(nestedArray[1], "Hello");
915+
Assert.IsTrue(nestedArray[2] is int[]);
916+
CollectionAssert.AreEqual((int[])nestedArray[2], new[] { 2, 3, 4 });
917+
918+
Assert.AreEqual(testAttribute.Animal, Animal.Llama);
919+
920+
PropertyInfo someComplexRandomAttribute = typeof(MyViewModelWithExplicitPropertyAttributes).GetProperty(nameof(MyViewModelWithExplicitPropertyAttributes.SomeComplexRandomAttribute))!;
921+
922+
Assert.IsNotNull(someComplexRandomAttribute.GetCustomAttribute<TestAttribute>());
923+
924+
PropertyInfoAttribute testAttribute2 = someComplexRandomAttribute.GetCustomAttribute<PropertyInfoAttribute>()!;
925+
926+
Assert.IsNotNull(testAttribute2);
927+
Assert.IsNull(testAttribute2.O);
928+
Assert.AreEqual(testAttribute2.T, typeof(MyViewModelWithExplicitPropertyAttributes));
929+
Assert.AreEqual(testAttribute2.Flag, true);
930+
Assert.AreEqual(testAttribute2.D, 6.28);
931+
Assert.IsNotNull(testAttribute2.Objects);
932+
Assert.IsTrue(testAttribute2.Objects is object[]);
933+
Assert.AreEqual(((object[])testAttribute2.Objects).Length, 1);
934+
Assert.AreEqual(((object[])testAttribute2.Objects)[0], "Test");
935+
CollectionAssert.AreEqual(testAttribute2.Names, new[] { "Bob", "Ross" });
936+
937+
object[]? nestedArray2 = (object[]?)testAttribute2.NestedArray;
938+
939+
Assert.IsNotNull(nestedArray2);
940+
Assert.AreEqual(nestedArray2!.Length, 4);
941+
Assert.AreEqual(nestedArray2[0], 1);
942+
Assert.AreEqual(nestedArray2[1], "Hello");
943+
Assert.AreEqual(nestedArray2[2], 42);
944+
Assert.IsNull(nestedArray2[3]);
945+
946+
Assert.AreEqual(testAttribute2.Animal, (Animal)67);
947+
}
948+
874949
public abstract partial class BaseViewModel : ObservableObject
875950
{
876951
public string? Content { get; set; }
@@ -1380,4 +1455,66 @@ public override void Save()
13801455
HasSaved = true;
13811456
}
13821457
}
1458+
1459+
public partial class MyViewModelWithExplicitPropertyAttributes : ObservableValidator
1460+
{
1461+
[ObservableProperty]
1462+
[property: Required]
1463+
[property: MinLength(1)]
1464+
[property: MaxLength(100)]
1465+
private string? name;
1466+
1467+
[ObservableProperty]
1468+
[property: JsonPropertyName("lastName")]
1469+
[property: XmlIgnore]
1470+
private string? lastName;
1471+
1472+
[ObservableProperty]
1473+
[property: Test]
1474+
private string? justOneSimpleAttribute;
1475+
1476+
[ObservableProperty]
1477+
[property: TestValidation(null, typeof(MyViewModelWithExplicitPropertyAttributes), true, 6.28, new[] { "Bob", "Ross" }, NestedArray = new object[] { 1, "Hello", new int[] { 2, 3, 4 } }, Animal = Animal.Llama)]
1478+
private int someComplexValidationAttribute;
1479+
1480+
[ObservableProperty]
1481+
[property: Test]
1482+
[property: PropertyInfo(null, typeof(MyViewModelWithExplicitPropertyAttributes), true, 6.28, new[] { "Bob", "Ross" }, new object[] { "Test" }, NestedArray = new object[] { 1, "Hello", 42, null }, Animal = (Animal)67)]
1483+
private int someComplexRandomAttribute;
1484+
}
1485+
1486+
[AttributeUsage(AttributeTargets.Property)]
1487+
private sealed class TestAttribute : Attribute
1488+
{
1489+
}
1490+
1491+
[AttributeUsage(AttributeTargets.Property)]
1492+
private sealed class PropertyInfoAttribute : Attribute
1493+
{
1494+
public PropertyInfoAttribute(object? o, Type t, bool flag, double d, string[] names, object[] objects)
1495+
{
1496+
O = o;
1497+
T = t;
1498+
Flag = flag;
1499+
D = d;
1500+
Names = names;
1501+
Objects = objects;
1502+
}
1503+
1504+
public object? O { get; }
1505+
1506+
public Type T { get; }
1507+
1508+
public bool Flag { get; }
1509+
1510+
public double D { get; }
1511+
1512+
public string[] Names { get; }
1513+
1514+
public object? Objects { get; set; }
1515+
1516+
public object? NestedArray { get; set; }
1517+
1518+
public Animal Animal { get; set; }
1519+
}
13831520
}

0 commit comments

Comments
 (0)