public void BindComplexModelCanBindArrays() {
            // Arrange
            ControllerContext controllerContext = new Mock<ControllerContext>().Object;

            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelName = "foo",
                ModelType = typeof(int[]),
                PropertyFilter = _ => false,
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "foo[0]", null }, { "foo[1]", null }, { "foo[2]", 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(typeof(int), bc.ModelType, "ModelType was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ModelState, bc.ModelState, "ModelState was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.PropertyFilter, bc.PropertyFilter, "PropertyFilter was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ValueProvider, bc.ValueProvider, "ValueProvider was not forwarded correctly.");
                        return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture);
                    });

            DefaultModelBinder binder = new DefaultModelBinder() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int), mockInnerBinder.Object }
                }
            };

            // Act
            object newModel = binder.BindComplexModel(controllerContext, bindingContext);

            // Assert
            Assert.IsInstanceOfType(newModel, typeof(int[]));
            int[] newIntArray = (int[])newModel;

            Assert.AreEqual(3, newIntArray.Length, "Model is not of correct length.");
            Assert.AreEqual(0, newIntArray[0]);
            Assert.AreEqual(1, newIntArray[1]);
            Assert.AreEqual(2, newIntArray[2]);
        }
        public void BindComplexModelReturnsNullArrayIfNoValuesProvided() {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelName = "foo",
                ModelType = typeof(int[]),
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "foo", null } }
            };

            Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
            mockInnerBinder
                .Expect(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ModelBindingContext bc) {
                        return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture);
                    });

            DefaultModelBinder binder = new DefaultModelBinder() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int), mockInnerBinder.Object }
                }
            };

            // Act
            object newModel = binder.BindComplexModel(null, bindingContext);

            // Assert
            Assert.IsNull(newModel, "Method should have returned null.");
        }
        public void BindComplexModelWhereModelTypeDoesNotContainBindAttribute() {
            // Arrange
            ControllerContext controllerContext = new Mock<ControllerContext>().Object;

            ModelWithoutBindAttribute model = new ModelWithoutBindAttribute() {
                Foo = "FooPreValue",
                Bar = "BarPreValue",
                Baz = "BazPreValue",
            };
            ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelType = typeof(ModelWithoutBindAttribute),
                ValueProvider = new Dictionary<string, ValueProviderResult>() { { "Foo", null }, { "Bar", 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(bindingContext.ValueProvider, bc.ValueProvider, "Value provider was not forwarded correctly.");
                        return bc.ModelName + "PostValue";
                    });

            DefaultModelBinder binder = new DefaultModelBinder() {
                Binders = new ModelBinderDictionary() {
                    { typeof(string), mockInnerBinder.Object }
                }
            };

            // Act
            binder.BindComplexModel(controllerContext, bindingContext);

            // Assert
            Assert.AreEqual("FooPostValue", model.Foo, "Foo property should have been updated.");
            Assert.AreEqual("BarPostValue", model.Bar, "Bar property should have been updated.");
            Assert.AreEqual("BazPreValue", model.Baz, "Baz property shouldn't have been updated since it wasn't part of the request.");
        }
        public void BindComplexModelCanBindDictionaries() {
            // Arrange
            ControllerContext controllerContext = new Mock<ControllerContext>().Object;

            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelType = typeof(IDictionary<int, string>),
                ModelName = "foo",
                PropertyFilter = _ => false,
                ValueProvider = new Dictionary<string, ValueProviderResult>() {
                    { "foo[0].key", null }, { "foo[0].value", null },
                    { "foo[1].key", null }, { "foo[1].value", null },
                    { "foo[2].key", null }, { "foo[2].value", null }
                }
            };

            Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
            mockIntBinder
                .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(typeof(int), bc.ModelType, "ModelType was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ModelState, bc.ModelState, "ModelState was not forwarded correctly.");
                        Assert.AreEqual(new ModelBindingContext().PropertyFilter, bc.PropertyFilter, "PropertyFilter should not have been set.");
                        Assert.AreEqual(bindingContext.ValueProvider, bc.ValueProvider, "ValueProvider was not forwarded correctly.");
                        return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture) + 10;
                    });

            Mock<IModelBinder> mockStringBinder = new Mock<IModelBinder>();
            mockStringBinder
                .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(typeof(string), bc.ModelType, "ModelType was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ModelState, bc.ModelState, "ModelState was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.PropertyFilter, bc.PropertyFilter, "PropertyFilter was not forwarded correctly.");
                        Assert.AreEqual(bindingContext.ValueProvider, bc.ValueProvider, "ValueProvider was not forwarded correctly.");
                        return (Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture) + 10) + "Value";
                    });

            DefaultModelBinder binder = new DefaultModelBinder() {
                Binders = new ModelBinderDictionary() {
                    { typeof(int), mockIntBinder.Object },
                    { typeof(string), mockStringBinder.Object }
                }
            };

            // Act
            object newModel = binder.BindComplexModel(controllerContext, bindingContext);

            // Assert
            Assert.IsInstanceOfType(newModel, typeof(IDictionary<int, string>));
            IDictionary<int, string> modelAsDictionary = (IDictionary<int, string>)newModel;

            Assert.AreEqual(3, modelAsDictionary.Count, "Model is not of correct length.");
            Assert.AreEqual("10Value", modelAsDictionary[10]);
            Assert.AreEqual("11Value", modelAsDictionary[11]);
            Assert.AreEqual("12Value", modelAsDictionary[12]);
        }