2010-05-12 Marek Habersack <mhabersack@novell.com>
authorMarek Habersack <grendel@twistedcode.net>
Wed, 12 May 2010 02:42:39 +0000 (02:42 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Wed, 12 May 2010 02:42:39 +0000 (02:42 -0000)
     * ValidationException.cs: partially implemented

     * ValidationAttribute.cs: implemented

     * RequiredAttribute.cs: implemented. Fixes bug #604100

     * AssociationAttribute.cs, ConcurrencyCheckAttribute.cs,
     CustomValidationAttribute.cs, EditableAttribute.cs,
     EnumDataTypeAttribute.cs, IValidatableObject.cs,
     ValidationContext.cs, ValidationResult.cs: added

svn path=/trunk/mcs/; revision=157187

21 files changed:
1  2 
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.dll.sources
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/AssociationAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ChangeLog
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ConcurrencyCheckAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/CustomValidationAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/EditableAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/EnumDataTypeAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/IValidatableObject.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/RequiredAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ValidationAttribute.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ValidationContext.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ValidationException.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations/ValidationResult.cs
mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations_test.dll.sources
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/AssociationAttributeTest.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/EnumDataTypeAttributeTest.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/RequiredAttributeTest.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/ValidationAttributeTest.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/ValidationContextTest.cs
mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/ValidationResultTest.cs
mcs/class/System.ComponentModel.DataAnnotations/net_4_0_System.ComponentModel.DataAnnotations.dll.sources

index aa307ea69d9edef214f5a7b250c2344cc2f5904d,aa307ea69d9edef214f5a7b250c2344cc2f5904d..47e24618b4c4d1c2795ef2b94c4e3340024d5cf6
@@@ -5,10 -5,10 +5,16 @@@ Assembly/AssemblyInfo.c
  System.ComponentModel.DataAnnotations/AssociatedMetadataTypePropertyDescriptor.cs
  System.ComponentModel.DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs
  System.ComponentModel.DataAnnotations/AssociatedMetadataTypeTypeDescriptionProvider.cs
++System.ComponentModel.DataAnnotations/AssociationAttribute.cs
++System.ComponentModel.DataAnnotations/ConcurrencyCheckAttribute.cs
++System.ComponentModel.DataAnnotations/CustomValidationAttribute.cs
  System.ComponentModel.DataAnnotations/DataType.cs
  System.ComponentModel.DataAnnotations/DataTypeAttribute.cs
  System.ComponentModel.DataAnnotations/DisplayColumnAttribute.cs
  System.ComponentModel.DataAnnotations/DisplayFormatAttribute.cs
++System.ComponentModel.DataAnnotations/EditableAttribute.cs
++System.ComponentModel.DataAnnotations/EnumDataTypeAttribute.cs
++System.ComponentModel.DataAnnotations/IValidatableObject.cs
  System.ComponentModel.DataAnnotations/MetadataTypeAttribute.cs
  System.ComponentModel.DataAnnotations/RangeAttribute.cs
  System.ComponentModel.DataAnnotations/RegularExpressionAttribute.cs
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7624c6090b95f025a3540ad8852f203d73ae50dc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,89 @@@
++//
++// AssociationAttribute.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      [AttributeUsage (AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
++      public sealed class AssociationAttribute : Attribute
++      {
++              static readonly char[] keySplitChars = { ',' };
++              
++              IEnumerable <string> otherKeyMembers;
++              IEnumerable <string> thisKeyMembers;
++              
++              public bool IsForeignKey { get; set; }
++              public string Name { get; private set; }
++              public string OtherKey { get; private set; }
++              
++              public IEnumerable<string> OtherKeyMembers {
++                      get {
++                              if (otherKeyMembers == null)
++                                      otherKeyMembers = GetKeyMembers (OtherKey);
++
++                              return otherKeyMembers;
++                      }
++              }
++              
++              public string ThisKey { get; private set; }
++              
++              public IEnumerable<string> ThisKeyMembers {
++                      get {
++                              if (thisKeyMembers == null)
++                                      thisKeyMembers = GetKeyMembers (ThisKey);
++
++                              return thisKeyMembers;
++                      }
++              }
++              
++              public AssociationAttribute (string name, string thisKey, string otherKey)
++              {
++                      this.Name = name;
++                      this.ThisKey = thisKey;
++                      this.OtherKey = otherKey;
++              }
++
++              IEnumerable <string> GetKeyMembers (string key)
++              {
++                      // .NET emulation
++                      if (key == null)
++                              throw new NullReferenceException (".NET emulation");
++
++                      string nows = key.Replace (" ", String.Empty);
++                      if (nows.Length == 0)
++                              return new string[] { String.Empty };
++                                      
++                      return nows.Split (keySplitChars);
++              }
++      }
++}
++#endif
index 3bc4ea696760b9d94e8b0630518c804978831aff,3bc4ea696760b9d94e8b0630518c804978831aff..2ba49bb81be3b479886f657e0c22d3068661a404
@@@ -1,3 -1,3 +1,16 @@@
++2010-05-12  Marek Habersack  <mhabersack@novell.com>
++
++      * ValidationException.cs: partially implemented
++
++      * ValidationAttribute.cs: implemented
++
++      * RequiredAttribute.cs: implemented. Fixes bug #604100
++
++      * AssociationAttribute.cs, ConcurrencyCheckAttribute.cs,
++      CustomValidationAttribute.cs, EditableAttribute.cs,
++      EnumDataTypeAttribute.cs, IValidatableObject.cs,
++      ValidationContext.cs, ValidationResult.cs: added
++
  2009-09-15  Marek Habersack  <mhabersack@novell.com>
  
        * DataTypeAttribute.cs: implemented GetDataTypeName
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6d5cdc72435f6887a52b346408d4578b648ff16e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,44 @@@
++//
++// ConcurrencyCheckAttribute.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      [AttributeUsage (AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
++      public sealed class ConcurrencyCheckAttribute : Attribute
++      {
++              public ConcurrencyCheckAttribute ()
++              {
++              }
++      }
++}
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7cca7f40e1f45e836696995589a42ae27223c6e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++//
++// CustomValidationAttribute.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)]
++      public sealed class CustomValidationAttribute : ValidationAttribute
++      {
++              public string Method { get; private set; }
++              public override object TypeId {
++                      get {
++                              throw new NotImplementedException ();
++                      }
++              }
++              public Type ValidatorType { get; private set; }
++              
++              public CustomValidationAttribute (Type validatorType, string method)
++              {
++                      this.ValidatorType = validatorType;
++                      this.Method = method;
++              }
++
++              public override string FormatErrorMessage (string name)
++              {
++                      throw new NotImplementedException ();
++              }
++
++              // LAMESPEC: MSDN doesn't document it at all, but corcompare shows it in the type
++              protected override ValidationResult IsValid (object value, ValidationContext validationContext)
++              {
++                      throw new NotImplementedException ();
++              }
++      }
++}
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..abfba998c24fb659275a6e12cc109a1c426f18c2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,48 @@@
++//
++// EditableAttribute.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      [AttributeUsage (AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
++      public sealed class EditableAttribute : Attribute
++      {
++              public bool AllowEdit { get; private set; }
++              public bool AllowInitialValue { get; set; }
++              
++              public EditableAttribute (bool allowEdit)
++              {
++                      this.AllowEdit = allowEdit;
++              }
++      }
++}
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a0efa1e846d6f9a67ef9c0b5b6c17381a434b3a8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,117 @@@
++//
++// EnumDataTypeAttribute.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++using System.ComponentModel;
++using System.Globalization;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      [AttributeUsage (AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
++      public sealed class EnumDataTypeAttribute : DataTypeAttribute
++      {
++              public Type EnumType { get; private set; }
++              
++              public EnumDataTypeAttribute (Type enumType)
++                      : base (DataType.Custom)
++              {
++                      this.EnumType = enumType;
++              }
++
++              public override bool IsValid (object value)
++              {
++                      Type type = EnumType;
++
++                      if (!type.IsEnum)
++                              throw new InvalidOperationException (
++                                      String.Format ("The type '{0}' needs to represent an enumeration type.", type.FullName)
++                              );
++
++                      if (value == null)
++                              return true;
++
++                      Type valueType = value.GetType ();
++                      if (valueType.IsEnum && valueType != type)
++                              return false;
++
++                      string s = value as string;
++                      if (s != null && s.Length == 0)
++                              return true;
++                      
++                      if (s != null && (valueType == typeof (bool) || valueType == typeof (char) || valueType == typeof (float)))
++                              return false;
++
++                      object o;
++
++                      if (s != null) {
++                              try {
++                                      o = Enum.Parse (type, s);
++                              } catch {
++                                      return false;
++                              }
++                      } else if (valueType.IsEnum)
++                              o = value;
++                      else {
++                              try {
++                                      o = Enum.ToObject (type, value);
++                              } catch {
++                                      return false;
++                              }
++                      }
++
++                      object[] attrs = type.GetCustomAttributes (typeof (FlagsAttribute), true);
++                      if (attrs != null && attrs.Length > 0) {
++                              string sval = Convert.ChangeType (o, Enum.GetUnderlyingType (type), CultureInfo.InvariantCulture).ToString ();
++
++                              // This looks weird, but what happens here is that if we have a
++                              // mismatch, the above type change will make sval equal o.ToString
++                              // () and if we have a match, then sval will be string
++                              // representation of the enum member's value. So, if we have an
++                              // enum:
++                              //
++                              // [Flags]
++                              // enum Test
++                              // {
++                              //     One = 1,
++                              //     Two = 2
++                              // }
++                              //
++                              // And the passed value was 3, then o.ToString () == "One, Two" and
++                              // sval == "3". If the passed value was 33, though, o.ToString () ==
++                              // "33" and sval == "33" - thus we DON'T have a match.
++                              return !sval.Equals (o.ToString ());
++                      }
++                      
++                      return Enum.IsDefined (type, o);
++              }
++      }
++}
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cf68fc3669c394229307efd9bb172c933505d935
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++//
++// IValidatableObject.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if NET_4_0
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      public interface IValidatableObject
++      {
++              IEnumerable<ValidationResult> Validate (ValidationContext validationContext);
++      }
++}
++#endif
index 645986d9c8577da25e23558f76aa08fc8b8135c9,645986d9c8577da25e23558f76aa08fc8b8135c9..46318de5d4e8db9d7939da3530d61480e5375e83
@@@ -4,7 -4,7 +4,7 @@@
  // Author:
  //    Atsushi Enomoto <atsushi@ximian.com>
  //
