Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

392 lines
15 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace Microsoft.Web.Mvc.ModelBinding.Test
{
public class ModelValidationNodeTest
{
[Fact]
public void ConstructorSetsCollectionInstance()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
string modelStateKey = "someKey";
ModelValidationNode[] childNodes = new[]
{
new ModelValidationNode(metadata, "someKey0"),
new ModelValidationNode(metadata, "someKey1")
};
// Act
ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey, childNodes);
// Assert
Assert.Equal(childNodes, node.ChildNodes.ToArray());
}
[Fact]
public void ConstructorThrowsIfModelMetadataIsNull()
{
// Act & assert
Assert.ThrowsArgumentNull(
delegate { new ModelValidationNode(null, "someKey"); }, "modelMetadata");
}
[Fact]
public void ConstructorThrowsIfModelStateKeyIsNull()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
// Act & assert
Assert.ThrowsArgumentNull(
delegate { new ModelValidationNode(metadata, null); }, "modelStateKey");
}
[Fact]
public void PropertiesAreSet()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
string modelStateKey = "someKey";
// Act
ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey);
// Assert
Assert.Equal(metadata, node.ModelMetadata);
Assert.Equal(modelStateKey, node.ModelStateKey);
Assert.NotNull(node.ChildNodes);
Assert.Empty(node.ChildNodes);
}
[Fact]
public void CombineWith()
{
// Arrange
List<string> log = new List<string>();
ModelValidationNode[] allChildNodes = new[]
{
new ModelValidationNode(GetModelMetadata(), "key1"),
new ModelValidationNode(GetModelMetadata(), "key2"),
new ModelValidationNode(GetModelMetadata(), "key3"),
};
ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
parentNode1.ChildNodes.Add(allChildNodes[0]);
parentNode1.Validating += delegate { log.Add("Validating parent1."); };
parentNode1.Validated += delegate { log.Add("Validated parent1."); };
ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
parentNode2.ChildNodes.Add(allChildNodes[1]);
parentNode2.ChildNodes.Add(allChildNodes[2]);
parentNode2.Validating += delegate { log.Add("Validating parent2."); };
parentNode2.Validated += delegate { log.Add("Validated parent2."); };
// Act
parentNode1.CombineWith(parentNode2);
parentNode1.Validate(new ControllerContext { Controller = new EmptyController() });
// Assert
Assert.Equal(new[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." }, log.ToArray());
Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
}
[Fact]
public void CombineWith_OtherNodeIsSuppressed_DoesNothing()
{
// Arrange
List<string> log = new List<string>();
ModelValidationNode[] allChildNodes = new[]
{
new ModelValidationNode(GetModelMetadata(), "key1"),
new ModelValidationNode(GetModelMetadata(), "key2"),
new ModelValidationNode(GetModelMetadata(), "key3"),
};
ModelValidationNode[] expectedChildNodes = new[]
{
allChildNodes[0]
};
ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
parentNode1.ChildNodes.Add(allChildNodes[0]);
parentNode1.Validating += delegate { log.Add("Validating parent1."); };
parentNode1.Validated += delegate { log.Add("Validated parent1."); };
ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
parentNode2.ChildNodes.Add(allChildNodes[1]);
parentNode2.ChildNodes.Add(allChildNodes[2]);
parentNode2.Validating += delegate { log.Add("Validating parent2."); };
parentNode2.Validated += delegate { log.Add("Validated parent2."); };
parentNode2.SuppressValidation = true;
// Act
parentNode1.CombineWith(parentNode2);
parentNode1.Validate(new ControllerContext { Controller = new EmptyController() });
// Assert
Assert.Equal(new[] { "Validating parent1.", "Validated parent1." }, log.ToArray());
Assert.Equal(expectedChildNodes, parentNode1.ChildNodes.ToArray());
}
[Fact]
public void Validate_Ordering()
{
// Proper order of invocation:
// 1. OnValidating()
// 2. Child validators
// 3. This validator
// 4. OnValidated()
// Arrange
List<string> log = new List<string>();
LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));
node.Validating += delegate { log.Add("In OnValidating()"); };
node.Validated += delegate { log.Add("In OnValidated()"); };
// Act
node.Validate(controllerContext);
// Assert
Assert.Equal(new[] { "In OnValidating()", "In IDataErrorInfo.get_Item('ValidStringProperty')", "In IDataErrorInfo.get_Error()", "In OnValidated()" }, log.ToArray());
}
[Fact]
public void Validate_PassesNullContainerInstanceIfCannotBeConvertedToProperType()
{
// Arrange
List<string> log1 = new List<string>();
LoggingDataErrorInfoModel model1 = new LoggingDataErrorInfoModel(log1);
ModelMetadata modelMetadata1 = GetModelMetadata(model1);
List<string> log2 = new List<string>();
LoggingDataErrorInfoModel model2 = new LoggingDataErrorInfoModel(log2);
ModelMetadata modelMetadata2 = GetModelMetadata(model2);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata1, "theKey");
node.ChildNodes.Add(new ModelValidationNode(modelMetadata2, "theKey.SomeProperty"));
// Act
node.Validate(controllerContext);
// Assert
Assert.Equal(new[] { "In IDataErrorInfo.get_Error()" }, log1.ToArray());
Assert.Equal(new[] { "In IDataErrorInfo.get_Error()" }, log2.ToArray());
}
[Fact]
public void Validate_SkipsRemainingValidationIfModelStateIsInvalid()
{
// Because a property validator fails, the model validator shouldn't run
// Arrange
List<string> log = new List<string>();
LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));
node.Validating += delegate { log.Add("In OnValidating()"); };
node.Validated += delegate { log.Add("In OnValidated()"); };
// Act
node.Validate(controllerContext);
// Assert
Assert.Equal(new[] { "In OnValidating()", "In IDataErrorInfo.get_Item('InvalidStringProperty')", "In OnValidated()" }, log.ToArray());
Assert.Equal("Sample error message", controllerContext.Controller.ViewData.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
}
[Fact]
public void Validate_SkipsValidationIfHandlerCancels()
{
// Arrange
List<string> log = new List<string>();
LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
node.Validating += (sender, e) =>
{
log.Add("In OnValidating()");
e.Cancel = true;
};
node.Validated += delegate { log.Add("In OnValidated()"); };
// Act
node.Validate(controllerContext);
// Assert
Assert.Equal(new[] { "In OnValidating()" }, log.ToArray());
}
[Fact]
public void Validate_SkipsValidationIfSuppressed()
{
// Arrange
List<string> log = new List<string>();
LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
{
SuppressValidation = true
};
node.Validating += (sender, e) => { log.Add("In OnValidating()"); };
node.Validated += delegate { log.Add("In OnValidated()"); };
// Act
node.Validate(controllerContext);
// Assert
Assert.Empty(log);
}
[Fact]
public void Validate_ThrowsIfControllerContextIsNull()
{
// Arrange
ModelValidationNode node = new ModelValidationNode(GetModelMetadata(), "someKey");
// Act & assert
Assert.ThrowsArgumentNull(
delegate { node.Validate(null); }, "controllerContext");
}
[Fact]
public void Validate_ValidateAllProperties_AddsValidationErrors()
{
// Arrange
ValidateAllPropertiesModel model = new ValidateAllPropertiesModel
{
RequiredString = null /* error */,
RangedInt = 0 /* error */,
ValidString = "dog"
};
ModelMetadata modelMetadata = GetModelMetadata(model);
ControllerContext controllerContext = new ControllerContext
{
Controller = new EmptyController()
};
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
{
ValidateAllProperties = true
};
controllerContext.Controller.ViewData.ModelState.AddModelError("theKey.RequiredString.Dummy", "existing Error Text");
// Act
node.Validate(controllerContext);
// Assert
Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey.RequiredString"]);
Assert.Equal("existing Error Text", controllerContext.Controller.ViewData.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
Assert.Equal("The field RangedInt must be between 10 and 30.", controllerContext.Controller.ViewData.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey.ValidString"]);
Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey"]);
}
private static ModelMetadata GetModelMetadata()
{
EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
return provider.GetMetadataForType(null, typeof(object));
}
private static ModelMetadata GetModelMetadata(object o)
{
DataAnnotationsModelMetadataProvider provider = new DataAnnotationsModelMetadataProvider();
return provider.GetMetadataForType(() => o, o.GetType());
}
private sealed class EmptyController : Controller
{
}
private sealed class LoggingDataErrorInfoModel : IDataErrorInfo
{
private readonly IList<string> _log;
public LoggingDataErrorInfoModel(IList<string> log)
{
_log = log;
}
string IDataErrorInfo.Error
{
get
{
_log.Add("In IDataErrorInfo.get_Error()");
return null;
}
}
string IDataErrorInfo.this[string columnName]
{
get
{
_log.Add("In IDataErrorInfo.get_Item('" + columnName + "')");
return (columnName == "ValidStringProperty") ? null : "Sample error message";
}
}
public string ValidStringProperty { get; set; }
public string InvalidStringProperty { get; set; }
}
private class ValidateAllPropertiesModel
{
[Required]
public string RequiredString { get; set; }
[Range(10, 30)]
public int RangedInt { get; set; }
[RegularExpression("dog")]
public string ValidString { get; set; }
}
}
}