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
--- /dev/null
--- /dev/null
++//
++// 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
++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
--- /dev/null
--- /dev/null
++//
++// 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
--- /dev/null
--- /dev/null
++//
++// 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
--- /dev/null
--- /dev/null
++//
++// 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
--- /dev/null
--- /dev/null
++//
++// 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
--- /dev/null
--- /dev/null
++//
++// 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
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
--// Copyright (C) 2008 Novell Inc. http://novell.com
++// Copyright (C) 2008-2010 Novell Inc. http://novell.com
//
//
[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;
}
}
}
//
--// 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);
}
}
}
--- /dev/null
--- /dev/null
++//
++// 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;
++ }
++ }
++ }
++}
}
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; }
--- /dev/null
--- /dev/null
++//
++// 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[] {};
++ }
++ }
++}
--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
--- /dev/null
--- /dev/null
++//
++// 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
++}
--- /dev/null
--- /dev/null
++//
++// 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
++}
--- /dev/null
--- /dev/null
++//
++// 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
++ }
++}
--- /dev/null
--- /dev/null
++//
++// 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";
++ }
++}
--- /dev/null
--- /dev/null
++//
++// 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
++}
--- /dev/null
--- /dev/null
++//
++// 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
++}
--- /dev/null
--- /dev/null
++#include System.ComponentModel.DataAnnotations.dll.sources
++
++System.ComponentModel.DataAnnotations/ValidationContext.cs
++System.ComponentModel.DataAnnotations/ValidationResult.cs