--// Copyright (C) 2008 Novell Inc. http://novell.com
++// Copyright (C) 2008-2010 Novell Inc. http://novell.com
  //
  
  //
@@@ -35,10 -35,10 +35,24 @@@ namespace System.ComponentModel.DataAnn
        [AttributeUsage (AttributeTargets.Property|AttributeTargets.Field, AllowMultiple = false)]
        public class RequiredAttribute : ValidationAttribute
        {
--              [MonoTODO]
++#if NET_4_0
++              public bool AllowEmptyStrings { get; set; }
++#endif
++
                public override bool IsValid (object value)
                {
--                      throw new NotImplementedException ();
++                      if (value == null)
++                              return false;
++
++                      string s = value as string;
++                      if (s != null
++#if NET_4_0
++                          && !AllowEmptyStrings
++#endif
++                      )
++                              return s.Length > 0;
++
++                      return true;
                }
        }
  }
index 237aa5f2b7b964c90c5fc321e7f38ae4da350b64,237aa5f2b7b964c90c5fc321e7f38ae4da350b64..45e96d656276a053242726b1f371b048b0f0d0fe
@@@ -1,10 -1,10 +1,11 @@@
  //
--// UIHintAttribute.cs
++// ValidationAttribute.cs
  //
--// Author:
++// Authors:
  //    Atsushi Enomoto <atsushi@ximian.com>
++//    Marek Habersack <mhabersack@novell.com>
  //
--// Copyright (C) 2008 Novell Inc. http://novell.com
++// Copyright (C) 2008-2010 Novell Inc. http://novell.com
  //
  
  //
  //
  using System;
  using System.ComponentModel;
