public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            Person model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(model)
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(new DateTime(1800, 1, 1), validationNode);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(null, bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
                       + "Parameter name: value",
                         bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
        public void ProcessDto_RequiredFieldNull_RaisesModelErrorWithMessage()
        {
            // Arrange
            Person model = new Person();
            ModelMetadata containerMetadata = GetMetadataForObject(model);
            HttpActionContext context = ContextUtil.CreateActionContext();

            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = containerMetadata,
                ModelName = "theModel"
            };

            ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

            // Make ValueTypeRequired invalid.
            ModelMetadata propertyMetadata = dto.PropertyMetadata.Single(p => p.PropertyName == "ValueTypeRequired");
            dto.Results[propertyMetadata] =
                new ComplexModelDtoResult(null, new ModelValidationNode(propertyMetadata, "theModel.ValueTypeRequired"));

            // Act
            testableBinder.ProcessDto(context, bindingContext, dto);

            // Assert
            ModelStateDictionary modelStateDictionary = bindingContext.ModelState;
            Assert.False(modelStateDictionary.IsValid);
            Assert.Equal(1, modelStateDictionary.Count);

            // Check ValueTypeRequired error.
            ModelState modelState;
            Assert.True(modelStateDictionary.TryGetValue("theModel.ValueTypeRequired", out modelState));
            Assert.Equal(1, modelState.Errors.Count);

            ModelError modelError = modelState.Errors[0];
            Assert.Null(modelError.Exception);
            Assert.NotNull(modelError.ErrorMessage);
            Assert.Equal("Sample message", modelError.ErrorMessage);
        }
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            Person model = new Person();
            HttpActionContext context = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(model)
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode);
            ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            validationNode.Validate(context);
            Assert.True(context.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
        public void ProcessDto_RequiredFieldMissing_RaisesModelErrorWithMessage()
        {
            // Arrange
            Person model = new Person();
            ModelMetadata containerMetadata = GetMetadataForObject(model);
            HttpActionContext context = ContextUtil.CreateActionContext();

            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = containerMetadata,
                ModelName = "theModel"
            };

            // Set no properties though ValueTypeRequired (a non-Nullable struct) property is required.
            ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.ProcessDto(context, bindingContext, dto);

            // Assert
            ModelStateDictionary modelStateDictionary = bindingContext.ModelState;
            Assert.False(modelStateDictionary.IsValid);
            Assert.Equal(1, modelStateDictionary.Count);

            // Check ValueTypeRequired error.
            ModelState modelState;
            Assert.True(modelStateDictionary.TryGetValue("theModel.ValueTypeRequired", out modelState));
            Assert.Equal(1, modelState.Errors.Count);

            ModelError modelError = modelState.Errors[0];
            Assert.Null(modelError.Exception);
            Assert.NotNull(modelError.ErrorMessage);
            Assert.Equal("Sample message", modelError.ErrorMessage);
        }