public void BindPropertyDoesNothingIfValueProviderContainsNoEntryForProperty() {
            // Arrange
            MyModel2 model = new MyModel2() { IntReadWrite = 3 };
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ValueProvider = new Dictionary<string, ValueProviderResult>()
            };

            PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicBindProperty(null, bindingContext, pd);

            // Assert
            Assert.AreEqual(3, model.IntReadWrite, "Property should not have been changed.");
        }
        public void BindPropertySetsPropertyToNullIfUserLeftTextEntryFieldBlankForOptionalValue() {
            // Arrange
            MyModel2 model = new MyModel2() { NullableIntReadWrite = 8 };
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "NullableIntReadWrite", null } }
            };

            Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
            mockInnerBinder.Expect(b => b.BindModel(null, It.IsAny<ModelBindingContext>())).Returns((object)null);

            PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["NullableIntReadWrite"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int?), mockInnerBinder.Object }
                }
            };

            // Act
            helper.PublicBindProperty(null, bindingContext, pd);

            // Assert
            Assert.AreEqual(0, bindingContext.ModelState.Count, "Should not have been an error.");
            Assert.AreEqual(null, model.NullableIntReadWrite, "Property should not have been updated.");
        }
        public void OnModelUpdatedDoesNothingIfModelImplementsIDataErrorInfoAndIsValid() {
            // Arrange
            DataErrorInfoProvider model = new DataErrorInfoProvider();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicOnModelUpdated(null, bindingContext);

            // Assert
            Assert.IsTrue(bindingContext.ModelState.IsValidField("themodel"), "ModelState should not have been changed.");
        }
        public void BindPropertyCanUpdateComplexReadOnlyProperties() {
            // Arrange
            // the Customer type contains a single read-only Address property
            Customer model = new Customer();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "Address", null } }
            };

            Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
            mockInnerBinder
                .Expect(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ModelBindingContext bc) {
                        Address address = (Address)bc.Model;
                        address.Street = "1 Microsoft Way";
                        address.Zip = "98052";
                        return address;
                    });

            PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["Address"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper() {
                Binders = new ModelBinderDictionary() {
                    { typeof(Address), mockInnerBinder.Object }
                }
            };

            // Act
            helper.PublicBindProperty(null, bindingContext, pd);

            // Assert
            Assert.AreEqual("1 Microsoft Way", model.Address.Street, "Property should have been updated.");
            Assert.AreEqual("98052", model.Address.Zip, "Property should have been updated.");
        }
        public void CreateInstanceCreatesModelInstanceForGenericIList() {
            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            object modelObj = helper.PublicCreateModel(null, null, typeof(IList<Guid>));

            // Assert
            Assert.IsInstanceOfType(modelObj, typeof(IList<Guid>));
        }
        public void CreateSubPropertyNameReturnsPropertyNameIfPrefixIsNull() {
            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            string newName = helper.PublicCreateSubPropertyName(null, "someProperty");

            // Assert
            Assert.AreEqual("someProperty", newName);
        }
        public void OnPropertyValidatingReturnsFalseIfModelIsAlreadyInvalid() {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelName = "theModel"
            };
            bindingContext.ModelState.AddModelError("themodel.readwriteproperty.stuff", "An error.");

            PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(MyModel))["ReadWriteProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            bool returned = helper.PublicOnPropertyValidating(null, bindingContext, property, null);

            // Assert
            Assert.IsFalse(returned, "Value should not have passed validation.");
            Assert.IsFalse(bindingContext.ModelState.ContainsKey("theModel.ReadWriteProperty"), "Shouldn't have modified ModelState if already contained errors.");
        }
        public void CreateInstanceCreatesModelInstance() {
            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            object modelObj = helper.PublicCreateModel(null, null, typeof(Guid));

            // Assert
            Assert.AreEqual(Guid.Empty, modelObj);
        }
        public void OnPropertyValidatedRecordsErrorIfPropertyImplementsIDataErrorInfoAndIsInvalid() {
            // Arrange
            DataErrorInfoProvider model = new DataErrorInfoProvider();
            model.Errors["readwriteproperty"] = "Some error message.";

            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(MyModel))["ReadWriteProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicOnPropertyValidated(null, bindingContext, property, 42);

            // Assert
            Assert.AreEqual("Some error message.", bindingContext.ModelState["themodel.readwriteproperty"].Errors[0].ErrorMessage);
        }
        public void OnPropertyValidatingReturnsFalseAndCreatesValueRequiredErrorIfNecessary() {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(MyModel))["ReadWriteProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            bool returned = helper.PublicOnPropertyValidating(null, bindingContext, property, null);

            // Assert
            Assert.IsFalse(returned, "Value should not have passed validation.");
            Assert.AreEqual("A value is required.", bindingContext.ModelState["theModel.ReadWriteProperty"].Errors[0].ErrorMessage);
        }
        public void OnPropertyValidatedDoesNothingIfPropertyImplementsIDataErrorInfoAndIsValid() {
            // Arrange
            DataErrorInfoProvider model = new DataErrorInfoProvider();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(MyModel))["ReadWriteProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicOnPropertyValidated(null, bindingContext, property, 42);

            // Assert
            Assert.IsTrue(bindingContext.ModelState.IsValidField("themodel.readwriteproperty"), "ModelState should not have been changed.");
        }
        public void OnModelUpdatingReturnsTrue() {
            // By default, this method does nothing, so we just want to make sure it returns true

            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            bool returned = helper.PublicOnModelUpdating(null, null);

            // Arrange
            Assert.IsTrue(returned);
        }
        public void OnModelUpdatedRecordsErrorIfModelImplementsIDataErrorInfoAndIsInvalid() {
            // Arrange
            DataErrorInfoProvider model = new DataErrorInfoProvider() { ErrorText = "Some error message." };

            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicOnModelUpdated(null, bindingContext);

            // Assert
            Assert.AreEqual("Some error message.", bindingContext.ModelState["themodel"].Errors[0].ErrorMessage);
        }
        public void BindPropertyUpdatesPropertyOnFailureIfInnerBinderReturnsNonNullObject() {
            // Arrange
            MyModel2 model = new MyModel2() { IntReadWriteNonNegative = 8 };
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "IntReadWriteNonNegative", null } }
            };

            Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
            mockInnerBinder
                .Expect(b => b.BindModel(null, It.IsAny<ModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ModelBindingContext bc) {
                        bc.ModelState.AddModelError("IntReadWriteNonNegative", "Some error text.");
                        return 4;
                    });

            PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWriteNonNegative"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int), mockInnerBinder.Object }
                }
            };

            // Act
            helper.PublicBindProperty(null, bindingContext, pd);

            // Assert
            Assert.AreEqual(false, bindingContext.ModelState.IsValidField("IntReadWriteNonNegative"), "Error should have propagated.");
            Assert.AreEqual(1, bindingContext.ModelState["IntReadWriteNonNegative"].Errors.Count, "Wrong number of errors.");
            Assert.AreEqual("Some error text.", bindingContext.ModelState["IntReadWriteNonNegative"].Errors[0].ErrorMessage, "Wrong error text.");
            Assert.AreEqual(4, model.IntReadWriteNonNegative, "Property should have been updated.");
        }
        public void OnPropertyValidatingReturnsTrueOnSuccess() {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(MyModel))["ReadWriteProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            bool returned = helper.PublicOnPropertyValidating(null, bindingContext, property, 42);

            // Assert
            Assert.IsTrue(returned, "Value should have passed validation.");
            Assert.AreEqual(0, bindingContext.ModelState.Count);
        }
        public void BindPropertyUpdatesPropertyOnSuccess() {
            // Arrange
            // Effectively, this is just testing updating a single property named "IntReadWrite"
            ControllerContext controllerContext = new Mock<ControllerContext>().Object;

            MyModel2 model = new MyModel2() { IntReadWrite = 3 };
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "foo",
                ModelState = new ModelStateDictionary() { { "blah", new ModelState() } },
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "foo.IntReadWrite", null } }
            };

            Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
            mockInnerBinder
                .Expect(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ModelBindingContext bc) {
                        Assert.AreEqual(controllerContext, cc, "ControllerContext was not forwarded correctly.");
                        Assert.AreEqual(3, bc.Model, "Original model was not forwarded correctly.");
                        Assert.AreEqual(typeof(int), bc.ModelType, "Model type was not forwarded correctly.");
                        Assert.AreEqual("foo.IntReadWrite", bc.ModelName, "Model name was not forwarded correctly.");
                        Assert.AreEqual(new ModelBindingContext().PropertyFilter, bc.PropertyFilter, "Property filter property should not have been set.");
                        Assert.AreEqual(bindingContext.ModelState, bc.ModelState, "ModelState was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ValueProvider, bc.ValueProvider, "Value provider was not forwarded correctly.");
                        return 4;
                    });

            PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int), mockInnerBinder.Object }
                }
            };

            // Act
            helper.PublicBindProperty(controllerContext, bindingContext, pd);

            // Assert
            Assert.AreEqual(4, model.IntReadWrite, "Property should have been updated.");
        }
        public void SetPropertyCapturesAnyExceptionThrown() {
            // Arrange
            MyModelWithBadPropertySetter model = new MyModelWithBadPropertySetter();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(model)["BadInt"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicSetProperty(null, bindingContext, property, 42);

            // Assert
            Assert.AreEqual(@"No earthly integer is valid for this method.
Parameter name: value", bindingContext.ModelState["theModel.BadInt"].Errors[0].Exception.Message);
        }
        public void CreateInstanceCreatesModelInstanceForGenericIEnumerable() {
            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            object modelObj = helper.PublicCreateModel(null, null, typeof(IEnumerable<Guid>));

            // Assert
            Assert.IsInstanceOfType(modelObj, typeof(ICollection<Guid>), "We must actually create an ICollection<> when asked to create an IEnumerable<>.");
        }
        public void SetPropertyDoesNothingIfPropertyIsReadOnly() {
            // Arrange
            MyModel model = new MyModel();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(model)["ReadOnlyProperty"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicSetProperty(null, bindingContext, property, 42);

            // Assert
            Assert.AreEqual(0, bindingContext.ModelState.Count, "ModelState should remain untouched.");
        }
        public void CreateSubIndexNameReturnsPrefixPlusIndex() {
            // Arrange
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            string newName = helper.PublicCreateSubIndexName("somePrefix", 2);

            // Assert
            Assert.AreEqual("somePrefix[2]", newName);
        }
        public void SetPropertySuccess() {
            // Arrange
            MyModelWithBadPropertySetter model = new MyModelWithBadPropertySetter();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            PropertyDescriptor property = TypeDescriptor.GetProperties(model)["NormalInt"];
            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicSetProperty(null, bindingContext, property, 42);

            // Assert
            Assert.AreEqual(42, model.NormalInt);
            Assert.AreEqual(0, bindingContext.ModelState.Count, "ModelState should remain untouched.");
        }
        public void GetModelPropertiesFiltersNonUpdateableProperties() {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelType = typeof(PropertyTestingModel),
                PropertyFilter = new BindAttribute() { Exclude = "Blacklisted" }.IsPropertyAllowed
            };

            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            PropertyDescriptorCollection properties = helper.PublicGetModelProperties(null, bindingContext);

            // Assert
            Assert.IsNotNull(properties["StringReadWrite"], "StringReadWrite: Read+write string properties are updateable.");
            Assert.IsNull(properties["StringReadOnly"], "StringReadOnly: Read-only string properties are not updateable.");
            Assert.IsNotNull(properties["IntReadWrite"], "IntReadWrite: Read+write ValueType properties are updateable.");
            Assert.IsNull(properties["IntReadOnly"], "IntReadOnly: Read-only string properties are not updateable.");
            Assert.IsNotNull(properties["ArrayReadWrite"], "ArrayReadWrite: Read+write array properties are updateable.");
            Assert.IsNull(properties["ArrayReadOnly"], "ArrayReadOnly: Read-only array properties are not updateable.");
            Assert.IsNotNull(properties["AddressReadWrite"], "AddressReadWrite: Read+write complex properties are updateable.");
            Assert.IsNotNull(properties["AddressReadOnly"], "AddressReadOnly: Read-only complex properties are updateable.");
            Assert.IsNotNull(properties["Whitelisted"], "Whitelisted: Whitelisted properties are updateable.");
            Assert.IsNull(properties["Blacklisted"], "Blacklisted: Blacklisted properties are not updateable.");
            Assert.AreEqual(6, properties.Count, "Incorrect number of properties returned.");
        }
        public void OnModelUpdatedDoesNothingIfModelDoesNotImplementIDataErrorInfo() {
            // Arrange
            MyModel model = new MyModel();
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = "theModel"
            };

            DefaultModelBinderHelper helper = new DefaultModelBinderHelper();

            // Act
            helper.PublicOnModelUpdated(null, bindingContext);

            // Assert
            Assert.IsTrue(bindingContext.ModelState.IsValidField("themodel.readwriteproperty"), "ModelState should not have been changed.");
        }