++using System.Reflection;
  
  namespace System.ComponentModel.DataAnnotations
  {
        public abstract class ValidationAttribute : Attribute
        {
++              const string DEFAULT_ERROR_MESSAGE = "The field {0} is invalid.";
++#if !NET_4_0
++              string errorMessage;
++              string errorMessageResourceName;
++              string errorMessageString;
++              Type errorMessageResourceType;
++#endif
++              string fallbackErrorMessage;
++              Func <string> errorMessageAccessor;
++              
                protected ValidationAttribute ()
--                      : this ("This member is required")
                {
                }
  
--              [MonoTODO]
                protected ValidationAttribute (Func<string> errorMessageAccessor)
                {
--                      throw new NotImplementedException ();
++                      this.errorMessageAccessor = errorMessageAccessor;
                }
  
                protected ValidationAttribute (string errorMessage)
                {
--                      ErrorMessage = errorMessage;
++                      fallbackErrorMessage = errorMessage;
                }
  
--              [MonoTODO]
                public virtual string FormatErrorMessage (string name)
                {
--                      throw new NotImplementedException ();
++                      return String.Format (ErrorMessageString, name);
                }
--
++#if NET_4_0
                public string ErrorMessage { get; set; }
                public string ErrorMessageResourceName { get; set; }
                public Type ErrorMessageResourceType { get; set; }
--              protected string ErrorMessageString { get; private set; }
++#else
++              public string ErrorMessage {
++                      get { return errorMessage; }
++
++                      set {
++                              if (errorMessage != null)
++                                      throw new InvalidOperationException ("This property can be set only once.");
++
++                              if (String.IsNullOrEmpty (value))
++                                      throw new ArgumentException ("Value cannot be null or empty.", "value");
++
++                              if (errorMessageResourceName != null || errorMessageResourceType != null)
++                                      throw new InvalidOperationException ("This property cannot be set because the attribute is already in the resource mode.");
++                              
++                              errorMessage = value;
++                      }
++              }
++
++              public string ErrorMessageResourceName {
++                      get { return errorMessageResourceName; }
++                      
++                      set {
++                              if (errorMessageResourceName != null)
++                                      throw new InvalidOperationException ("This property can be set only once.");
  
++                              if (String.IsNullOrEmpty (value))
++                                      throw new ArgumentException ("Value cannot be null or empty.", "value");
++
++                              errorMessageResourceName = value;
++                              if (errorMessageResourceType != null)
++                                      errorMessageString = GetStringFromResourceAccessor ();
++                      }
++              }
++
++              public Type ErrorMessageResourceType {
++                      get { return errorMessageResourceType; }
++                      set {
++                              errorMessageResourceType = value;
++                              if (!String.IsNullOrEmpty (errorMessageResourceName))
++                                      errorMessageString = GetStringFromResourceAccessor ();
++                      }
++              }
++#endif                
++              protected string ErrorMessageString {
++                      get {
++#if NET_4_0
++                              return GetStringFromResourceAccessor ();
++#else
++                              return errorMessageString;
++#endif
++                      }
++              }
++#if NET_4_0
++              public virtual bool IsValid (object value)
++              {
++                      throw new NotImplementedException ("IsValid(object value) has not been implemented by this class.  The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context).");
++              }
++
++              protected virtual ValidationResult IsValid (object value, ValidationContext validationContext)
++              {
++                      // .NET emulation
++                      if (validationContext == null)
++                              throw new NullReferenceException (".NET emulation.");
++                      
++                      if (!IsValid (value)) {
++                              string memberName = validationContext.MemberName;
++                              return new ValidationResult (FormatErrorMessage (validationContext.DisplayName), memberName != null ? new string[] { memberName } : new string[] {});
++                      }
++
++                      return ValidationResult.Success;
++              }
++#else
                public abstract bool IsValid (object value);
++#endif
++
++#if NET_4_0
++              public ValidationResult GetValidationResult (object value, ValidationContext validationContext)
++              {
++                      if (validationContext == null)
++                              throw new ArgumentNullException ("validationContext");
++
++                      ValidationResult ret = IsValid (value, validationContext);
++                      if (ret != null && String.IsNullOrEmpty (ret.ErrorMessage))
++                              ret.ErrorMessage = FormatErrorMessage (validationContext.DisplayName);
++                              
++                      return ret;
++              }
++#endif
++              string GetStringFromResourceAccessor ()
++              {
++                      string resourceName = ErrorMessageResourceName;
++                      Type resourceType = ErrorMessageResourceType;
++                      string errorMessage = ErrorMessage;
  
--              [MonoTODO]
++                      if (resourceName != null && errorMessage != null)
++                              throw new InvalidOperationException ("Either ErrorMessage or ErrorMessageResourceName must be set, but not both.");
++                      
++                      if (resourceType == null ^ resourceName == null)
++                              throw new InvalidOperationException ("Both ErrorMessageResourceType and ErrorMessageResourceName must be set on this attribute.");
++
++                      if (errorMessageAccessor != null)
++                              return errorMessageAccessor ();
++                      
++                      if (resourceType != null) {
++                              PropertyInfo pi = resourceType.GetProperty (resourceName, BindingFlags.Public | BindingFlags.Static);
++                              if (pi == null || !pi.CanRead)
++                                      throw new InvalidOperationException (
++                                              String.Format ("Resource type '{0}' does not have an accessible static property named '{1}'.",
++                                                             resourceType, resourceName)
++                                      );
++
++                              if (pi.PropertyType != typeof (string))
++                                      throw new InvalidOperationException (
++                                              String.Format ("The property '{0}' on resource type '{1}' is not a string type.",
++                                                             resourceName, resourceType)
++                                      );
++                              
++                              return pi.GetValue (null, null) as string;
++                      }
++                      
++                      if (errorMessage == null)
++                              if (fallbackErrorMessage != null)
++                                      return fallbackErrorMessage;
++                              else
++                                      return DEFAULT_ERROR_MESSAGE;
++
++                      return errorMessage;
++              }
++#if NET_4_0
++              public void Validate (object value, ValidationContext validationContext)
++              {
++                      if (validationContext == null)
++                              throw new ArgumentNullException ("validationContext");
++
++                      ValidationResult result = IsValid (value, validationContext);
++                      if (result != null) {
++                              string message = result.ErrorMessage;
++                              if (message == null)
++                                      message = FormatErrorMessage (validationContext.DisplayName);
++                              
++                              throw new ValidationException (message, this, value);
++                      }
++              }
++#endif
                public void Validate (object value, string name)
                {
--                      throw new NotImplementedException ();
++                      if (!IsValid (value))
++                              throw new ValidationException (FormatErrorMessage (name), this, value);
                }
        }
  }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e99efe58d4017638a9e314e51ffc5cee3f3b2a99
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,139 @@@
++//
++// ValidationContext.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.Design;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      public sealed class ValidationContext : IServiceProvider
++      {
++              public string DisplayName { get; set; }
++              public IDictionary <object, object> Items { get; private set; }
++              public string MemberName { get; set; }
++              public object ObjectInstance { get; private set; }
++              public Type ObjectType { get; private set; }
++              public IServiceContainer ServiceContainer { get; private set; }
++              
++              public ValidationContext (object instance, IServiceProvider serviceProvider, IDictionary<object, object> items)
++              {
++                      if (instance == null)
++                              throw new ArgumentNullException ("instance");
++                      
++                      ObjectInstance = instance;
++                      ObjectType = instance.GetType ();
++                      if (items != null)
++                              Items = new Dictionary <object, object> (items);
++                      else
++                              Items = new Dictionary <object, object> ();
++                      
++                      DisplayName = instance.GetType ().Name;
++
++                      // LAMESPEC: MSDN says vc.ServiceContainer should be initialized with the passed container if it implements 
++                      // the IServiceContainer interface - not the case, though.
++                      //
++                      // IServiceContainer container = serviceProvider as IServiceContainer;
++                      // if (container != null)
++                      //      ServiceContainer = container;
++                      // else
++                      ServiceContainer = new ValidationContextServiceContainer ();
++              }
++
++              public object GetService (Type serviceType)
++              {
++                      return ServiceContainer.GetService (serviceType);
++              }
++
++              sealed class ValidationContextServiceContainer : IServiceContainer
++              {
++                      Dictionary <Type, object> services = new Dictionary <Type, object> ();
++                      
++                      public void AddService (Type serviceType, ServiceCreatorCallback callback, bool promote)
++                      {
++                              AddService (serviceType, (object)callback, promote);
++                      }
++
++                      public void AddService (Type serviceType, ServiceCreatorCallback callback)
++                      {
++                              AddService (serviceType, callback, false);
++                      }
++
++                      public void AddService (Type serviceType, object serviceInstance, bool promote)
++                      {
++                              if (serviceType == null)
++                                      throw new ArgumentNullException ("serviceType");
++                              
++                              if (services.ContainsKey (serviceType))
++                                      throw new ArgumentException (
++                                              String.Format ("A service of type '{0}' already exists in the container.", serviceType)
++                                      );
++
++                              services.Add (serviceType, serviceInstance);
++                      }
++
++                      public void AddService (Type serviceType, object serviceInstance)
++                      {
++                              AddService (serviceType, serviceInstance, false);
++                      }
++
++                      public void RemoveService (Type serviceType, bool promote)
++                      {
++                              if (serviceType == null)
++                                      throw new ArgumentNullException ("serviceType");
++                              
++                              if (!services.ContainsKey (serviceType))
++                                      return;
++
++                              services.Remove (serviceType);
++                      }
++
++                      public void RemoveService (Type serviceType)
++                      {
++                              RemoveService (serviceType, false);
++                      }
++
++                      public object GetService (Type serviceType)
++                      {
++                              if (serviceType == null)
++                                      throw new ArgumentNullException ("serviceType");
++                              
++                              object o;
++                              if (!services.TryGetValue (serviceType, out o))
++                                      return null;
++
++                              var cb = o as ServiceCreatorCallback;
++                              if (cb != null)
++                                      return cb (this, serviceType);
++
++                              return o;
++                      }
++              }
++      }
++}
index 5df494153250018b482077cec55396725977562a,5df494153250018b482077cec55396725977562a..ccdd98951faf91ddd1a3475559119d9c615b3678
@@@ -50,8 -50,8 +50,10 @@@ namespace System.ComponentModel.DataAnn
                }
  
                public ValidationException (string errorMessage, ValidationAttribute validatingAttribute, object value)
++                      : base (errorMessage)
                {
--                      throw new NotImplementedException ();
++                      ValidationAttribute = validatingAttribute;
++                      Value = value;
                }
  
                protected ValidationException (SerializationInfo info, StreamingContext context)
                {
                        throw new NotImplementedException ();
                }
