1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 using System.Collections.Generic; 4 using System.ComponentModel.DataAnnotations; 5 using Moq; 6 using Xunit; 7 using Assert = Microsoft.TestCommon.AssertEx; 8 9 namespace System.Web.Mvc.Test 10 { 11 public class CompareAttributeTest 12 { 13 [Fact] GuardClauses()14 public void GuardClauses() 15 { 16 //Act & Assert 17 Assert.ThrowsArgumentNull( 18 delegate { new CompareAttribute(null); }, "otherProperty"); 19 20 Assert.ThrowsArgumentNullOrEmpty( 21 delegate { CompareAttribute.FormatPropertyForClientValidation(null); }, "property"); 22 } 23 24 [Fact] FormatPropertyForClientValidationPrependsStarDot()25 public void FormatPropertyForClientValidationPrependsStarDot() 26 { 27 string prepended = CompareAttribute.FormatPropertyForClientValidation("test"); 28 Assert.Equal(prepended, "*.test"); 29 } 30 31 [Fact] ValidateDoesNotThrowWhenComparedObjectsAreEqual()32 public void ValidateDoesNotThrowWhenComparedObjectsAreEqual() 33 { 34 object otherObject = new CompareObject("test"); 35 CompareObject currentObject = new CompareObject("test"); 36 ValidationContext testContext = new ValidationContext(otherObject, null, null); 37 38 CompareAttribute attr = new CompareAttribute("CompareProperty"); 39 attr.Validate(currentObject.CompareProperty, testContext); 40 } 41 42 [Fact] ValidateThrowsWhenComparedObjectsAreNotEqual()43 public void ValidateThrowsWhenComparedObjectsAreNotEqual() 44 { 45 CompareObject currentObject = new CompareObject("a"); 46 object otherObject = new CompareObject("b"); 47 48 ValidationContext testContext = new ValidationContext(otherObject, null, null); 49 testContext.DisplayName = "CurrentProperty"; 50 51 CompareAttribute attr = new CompareAttribute("CompareProperty"); 52 Assert.Throws<ValidationException>( 53 delegate { attr.Validate(currentObject.CompareProperty, testContext); }, "'CurrentProperty' and 'CompareProperty' do not match."); 54 } 55 56 [Fact] ValidateThrowsWithOtherPropertyDisplayName()57 public void ValidateThrowsWithOtherPropertyDisplayName() 58 { 59 CompareObject currentObject = new CompareObject("a"); 60 object otherObject = new CompareObject("b"); 61 62 ValidationContext testContext = new ValidationContext(otherObject, null, null); 63 testContext.DisplayName = "CurrentProperty"; 64 65 CompareAttribute attr = new CompareAttribute("ComparePropertyWithDisplayName"); 66 Assert.Throws<ValidationException>( 67 delegate { attr.Validate(currentObject.CompareProperty, testContext); }, "'CurrentProperty' and 'DisplayName' do not match."); 68 } 69 70 [Fact] ValidateUsesSetDisplayName()71 public void ValidateUsesSetDisplayName() 72 { 73 CompareObject currentObject = new CompareObject("a"); 74 object otherObject = new CompareObject("b"); 75 76 ValidationContext testContext = new ValidationContext(otherObject, null, null); 77 testContext.DisplayName = "CurrentProperty"; 78 79 CompareAttribute attr = new CompareAttribute("ComparePropertyWithDisplayName"); 80 attr.OtherPropertyDisplayName = "SetDisplayName"; 81 82 Assert.Throws<ValidationException>( 83 delegate { attr.Validate(currentObject.CompareProperty, testContext); }, "'CurrentProperty' and 'SetDisplayName' do not match."); 84 } 85 86 [Fact] ValidateThrowsWhenPropertyNameIsUnknown()87 public void ValidateThrowsWhenPropertyNameIsUnknown() 88 { 89 CompareObject currentObject = new CompareObject("a"); 90 object otherObject = new CompareObject("b"); 91 92 ValidationContext testContext = new ValidationContext(otherObject, null, null); 93 testContext.DisplayName = "CurrentProperty"; 94 95 CompareAttribute attr = new CompareAttribute("UnknownPropertyName"); 96 Assert.Throws<ValidationException>( 97 () => attr.Validate(currentObject.CompareProperty, testContext), 98 "Could not find a property named UnknownPropertyName." 99 ); 100 } 101 102 [Fact] GetClientValidationRulesReturnsModelClientValidationEqualToRule()103 public void GetClientValidationRulesReturnsModelClientValidationEqualToRule() 104 { 105 Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>(); 106 Mock<ModelMetadata> metadata = new Mock<ModelMetadata>(provider.Object, null, null, typeof(string), null); 107 metadata.Setup(m => m.DisplayName).Returns("CurrentProperty"); 108 109 CompareAttribute attr = new CompareAttribute("CompareProperty"); 110 List<ModelClientValidationRule> ruleList = new List<ModelClientValidationRule>(attr.GetClientValidationRules(metadata.Object, null)); 111 112 Assert.Equal(ruleList.Count, 1); 113 114 ModelClientValidationEqualToRule actualRule = ruleList[0] as ModelClientValidationEqualToRule; 115 116 Assert.Equal("'CurrentProperty' and 'CompareProperty' do not match.", actualRule.ErrorMessage); 117 Assert.Equal("equalto", actualRule.ValidationType); 118 Assert.Equal("*.CompareProperty", actualRule.ValidationParameters["other"]); 119 } 120 121 [Fact] ModelClientValidationEqualToRuleErrorMessageUsesOtherPropertyDisplayName()122 public void ModelClientValidationEqualToRuleErrorMessageUsesOtherPropertyDisplayName() 123 { 124 Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>(); 125 ModelMetadata metadata = new ModelMetadata(provider.Object, typeof(CompareObject), null, typeof(string), null); 126 metadata.DisplayName = "CurrentProperty"; 127 128 CompareAttribute attr = new CompareAttribute("ComparePropertyWithDisplayName"); 129 List<ModelClientValidationRule> ruleList = new List<ModelClientValidationRule>(attr.GetClientValidationRules(metadata, null)); 130 131 Assert.Equal(ruleList.Count, 1); 132 133 ModelClientValidationEqualToRule actualRule = ruleList[0] as ModelClientValidationEqualToRule; 134 135 Assert.Equal("'CurrentProperty' and 'DisplayName' do not match.", actualRule.ErrorMessage); 136 Assert.Equal("equalto", actualRule.ValidationType); 137 Assert.Equal("*.ComparePropertyWithDisplayName", actualRule.ValidationParameters["other"]); 138 } 139 140 [Fact] ModelClientValidationEqualToRuleUsesSetDisplayName()141 public void ModelClientValidationEqualToRuleUsesSetDisplayName() 142 { 143 Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>(); 144 ModelMetadata metadata = new ModelMetadata(provider.Object, typeof(CompareObject), null, typeof(string), null); 145 metadata.DisplayName = "CurrentProperty"; 146 147 CompareAttribute attr = new CompareAttribute("ComparePropertyWithDisplayName"); 148 attr.OtherPropertyDisplayName = "SetDisplayName"; 149 150 List<ModelClientValidationRule> ruleList = new List<ModelClientValidationRule>(attr.GetClientValidationRules(metadata, null)); 151 Assert.Equal(ruleList.Count, 1); 152 ModelClientValidationEqualToRule actualRule = ruleList[0] as ModelClientValidationEqualToRule; 153 154 Assert.Equal("'CurrentProperty' and 'SetDisplayName' do not match.", actualRule.ErrorMessage); 155 } 156 157 [Fact] CompareAttributeCanBeDerivedFromAndOverrideIsValid()158 public void CompareAttributeCanBeDerivedFromAndOverrideIsValid() 159 { 160 object otherObject = new CompareObject("a"); 161 CompareObject currentObject = new CompareObject("b"); 162 ValidationContext testContext = new ValidationContext(otherObject, null, null); 163 164 DerivedCompareAttribute attr = new DerivedCompareAttribute("CompareProperty"); 165 attr.Validate(currentObject.CompareProperty, testContext); 166 } 167 168 private class DerivedCompareAttribute : CompareAttribute 169 { DerivedCompareAttribute(string otherProperty)170 public DerivedCompareAttribute(string otherProperty) 171 : base(otherProperty) 172 { 173 } 174 IsValid(object value)175 public override bool IsValid(object value) 176 { 177 return false; 178 } 179 IsValid(object value, ValidationContext context)180 protected override ValidationResult IsValid(object value, ValidationContext context) 181 { 182 return null; 183 } 184 } 185 186 private class CompareObject 187 { 188 public string CompareProperty { get; set; } 189 190 [Display(Name = "DisplayName")] 191 public string ComparePropertyWithDisplayName { get; set; } 192 CompareObject(string otherValue)193 public CompareObject(string otherValue) 194 { 195 CompareProperty = otherValue; 196 ComparePropertyWithDisplayName = otherValue; 197 } 198 } 199 } 200 } 201