// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Web.Mvc; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace Microsoft.Web.Mvc.ModelBinding.Test { public class ModelBinderUtilTest { [Fact] public void CastOrDefault_CorrectType_ReturnsInput() { // Act int retVal = ModelBinderUtil.CastOrDefault(42); // Assert Assert.Equal(42, retVal); } [Fact] public void CastOrDefault_IncorrectType_ReturnsDefaultTModel() { // Act DateTime retVal = ModelBinderUtil.CastOrDefault(42); // Assert Assert.Equal(default(DateTime), retVal); } [Fact] public void CreateIndexModelName_EmptyParentName() { // Act string fullChildName = ModelBinderUtil.CreateIndexModelName("", 42); // Assert Assert.Equal("[42]", fullChildName); } [Fact] public void CreateIndexModelName_IntIndex() { // Act string fullChildName = ModelBinderUtil.CreateIndexModelName("parentName", 42); // Assert Assert.Equal("parentName[42]", fullChildName); } [Fact] public void CreateIndexModelName_StringIndex() { // Act string fullChildName = ModelBinderUtil.CreateIndexModelName("parentName", "index"); // Assert Assert.Equal("parentName[index]", fullChildName); } [Fact] public void CreatePropertyModelName() { // Act string fullChildName = ModelBinderUtil.CreatePropertyModelName("parentName", "childName"); // Assert Assert.Equal("parentName.childName", fullChildName); } [Fact] public void CreatePropertyModelName_EmptyParentName() { // Act string fullChildName = ModelBinderUtil.CreatePropertyModelName("", "childName"); // Assert Assert.Equal("childName", fullChildName); } [Fact] public void GetPossibleBinderInstance_Match_ReturnsBinder() { // Act IExtensibleModelBinder binder = ModelBinderUtil.GetPossibleBinderInstance(typeof(List), typeof(List<>), typeof(SampleGenericBinder<>)); // Assert Assert.IsType>(binder); } [Fact] public void GetPossibleBinderInstance_NoMatch_ReturnsNull() { // Act IExtensibleModelBinder binder = ModelBinderUtil.GetPossibleBinderInstance(typeof(ArraySegment), typeof(List<>), typeof(SampleGenericBinder<>)); // Assert Assert.Null(binder); } [Fact] public void RawValueToObjectArray_RawValueIsEnumerable_ReturnsInputAsArray() { // Assert List original = new List { 1, 2, 3, 4 }; // Act object[] retVal = ModelBinderUtil.RawValueToObjectArray(original); // Assert Assert.Equal(new object[] { 1, 2, 3, 4 }, retVal); } [Fact] public void RawValueToObjectArray_RawValueIsObject_WrapsObjectInSingleElementArray() { // Act object[] retVal = ModelBinderUtil.RawValueToObjectArray(42); // Assert Assert.Equal(new object[] { 42 }, retVal); } [Fact] public void RawValueToObjectArray_RawValueIsObjectArray_ReturnsInputInstance() { // Assert object[] original = new object[2]; // Act object[] retVal = ModelBinderUtil.RawValueToObjectArray(original); // Assert Assert.Same(original, retVal); } [Fact] public void RawValueToObjectArray_RawValueIsString_WrapsStringInSingleElementArray() { // Act object[] retVal = ModelBinderUtil.RawValueToObjectArray("hello"); // Assert Assert.Equal(new object[] { "hello" }, retVal); } [Fact] public void ReplaceEmptyStringWithNull_ConvertEmptyStringToNullDisabled_ModelIsEmptyString_LeavesModelAlone() { // Arrange ModelMetadata modelMetadata = GetMetadata(typeof(string)); modelMetadata.ConvertEmptyStringToNull = false; // Act object model = ""; ModelBinderUtil.ReplaceEmptyStringWithNull(modelMetadata, ref model); // Assert Assert.Equal("", model); } [Fact] public void ReplaceEmptyStringWithNull_ConvertEmptyStringToNullEnabled_ModelIsEmptyString_ReplacesModelWithNull() { // Arrange ModelMetadata modelMetadata = GetMetadata(typeof(string)); modelMetadata.ConvertEmptyStringToNull = true; // Act object model = ""; ModelBinderUtil.ReplaceEmptyStringWithNull(modelMetadata, ref model); // Assert Assert.Null(model); } [Fact] public void ReplaceEmptyStringWithNull_ConvertEmptyStringToNullEnabled_ModelIsWhitespaceString_ReplacesModelWithNull() { // Arrange ModelMetadata modelMetadata = GetMetadata(typeof(string)); modelMetadata.ConvertEmptyStringToNull = true; // Act object model = " "; // whitespace ModelBinderUtil.ReplaceEmptyStringWithNull(modelMetadata, ref model); // Assert Assert.Null(model); } [Fact] public void ReplaceEmptyStringWithNull_ConvertEmptyStringToNullDisabled_ModelIsNotEmptyString_LeavesModelAlone() { // Arrange ModelMetadata modelMetadata = GetMetadata(typeof(string)); modelMetadata.ConvertEmptyStringToNull = true; // Act object model = 42; ModelBinderUtil.ReplaceEmptyStringWithNull(modelMetadata, ref model); // Assert Assert.Equal(42, model); } [Fact] public void ValidateBindingContext_SuccessWithNonNullModel() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext { ModelMetadata = GetMetadata(typeof(string)) }; bindingContext.ModelMetadata.Model = "hello!"; // Act ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), false); // Assert // Nothing to do - if we got this far without throwing, the test succeeded } [Fact] public void ValidateBindingContext_SuccessWithNullModel() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext { ModelMetadata = GetMetadata(typeof(string)) }; // Act ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), true); // Assert // Nothing to do - if we got this far without throwing, the test succeeded } [Fact] public void ValidateBindingContextThrowsIfBindingContextIsNull() { // Act & assert Assert.ThrowsArgumentNull( delegate { ModelBinderUtil.ValidateBindingContext(null, typeof(string), true); }, "bindingContext"); } [Fact] public void ValidateBindingContextThrowsIfModelInstanceIsWrongType() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext { ModelMetadata = GetMetadata(typeof(string)) }; bindingContext.ModelMetadata.Model = 42; // Act & assert Assert.Throws( delegate { ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), true); }, @"The binding context has a Model of type 'System.Int32', but this binder can only operate on models of type 'System.String'. Parameter name: bindingContext"); } [Fact] public void ValidateBindingContextThrowsIfModelIsNullButCannotBe() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext { ModelMetadata = GetMetadata(typeof(string)) }; // Act & assert Assert.Throws( delegate { ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), false); }, @"The binding context has a null Model, but this binder requires a non-null model of type 'System.String'. Parameter name: bindingContext"); } [Fact] public void ValidateBindingContextThrowsIfModelMetadataIsNull() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext(); // Act & assert Assert.Throws( delegate { ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), true); }, @"The binding context cannot have a null ModelMetadata. Parameter name: bindingContext"); } [Fact] public void ValidateBindingContextThrowsIfModelTypeIsWrong() { // Arrange ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext { ModelMetadata = GetMetadata(typeof(object)) }; // Act & assert Assert.Throws( delegate { ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(string), true); }, @"The binding context has a ModelType of 'System.Object', but this binder can only operate on models of type 'System.String'. Parameter name: bindingContext"); } private static ModelMetadata GetMetadata(Type modelType) { EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider(); return provider.GetMetadataForType(null, modelType); } private class SampleGenericBinder : IExtensibleModelBinder { public bool BindModel(ControllerContext controllerContext, ExtensibleModelBindingContext bindingContext) { throw new NotImplementedException(); } } } }