--
++#if NET_4_0
++              public ValidationException (ValidationResult validationResult, ValidationAttribute validatingAttribute, object value)
++              {
++              }
++#endif
                public ValidationAttribute ValidationAttribute { get; private set; }
                public object Value { get; private set; }
  
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..efc38b04cdc76f563fc479d22dd8b3b16a063c6a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,61 @@@
++//
++// ValidationResult.cs
++//
++// Authors:
++//    Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell Inc. (http://novell.com)
++//
++
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++
++namespace System.ComponentModel.DataAnnotations
++{
++      public class ValidationResult
++      {
++              public static readonly ValidationResult Success = null; // it is supposed to be null
++
++              public string ErrorMessage { get; set; }
++              public IEnumerable<string> MemberNames { get; private set; }
++              
++              public ValidationResult (string errorMessage)
++              : this (errorMessage, new string[] {})
++                      
++              {
++              }
++
++              protected ValidationResult (ValidationResult validationResult)
++              {
++              }
++
++              public ValidationResult (string errorMessage, IEnumerable<string> memberNames)
++              {
++                      ErrorMessage = errorMessage;
++                      if (memberNames != null)
++                              MemberNames = memberNames;
++                      else
++                              MemberNames = new string[] {};
++              }
++      }
++}
index 11a774f2971ae9d23aac96a6f590d3ccbd24a253,11a774f2971ae9d23aac96a6f590d3ccbd24a253..170cff4263db000b44ae7d12e9105e9aa127ca17
@@@ -1,1 -1,1 +1,7 @@@
--System.ComponentModel.DataAnnotations/AssociatedMetadataTypeTypeDescriptionProviderTests.cs
++System.ComponentModel.DataAnnotations/AssociatedMetadataTypeTypeDescriptionProviderTests.cs
++System.ComponentModel.DataAnnotations/AssociationAttributeTest.cs
++System.ComponentModel.DataAnnotations/EnumDataTypeAttributeTest.cs
++System.ComponentModel.DataAnnotations/RequiredAttributeTest.cs
++System.ComponentModel.DataAnnotations/ValidationAttributeTest.cs
++System.ComponentModel.DataAnnotations/ValidationContextTest.cs
++System.ComponentModel.DataAnnotations/ValidationResultTest.cs
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..14c2bff222e72a72215fd26cbb137e193bd78f94
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,129 @@@
++//
++// AssociationAttributeTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.ComponentModel.Design;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++#if NET_4_0
++      [TestFixture]
++      public class AssociationAttributeTest
++      {
++              [Test]
++              public void Constructor ()
++              {
++                      AssociationAttribute attr;
++
++                      attr = new AssociationAttribute (null, "key1,key2", "key3,key4");
++                      Assert.AreEqual (null, attr.Name, "#A1-1");
++                      Assert.AreEqual ("key1,key2", attr.ThisKey, "#A1-2");
++                      Assert.AreEqual ("key3,key4", attr.OtherKey, "#A1-3");
++                      Assert.IsNotNull (attr.OtherKeyMembers, "#A2-1");
++
++                      int count = 0;
++                      var list = new List<string> ();
++                      foreach (string m in attr.OtherKeyMembers) {
++                              count++;
++                              list.Add (m);
++                      }
++                      Assert.AreEqual (2, count, "#A2-2");
++                      Assert.AreEqual ("key3", list [0], "#A2-3");
++                      Assert.AreEqual ("key4", list [1], "#A2-4");
++
++                      Assert.IsNotNull (attr.ThisKeyMembers, "#A3-1");
++
++                      count = 0;
++                      list = new List<string> ();
++                      foreach (string m in attr.ThisKeyMembers) {
++                              count++;
++                              list.Add (m);
++                      }
++                      Assert.AreEqual (2, count, "#A3-2");
++                      Assert.AreEqual ("key1", list [0], "#A3-3");
++                      Assert.AreEqual ("key2", list [1], "#A3-4");
++
++                      attr = new AssociationAttribute ("name", null, "key3,key4");
++                      Assert.AreEqual ("name", attr.Name, "#B1-1");
++                      Assert.AreEqual (null, attr.ThisKey, "#B1-2");
++                      Assert.AreEqual ("key3,key4", attr.OtherKey, "#B1-3");
++                      Assert.IsNotNull (attr.OtherKeyMembers, "#B2-1");
++
++                      count = 0;
++                      list = new List<string> ();
++                      foreach (string m in attr.OtherKeyMembers) {
++                              count++;
++                              list.Add (m);
++                      }
++                      Assert.AreEqual (2, count, "#B2-2");
++                      Assert.AreEqual ("key3", list [0], "#B2-3");
++                      Assert.AreEqual ("key4", list [1], "#B2-4");
++
++                      // this is just sad...
++                      try {
++                              var m = attr.ThisKeyMembers;
++                              Assert.Fail ("#B2-5");
++                      } catch (NullReferenceException) {
++                              // success
++                      }
++
++                      attr = new AssociationAttribute ("name", " key1  ,   key 2  ,, ,key    3  ", "       ");
++                      Assert.IsNotNull (attr.ThisKeyMembers, "#C1");
++
++                      count = 0;
++                      list = new List<string> ();
++                      foreach (string m in attr.ThisKeyMembers) {
++                              count++;
++                              list.Add (m);
++                      }
++
++                      // It seems all the whitespace is removed from key names
++                      Assert.AreEqual (5, count, "#C2-1");
++                      Assert.AreEqual ("key1", list [0], "#C2-2");
++                      Assert.AreEqual ("key2", list [1], "#C2-3");
++                      Assert.AreEqual (String.Empty, list [2], "#C2-4");
++                      Assert.AreEqual (String.Empty, list [3], "#C2-5");
++                      Assert.AreEqual ("key3", list [4], "#C2-6");
++
++                      Assert.IsNotNull (attr.OtherKeyMembers, "#C3");
++                      count = 0;
++                      list = new List<string> ();
++                      foreach (string m in attr.OtherKeyMembers) {
++                              count++;
++                              list.Add (m);
++                      }
++                      Assert.AreEqual (1, count, "#C4-1");
++                      Assert.AreEqual (String.Empty, list [0], "#C4-2");
++              }
++      }
++#endif
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cf7c641f9fede6ac070dcf5984f418a1b3e2c80e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,137 @@@
++//
++// EnumDataTypeAttributeTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.ComponentModel.Design;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++#if NET_4_0
++      [TestFixture]
++      public class EnumDataTypeAttributeTest
++      {
++              [Test]
++              public void Constructor ()
++              {
++                      var attr = new EnumDataTypeAttribute (typeof (string));
++
++                      Assert.AreEqual (DataType.Custom, attr.DataType, "#A1-1");
++                      Assert.AreEqual (typeof (string), attr.EnumType, "#A1-2");
++
++                      attr = new EnumDataTypeAttribute (typeof (TestEnum));
++                      Assert.AreEqual (DataType.Custom, attr.DataType, "#B1-1");
++                      Assert.AreEqual (typeof (TestEnum), attr.EnumType, "#B1-2");
++
++                      attr = new EnumDataTypeAttribute (null);
++                      Assert.AreEqual (DataType.Custom, attr.DataType, "#C1-1");
++                      Assert.AreEqual (null, attr.EnumType, "#C1-2");
++              }
++
++              [Test]
++              public void IsValid ()
++              {
++                      var attr = new EnumDataTypeAttribute (typeof (string));
++                      
++                      try {
++                              attr.IsValid (null);
++                              Assert.Fail ("#A1-1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      try {
++                              attr.IsValid ("stuff");
++                              Assert.Fail ("#A1-2");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new EnumDataTypeAttribute (typeof (TestEnum));
++                      Assert.IsTrue (attr.IsValid (null), "#A2-1");
++                      Assert.IsTrue (attr.IsValid (1), "#A2-2");
++                      Assert.IsFalse (attr.IsValid (0), "#A2-3");
++                      Assert.IsTrue (attr.IsValid (TestEnum.Two), "#A2-4");
++                      Assert.IsFalse (attr.IsValid (AnotherEnum.Five), "#A2-5");
++                      Assert.IsFalse (attr.IsValid ("stuff"), "#A2-5");
++
++                      AnotherEnum val = AnotherEnum.Six;
++                      Assert.IsFalse (attr.IsValid (val), "#A2-6");
++
++                      Assert.IsTrue (attr.IsValid (String.Empty), "#A2-7");
++                      Assert.IsTrue (attr.IsValid ("Three"), "#A2-8");
++                      Assert.IsFalse (attr.IsValid ("Four"), "#A2-9");
++                      Assert.IsFalse (attr.IsValid (true), "#A2-10");
++                      Assert.IsFalse (attr.IsValid (' '), "#A2-11");
++                      Assert.IsFalse (attr.IsValid (0.12F), "#A2-12");
++                      Assert.IsTrue (attr.IsValid ((short) 1), "#A2-13");
++                      Assert.IsFalse (attr.IsValid (12.3M), "#A2-14");
++                      Assert.IsFalse (attr.IsValid (12.3D), "#A2-15");
++                      Assert.IsTrue (attr.IsValid ((long) 1), "#A2-16");
++
++                      attr = new EnumDataTypeAttribute (typeof (AnotherEnum));
++                      Assert.IsTrue (attr.IsValid (null), "#A3-1");
++                      Assert.IsTrue (attr.IsValid (4), "#A3-2");
++                      Assert.IsFalse (attr.IsValid (0), "#A3-3");
++                      Assert.IsTrue (attr.IsValid (AnotherEnum.Five), "#A3-4");
++                      Assert.IsFalse (attr.IsValid (TestEnum.One), "#A3-5");
++                      Assert.IsFalse (attr.IsValid ("stuff"), "#A3-5");
++
++                      val = AnotherEnum.Four;
++                      Assert.IsTrue (attr.IsValid (val), "#A3-6");
++
++                      Assert.IsTrue (attr.IsValid (String.Empty), "#A3-7");
++                      Assert.IsTrue (attr.IsValid ("Four"), "#A3-8");
++                      Assert.IsFalse (attr.IsValid ("Three"), "#A3-9");
++                      Assert.IsTrue (attr.IsValid (12), "#A3-10");
++                      Assert.IsTrue (attr.IsValid ("Five, Six"), "#A3-11");
++                      Assert.IsFalse (attr.IsValid (true), "#A3-12");
++                      Assert.IsFalse (attr.IsValid (' '), "#A3-13");
++                      Assert.IsFalse (attr.IsValid (0.12), "#A3-14");
++              }
++      }
++
++      enum TestEnum
++      {
++              One = 1,
++              Two,
++              Three
++      }
++
++      [Flags]
++      enum AnotherEnum
++      {
++              Four = 4,
++              Five = 8,
++              Six = 16
++      }
++#endif
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7930002ab0ffafabee486f89f8eecb4b551e6492
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++//
++// RequiredAttributeTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++      [TestFixture]
++      public class RequiredAttributeTest
++      {
++              [Test]
++              public void IsRequired ()
++              {
++                      var attr = new RequiredAttribute ();
++                      Assert.IsFalse (attr.IsValid (null), "#A1");
++                      Assert.IsFalse (attr.IsValid (String.Empty), "#A2");
++                      Assert.IsTrue (attr.IsValid ("string"), "#A3");
++                      Assert.IsTrue (attr.IsValid (1), "#A4");
++#if NET_4_0
++                      attr.AllowEmptyStrings = true;
++                      Assert.IsTrue (attr.IsValid (String.Empty), "#A5");
++#endif
++              }
++#if NET_4_0
++              [Test]
++              public void AllowEmptyStrings ()
++              {
++                      var attr = new RequiredAttribute ();
++
++                      Assert.IsFalse (attr.AllowEmptyStrings, "#A1");
++                      attr.AllowEmptyStrings = true;
++                      Assert.IsTrue (attr.AllowEmptyStrings, "#A2");
++              }
++#endif
++      }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..edafd4b74354c47fddbe26eb61fe28745bcedb72
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,657 @@@
++//
++// ValidationAttributeTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++      [TestFixture]
++      public class ValidationAttributeTest
++      {
++              const string TEST_ERROR_MESSAGE = "Test Error Message";
++              string ErrorMessageAccessor ()
++              {
++                      return TEST_ERROR_MESSAGE;
++              }
++
++              [Test]
++              public void Constructor ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNull (attr.ErrorMessage, "#A1");
++                      Assert.IsNull (attr.ErrorMessageResourceName, "#A2");
++                      Assert.IsNull (attr.ErrorMessageResourceType, "#A3");
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#A4");
++              }
++
++              [Test]
++              public void Constructor_Func ()
++              {
++                      var attr = new ValidateFooAttribute (ErrorMessageAccessor);
++
++                      Assert.IsNull (attr.ErrorMessage, "#A1");
++                      Assert.IsNull (attr.ErrorMessageResourceName, "#A2");
++                      Assert.IsNull (attr.ErrorMessageResourceType, "#A3");
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#A4");
++                      Assert.AreEqual (TEST_ERROR_MESSAGE, attr.GetErrorMessageString (), "#A4");
++              }
++
++              [Test]
++              public void Constructor_String ()
++              {
++                      var attr = new ValidateFooAttribute ("Another Test Error Message");
++
++                      Assert.IsNull (attr.ErrorMessage, "#A1");
++                      Assert.IsNull (attr.ErrorMessageResourceName, "#A2");
++                      Assert.IsNull (attr.ErrorMessageResourceType, "#A3");
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#A4");
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#A4-1");
++                      Assert.AreEqual ("Another Test Error Message", attr.GetErrorMessageString (), "#A4-2");
++              }
++
++              [Test]
++              public void ErrorMessage ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNull (attr.ErrorMessage, "#A1");
++
++                      attr.ErrorMessage = "Test";
++                      Assert.AreEqual ("Test", attr.ErrorMessage, "#A2");
++#if NET_4_0
++                      attr.ErrorMessage = String.Empty;
++                      Assert.AreEqual (String.Empty, attr.ErrorMessage, "#A3");
++
++                      attr.ErrorMessage = null;
++                      Assert.IsNull (attr.ErrorMessage, "#A4");
++#else
++                      try {
++                              attr.ErrorMessage = String.Empty;
++                              Assert.Fail ("#A3");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ("Test");
++                      try {
++                              attr.ErrorMessage = null;
++                              Assert.Fail ("#A4");
++                      } catch (ArgumentException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ("Test");
++                      try {
++                              attr.ErrorMessage = String.Empty;
++                              Assert.Fail ("#A4");
++                      } catch (ArgumentException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty1";
++
++                      try {
++                              attr.ErrorMessage = "Test Message";
++                              Assert.Fail ("#E1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#endif
++                      
++              }
++
++              [Test]
++              public void ErrorMessageResourceName ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNull (attr.ErrorMessageResourceName, "#A1");
++
++                      attr.ErrorMessageResourceName = "Test";
++                      Assert.IsNotNull (attr.ErrorMessageResourceName, "#A2-1");
++                      Assert.AreEqual ("Test", attr.ErrorMessageResourceName, "#A2-2");
++#if NET_4_0
++                      attr.ErrorMessageResourceName = String.Empty;
++                      Assert.IsNotNull (attr.ErrorMessageResourceName, "#A3-1");
++                      Assert.AreEqual (String.Empty, attr.ErrorMessageResourceName, "#A3-2");
++
++                      attr.ErrorMessageResourceName = null;
++                      Assert.IsNull (attr.ErrorMessageResourceName, "#A3-1");
++#else
++                      try {
++                              attr.ErrorMessageResourceName = String.Empty;
++                              Assert.Fail ("#A3-1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ("Test");
++                      try {
++                              attr.ErrorMessageResourceName = String.Empty;
++                              Assert.Fail ("#A3-2");
++                      } catch (ArgumentException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ("Test");
++                      try {
++                              attr.ErrorMessageResourceName = null;
++                              Assert.Fail ("#A3-3");
++                      } catch (ArgumentException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++
++                      try {
++                              attr.ErrorMessageResourceName = "NoSuchProperty";
++                              Assert.Fail ("#A3-4");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#endif
++              }
++
++              [Test]
++              public void ErrorMessageResourceType ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNull (attr.ErrorMessageResourceType, "#A1");
++
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.ErrorMessageResourceType, "#A2-1");
++                      Assert.AreEqual (typeof (FooErrorMessageProvider), attr.ErrorMessageResourceType, "#A2-2");
++#if !NET_4_0
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "NoSuchProperty";
++                      
++                      try {
++                              attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                              Assert.Fail ("#A3");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#endif
++              }
++
++              [Test]
++              public void ErrorMessageString ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#A1-1");
++                      Assert.IsTrue (attr.GetErrorMessageString ().Length > 0, "#A1-2");
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "TestResource";
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A2-1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#if NET_4_0
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = String.Empty;
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A2-1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      attr.ErrorMessageResourceName = null;
++                      
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A3-1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = String.Empty;
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              string s = attr.GetErrorMessageString ();
++                              Assert.Fail ("#A3-2");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "NoSuchProperty";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A4");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty2";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A5");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty3";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A5");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty4";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A6");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty5";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#A7");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorField1";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#B1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorField2";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#B2");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#endif
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty1";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#C1-1");
++                      Assert.AreEqual ("Error Message 1", attr.GetErrorMessageString (), "#C1-2");
++
++                      attr = new ValidateFooAttribute (ErrorMessageAccessor);
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#D1-1");
++                      Assert.AreEqual (TEST_ERROR_MESSAGE, attr.GetErrorMessageString (), "#D1-2");
++
++                      attr = new ValidateFooAttribute ();
++                      attr.ErrorMessageResourceName = "ErrorProperty1";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.GetErrorMessageString (), "#D1-3");
++                      Assert.AreEqual ("Error Message 1", attr.GetErrorMessageString (), "#D1-4");
++#if NET_4_0
++                      attr.ErrorMessage = "Test Message";
++                      try {
++                              attr.GetErrorMessageString ();
++                              Assert.Fail ("#E1");
++                      } catch (InvalidOperationException) {
++                              // success
++                      }
++#endif
++              }
++
++              [Test]
++              public void FormatErrorMessage ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      Assert.IsNotNull (attr.FormatErrorMessage ("SomeField"), "#A1-1");
++                      Assert.AreEqual ("The field SomeField is invalid.", attr.FormatErrorMessage ("SomeField"), "#A1-2");
++
++                      attr.ErrorMessage = "Test: {0}";
++                      Assert.IsNotNull (attr.FormatErrorMessage ("SomeField"), "#A2-1");
++                      Assert.AreEqual ("Test: SomeField", attr.FormatErrorMessage ("SomeField"), "#A2-2");
++#if !NET_4_0
++                      attr = new ValidateFooAttribute ();
++#else
++                      attr.ErrorMessage = null;
++#endif
++                      attr.ErrorMessageResourceName = "ErrorProperty1";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.FormatErrorMessage ("SomeField"), "#B1-1");
++                      Assert.AreEqual ("Error Message 1", attr.FormatErrorMessage ("SomeField"), "#B1-2");
++#if !NET_4_0
++                      attr = new ValidateFooAttribute ();
++#endif
++                      attr.ErrorMessageResourceName = "ErrorProperty6";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.FormatErrorMessage ("SomeField"), "#B2-1");
++                      Assert.AreEqual ("Error Message 6: SomeField", attr.FormatErrorMessage ("SomeField"), "#B2-2");
++#if !NET_4_0
++                      attr = new ValidateFooAttribute ();
++#endif
++                      attr.ErrorMessageResourceName = "ErrorProperty6";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      Assert.IsNotNull (attr.FormatErrorMessage ("SomeField"), "#B3-1");
++                      Assert.AreEqual ("Error Message 6: ", attr.FormatErrorMessage (null), "#B3-2");
++              }
++#if NET_4_0
++              [Test]
++              public void GetValidationResult ()
++              {
++                      var attr = new ValidateBarAttribute ();
++
++                      try {
++                              attr.GetValidationResult ("stuff", null);
++                              Assert.Fail ("#A1");
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      var vc = new ValidationContext ("stuff", null, null);
++                      vc.DisplayName = "MyStuff";
++                      var vr = attr.GetValidationResult ("stuff", vc);
++                      Assert.IsNull (vr, "#A2");
++
++                      vr = attr.GetValidationResult (null, vc);
++                      Assert.IsNotNull(vr, "#A3-1");
++                      Assert.IsNotNull (vr.ErrorMessage, "#A3-2");
++                      Assert.AreEqual ("The field MyStuff is invalid.", vr.ErrorMessage, "#A3-3");
++
++                      attr.ErrorMessage = "My Error Message: {0}";
++                      vr = attr.GetValidationResult (null, vc);
++                      Assert.IsNotNull (vr, "#A4-1");
++                      Assert.IsNotNull (vr.ErrorMessage, "#A4-2");
++                      Assert.AreEqual ("My Error Message: MyStuff", vr.ErrorMessage, "#A4-3");
++
++                      attr.ErrorMessage = null;
++                      attr.ErrorMessageResourceName = "ErrorProperty1";
++                      attr.ErrorMessageResourceType = typeof (FooErrorMessageProvider);
++                      vr = attr.GetValidationResult (null, vc);
++                      Assert.IsNotNull (vr, "#A5-1");
++                      Assert.IsNotNull (vr.ErrorMessage, "#A5-2");
++                      Assert.AreEqual ("Error Message 1", vr.ErrorMessage, "#A5-3");
++
++                      attr.ErrorMessage = "My Error Message: {0}";
++                      attr.ErrorMessageResourceName = null;
++                      attr.ErrorMessageResourceType = null;
++                      vr = attr.GetValidationResult (null, vc);
++                      Assert.IsNotNull (vr, "#A6-1");
++                      Assert.IsNotNull (vr.MemberNames, "#A6-2");
++                      int count = 0;
++                      foreach (string s in vr.MemberNames)
++                              count++;
++                      Assert.AreEqual (0, count, "#A6-3");
++                      Assert.AreEqual ("My Error Message: MyStuff", vr.ErrorMessage, "#A6-4");
++
++                      attr.ValidationResultErrorMessage = "My VR message";
++                      vr = attr.GetValidationResult (null, vc);
++                      Assert.IsNotNull (vr, "#A7-1");
++                      Assert.AreEqual ("My VR message", vr.ErrorMessage, "#A7-2");
++              }
++
++              [Test]
++              public void IsValid_Object ()
++              {
++                      var attr = new ValidateFooAttribute ();
++
++                      try {
++                              attr.IsValid (null);
++                              Assert.Fail ("#A1-1");
++                      } catch (NotImplementedException) {
++                              // success
++                      }
++
++                      try {
++                              attr.IsValid ("stuff");
++                              Assert.Fail ("#A1-2");
++                      } catch (NotImplementedException) {
++                              // success
++                      }
++              }
++
++              [Test]
++              public void IsValid_Object_ValidationContext ()
++              {
++                      var attr = new ValidateBarAttribute ();
++
++                      try {
++                              // ...
++                              attr.CallIsValid (null, null);
++                              Assert.Fail ("#A1");
++                      } catch (NullReferenceException) {
++                              // success
++                      }
++
++                      var vc = new ValidationContext ("stuff", null, null);
++                      var vr = attr.CallIsValid (null, vc);
++                      Assert.IsNotNull (vr, "#A2-1");
++                      Assert.IsNotNull (vr.ErrorMessage, "#A2-2");
++                      Assert.AreEqual ("The field String is invalid.", vr.ErrorMessage, "#A2-3");
++                      Assert.IsNotNull (vr.MemberNames, "#A2-4"); 
++                      
++                      int count = 0;
++                      foreach (string s in vr.MemberNames)
++                              count++;
++                      Assert.AreEqual (0, count, "#A2-5");
++
++                      vc.MemberName = "SomeMember";
++                      vr = attr.CallIsValid (null, vc);
++                      Assert.IsNotNull (vr, "#A3-1");
++                      Assert.IsNotNull (vr.ErrorMessage, "#A3-2");
++                      Assert.AreEqual ("The field String is invalid.", vr.ErrorMessage, "#A3-3");
++                      Assert.IsNotNull (vr.MemberNames, "#A3-4");
++
++                      var list = new List <string> ();
++                      foreach (string s in vr.MemberNames)
++                              list.Add (s);
++                      Assert.AreEqual (1, list.Count, "#A3-5");
++                      Assert.AreEqual ("SomeMember", list [0], "#A3-6");
++              }
++
++              [Test]
++              public void Validate_Object_ValidationContext ()
++              {
++                      var attr = new ValidateBazAttribute ();
++
++                      try {
++                              attr.Validate ("stuff", (ValidationContext) null);
++                              Assert.Fail ("#A1");
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      var vc = new ValidationContext ("stuff", null, null);
++                      try {
++                              attr.Validate (null, vc);
++                              Assert.Fail ("#A2-1");
++                      } catch (ValidationException) {
++                              // success
++                      }
++                      Assert.AreEqual (3, attr.Calls.Count, "#A2-1");
++                      Assert.AreEqual ("ValidationResult IsValid (object value, ValidationContext validationContext)", attr.Calls [0], "#A2-2");
++                      Assert.AreEqual ("bool IsValid (object value)", attr.Calls [1], "#A2-3");
++                      Assert.AreEqual ("string FormatErrorMessage (string name)", attr.Calls [2], "#A2-4");
++              }
++#endif
++              [Test]
++              public void Validate_Object_String ()
++              {
++                      var attr = new ValidateBazAttribute ();
++
++                      try {
++                              attr.Validate (null, (string) null);
++                              Assert.Fail ("#A2");
++                      } catch (ValidationException) {
++                              // success
++                      }
++
++                      Assert.AreEqual (2, attr.Calls.Count, "#A2-1");
++                      Assert.AreEqual ("bool IsValid (object value)", attr.Calls [0], "#A2-2");
++                      Assert.AreEqual ("string FormatErrorMessage (string name)", attr.Calls [1], "#A2-3");
++              }
++      }
++
++      class ValidateFooAttribute : ValidationAttribute
++      {
++              public ValidateFooAttribute ()
++                      : base ()
++              { }
++
++              public ValidateFooAttribute (Func<string> errorMessageAccessor)
++                      : base (errorMessageAccessor)
++              { }
++
++              public ValidateFooAttribute (string errorMessage)
++                      : base (errorMessage)
++              { }
++
++              public string GetErrorMessageString ()
++              {
++                      return ErrorMessageString;
++              }
++#if !NET_4_0
++              public override bool IsValid (object value)
++              {
++                      return value != null;
++              }
++#endif
++      }
++
++      class ValidateBarAttribute : ValidateFooAttribute
++      {
++              public string ValidationResultErrorMessage
++              {
++                      get;
++                      set;
++              }
++
++              public override bool IsValid (object value)
++              {
++                      return value != null;
++              }
++#if NET_4_0
++              protected override ValidationResult IsValid (object value, ValidationContext validationContext)
++              {
++                      if (!IsValid (value))
++                              return new ValidationResult (ValidationResultErrorMessage);
++                      return null;
++              }
++
++              public ValidationResult CallIsValid (object value, ValidationContext validationContext)
++              {
++                      return base.IsValid (value, validationContext);
++              }
++#endif
++      }
++
++      class ValidateBazAttribute : ValidateBarAttribute
++      {
++              public readonly List<string> Calls = new List<string> ();
++
++              public override bool IsValid (object value)
++              {
++                      Calls.Add ("bool IsValid (object value)");
++                      return base.IsValid (value);
++              }
++#if NET_4_0
++              protected override ValidationResult IsValid (object value, ValidationContext validationContext)
++              {
++                      Calls.Add ("ValidationResult IsValid (object value, ValidationContext validationContext)");
++                      return base.IsValid (value, validationContext);
++              }
++#endif
++              public override string FormatErrorMessage (string name)
++              {
++                      Calls.Add ("string FormatErrorMessage (string name)");
++                      return base.FormatErrorMessage (name);
++              }
++      }
++
++      class FooErrorMessageProvider
++      {
++              public static string ErrorProperty1
++              {
++                      get { return "Error Message 1"; }
++              }
++
++              public static int ErrorProperty2
++              {
++                      get { return 1; }
++              }
++
++              public string ErrorProperty3
++              {
++                      get { return "Error Message 2"; }
++              }
++
++              protected static string ErrorProperty4
++              {
++                      get { return "Error Message 3"; }
++              }
++
++              public static string ErrorProperty5
++              {
++                      set { }
++              }
++
++              public static string ErrorProperty6
++              {
++                      get { return "Error Message 6: {0}"; }
++              }
++
++              public string ErrorField1 = "Error Message 4";
++              public static string ErrorField2 = "Error Message 5";
++      }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2a73735bf89e201c67a9310d5ed350259ef7b2f4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,242 @@@
++//
++// ValidationContextTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.ComponentModel.Design;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++#if NET_4_0
++      [TestFixture]
++      public class ValidationContextTest
++      {
++              [Test]
++              public void Constructor ()
++              {
++                      ValidationContext vc;
++                      try {
++                              vc = new ValidationContext (null, new FakeServiceProvider (), new Dictionary <object, object> ());
++                              Assert.Fail ("#A1-1");
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      try {
++                              vc = new ValidationContext ("stuff", null, new Dictionary<object, object> ());
++                      } catch {
++                              Assert.Fail ("#A1-2");
++                      }
++
++                      try {
++                              vc = new ValidationContext ("stuff", new FakeServiceProvider (), null);
++                      } catch {
++                              Assert.Fail ("#A1-3");
++                      }
++
++                      object o = "stuff";
++                      vc = new ValidationContext (o, null, null);
++                      Assert.AreSame (o, vc.ObjectInstance, "#A2-1");
++                      Assert.AreEqual (o.GetType ().Name, vc.DisplayName, "#A2-2");
++                      Assert.AreEqual (o.GetType (), vc.ObjectType, "#A2-3");
++
++                      o = 12;
++                      var dict = new Dictionary<object, object> () {
++                              {"stuff", 1}
++                      };
++                      vc = new ValidationContext (o, null, dict);
++                      Assert.IsNotNull (vc.Items, "#A3-1");
++                      Assert.AreEqual (1, vc.Items.Count, "#A3-2");
++                      Assert.AreNotSame (dict, vc.Items, "#A3-3");
++                      Assert.AreEqual (typeof (Dictionary <object, object>), vc.Items.GetType (), "#A3-4");
++                      Assert.AreEqual (1, vc.Items ["stuff"], "#A3-5");
++                      Assert.AreEqual (o.GetType ().Name, vc.DisplayName, "#A3-6");
++                      Assert.AreEqual (o.GetType (), vc.ObjectType, "#A3-7");
++                      Assert.AreEqual (null, vc.MemberName, "#A3-8");
++                      Assert.IsNotNull (vc.ServiceContainer, "#A3-9");
++                      Assert.AreEqual ("System.ComponentModel.DataAnnotations.ValidationContext+ValidationContextServiceContainer", vc.ServiceContainer.GetType ().FullName, "#A3-10");
++              }
++
++              [Test]
++              public void ServiceContainer ()
++              {
++                      var vc = new ValidationContext ("stuff", null, null);
++
++                      // Test the default container
++                      IServiceContainer container = vc.ServiceContainer;
++                      Assert.AreEqual ("System.ComponentModel.DataAnnotations.ValidationContext+ValidationContextServiceContainer", container.GetType ().FullName, "#A1");
++
++                      var fs1 = new FakeService1 ();
++                      container.AddService (typeof (FakeService1), fs1);
++                      container.AddService (typeof (FakeService2), CreateFakeService);
++
++                      var fs3 = new FakeService3 ();
++                      container.AddService (typeof (FakeService3), fs3, false);
++                      container.AddService (typeof (FakeService4), CreateFakeService, false);
++
++                      try {
++                              container.AddService (null, CreateFakeService);
++                              Assert.Fail ("#A2-1");
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      try {
++                              container.AddService (typeof (string), null);
++                      } catch {
++                              Assert.Fail ("#A2-2");
++                      }
++
++                      try {
++                              container.AddService (typeof (FakeService2), CreateFakeService);
++                              Assert.Fail ("#A2-3");
++                      } catch (ArgumentException) {
++                              // success
++                      }
++
++                      try {
++                              container.RemoveService (GetType ());
++                      } catch {
++                              Assert.Fail ("#A2-4");
++                      }
++
++                      try {
++                              container.RemoveService (null);
++                              Assert.Fail ("#A2-5");
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      try {
++                              container.GetService (null);
++                      } catch (ArgumentNullException) {
++                              // success
++                      }
++
++                      object o = container.GetService (typeof (FakeService1));
++                      Assert.IsNotNull (o, "#B1-1");
++                      Assert.AreSame (fs1, o, "#B1-2");
++
++                      o = container.GetService (typeof (FakeService2));
++                      Assert.IsNotNull (o, "#B2-1");
++                      Assert.AreEqual (typeof (FakeService2), o.GetType (), "#B2-2");
++
++                      o = container.GetService (typeof (FakeService3));
++                      Assert.IsNotNull (o, "#B3-1");
++                      Assert.AreSame (fs3, o, "#B3-2");
++
++                      o = container.GetService (typeof (FakeService4));
++                      Assert.IsNotNull (o, "#B4-1");
++                      Assert.AreEqual (typeof (FakeService4), o.GetType (), "#B4-2");
++
++                      o = container.GetService (GetType ());
++                      Assert.IsNull (o, "#B5");
++
++                      // Test custom container
++                      var fsc = new FakeServiceContainer ();
++                      vc = new ValidationContext ("stuff", fsc, null);
++                      container = vc.ServiceContainer;
++                      Assert.IsNotNull (container, "#B6-1");
++
++                      // LAMESPEC: MSDN says vc.ServiceContainer should be initialized with the passed container if it implements 
++                      // the IServiceContainer interface - not the case, though.
++                      Assert.AreNotSame (fsc, container, "#B6-2");
++              }
++
++              object CreateFakeService (IServiceContainer container, Type serviceType)
++              {
++                      if (serviceType == typeof (FakeService2))
++                              return Activator.CreateInstance (serviceType);
++
++                      if (serviceType == typeof (FakeService4))
++                              return Activator.CreateInstance (serviceType);
++
++                      return null;
++              }
++      }
++
++      class FakeService1
++      { }
++
++      class FakeService2
++      { }
++
++      class FakeService3
++      { }
++
++      class FakeService4
++      { }
++
++      class FakeServiceProvider : IServiceProvider
++      {
++              #region IServiceProvider Members
++
++              public object GetService (Type serviceType)
++              {
++                      return Activator.CreateInstance (serviceType);
++              }
++
++              #endregion
++      }
++
++      class FakeServiceContainer : IServiceContainer
++      {
++              public void AddService (Type serviceType, ServiceCreatorCallback callback, bool promote)
++              {
++              }
++
++              public void AddService (Type serviceType, ServiceCreatorCallback callback)
++              {
++              }
++
++              public void AddService (Type serviceType, object serviceInstance, bool promote)
++              {
++              }
++
++              public void AddService (Type serviceType, object serviceInstance)
++              {
++              }
++
++              public void RemoveService (Type serviceType, bool promote)
++              {
++              }
++
++              public void RemoveService (Type serviceType)
++              {
++              }
++
++              public object GetService (Type serviceType)
++              {
++                      return null;
++              }
++      }
++#endif
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..05ddfa9f827be022b4fa7c6efec58476653cd8ac
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,97 @@@
++//
++// ValidationResultTest.cs
++//
++// Authors:
++//      Marek Habersack <mhabersack@novell.com>
++//
++// Copyright (C) 2010 Novell, Inc. (http://novell.com/)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++using System;
++using System.Collections.Generic;
++using System.ComponentModel.DataAnnotations;
++using System.ComponentModel.Design;
++using System.Text;
++
++using NUnit.Framework;
++
++namespace MonoTests.System.ComponentModel.DataAnnotations
++{
++#if NET_4_0
++      [TestFixture]
++      public class ValidationResultTest
++      {
++              [Test]
++              public void Constructor_String ()
++              {
++                      var vr = new ValidationResult ("message");
++
++                      Assert.AreEqual ("message", vr.ErrorMessage, "#A1");
++                      Assert.IsNotNull (vr.MemberNames, "#A2-1");
++
++                      int count = 0;
++                      foreach (string m in vr.MemberNames)
++                              count++;
++                      Assert.AreEqual (0, count, "#A2-2");
++
++                      vr = new ValidationResult (null);
++                      Assert.AreEqual (null, vr.ErrorMessage, "#A3");
++              }
++
++              [Test]
++              public void Constructor_String_IEnumerable ()
++              {
++                      var vr = new ValidationResult ("message", null);
++
++                      Assert.AreEqual ("message", vr.ErrorMessage, "#A1");
++                      Assert.IsNotNull (vr.MemberNames, "#A2-1");
++
++                      int count = 0;
++                      foreach (string m in vr.MemberNames)
++                              count++;
++                      Assert.AreEqual (0, count, "#A2-2");
++
++                      var names = new string[] { "one", "two" };
++                      vr = new ValidationResult ("message", names);
++
++                      Assert.AreEqual ("message", vr.ErrorMessage, "#A1");
++                      Assert.IsNotNull (vr.MemberNames, "#A2-1");
++                      Assert.AreSame (names, vr.MemberNames, "#A2-2");
++
++                      count = 0;
++                      foreach (string m in vr.MemberNames)
++                              count++;
++                      Assert.AreEqual (2, count, "#A2-3");
++
++                      vr = new ValidationResult (null, null);
++                      Assert.AreEqual (null, vr.ErrorMessage, "#A3");
++              }
++
++              [Test]
++              public void Success ()
++              {
++                      ValidationResult success = ValidationResult.Success;
++
++                      Assert.IsNull (success, "#A1");
++              }
++      }
++#endif
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ddf3de9e983dfa9a233f2bf3ec2b09dd774c5dd8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#include System.ComponentModel.DataAnnotations.dll.sources
++
++System.ComponentModel.DataAnnotations/ValidationContext.cs
++System.ComponentModel.DataAnnotations/ValidationResult.cs