|
9 | 9 | using System.Linq;
|
10 | 10 | using System.Reflection;
|
11 | 11 | using System.Runtime.CompilerServices;
|
| 12 | +using System.Text.Json.Serialization; |
12 | 13 | using System.Threading.Tasks;
|
| 14 | +using System.Xml.Serialization; |
13 | 15 | using CommunityToolkit.Mvvm.ComponentModel;
|
14 | 16 | using CommunityToolkit.Mvvm.ExternalAssembly;
|
15 | 17 | using CommunityToolkit.Mvvm.Input;
|
@@ -871,6 +873,79 @@ public void Test_ObservableProperty_WithCommandReferencingGeneratedPropertyFromO
|
871 | 873 | Assert.IsTrue(model.HasSaved);
|
872 | 874 | }
|
873 | 875 |
|
| 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 | + |
874 | 949 | public abstract partial class BaseViewModel : ObservableObject
|
875 | 950 | {
|
876 | 951 | public string? Content { get; set; }
|
@@ -1380,4 +1455,66 @@ public override void Save()
|
1380 | 1455 | HasSaved = true;
|
1381 | 1456 | }
|
1382 | 1457 | }
|
| 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 | + } |
1383 | 1520 | }
|
0 commit comments