[DataAnnotation.Validator] Add support for nullable types, patch from lmarinucci...
authorMiguel de Icaza <miguel@gnome.org>
Wed, 12 Feb 2014 03:02:25 +0000 (22:02 -0500)
committerMiguel de Icaza <miguel@gnome.org>
Wed, 12 Feb 2014 03:02:25 +0000 (22:02 -0500)
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/Validator.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/ValidatorTest.cs

index 60534455807e2d1e45c7895a6091b759cbaf0dcd..18f98fe2bf72e1e34e0aec14f7172e6f4dcf0e39 100644 (file)
@@ -93,15 +93,13 @@ namespace System.ComponentModel.DataAnnotations
                        Type propertyType = pdesc.PropertyType;
                        bool invalidType = false;
 
-                       Console.WriteLine ("valueType == {0}; propertyType == {1} (reference? {2})", valueType == null ? "<null>" : valueType.FullName,
-                                          propertyType, !propertyType.IsValueType || (Nullable.GetUnderlyingType (propertyType) != null));
                        if (valueType == null)
-                               invalidType = !(!propertyType.IsValueType || (Nullable.GetUnderlyingType (propertyType) != null));
-                       else if (propertyType != valueType)
-                               invalidType = true;
-
+                               invalidType = (propertyType.IsValueType && Nullable.GetUnderlyingType(propertyType) == null);
+                       else
+                               invalidType = !propertyType.IsAssignableFrom(valueType);
+                       
                        if (invalidType)
-                               throw new ArgumentException (String.Format ("The value of property '{0}' must be of type '{1}'.", propertyName, type.FullName), "propertyName");
+                               throw new ArgumentException (String.Format ("The value of property '{0}' must be of type '{1}'.", propertyName, propertyType.FullName), "propertyName");
                        
                        return pdesc;
                }
@@ -113,8 +111,6 @@ namespace System.ComponentModel.DataAnnotations
                                throw new ArgumentNullException ("validationContext");
 
                        PropertyDescriptor pdesc = GetProperty (validationContext.ObjectType, validationContext.MemberName, value);
-                       if (value == null)
-                               return true;
 
                        bool valid = true;
                        ValidateProperty (pdesc, value, validationContext, validationResults, true, ref valid);
index 0980055bff84ad43b12265f676f66ec3382d3466..0c3787f2f54ad5ffecb7ef1a220adbaf34f7da34 100644 (file)
@@ -26,7 +26,6 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.Design;
 using System.Text;
 
 using NUnit.Framework;
@@ -972,6 +971,97 @@ namespace MonoTests.System.ComponentModel.DataAnnotations
                                Validator.ValidateValue ("dummy", ctx, null);
                        }, "#B3");
                }
+               
+               [Test]
+               public void TryValidateValue_Throws_ValidationException_When_Property_Is_NullableAndRequired_And_Value_Is_Null ()
+               {
+                       EntityMock entity = new EntityMock ();
+                       ICollection<ValidationResult> result = new List<ValidationResult>();
+
+                       ICollection<ValidationAttribute> attributes = new List<ValidationAttribute> ();
+                       attributes.Add (new RequiredAttribute ());
+
+                       // Year = null
+                       bool isValid = Validator.TryValidateValue (null, new ValidationContext (entity, null, null) { MemberName = "Year" }, result, attributes);
+
+                       Assert.IsFalse (isValid, "#A1-1");
+                       Assert.AreEqual (1, result.Count, "#A1-2");
+
+                       // Name = null, string
+                       result.Clear ();
+
+                       isValid = Validator.TryValidateValue (null, new ValidationContext (entity, null, null) { MemberName =  "Name" }, result, attributes);
+
+                       Assert.IsFalse (isValid, "#A2-1");
+                       Assert.AreEqual (1, result.Count, "#A2-2");
+
+                       // Name = string.Empty, string
+                       result.Clear ();
+
+                       isValid = Validator.TryValidateValue (String.Empty, new ValidationContext (entity, null, null) { MemberName = "Name" }, result, attributes);
+
+                       Assert.IsFalse (isValid, "#A3-1");
+                       Assert.AreEqual (1, result.Count, "#A3-2");
+               }
+
+               [Test]
+               public void TryValidateProperty_Throws_ValidationException_When_Property_Is_NullableAndRequired_And_Value_Is_Null ()
+               {
+                       EntityMock entity = new EntityMock ();
+                       ICollection<ValidationResult> result = new List<ValidationResult> ();
+
+                       // Year = null
+                       bool isValid = Validator.TryValidateProperty (null, new ValidationContext (entity, null, null) { MemberName = "Year" }, result);
+
+                       Assert.IsFalse (isValid, "#A1-1");
+                       Assert.AreEqual (1, result.Count, "#A1-2");
+
+                       // Name = null, string
+                       result.Clear ();
+
+                       isValid = Validator.TryValidateProperty (null, new ValidationContext (entity, null, null) { MemberName = "Name" }, result);
+
+                       Assert.IsFalse (isValid, "#A2-1");
+                       Assert.AreEqual (1, result.Count, "#A2-2");
+
+                       // Name = string.Empty, string
+                       result.Clear ();
+
+                       isValid = Validator.TryValidateProperty (String.Empty, new ValidationContext (entity, null, null) { MemberName = "Name" }, result);
+
+                       Assert.IsFalse (isValid, "#A3-1");
+                       Assert.AreEqual (1, result.Count, "#A3-2");
+               }
+
+               [Test]
+               public void TryValidateObject_Throws_ValidationException_When_Property_Is_NullableAndRequired_And_Value_Is_Null ()
+               {
+                       EntityMock entity = new EntityMock ();
+                       ICollection<ValidationResult> result = new List<ValidationResult> ();
+
+                       // Year = null
+                       bool isValid = Validator.TryValidateObject (entity, new ValidationContext (entity, null, null), result);
+
+                       Assert.IsFalse (isValid, "#A1-1");
+                       Assert.AreEqual (2, result.Count, "#A1-2");
+
+                       // Name = null, string
+                       result.Clear ();
+
+                       isValid = Validator.TryValidateObject (entity, new ValidationContext (entity, null, null), result);
+
+                       Assert.IsFalse (isValid, "#A2-1");
+                       Assert.AreEqual (2, result.Count, "#A2-2");
+
+                       // Name = string.Empty, string
+                       result.Clear ();
+
+                       entity.Name = String.Empty;
+                       isValid = Validator.TryValidateObject (entity, new ValidationContext (entity, null, null), result);
+
+                       Assert.IsFalse (isValid, "#A3-1");
+                       Assert.AreEqual (2, result.Count, "#A3-2");
+               }
 
                public static ValidationResult DummyValidationMethod (object o)
                {
@@ -1115,6 +1205,33 @@ namespace MonoTests.System.ComponentModel.DataAnnotations
                        [CustomValidation (typeof (ValidatorTest), "SecondPropertyValidationMethod")]
                        public string SecondProperty { get; set; }
                }
+               
+               class EntityMock
+               {
+                       private int? _year;
+
+                       [Required]
+                       public int? Year
+                       {
+                               get { return _year; }
+                               set
+                               {
+                                       _year = value;
+                               }
+                       }
+
+                       private string _name;
+
+                       [Required]
+                       public string Name
+                       {
+                               get { return _name; }
+                               set
+                               {
+                                       _name = value;
+                               }
+                       }
+               }
        }
 #endif
 }