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 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 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 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.");
        }