diff options
author | Steve Pfister <steveisok@users.noreply.github.com> | 2020-03-03 23:26:46 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-03 23:26:46 +0300 |
commit | c483eaf070b9eeb147e6d396d23639f0d370d09e (patch) | |
tree | 939b5f34a256897537c602b21a5ebb12ba275857 /mcs | |
parent | ede05b997bf7a98ebd712a5c6731c5ad2b9153b4 (diff) |
Changed Max and MinLengthAttribute validation (#19084)
It should now validate against ICollection or any other type that has a Count property for that matter.
We're still relying on the reference source implementation because corefx strips some types out.
Fixes https://github.com/mono/mono/issues/19022
Diffstat (limited to 'mcs')
8 files changed, 125 insertions, 16 deletions
diff --git a/mcs/class/System.ComponentModel.DataAnnotations/ReferenceSources/SR.cs b/mcs/class/System.ComponentModel.DataAnnotations/ReferenceSources/SR.cs index 35ee14f949f..5cda102a1cd 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/ReferenceSources/SR.cs +++ b/mcs/class/System.ComponentModel.DataAnnotations/ReferenceSources/SR.cs @@ -63,5 +63,6 @@ partial class DataAnnotationsResources public const string MinLengthAttribute_InvalidMinLength = "MinLengthAttribute must have a Length value that is zero or greater."; public const string MinLengthAttribute_ValidationError = "The field {0} must be a string or array type with a minimum length of '{1}'."; public const string ArgumentIsNullOrWhitespace = "The argument '{0}' cannot be null, empty or contain only white space."; + public const string LengthAttribute_InvalidValueType = "The field of type {0} must be a string, array or ICollection type."; } }
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.csproj b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.csproj index 8257ab78c78..4998156ab08 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.csproj +++ b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.csproj @@ -168,6 +168,7 @@ <Compile Include="..\referencesource\System.ComponentModel.DataAnnotations\DataAnnotations\Validator.cs" /> <Compile Include="Assembly\AssemblyInfo.cs" /> <Compile Include="ReferenceSources\SR.cs" /> + <Compile Include="corefx\CountPropertyHelper.cs" /> <ProjectReference Include="$(SolutionDir)\msvc\scripts\genconsts.csproj"> <Name>genconsts</Name> <Project>{702AE2C0-71DD-4112-9A06-E4FABCA59986}</Project> diff --git a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.dll.sources b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.dll.sources index c41ac4477fe..fc1acff6a10 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.dll.sources +++ b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.dll.sources @@ -1,5 +1,6 @@ ../../build/common/Consts.cs Assembly/AssemblyInfo.cs +corefx/CountPropertyHelper.cs ../referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/AppSettings.cs ../referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/AssociatedMetadataTypeTypeDescriptionProvider.cs ../referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs diff --git a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations_test.dll.sources b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations_test.dll.sources index 9454422b250..663f8288e4c 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations_test.dll.sources +++ b/mcs/class/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations_test.dll.sources @@ -18,3 +18,4 @@ System.ComponentModel.DataAnnotations/PhoneAttributeTest.cs System.ComponentModel.DataAnnotations/CreditCardAttributeTest.cs System.ComponentModel.DataAnnotations/FileExtensionsAttributeTest.cs System.ComponentModel.DataAnnotations/CompareAttributeTest.cs +System.ComponentModel.DataAnnotations/MaxMinLengthAttributeTest.cs diff --git a/mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/MaxMinLengthAttributeTest.cs b/mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/MaxMinLengthAttributeTest.cs new file mode 100644 index 00000000000..e664f068273 --- /dev/null +++ b/mcs/class/System.ComponentModel.DataAnnotations/Test/System.ComponentModel.DataAnnotations/MaxMinLengthAttributeTest.cs @@ -0,0 +1,77 @@ +// +// MaxMinLengthAttributeTest.cs +// +// 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 MaxMinLengthAttributeTest + { + [Test] + public void CheckMinLength () { + var attr = new MinLengthAttribute (2); + + Assert.IsTrue (attr.IsValid (null), "#A1"); + Assert.IsFalse (attr.IsValid ("1"), "#A2"); + + Assert.IsTrue (attr.IsValid ("12"), "#A3"); + Assert.IsTrue (attr.IsValid ("123"), "#A4"); + + Assert.IsFalse (attr.IsValid (BuildQuickList (1)), "#A5"); + Assert.IsTrue (attr.IsValid (BuildQuickList (2)), "#A6"); + Assert.IsTrue (attr.IsValid (BuildQuickList (3)), "#A7"); + } + + [Test] + public void CheckMaxLength () { + var attr = new MaxLengthAttribute (2); + + Assert.IsTrue (attr.IsValid (null), "#A1"); + Assert.IsTrue (attr.IsValid ("1"), "#A2"); + Assert.IsTrue (attr.IsValid ("12"), "#A3"); + + Assert.IsFalse (attr.IsValid ("123"), "#A4"); + + Assert.IsTrue (attr.IsValid (BuildQuickList (1)), "#A5"); + Assert.IsTrue (attr.IsValid (BuildQuickList (2)), "#A6"); + Assert.IsFalse (attr.IsValid (BuildQuickList (3)), "#A7"); + } + + List<string> BuildQuickList (int count) { + var items = new List<string> (); + + for (int i = 0; i < count; i++) { + items.Add(i.ToString()); + } + + return items; + } + } +} diff --git a/mcs/class/System.ComponentModel.DataAnnotations/corefx/CountPropertyHelper.cs b/mcs/class/System.ComponentModel.DataAnnotations/corefx/CountPropertyHelper.cs new file mode 100644 index 00000000000..f91a97ee27f --- /dev/null +++ b/mcs/class/System.ComponentModel.DataAnnotations/corefx/CountPropertyHelper.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Diagnostics; +using System.Reflection; + +internal static class CountPropertyHelper +{ + public static bool TryGetCount(object value, out int count) + { + Debug.Assert(value != null); + + if (value is ICollection collection) + { + count = collection.Count; + return true; + } + + PropertyInfo property = value.GetType().GetRuntimeProperty("Count"); + if (property != null && property.CanRead && property.PropertyType == typeof(int)) + { + count = (int)property.GetValue(value); + return true; + } + + count = -1; + return false; + } +}
\ No newline at end of file diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MaxLengthAttribute.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MaxLengthAttribute.cs index 8c983c737e4..6d3e61611a0 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MaxLengthAttribute.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MaxLengthAttribute.cs @@ -60,15 +60,15 @@ namespace System.ComponentModel.DataAnnotations { if (value == null) { return true; } + + if (value is string str) { + length = str.Length; + } + else if (CountPropertyHelper.TryGetCount(value, out var count)) { + length = count; + } else { - var str = value as string; - if (str != null) { - length = str.Length; - } - else { - // We expect a cast exception if a non-{string|array} property was passed in. - length = ((Array)value).Length; - } + throw new InvalidCastException(String.Format(DataAnnotationsResources.LengthAttribute_InvalidValueType, value.GetType())); } return MaxAllowableLength == Length || length <= Length; diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MinLengthAttribute.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MinLengthAttribute.cs index ca80e8e1e44..1b1204b67a6 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MinLengthAttribute.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/MinLengthAttribute.cs @@ -45,15 +45,16 @@ namespace System.ComponentModel.DataAnnotations { if (value == null) { return true; } + + if (value is string str) { + length = str.Length; + } + else if (CountPropertyHelper.TryGetCount(value, out var count)) + { + length = count; + } else { - var str = value as string; - if (str != null) { - length = str.Length; - } - else { - // We expect a cast exception if a non-{string|array} property was passed in. - length = ((Array)value).Length; - } + throw new InvalidCastException(String.Format(DataAnnotationsResources.LengthAttribute_InvalidValueType, value.GetType())); } return length >= Length; |